From 9f0600856530b16c4762e774cdc6ad5d545a8436 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 4 Feb 2019 22:51:25 -0600 Subject: [PATCH 01/16] Translate several functions in output.F90 to C++ --- include/openmc/output.h | 40 +++++--- src/initialize.cpp | 2 - src/input_xml.F90 | 1 - src/output.F90 | 206 ---------------------------------------- src/output.cpp | 170 +++++++++++++++++++++++++++++++-- src/simulation.cpp | 3 - 6 files changed, 191 insertions(+), 231 deletions(-) diff --git a/include/openmc/output.h b/include/openmc/output.h index 6c8226c65..5c7ebcd59 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -10,42 +10,56 @@ namespace openmc { -//============================================================================== +//! \brief Display the main title banner as well as information about the +//! program developers, version, and date/time which the problem was run. + +void title(); + //! Display a header block. -//! +// //! \param msg The main text of the header //! \param level The lowest verbosity level at which this header is printed -//============================================================================== void header(const char* msg, int level); -//============================================================================== //! Retrieve a time stamp. -//! +// //! \return current time stamp (format: "yyyy-mm-dd hh:mm:ss") -//============================================================================== std::string time_stamp(); -//============================================================================== //! Display the attributes of a particle. -//============================================================================== extern "C" void print_particle(Particle* p); -//============================================================================== //! Display plot information. -//============================================================================== void print_plot(); -//============================================================================== //! Display information regarding cell overlap checking. -//============================================================================== void print_overlap_check(); -extern "C" void title(); +//! Display information about command line usage of OpenMC + +void print_usage(); + +//! Display current version and copright/license information + +void print_version(); + +//! Display header listing what physical values will displayed + +void print_columns(); + +//! Display information about a generation of neutrons + +void print_generation(); + +//! \brief Display last batch's tallied value of the neutron multiplication +//! factor as well as the average value if we're in active batches + +void print_batch_keff(); } // namespace openmc #endif // OPENMC_OUTPUT_H diff --git a/src/initialize.cpp b/src/initialize.cpp index 69986fdc0..e454917d0 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -30,8 +30,6 @@ #include "openmc/timer.h" // data/functions from Fortran side -extern "C" void print_usage(); -extern "C" void print_version(); extern "C" void read_command_line(); extern "C" void read_geometry_xml(); extern "C" void read_materials_xml(); diff --git a/src/input_xml.F90 b/src/input_xml.F90 index d78135d77..1e2a03a45 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -17,7 +17,6 @@ module input_xml use message_passing use mgxs_interface use nuclide_header - use output, only: title, header use photon_header use random_lcg, only: prn use surface_header diff --git a/src/output.F90 b/src/output.F90 index 90d98526e..3f864536f 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -45,73 +45,6 @@ module output contains -!=============================================================================== -! TITLE prints the main title banner as well as information about the program -! developers, version, and date/time which the problem was run. -!=============================================================================== - - subroutine title() bind(C) - -#ifdef _OPENMP - use omp_lib -#endif - - write(UNIT=OUTPUT_UNIT, FMT='(/23(A/))') & - ' %%%%%%%%%%%%%%%', & - ' %%%%%%%%%%%%%%%%%%%%%%%%', & - ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%', & - ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%', & - ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%', & - ' %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%', & - ' %%%%%%%%%%%%%%%%%%%%%%%%', & - ' %%%%%%%%%%%%%%%%%%%%%%%%', & - ' ############### %%%%%%%%%%%%%%%%%%%%%%%%', & - ' ################## %%%%%%%%%%%%%%%%%%%%%%%', & - ' ################### %%%%%%%%%%%%%%%%%%%%%%%', & - ' #################### %%%%%%%%%%%%%%%%%%%%%%', & - ' ##################### %%%%%%%%%%%%%%%%%%%%%', & - ' ###################### %%%%%%%%%%%%%%%%%%%%', & - ' ####################### %%%%%%%%%%%%%%%%%%', & - ' ####################### %%%%%%%%%%%%%%%%%', & - ' ###################### %%%%%%%%%%%%%%%%%', & - ' #################### %%%%%%%%%%%%%%%%%', & - ' ################# %%%%%%%%%%%%%%%%%', & - ' ############### %%%%%%%%%%%%%%%%', & - ' ############ %%%%%%%%%%%%%%%', & - ' ######## %%%%%%%%%%%%%%', & - ' %%%%%%%%%%%' - - ! Write version information - write(UNIT=OUTPUT_UNIT, FMT=*) & - ' | The OpenMC Monte Carlo Code' - write(UNIT=OUTPUT_UNIT, FMT=*) & - ' Copyright | 2011-2018 MIT and OpenMC contributors' - write(UNIT=OUTPUT_UNIT, FMT=*) & - ' License | http://openmc.readthedocs.io/en/latest/license.html' - write(UNIT=OUTPUT_UNIT, FMT='(11X,"Version | ",I1,".",I2,".",I1)') & - VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE -#ifdef GIT_SHA1 - write(UNIT=OUTPUT_UNIT, FMT='(10X,"Git SHA1 | ",A)') GIT_SHA1 -#endif - - ! Write the date and time - write(UNIT=OUTPUT_UNIT, FMT='(9X,"Date/Time | ",A)') time_stamp() - -#ifdef OPENMC_MPI - ! Write number of processors - write(UNIT=OUTPUT_UNIT, FMT='(5X,"MPI Processes | ",A)') & - trim(to_str(n_procs)) -#endif - -#ifdef _OPENMP - ! Write number of OpenMP threads - write(UNIT=OUTPUT_UNIT, FMT='(4X,"OpenMP Threads | ",A)') & - trim(to_str(omp_get_max_threads())) -#endif - write(UNIT=OUTPUT_UNIT, FMT=*) - - end subroutine title - !=============================================================================== ! TIME_STAMP returns the current date and time in a formatted string !=============================================================================== @@ -166,145 +99,6 @@ contains end subroutine header -!=============================================================================== -! PRINT_VERSION shows the current version as well as copright and license -! information -!=============================================================================== - - subroutine print_version() bind(C) - - if (master) then - write(UNIT=OUTPUT_UNIT, FMT='(1X,A,1X,I1,".",I2,".",I1)') & - "OpenMC version", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE -#ifdef GIT_SHA1 - write(UNIT=OUTPUT_UNIT, FMT='(1X,A,A)') "Git SHA1: ", GIT_SHA1 -#endif - write(UNIT=OUTPUT_UNIT, FMT=*) "Copyright (c) 2011-2018 & - &Massachusetts Institute of Technology and OpenMC contributors" - write(UNIT=OUTPUT_UNIT, FMT=*) "MIT/X license at & - &" - end if - - end subroutine print_version - -!=============================================================================== -! PRINT_USAGE displays information about command line usage of OpenMC -!=============================================================================== - - subroutine print_usage() bind(C) - - if (master) then - write(OUTPUT_UNIT,*) 'Usage: openmc [options] [directory]' - write(OUTPUT_UNIT,*) - write(OUTPUT_UNIT,*) 'Options:' - write(OUTPUT_UNIT,*) ' -c, --volume Run in stochastic volume calculation mode' - write(OUTPUT_UNIT,*) ' -g, --geometry-debug Run with geometry debugging on' - write(OUTPUT_UNIT,*) ' -n, --particles Number of particles per generation' - write(OUTPUT_UNIT,*) ' -p, --plot Run in plotting mode' - write(OUTPUT_UNIT,*) ' -r, --restart Restart a previous run from a state point' - write(OUTPUT_UNIT,*) ' or a particle restart file' - write(OUTPUT_UNIT,*) ' -s, --threads Number of OpenMP threads' - write(OUTPUT_UNIT,*) ' -t, --track Write tracks for all particles' - write(OUTPUT_UNIT,*) ' -v, --version Show version information' - write(OUTPUT_UNIT,*) ' -h, --help Show this message' - end if - - end subroutine print_usage - -!=============================================================================== -! PRINT_COLUMNS displays a header listing what physical values will displayed -! below them -!=============================================================================== - - subroutine print_columns() bind(C) - - write(UNIT=ou, FMT='(2X,A9,3X)', ADVANCE='NO') "Bat./Gen." - write(UNIT=ou, FMT='(A8,3X)', ADVANCE='NO') " k " - if (entropy_on) write(UNIT=ou, FMT='(A8,3X)', ADVANCE='NO') "Entropy " - write(UNIT=ou, FMT='(A20,3X)', ADVANCE='NO') " Average k " - write(UNIT=ou, FMT=*) - - write(UNIT=ou, FMT='(2X,A9,3X)', ADVANCE='NO') "=========" - write(UNIT=ou, FMT='(A8,3X)', ADVANCE='NO') "========" - if (entropy_on) write(UNIT=ou, FMT='(A8,3X)', ADVANCE='NO') "========" - write(UNIT=ou, FMT='(A20,3X)', ADVANCE='NO') "====================" - write(UNIT=ou, FMT=*) - - end subroutine print_columns - -!=============================================================================== -! PRINT_GENERATION displays information for a generation of neutrons. -!=============================================================================== - - subroutine print_generation() bind(C) - - integer :: i ! overall generation - integer :: n ! number of active generations - - ! Determine overall generation and number of active generations - i = overall_generation() - if (current_batch > n_inactive) then - n = gen_per_batch*n_realizations + current_gen - else - n = 0 - end if - - ! write out information about batch and generation - write(UNIT=OUTPUT_UNIT, FMT='(2X,A9)', ADVANCE='NO') & - trim(to_str(current_batch)) // "/" // trim(to_str(current_gen)) - write(UNIT=OUTPUT_UNIT, FMT='(3X,F8.5)', ADVANCE='NO') k_generation(i) - - ! write out entropy info - if (entropy_on) write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5)', ADVANCE='NO') & - entropy(i) - - if (n > 1) then - write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5," +/-",F8.5)', ADVANCE='NO') & - keff, keff_std - end if - - ! next line - write(UNIT=OUTPUT_UNIT, FMT=*) - - end subroutine print_generation - -!=============================================================================== -! PRINT_BATCH_KEFF displays the last batch's tallied value of the neutron -! multiplication factor as well as the average value if we're in active batches -!=============================================================================== - - subroutine print_batch_keff() bind(C) - - integer :: i ! overall generation - integer :: n ! number of active generations - - ! Determine overall generation and number of active generations - i = current_batch*gen_per_batch - n = n_realizations*gen_per_batch - - ! write out information batch and option independent output - write(UNIT=OUTPUT_UNIT, FMT='(2X,A9)', ADVANCE='NO') & - trim(to_str(current_batch)) // "/" // trim(to_str(gen_per_batch)) - write(UNIT=OUTPUT_UNIT, FMT='(3X,F8.5)', ADVANCE='NO') & - k_generation(i) - - ! write out entropy info - if (entropy_on) write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5)', ADVANCE='NO') & - entropy(i) - - ! write out accumulated k-effective if after first active batch - if (n > 1) then - write(UNIT=OUTPUT_UNIT, FMT='(3X, F8.5," +/-",F8.5)', ADVANCE='NO') & - keff, keff_std - else - write(UNIT=OUTPUT_UNIT, FMT='(23X)', ADVANCE='NO') - end if - - ! next line - write(UNIT=OUTPUT_UNIT, FMT=*) - - end subroutine print_batch_keff - !=============================================================================== ! PRINT_RUNTIME displays the total time elapsed for the entire run, for ! initialization, for computation, and for intergeneration synchronization. diff --git a/src/output.cpp b/src/output.cpp index 16b96d4be..0c9d35cef 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -7,20 +7,79 @@ #include #include +#include + #include "openmc/capi.h" #include "openmc/cell.h" #include "openmc/constants.h" +#include "openmc/eigenvalue.h" #include "openmc/geometry.h" #include "openmc/lattice.h" #include "openmc/message_passing.h" #include "openmc/plot.h" #include "openmc/settings.h" +#include "openmc/simulation.h" #include "openmc/surface.h" namespace openmc { //============================================================================== +void title() +{ + std::cout << + " %%%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%%%%%%%%%%%%%%\n" << + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n" << + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n" << + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n" << + " #################### %%%%%%%%%%%%%%%%%%%%%%\n" << + " ##################### %%%%%%%%%%%%%%%%%%%%%\n" << + " ###################### %%%%%%%%%%%%%%%%%%%%\n" << + " ####################### %%%%%%%%%%%%%%%%%%\n" << + " ####################### %%%%%%%%%%%%%%%%%\n" << + " ###################### %%%%%%%%%%%%%%%%%\n" << + " #################### %%%%%%%%%%%%%%%%%\n" << + " ################# %%%%%%%%%%%%%%%%%\n" << + " ############### %%%%%%%%%%%%%%%%\n" << + " ############ %%%%%%%%%%%%%%%\n" << + " ######## %%%%%%%%%%%%%%\n" << + " %%%%%%%%%%%\n"; + + // Write version information + std::cout << + " | The OpenMC Monte Carlo Code\n" << + " Copyright | 2011-2019 MIT and OpenMC contributors\n" << + " License | http://openmc.readthedocs.io/en/latest/license.html\n" << + " Version | " << VERSION_MAJOR << '.' << VERSION_MINOR << '.' + << VERSION_RELEASE << '\n'; +#ifdef GIT_SHA1 + std::cout << " Git SHA1 | " << GIT_SHA1 << '\n'; +#endif + + // Write the date and time + std::cout << " Date/Time | " << time_stamp() << '\n'; + +#ifdef OPENMC_MPI + // Write number of processors + std::cout << " MPI Processes | " << mpi::n_procs << '\n'; +#endif + +#ifdef _OPENMP + // Write number of OpenMP threads + std::cout << " OpenMC Threads | " << omp_get_max_threads() << '\n'; +#endif + std::cout << '\n'; +} + +//============================================================================== + void header(const char* msg, int level) { // Determine how many times to repeat the '=' character. @@ -49,13 +108,9 @@ header(const char* msg, int level) { std::string time_stamp() { - int base_year = 1990; std::stringstream ts; - std::time_t t = std::time(0); // get time now - std::tm* now = std::localtime(&t); - ts << now->tm_year + base_year << "-" << now->tm_mon - << "-" << now->tm_mday << " " << now->tm_hour - << ":" << now->tm_min << ":" << now->tm_sec; + std::time_t t = std::time(nullptr); // get time now + ts << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S"); return ts.str(); } @@ -230,4 +285,107 @@ print_overlap_check() } } +//============================================================================== + +void print_usage() +{ + if (mpi::master) { + std::cout << + "Usage: openmc [options] [directory]\n\n" + "Options:\n" + " -c, --volume Run in stochastic volume calculation mode\n" + " -g, --geometry-debug Run with geometry debugging on\n" + " -n, --particles Number of particles per generation\n" + " -p, --plot Run in plotting mode\n" + " -r, --restart Restart a previous run from a state point\n" + " or a particle restart file\n" + " -s, --threads Number of OpenMP threads\n" + " -t, --track Write tracks for all particles\n" + " -v, --version Show version information\n" + " -h, --help Show this message\n"; + } +} + +//============================================================================== + +void print_version() +{ + if (mpi::master) { + std::cout << "OpenMC version " << VERSION_MAJOR << '.' << VERSION_MINOR + << '.' << VERSION_RELEASE << '\n'; +#ifdef GIT_SHA1 + std::cout << "Git SHA1: " << GIT_SHA1 << '\n'; +#endif + std::cout << "Copyright (c) 2011-2019 Massachusetts Institute of " + "Technology and OpenMC contributors\nMIT/X license at " + "\n"; + } +} + +//============================================================================== + +void print_columns() +{ + if (settings::entropy_on) { + std::cout << + " Bat./Gen. k Entropy Average k \n" + " ========= ======== ======== ====================\n"; + } else { + std::cout << + " Bat./Gen. k Average k\n" + " ========= ======== ====================\n"; + } +} + +//============================================================================== + +void print_generation() +{ + // Determine overall generation and number of active generations + int i = overall_generation() - 1; + int n = simulation::current_batch > settings::n_inactive ? + settings::gen_per_batch*n_realizations + simulation::current_gen : 0; + + // write out information batch and option independent output + std::cout << " " << std::setw(9) << std::to_string(simulation::current_batch) + + "/" + std::to_string(simulation::current_gen) << " " << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::k_generation[i]; + + // write out entropy info + if (settings::entropy_on) std::cout << " " << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::entropy[i]; + + if (n > 1) { + std::cout << " " << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff << " +/-" << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff_std; + } + std::cout << '\n'; +} + +//============================================================================== + +void print_batch_keff() +{ + // Determine overall generation and number of active generations + int i = simulation::current_batch*settings::gen_per_batch - 1; + int n = n_realizations*settings::gen_per_batch; + + // write out information batch and option independent output + std::cout << " " << std::setw(9) << std::to_string(simulation::current_batch) + + "/" + std::to_string(settings::gen_per_batch) << " " << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::k_generation[i]; + + // write out entropy info + if (settings::entropy_on) std::cout << " " << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::entropy[i]; + + if (n > 1) { + std::cout << " " << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff << " +/-" << + std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff_std; + } + std::cout << '\n'; +} + } // namespace openmc diff --git a/src/simulation.cpp b/src/simulation.cpp index dd1a2c2a7..7f4f0dc03 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -31,9 +31,6 @@ extern "C" void allocate_tally_results(); extern "C" void check_triggers(); extern "C" void init_tally_routines(); extern "C" void load_state_point(); -extern "C" void print_batch_keff(); -extern "C" void print_columns(); -extern "C" void print_generation(); extern "C" void print_results(); extern "C" void print_runtime(); extern "C" void setup_active_tallies(); From a7b0babb96004c1b7e0e2437ae5f9d782102d91e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Feb 2019 08:17:56 -0600 Subject: [PATCH 02/16] Translate print_runtime to C++ --- include/openmc/output.h | 4 ++ src/output.F90 | 77 ----------------------- src/output.cpp | 135 +++++++++++++++++++++++++++++++++++----- src/simulation.cpp | 1 - 4 files changed, 124 insertions(+), 93 deletions(-) diff --git a/include/openmc/output.h b/include/openmc/output.h index 5c7ebcd59..c80ca1167 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -61,5 +61,9 @@ void print_generation(); void print_batch_keff(); +//! Display time elapsed for various stages of a run + +void print_runtime(); + } // namespace openmc #endif // OPENMC_OUTPUT_H diff --git a/src/output.F90 b/src/output.F90 index 3f864536f..78e784220 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -31,12 +31,6 @@ module output integer :: eu = ERROR_UNIT interface - function entropy(i) result(h) bind(C, name='entropy_c') - import C_INT, C_DOUBLE - integer(C_INT), value :: i - real(C_DOUBLE) :: h - end function - subroutine print_particle(p) bind(C) import Particle type(Particle), intent(in) :: p @@ -99,77 +93,6 @@ contains end subroutine header -!=============================================================================== -! PRINT_RUNTIME displays the total time elapsed for the entire run, for -! initialization, for computation, and for intergeneration synchronization. -!=============================================================================== - - subroutine print_runtime() bind(C) - - integer :: n_active - real(8) :: speed_inactive ! # of neutrons/second in inactive batches - real(8) :: speed_active ! # of neutrons/second in active batches - character(15) :: string - - ! display header block - call header("Timing Statistics", 6) - - ! display time elapsed for various sections - write(ou,100) "Total time for initialization", time_initialize_elapsed() - write(ou,100) " Reading cross sections", time_read_xs_elapsed() - write(ou,100) "Total time in simulation", time_inactive_elapsed() + & - time_active_elapsed() - write(ou,100) " Time in transport only", time_transport_elapsed() - if (run_mode == MODE_EIGENVALUE) then - write(ou,100) " Time in inactive batches", time_inactive_elapsed() - end if - write(ou,100) " Time in active batches", time_active_elapsed() - if (run_mode == MODE_EIGENVALUE) then - write(ou,100) " Time synchronizing fission bank", time_bank_elapsed() - write(ou,100) " Sampling source sites", time_bank_sample_elapsed() - write(ou,100) " SEND/RECV source sites", time_bank_sendrecv_elapsed() - end if - write(ou,100) " Time accumulating tallies", time_tallies_elapsed() - write(ou,100) "Total time for finalization", time_finalize_elapsed() - write(ou,100) "Total time elapsed", time_total_elapsed() - - ! Calculate particle rate in active/inactive batches - n_active = current_batch - n_inactive - if (restart_run) then - if (restart_batch < n_inactive) then - speed_inactive = real(n_particles * (n_inactive - restart_batch) * & - gen_per_batch) / time_inactive_elapsed() - speed_active = real(n_particles * n_active * gen_per_batch) / & - time_active_elapsed() - else - speed_inactive = ZERO - speed_active = real(n_particles * (n_batches - restart_batch) * & - gen_per_batch) / time_active_elapsed() - end if - else - if (n_inactive > 0) then - speed_inactive = real(n_particles * n_inactive * gen_per_batch) / & - time_inactive_elapsed() - end if - speed_active = real(n_particles * n_active * gen_per_batch) / & - time_active_elapsed() - end if - - ! display calculation rate - if (.not. (restart_run .and. (restart_batch >= n_inactive)) & - .and. n_inactive > 0) then - string = to_str(speed_inactive) - write(ou,101) "Calculation Rate (inactive)", trim(string) - end if - string = to_str(speed_active) - write(ou,101) "Calculation Rate (active)", trim(string) - - ! format for write statements -100 format (1X,A,T36,"= ",ES11.4," seconds") -101 format (1X,A,T36,"= ",A," particles/second") - - end subroutine print_runtime - !=============================================================================== ! PRINT_RESULTS displays various estimates of k-effective as well as the global ! leakage rate. diff --git a/src/output.cpp b/src/output.cpp index 0c9d35cef..39ebf0dce 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -2,7 +2,8 @@ #include // for std::transform #include // for strlen -#include // for setw +#include // for setw, setprecision +#include // for fixed, scientific, left #include #include #include @@ -20,6 +21,7 @@ #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/surface.h" +#include "openmc/timer.h" namespace openmc { @@ -341,51 +343,154 @@ void print_columns() void print_generation() { + // Save state of cout + auto f {std::cout.flags()}; + // Determine overall generation and number of active generations int i = overall_generation() - 1; int n = simulation::current_batch > settings::n_inactive ? settings::gen_per_batch*n_realizations + simulation::current_gen : 0; + // Set format for values + std::cout << std::fixed << std::setprecision(5); + // write out information batch and option independent output std::cout << " " << std::setw(9) << std::to_string(simulation::current_batch) - + "/" + std::to_string(simulation::current_gen) << " " << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::k_generation[i]; + + "/" + std::to_string(simulation::current_gen) << " " << std::setw(8) + << simulation::k_generation[i]; // write out entropy info - if (settings::entropy_on) std::cout << " " << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::entropy[i]; + if (settings::entropy_on) { + std::cout << " " << std::setw(8) << simulation::entropy[i]; + } if (n > 1) { - std::cout << " " << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff << " +/-" << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff_std; + std::cout << " " << std::setw(8) << simulation::keff << " +/-" + << std::setw(8) << simulation::keff_std; } std::cout << '\n'; + + // Restore state of cout + std::cout.flags(f); } //============================================================================== void print_batch_keff() { + // Save state of cout + auto f {std::cout.flags()}; + // Determine overall generation and number of active generations int i = simulation::current_batch*settings::gen_per_batch - 1; int n = n_realizations*settings::gen_per_batch; + // Set format for values + std::cout << std::fixed << std::setprecision(5); + // write out information batch and option independent output std::cout << " " << std::setw(9) << std::to_string(simulation::current_batch) - + "/" + std::to_string(settings::gen_per_batch) << " " << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::k_generation[i]; + + "/" + std::to_string(settings::gen_per_batch) << " " << std::setw(8) + << simulation::k_generation[i]; // write out entropy info - if (settings::entropy_on) std::cout << " " << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::entropy[i]; + if (settings::entropy_on) { + std::cout << " " << std::setw(8) << simulation::entropy[i]; + } if (n > 1) { - std::cout << " " << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff << " +/-" << - std::fixed << std::setw(8) << std::setprecision(5) << simulation::keff_std; + std::cout << " " << std::setw(8) << simulation::keff << " +/-" + << std::setw(8) << simulation::keff_std; } std::cout << '\n'; + + // Restore state of cout + std::cout.flags(f); +} + +//============================================================================== + +void show_time(const char* label, double value) +{ + std::cout << " " << std::setw(33) << std::left << label << " = " + << std::setw(10) << std::right << value << " seconds\n"; +} + +void show_rate(const char* label, double value) +{ + std::cout << " " << std::setw(33) << std::left << label << " = " << + value << " particles/second\n"; +} + +void print_runtime() +{ + using namespace simulation; + + // display header block + header("Timing Statistics", 6); + + // Save state of cout + auto f {std::cout.flags()}; + + // display time elapsed for various sections + std::cout << std::scientific << std::setprecision(4); + show_time("Total time for initialization", time_initialize.elapsed()); + show_time(" Reading cross sections", time_read_xs.elapsed()); + show_time("Total time in simulation", time_inactive.elapsed() + + time_active.elapsed()); + show_time(" Time in transport only", time_transport.elapsed()); + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + show_time(" Time in inactive batches", time_inactive.elapsed()); + } + show_time(" Time in active batches", time_active.elapsed()); + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + show_time(" Time synchronizing fission bank", time_bank.elapsed()); + show_time(" Sampling source sites", time_bank_sample.elapsed()); + show_time(" SEND/RECV source sites", time_bank_sendrecv.elapsed()); + } + show_time(" Time accumulating tallies", time_tallies.elapsed()); + show_time("Total time for finalization", time_finalize.elapsed()); + show_time("Total time elapsed", time_total.elapsed()); + + // Restore state of cout + std::cout.flags(f); + + // Calculate particle rate in active/inactive batches + int n_active = simulation::current_batch - settings::n_inactive; + double speed_inactive; + double speed_active; + if (settings::restart_run) { + if (simulation::restart_batch < settings::n_inactive) { + speed_inactive = (settings::n_particles * (settings::n_inactive + - simulation::restart_batch) * settings::gen_per_batch) + / time_inactive.elapsed(); + speed_active = (settings::n_particles * n_active + * settings::gen_per_batch) / time_active.elapsed(); + } else { + speed_inactive = 0.0; + speed_active = (settings::n_particles * (settings::n_batches + - simulation::restart_batch) * settings::gen_per_batch) + / time_active.elapsed(); + } + } else { + if (settings::n_inactive > 0) { + speed_inactive = (settings::n_particles * settings::n_inactive + * settings::gen_per_batch) / time_inactive.elapsed(); + } + speed_active = (settings::n_particles * n_active * settings::gen_per_batch) + / time_active.elapsed(); + } + + // display calculation rate + std::cout << std::setprecision(6) << std::showpoint; + if (!(settings::restart_run && (simulation::restart_batch >= settings::n_inactive)) + && settings::n_inactive > 0) { + show_rate("Calculation Rate (inactive)", speed_inactive); + } + show_rate("Calculation Rate (active)", speed_active); + + // Restore state of cout + std::cout.flags(f); } } // namespace openmc diff --git a/src/simulation.cpp b/src/simulation.cpp index 7f4f0dc03..3d362890c 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -32,7 +32,6 @@ extern "C" void check_triggers(); extern "C" void init_tally_routines(); extern "C" void load_state_point(); extern "C" void print_results(); -extern "C" void print_runtime(); extern "C" void setup_active_tallies(); extern "C" void simulation_init_f(); extern "C" void simulation_finalize_f(); From a732efbe51d29d87a8ed7f655f4122aba3a36dd7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Feb 2019 12:06:26 -0600 Subject: [PATCH 03/16] Translate print_results to C++ --- include/openmc/math_functions.h | 2 +- include/openmc/output.h | 9 ++++ src/eigenvalue.cpp | 2 +- src/math.F90 | 3 +- src/math_functions.cpp | 2 +- src/output.F90 | 67 ------------------------- src/output.cpp | 86 ++++++++++++++++++++++++++++++++- src/simulation.cpp | 1 - 8 files changed, 98 insertions(+), 74 deletions(-) diff --git a/include/openmc/math_functions.h b/include/openmc/math_functions.h index 87710fb6b..e07374df3 100644 --- a/include/openmc/math_functions.h +++ b/include/openmc/math_functions.h @@ -34,7 +34,7 @@ extern "C" double normal_percentile(double p); //! \return The requested percentile //============================================================================== -extern "C" double t_percentile_c(double p, int df); +extern "C" double t_percentile(double p, int df); //============================================================================== //! Calculate the n-th order Legendre polynomials at the value of x. diff --git a/include/openmc/output.h b/include/openmc/output.h index c80ca1167..0f26caa4f 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -5,6 +5,7 @@ #define OPENMC_OUTPUT_H #include +#include // for pair #include "openmc/particle.h" @@ -65,5 +66,13 @@ void print_batch_keff(); void print_runtime(); +//! Display results for global tallies including k-effective estimators + +void print_results(); + +//! Calculate the mean and standard deviation for a tally result + +std::pair mean_stdev(const double* x, int n); + } // namespace openmc #endif // OPENMC_OUTPUT_H diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index b3b8b850c..2b0f731cb 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -331,7 +331,7 @@ void calculate_average_keff() if (settings::confidence_intervals) { // Calculate t-value for confidence intervals double alpha = 1.0 - CONFIDENCE_LEVEL; - t_value = t_percentile_c(1.0 - alpha/2.0, n - 1); + t_value = t_percentile(1.0 - alpha/2.0, n - 1); } else { t_value = 1.0; } diff --git a/src/math.F90 b/src/math.F90 index 5607a9556..5a0a582a4 100644 --- a/src/math.F90 +++ b/src/math.F90 @@ -11,8 +11,7 @@ module math interface - pure function t_percentile(p, df) bind(C, name='t_percentile_c') & - result(t) + pure function t_percentile(p, df) bind(C) result(t) use ISO_C_BINDING implicit none real(C_DOUBLE), value, intent(in) :: p diff --git a/src/math_functions.cpp b/src/math_functions.cpp index fe2c53230..919c305c4 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -60,7 +60,7 @@ double normal_percentile(double p) { } -double t_percentile_c(double p, int df){ +double t_percentile(double p, int df){ double t; if (df == 1) { diff --git a/src/output.F90 b/src/output.F90 index 78e784220..209d588b2 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -93,73 +93,6 @@ contains end subroutine header -!=============================================================================== -! PRINT_RESULTS displays various estimates of k-effective as well as the global -! leakage rate. -!=============================================================================== - - subroutine print_results() bind(C) - - integer :: n ! number of realizations - real(8) :: alpha ! significance level for CI - real(8) :: t_n1 ! t-value with N-1 degrees of freedom - real(8) :: t_n3 ! t-value with N-3 degrees of freedom - real(8) :: x(2) ! mean and standard deviation - real(C_DOUBLE) :: k_combined(2) - integer(C_INT) :: err - - ! display header block for results - call header("Results", 4) - - n = n_realizations - - if (confidence_intervals) then - ! Calculate t-value for confidence intervals - alpha = ONE - CONFIDENCE_LEVEL - t_n1 = t_percentile(ONE - alpha/TWO, n - 1) - t_n3 = t_percentile(ONE - alpha/TWO, n - 3) - else - t_n1 = ONE - t_n3 = ONE - end if - - ! write global tallies - if (n > 1) then - associate (r => global_tallies(RESULT_SUM:RESULT_SUM_SQ, :)) - if (run_mode == MODE_EIGENVALUE) then - x(:) = mean_stdev(r(:, K_COLLISION), n) - write(ou,102) "k-effective (Collision)", x(1), t_n1 * x(2) - x(:) = mean_stdev(r(:, K_TRACKLENGTH), n) - write(ou,102) "k-effective (Track-length)", x(1), t_n1 * x(2) - x(:) = mean_stdev(r(:, K_ABSORPTION), n) - write(ou,102) "k-effective (Absorption)", x(1), t_n1 * x(2) - if (n > 3) then - err = openmc_get_keff(k_combined) - write(ou,102) "Combined k-effective", k_combined(1), & - t_n3 * k_combined(2) - end if - end if - x(:) = mean_stdev(r(:, LEAKAGE), n) - write(ou,102) "Leakage Fraction", x(1), t_n1 * x(2) - end associate - else - if (master) call warning("Could not compute uncertainties -- only one & - &active batch simulated!") - - if (run_mode == MODE_EIGENVALUE) then - write(ou,103) "k-effective (Collision)", global_tallies(RESULT_SUM, K_COLLISION) / n - write(ou,103) "k-effective (Track-length)", global_tallies(RESULT_SUM, K_TRACKLENGTH) / n - write(ou,103) "k-effective (Absorption)", global_tallies(RESULT_SUM, K_ABSORPTION) / n - end if - write(ou,103) "Leakage Fraction", global_tallies(RESULT_SUM, LEAKAGE) / n - end if - write(ou,*) - -102 format (1X,A,T30,"= ",F8.5," +/- ",F8.5) -103 format (1X,A,T30,"= ",F8.5) - - end subroutine print_results - !=============================================================================== ! WRITE_TALLIES creates an output file and writes out the mean values of all ! tallies and their standard deviations diff --git a/src/output.cpp b/src/output.cpp index 39ebf0dce..567a588fa 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -9,19 +9,23 @@ #include #include +#include "xtensor/xview.hpp" #include "openmc/capi.h" #include "openmc/cell.h" #include "openmc/constants.h" #include "openmc/eigenvalue.h" +#include "openmc/error.h" #include "openmc/geometry.h" #include "openmc/lattice.h" +#include "openmc/math_functions.h" #include "openmc/message_passing.h" #include "openmc/plot.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/surface.h" #include "openmc/timer.h" +#include "openmc/tallies/tally.h" namespace openmc { @@ -102,7 +106,7 @@ header(const char* msg, int level) { // Print header based on verbosity level. if (settings::verbosity >= level) { - std::cout << out.str() << "\n\n"; + std::cout << '\n' << out.str() << "\n\n"; } } @@ -493,4 +497,84 @@ void print_runtime() std::cout.flags(f); } +//============================================================================== + +void print_results() +{ + // Save state of cout + auto f {std::cout.flags()}; + + // display header block for results + header("Results", 4); + + // Calculate t-value for confidence intervals + int n = n_realizations; + double alpha, t_n1, t_n3; + if (settings::confidence_intervals) { + alpha = 1.0 - CONFIDENCE_LEVEL; + t_n1 = t_percentile(1.0 - alpha/2.0, n - 1); + t_n3 = t_percentile(1.0 - alpha/2.0, n - 3); + } else { + t_n1 = 1.0; + t_n3 = 1.0; + } + + // Set formatting for floats + std::cout << std::fixed << std::setprecision(5); + + // write global tallies + auto gt = global_tallies(); + double mean, stdev; + if (n > 1) { + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + std::tie(mean, stdev) = mean_stdev(>(K_COLLISION, 0), n); + std::cout << " k-effective (Collision) = " + << mean << " +/- " << t_n1 * stdev << '\n'; + std::tie(mean, stdev) = mean_stdev(>(K_TRACKLENGTH, 0), n); + std::cout << " k-effective (Track-length) = " + << mean << " +/- " << t_n1 * stdev << '\n'; + std::tie(mean, stdev) = mean_stdev(>(K_ABSORPTION, 0), n); + std::cout << " k-effective (Absorption) = " + << mean << " +/- " << t_n1 * stdev << '\n'; + if (n > 3) { + double k_combined[2]; + openmc_get_keff(k_combined); + std::cout << " Combined k-effective = " + << k_combined[0] << " +/- " << t_n3 * k_combined[1] << '\n'; + } + } + std::tie(mean, stdev) = mean_stdev(>(LEAKAGE, 0), n); + std::cout << " Leakage Fraction = " + << mean << " +/- " << t_n1 * stdev << '\n'; + } else { + if (mpi::master) warning("Could not compute uncertainties -- only one " + "active batch simulated!"); + + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + std::cout << " k-effective (Collision) = " + << gt(K_COLLISION, RESULT_SUM) / n << '\n'; + std::cout << " k-effective (Track-length) = " + << gt(K_TRACKLENGTH, RESULT_SUM) / n << '\n'; + std::cout << " k-effective (Absorption) = " + << gt(K_ABSORPTION, RESULT_SUM) / n << '\n'; + } + std::cout << " Leakage Fraction = " + << gt(LEAKAGE, RESULT_SUM) / n << '\n'; + } + std::cout << '\n'; + + // Restore state of cout + std::cout.flags(f); +} + +//============================================================================== + +std::pair mean_stdev(const double* x, int n) +{ + double mean = x[RESULT_SUM] / n; + double stdev = n > 1 ? std::sqrt((x[RESULT_SUM_SQ]/n + - mean*mean)/(n - 1)) : 0.0; + return {mean, stdev}; +} + } // namespace openmc diff --git a/src/simulation.cpp b/src/simulation.cpp index 3d362890c..cf6000398 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -31,7 +31,6 @@ extern "C" void allocate_tally_results(); extern "C" void check_triggers(); extern "C" void init_tally_routines(); extern "C" void load_state_point(); -extern "C" void print_results(); extern "C" void setup_active_tallies(); extern "C" void simulation_init_f(); extern "C" void simulation_finalize_f(); From 8f5517c2120dad5fb27e5685e9b3cdf22a7c3871 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Feb 2019 15:55:17 -0600 Subject: [PATCH 04/16] Start translating openmc_statepoint_write to C++ --- include/openmc/capi.h | 2 +- include/openmc/constants.h | 1 + include/openmc/eigenvalue.h | 5 + include/openmc/mesh.h | 2 +- openmc/capi/math.py | 8 +- src/eigenvalue.cpp | 2 +- src/state_point.F90 | 439 +++++++++++------------------------- src/state_point.cpp | 139 ++++++++++++ 8 files changed, 286 insertions(+), 312 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 6c3338854..e674dcc2a 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -100,7 +100,7 @@ extern "C" { int openmc_sphharm_filter_get_cosine(int32_t index, char cosine[]); int openmc_sphharm_filter_set_order(int32_t index, int order); int openmc_sphharm_filter_set_cosine(int32_t index, const char cosine[]); - int openmc_statepoint_write(const char filename[], bool* write_source); + int openmc_statepoint_write(const char* filename, bool* write_source); int openmc_tally_allocate(int32_t index, const char* type); int openmc_tally_get_active(int32_t index, bool* active); int openmc_tally_get_estimator(int32_t index, int32_t* estimator); diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 375ebc276..956e38ca2 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -28,6 +28,7 @@ constexpr std::array VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELE constexpr int HDF5_VERSION[] {2, 0}; // Version numbers for binary files +constexpr std::array VERSION_STATEPOINT {17, 0}; constexpr std::array VERSION_PARTICLE_RESTART {2, 0}; constexpr std::array VERSION_TRACK {2, 0}; constexpr std::array VERSION_SUMMARY {6, 0}; diff --git a/include/openmc/eigenvalue.h b/include/openmc/eigenvalue.h index f7e93ec2b..f89bdc8bf 100644 --- a/include/openmc/eigenvalue.h +++ b/include/openmc/eigenvalue.h @@ -9,6 +9,7 @@ #include #include "xtensor/xtensor.hpp" +#include #include "openmc/particle.h" @@ -78,6 +79,10 @@ void ufs_count_sites(); //! Get UFS weight corresponding to particle's location extern "C" double ufs_get_weight(const Particle* p); +//! Write data related to k-eigenvalue to statepoint +//! \param[in] group HDF5 group +void write_eigenvalue_hdf5(hid_t group); + } // namespace openmc #endif // OPENMC_EIGENVALUE_H diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 7fcd58a06..1ca4d57b4 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -128,7 +128,7 @@ extern "C" void read_meshes(pugi::xml_node* root); //! Write mesh data to an HDF5 group //! \param[in] group HDF5 group -extern "C" void meshes_to_hdf5(hid_t group); +void meshes_to_hdf5(hid_t group); } // namespace openmc diff --git a/openmc/capi/math.py b/openmc/capi/math.py index e5a4b12c6..1baa9cf64 100644 --- a/openmc/capi/math.py +++ b/openmc/capi/math.py @@ -6,8 +6,8 @@ from numpy.ctypeslib import ndpointer from . import _dll -_dll.t_percentile_c.restype = c_double -_dll.t_percentile_c.argtypes = [c_double, c_int] +_dll.t_percentile.restype = c_double +_dll.t_percentile.argtypes = [c_double, c_int] _dll.calc_pn_c.restype = None _dll.calc_pn_c.argtypes = [c_int, c_double, ndpointer(c_double)] @@ -58,7 +58,7 @@ def t_percentile(p, df): """ - return _dll.t_percentile_c(p, df) + return _dll.t_percentile(p, df) def calc_pn(n, x): @@ -261,7 +261,7 @@ def normal_variate(mean_value, std_dev): Parameters ---------- mean_value : float - Mean of the Normal distribution + Mean of the Normal distribution std_dev : float Standard deviation of the normal distribution diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index 2b0f731cb..446052fbb 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -622,7 +622,7 @@ double ufs_get_weight(const Particle* p) } } -extern "C" void write_eigenvalue_hdf5(hid_t group) +void write_eigenvalue_hdf5(hid_t group) { write_dataset(group, "n_inactive", settings::n_inactive); write_dataset(group, "generations_per_batch", settings::gen_per_batch); diff --git a/src/state_point.F90 b/src/state_point.F90 index e7d161127..04e354142 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -51,294 +51,172 @@ contains ! OPENMC_STATEPOINT_WRITE writes an HDF5 statepoint file to disk !=============================================================================== - function openmc_statepoint_write(filename, write_source) result(err) bind(C) - type(C_PTR), value :: filename - logical(C_BOOL), intent(in), optional :: write_source - integer(C_INT) :: err + subroutine statepoint_write_f(file_id) bind(C) + integer(HID_T), value :: file_id - logical :: write_source_ integer :: i, j integer :: i_xs integer, allocatable :: id_array(:) - integer(HID_T) :: file_id integer(HID_T) :: tallies_group, tally_group, & filters_group, filter_group, derivs_group, & - deriv_group, runtime_group + deriv_group character(MAX_WORD_LEN), allocatable :: str_array(:) - character(C_CHAR), pointer :: string(:) - character(len=:, kind=C_CHAR), allocatable :: filename_ character(MAX_WORD_LEN, kind=C_CHAR) :: temp_name - logical :: parallel - interface - subroutine meshes_to_hdf5(group) bind(C) - import HID_T - integer(HID_T), value :: group - end subroutine - subroutine write_eigenvalue_hdf5(group) bind(C) - import HID_T - integer(HID_T), value :: group - end subroutine - subroutine write_tally_results_nr(file_id) bind(C) - import HID_T - integer(HID_T), value :: file_id - end subroutine - end interface + ! Open tallies group + tallies_group = open_group(file_id, "tallies") - err = 0 - - ! Set the filename - if (c_associated(filename)) then - call c_f_pointer(filename, string, [MAX_FILE_LEN]) - filename_ = to_f_string(string) - else - ! Set filename for state point - filename_ = trim(path_output) // 'statepoint.' // & - & zero_padded(current_batch, count_digits(n_max_batches)) - filename_ = trim(filename_) // '.h5' + ! Write information for derivatives. + if (size(tally_derivs) > 0) then + derivs_group = create_group(tallies_group, "derivatives") + do i = 1, size(tally_derivs) + associate(deriv => tally_derivs(i)) + deriv_group = create_group(derivs_group, "derivative " & + // trim(to_str(deriv % id))) + select case (deriv % variable) + case (DIFF_DENSITY) + call write_dataset(deriv_group, "independent variable", "density") + call write_dataset(deriv_group, "material", deriv % diff_material) + case (DIFF_NUCLIDE_DENSITY) + call write_dataset(deriv_group, "independent variable", & + "nuclide_density") + call write_dataset(deriv_group, "material", deriv % diff_material) + call write_dataset(deriv_group, "nuclide", & + nuclides(deriv % diff_nuclide) % name) + case (DIFF_TEMPERATURE) + call write_dataset(deriv_group, "independent variable", & + "temperature") + call write_dataset(deriv_group, "material", deriv % diff_material) + case default + call fatal_error("Independent variable for derivative " & + // trim(to_str(deriv % id)) // " not defined in & + &state_point.F90.") + end select + call close_group(deriv_group) + end associate + end do + call close_group(derivs_group) end if - ! Determine whether or not to write the source bank - if (present(write_source)) then - write_source_ = write_source - else - write_source_ = .true. + ! Write number of filters + filters_group = create_group(tallies_group, "filters") + call write_attribute(filters_group, "n_filters", n_filters) + + if (n_filters > 0) then + ! Write IDs of filters + allocate(id_array(n_filters)) + do i = 1, n_filters + id_array(i) = filters(i) % obj % id + end do + call write_attribute(filters_group, "ids", id_array) + deallocate(id_array) + + ! Write filter information + FILTER_LOOP: do i = 1, n_filters + filter_group = create_group(filters_group, "filter " // & + trim(to_str(filters(i) % obj % id))) + call filters(i) % obj % to_statepoint(filter_group) + call close_group(filter_group) + end do FILTER_LOOP end if - ! Write message - call write_message("Creating state point " // trim(filename_) // "...", 5) - - if (master) then - ! Create statepoint file - file_id = file_open(filename_, 'w') - - ! Write file type - call write_attribute(file_id, "filetype", "statepoint") - - ! Write revision number for state point file - call write_attribute(file_id, "version", VERSION_STATEPOINT) - - ! Write OpenMC version - call write_attribute(file_id, "openmc_version", VERSION) -#ifdef GIT_SHA1 - call write_attribute(file_id, "git_sha1", GIT_SHA1) -#endif - - ! Write current date and time - call write_attribute(file_id, "date_and_time", time_stamp()) - - ! Write path to input - call write_attribute(file_id, "path", path_input) - - ! Write out random number seed - call write_dataset(file_id, "seed", openmc_get_seed()) - - ! Write run information - if (run_CE) then - call write_dataset(file_id, "energy_mode", "continuous-energy") - else - call write_dataset(file_id, "energy_mode", "multi-group") - end if - select case(run_mode) - case (MODE_FIXEDSOURCE) - call write_dataset(file_id, "run_mode", "fixed source") - case (MODE_EIGENVALUE) - call write_dataset(file_id, "run_mode", "eigenvalue") - end select - if (photon_transport) then - call write_attribute(file_id, "photon_transport", 1) - else - call write_attribute(file_id, "photon_transport", 0) - end if - call write_dataset(file_id, "n_particles", n_particles) - call write_dataset(file_id, "n_batches", n_batches) - - ! Write out current batch number - call write_dataset(file_id, "current_batch", current_batch) - - ! Indicate whether source bank is stored in statepoint - if (write_source_) then - call write_attribute(file_id, "source_present", 1) - else - call write_attribute(file_id, "source_present", 0) - end if - - ! Write out information for eigenvalue run - if (run_mode == MODE_EIGENVALUE) then - call write_eigenvalue_hdf5(file_id) - end if - - tallies_group = create_group(file_id, "tallies") - - ! Write meshes - call meshes_to_hdf5(tallies_group) - - ! Write information for derivatives. - if (size(tally_derivs) > 0) then - derivs_group = create_group(tallies_group, "derivatives") - do i = 1, size(tally_derivs) - associate(deriv => tally_derivs(i)) - deriv_group = create_group(derivs_group, "derivative " & - // trim(to_str(deriv % id))) - select case (deriv % variable) - case (DIFF_DENSITY) - call write_dataset(deriv_group, "independent variable", "density") - call write_dataset(deriv_group, "material", deriv % diff_material) - case (DIFF_NUCLIDE_DENSITY) - call write_dataset(deriv_group, "independent variable", & - "nuclide_density") - call write_dataset(deriv_group, "material", deriv % diff_material) - call write_dataset(deriv_group, "nuclide", & - nuclides(deriv % diff_nuclide) % name) - case (DIFF_TEMPERATURE) - call write_dataset(deriv_group, "independent variable", & - "temperature") - call write_dataset(deriv_group, "material", deriv % diff_material) - case default - call fatal_error("Independent variable for derivative " & - // trim(to_str(deriv % id)) // " not defined in & - &state_point.F90.") - end select - call close_group(deriv_group) - end associate - end do - call close_group(derivs_group) - end if - - ! Write number of filters - filters_group = create_group(tallies_group, "filters") - call write_attribute(filters_group, "n_filters", n_filters) - - if (n_filters > 0) then - ! Write IDs of filters - allocate(id_array(n_filters)) - do i = 1, n_filters - id_array(i) = filters(i) % obj % id - end do - call write_attribute(filters_group, "ids", id_array) - deallocate(id_array) - - ! Write filter information - FILTER_LOOP: do i = 1, n_filters - filter_group = create_group(filters_group, "filter " // & - trim(to_str(filters(i) % obj % id))) - call filters(i) % obj % to_statepoint(filter_group) - call close_group(filter_group) - end do FILTER_LOOP - end if - - call close_group(filters_group) + call close_group(filters_group) ! Write number of tallies - call write_attribute(tallies_group, "n_tallies", n_tallies) + call write_attribute(tallies_group, "n_tallies", n_tallies) - if (n_tallies > 0) then - ! Write array of tally IDs - allocate(id_array(n_tallies)) - do i = 1, n_tallies - id_array(i) = tallies(i) % obj % id - end do - call write_attribute(tallies_group, "ids", id_array) - deallocate(id_array) + if (n_tallies > 0) then + ! Write array of tally IDs + allocate(id_array(n_tallies)) + do i = 1, n_tallies + id_array(i) = tallies(i) % obj % id + end do + call write_attribute(tallies_group, "ids", id_array) + deallocate(id_array) - ! Write all tally information except results - TALLY_METADATA: do i = 1, n_tallies + ! Write all tally information except results + TALLY_METADATA: do i = 1, n_tallies - ! Get pointer to tally - associate (tally => tallies(i) % obj) - tally_group = create_group(tallies_group, "tally " // & - trim(to_str(tally % id))) + ! Get pointer to tally + associate (tally => tallies(i) % obj) + tally_group = create_group(tallies_group, "tally " // & + trim(to_str(tally % id))) - ! Write the name for this tally - call write_dataset(tally_group, "name", tally % name) + ! Write the name for this tally + call write_dataset(tally_group, "name", tally % name) - select case(tally % estimator) - case (ESTIMATOR_ANALOG) - call write_dataset(tally_group, "estimator", "analog") - case (ESTIMATOR_TRACKLENGTH) - call write_dataset(tally_group, "estimator", "tracklength") - case (ESTIMATOR_COLLISION) - call write_dataset(tally_group, "estimator", "collision") - end select - call write_dataset(tally_group, "n_realizations", & - tally % n_realizations) + select case(tally % estimator) + case (ESTIMATOR_ANALOG) + call write_dataset(tally_group, "estimator", "analog") + case (ESTIMATOR_TRACKLENGTH) + call write_dataset(tally_group, "estimator", "tracklength") + case (ESTIMATOR_COLLISION) + call write_dataset(tally_group, "estimator", "collision") + end select + call write_dataset(tally_group, "n_realizations", & + tally % n_realizations) - call write_dataset(tally_group, "n_filters", size(tally % filter)) - if (size(tally % filter) > 0) then - ! Write IDs of filters - allocate(id_array(size(tally % filter))) - do j = 1, size(tally % filter) - id_array(j) = filters(tally % filter(j)) % obj % id - end do - call write_dataset(tally_group, "filters", id_array) - deallocate(id_array) - end if + call write_dataset(tally_group, "n_filters", size(tally % filter)) + if (size(tally % filter) > 0) then + ! Write IDs of filters + allocate(id_array(size(tally % filter))) + do j = 1, size(tally % filter) + id_array(j) = filters(tally % filter(j)) % obj % id + end do + call write_dataset(tally_group, "filters", id_array) + deallocate(id_array) + end if - ! Set up nuclide bin array and then write - allocate(str_array(tally % n_nuclide_bins)) - NUCLIDE_LOOP: do j = 1, tally % n_nuclide_bins - if (tally % nuclide_bins(j) > 0) then - if (run_CE) then - i_xs = index(nuclides(tally % nuclide_bins(j)) % name, '.') - if (i_xs > 0) then - str_array(j) = nuclides(tally % nuclide_bins(j)) % name(1 : i_xs-1) - else - str_array(j) = nuclides(tally % nuclide_bins(j)) % name - end if + ! Set up nuclide bin array and then write + allocate(str_array(tally % n_nuclide_bins)) + NUCLIDE_LOOP: do j = 1, tally % n_nuclide_bins + if (tally % nuclide_bins(j) > 0) then + if (run_CE) then + i_xs = index(nuclides(tally % nuclide_bins(j)) % name, '.') + if (i_xs > 0) then + str_array(j) = nuclides(tally % nuclide_bins(j)) % name(1 : i_xs-1) else - call get_name_c(tally % nuclide_bins(j), len(temp_name), & - temp_name) - i_xs = index(temp_name, '.') - if (i_xs > 0) then - str_array(j) = trim(temp_name(1 : i_xs-1)) - else - str_array(j) = trim(temp_name) - end if + str_array(j) = nuclides(tally % nuclide_bins(j)) % name end if else - str_array(j) = 'total' + call get_name_c(tally % nuclide_bins(j), len(temp_name), & + temp_name) + i_xs = index(temp_name, '.') + if (i_xs > 0) then + str_array(j) = trim(temp_name(1 : i_xs-1)) + else + str_array(j) = trim(temp_name) + end if end if - end do NUCLIDE_LOOP - call write_dataset(tally_group, "nuclides", str_array) - deallocate(str_array) - - ! Write derivative information. - if (tally % deriv /= NONE) then - call write_dataset(tally_group, "derivative", & - tally_derivs(tally % deriv) % id) + else + str_array(j) = 'total' end if + end do NUCLIDE_LOOP + call write_dataset(tally_group, "nuclides", str_array) + deallocate(str_array) - ! Write scores. - call write_dataset(tally_group, "n_score_bins", tally % n_score_bins) - allocate(str_array(size(tally % score_bins))) - do j = 1, size(tally % score_bins) - str_array(j) = reaction_name(tally % score_bins(j)) - end do - call write_dataset(tally_group, "score_bins", str_array) + ! Write derivative information. + if (tally % deriv /= NONE) then + call write_dataset(tally_group, "derivative", & + tally_derivs(tally % deriv) % id) + end if - deallocate(str_array) + ! Write scores. + call write_dataset(tally_group, "n_score_bins", tally % n_score_bins) + allocate(str_array(size(tally % score_bins))) + do j = 1, size(tally % score_bins) + str_array(j) = reaction_name(tally % score_bins(j)) + end do + call write_dataset(tally_group, "score_bins", str_array) - call close_group(tally_group) - end associate - end do TALLY_METADATA + deallocate(str_array) - end if - - call close_group(tallies_group) + call close_group(tally_group) + end associate + end do TALLY_METADATA end if - ! Check for the no-tally-reduction method - if (.not. reduce_tallies) then - ! If using the no-tally-reduction method, we need to collect tally - ! results before writing them to the state point file. - - call write_tally_results_nr(file_id) - - elseif (master) then - - ! Write number of global realizations - call write_dataset(file_id, "n_realizations", n_realizations) - + if (reduce_tallies) then ! Write global tallies call write_dataset(file_id, "global_tallies", global_tallies) @@ -347,8 +225,6 @@ contains ! Indicate that tallies are on call write_attribute(file_id, "tallies_present", 1) - tallies_group = open_group(file_id, "tallies") - ! Write all tally results TALLY_RESULTS: do i = 1, n_tallies associate (tally => tallies(i) % obj) @@ -359,61 +235,14 @@ contains call close_group(tally_group) end associate end do TALLY_RESULTS - - call close_group(tallies_group) else ! Indicate tallies are off call write_attribute(file_id, "tallies_present", 0) end if - - - ! Write out the runtime metrics. - runtime_group = create_group(file_id, "runtime") - call write_dataset(runtime_group, "total initialization", & - time_initialize_elapsed()) - call write_dataset(runtime_group, "reading cross sections", & - time_read_xs_elapsed()) - call write_dataset(runtime_group, "simulation", & - time_inactive_elapsed() + time_active_elapsed()) - call write_dataset(runtime_group, "transport", & - time_transport_elapsed()) - if (run_mode == MODE_EIGENVALUE) then - call write_dataset(runtime_group, "inactive batches", & - time_inactive_elapsed()) - end if - call write_dataset(runtime_group, "active batches", & - time_active_elapsed()) - if (run_mode == MODE_EIGENVALUE) then - call write_dataset(runtime_group, "synchronizing fission bank", & - time_bank_elapsed()) - call write_dataset(runtime_group, "sampling source sites", & - time_bank_sample_elapsed()) - call write_dataset(runtime_group, "SEND-RECV source sites", & - time_bank_sendrecv_elapsed()) - end if - call write_dataset(runtime_group, "accumulating tallies", & - time_tallies_elapsed()) - call write_dataset(runtime_group, "total", time_total_elapsed()) - call close_group(runtime_group) - - call file_close(file_id) end if -#ifdef PHDF5 - parallel = .true. -#else - parallel = .false. -#endif - - ! Write the source bank if desired - if (write_source_) then - if (master .or. parallel) then - file_id = file_open(filename_, 'a', parallel=.true.) - end if - call write_source_bank(file_id) - if (master .or. parallel) call file_close(file_id) - end if - end function openmc_statepoint_write + call close_group(tallies_group) + end subroutine !=============================================================================== ! LOAD_STATE_POINT diff --git a/src/state_point.cpp b/src/state_point.cpp index a808e3ef5..3668b7b7c 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -14,13 +14,152 @@ #include "openmc/eigenvalue.h" #include "openmc/error.h" #include "openmc/hdf5_interface.h" +#include "openmc/mesh.h" #include "openmc/message_passing.h" +#include "openmc/output.h" #include "openmc/settings.h" #include "openmc/simulation.h" +#include "openmc/tallies/filter.h" #include "openmc/tallies/tally.h" +#include "openmc/timer.h" namespace openmc { +extern "C" void statepoint_write_f(hid_t file_id); + +extern "C" int +openmc_statepoint_write(const char* filename, bool* write_source) +{ + // Set the filename + std::string filename_; + if (filename) { + filename_ = filename; + } else { + // Determine width for zero padding + int w = std::to_string(settings::n_max_batches).size(); + + // Set filename for state point + std::stringstream ss; + ss << settings::path_output << "statepoint." << std::setfill('0') + << std::setw(w) << simulation::current_batch << ".h5"; + filename_ = ss.str(); + } + + // Determine whether or not to write the source bank + bool write_source_ = write_source ? *write_source : true; + + // Write message + write_message("Creating state point " + filename_ + "...", 5); + + hid_t file_id; + if (mpi::master) { + // Create statepoint file + file_id = file_open(filename_, 'w'); + + // Write file type + write_attribute(file_id, "filetype", "statepoint"); + + // Write revision number for state point file + write_attribute(file_id, "version", VERSION_STATEPOINT); + + // Write OpenMC version + write_attribute(file_id, "openmc_version", VERSION); +#ifdef GIT_SHA1 + write_attribute(file_id, "git_sha1", GIT_SHA1); +#endif + + // Write current date and time + write_attribute(file_id, "date_and_time", time_stamp()); + + // Write path to input + write_attribute(file_id, "path", settings::path_input); + + // Write out random number seed + write_dataset(file_id, "seed", openmc_get_seed()); + + // Write run information + write_dataset(file_id, "energy_mode", settings::run_CE ? + "continuous-energy" : "multi-group"); + switch (settings::run_mode) { + case RUN_MODE_FIXEDSOURCE: + write_dataset(file_id, "run_mode", "fixed source"); + break; + case RUN_MODE_EIGENVALUE: + write_dataset(file_id, "run_mode", "eigenvalue"); + break; + } + write_attribute(file_id, "photon_transport", settings::photon_transport); + write_dataset(file_id, "n_particles", settings::n_particles); + write_dataset(file_id, "n_batches", settings::n_batches); + + // Write out current batch number + write_dataset(file_id, "current_batch", simulation::current_batch); + + // Indicate whether source bank is stored in statepoint + write_attribute(file_id, "source_present", write_source_); + + // Write out information for eigenvalue run + if (settings::run_mode == RUN_MODE_EIGENVALUE) write_eigenvalue_hdf5(file_id); + + // Write tally-related data + hid_t tallies_group = create_group(file_id, "tallies"); + meshes_to_hdf5(tallies_group); + statepoint_write_f(file_id); + close_group(tallies_group); + } + + // Check for the no-tally-reduction method + if (!settings::reduce_tallies) { + // If using the no-tally-reduction method, we need to collect tally + // results before writing them to the state point file. + + write_tally_results_nr(file_id); + + } else if (mpi::master) { + + // Write number of global realizations + write_dataset(file_id, "n_realizations", n_realizations); + + // Write out the runtime metrics. + using namespace simulation; + hid_t runtime_group = create_group(file_id, "runtime"); + write_dataset(runtime_group, "total initialization", time_initialize.elapsed()); + write_dataset(runtime_group, "reading cross sections", time_read_xs.elapsed()); + write_dataset(runtime_group, "simulation", time_inactive.elapsed() + + time_active.elapsed()); + write_dataset(runtime_group, "transport", time_transport.elapsed()); + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + write_dataset(runtime_group, "inactive batches", time_inactive.elapsed()); + } + write_dataset(runtime_group, "active batches", time_active.elapsed()); + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + write_dataset(runtime_group, "synchronizing fission bank", time_bank.elapsed()); + write_dataset(runtime_group, "sampling source sites", time_bank_sample.elapsed()); + write_dataset(runtime_group, "SEND-RECV source sites", time_bank_sendrecv.elapsed()); + } + write_dataset(runtime_group, "accumulating tallies", time_tallies.elapsed()); + write_dataset(runtime_group, "total", time_total.elapsed()); + close_group(runtime_group); + + file_close(file_id); + } + +#ifdef PHDF5 + bool parallel = true; +#else + bool parallel = false; +#endif + + // Write the source bank if desired + if (write_source_) { + if (mpi::master || parallel) file_id = file_open(filename_, 'a', true); + write_source_bank(file_id); + if (mpi::master || parallel) file_close(file_id); + } + + return 0; +} + hid_t h5banktype() { // Create type for array of 3 reals hsize_t dims[] {3}; From b178a66e7f378058e3f2098b16f22bc85288c2d5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Feb 2019 22:14:08 -0600 Subject: [PATCH 05/16] Add implementation of warning() in C++ --- include/openmc/error.h | 6 +---- src/error.cpp | 57 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/include/openmc/error.h b/include/openmc/error.h index b02c0a9f8..9bfebb2ce 100644 --- a/include/openmc/error.h +++ b/include/openmc/error.h @@ -50,11 +50,7 @@ void fatal_error(const std::stringstream& message) fatal_error(message.str()); } -inline -void warning(const std::string& message) -{ - warning_from_c(message.c_str(), message.length()); -} +void warning(const std::string& message); inline void warning(const std::stringstream& message) diff --git a/src/error.cpp b/src/error.cpp index d17219f31..fdb42d269 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -2,13 +2,68 @@ #include "openmc/message_passing.h" +#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) +#include // for isatty +#endif + +#include // for setw +#include + namespace openmc { #ifdef OPENMC_MPI void abort_mpi(int code) { - MPI_Abort(mpi::intracomm, code); + MPI_Abort(mpi::intracomm, code); } #endif +void warning(const std::string& message) +{ +#ifdef _POSIX_VERSION + // Make output yellow if user is in a terminal + if (isatty(STDERR_FILENO)) { + std::cerr << "\033[0;33m"; + } +#endif + + // Write warning at beginning + std::cerr << " WARNING: "; + + // Set line wrapping and indentation + int line_wrap = 80; + int indent = 10; + + // Determine length of message + int length = message.size(); + + int i_start = 0; + int line_len = line_wrap - indent + 1; + while (i_start < length) { + if (length - i_start < line_len) { + // Remainder of message will fit on line + std::cerr << message.substr(i_start) << '\n'; + break; + + } else { + // Determine last space in current line + std::string s = message.substr(i_start, line_len); + auto pos = s.find_last_of(' '); + + // Write up to last space, or whole line if no space is present + std::cerr << s.substr(0, pos) << '\n' << std::setw(indent) << " "; + + // Advance starting position + i_start += (pos == std::string::npos) ? line_len : pos + 1; + } + } + +#ifdef _POSIX_VERSION + // Reset color for terminal + if (isatty(STDERR_FILENO)) { + std::cerr << "\033[0m"; + } +#endif +} + } // namespace openmc From 102aa934ae58e1fa3b68ffadbf49f3ed8cb610a2 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Feb 2019 22:53:53 -0600 Subject: [PATCH 06/16] Add implementation of write_message and fatal_error in error.cpp --- include/openmc/error.h | 35 +++++----------------- src/error.F90 | 26 ---------------- src/error.cpp | 68 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 65 deletions(-) diff --git a/include/openmc/error.h b/include/openmc/error.h index 9bfebb2ce..ee7168a4e 100644 --- a/include/openmc/error.h +++ b/include/openmc/error.h @@ -9,11 +9,6 @@ namespace openmc { -extern "C" void fatal_error_from_c(const char* message, int message_len); -extern "C" void warning_from_c(const char* message, int message_len); -extern "C" void write_message_from_c(const char* message, int message_len, - int level); - inline void set_errmsg(const char* message) { @@ -32,17 +27,7 @@ set_errmsg(const std::stringstream& message) std::strcpy(openmc_err_msg, message.str().c_str()); } -inline -void fatal_error(const char* message) -{ - fatal_error_from_c(message, std::strlen(message)); -} - -inline -void fatal_error(const std::string& message) -{ - fatal_error_from_c(message.c_str(), message.length()); -} +[[noreturn]] void fatal_error(const std::string& message, int err=-1); inline void fatal_error(const std::stringstream& message) @@ -50,6 +35,12 @@ void fatal_error(const std::stringstream& message) fatal_error(message.str()); } +inline +void fatal_error(const char* message) +{ + fatal_error({message, std::strlen(message)}); +} + void warning(const std::string& message); inline @@ -58,17 +49,7 @@ void warning(const std::stringstream& message) warning(message.str()); } -inline -void write_message(const char* message, int level) -{ - write_message_from_c(message, std::strlen(message), level); -} - -inline -void write_message(const std::string& message, int level) -{ - write_message_from_c(message.c_str(), message.length(), level); -} +void write_message(const std::string& message, int level); inline void write_message(const std::stringstream& message, int level) diff --git a/src/error.F90 b/src/error.F90 index ad07987eb..ca94c6ce7 100644 --- a/src/error.F90 +++ b/src/error.F90 @@ -111,14 +111,6 @@ contains end subroutine warning - subroutine warning_from_c(message, message_len) bind(C) - integer(C_INT), intent(in), value :: message_len - character(kind=C_CHAR), intent(in) :: message(message_len) - character(message_len+1) :: message_out - write(message_out, *) message - call warning(message_out) - end subroutine - !=============================================================================== ! FATAL_ERROR alerts the user that an error has been encountered and displays a ! message about the particular problem. Errors are considered 'fatal' and hence @@ -208,14 +200,6 @@ contains end subroutine fatal_error - subroutine fatal_error_from_c(message, message_len) bind(C) - integer(C_INT), intent(in), value :: message_len - character(kind=C_CHAR), intent(in) :: message(message_len) - character(message_len+1) :: message_out - write(message_out, *) message - call fatal_error(message_out) - end subroutine - !=============================================================================== ! WRITE_MESSAGE displays an informational message to the log file and the ! standard output stream. @@ -271,14 +255,4 @@ contains end subroutine write_message - subroutine write_message_from_c(message, message_len, level) bind(C) - integer(C_INT), intent(in), value :: message_len - character(kind=C_CHAR), intent(in) :: message(message_len) - integer(C_INT), intent(in), value :: level - character(message_len+1) :: message_out - ! Using * in the internal write adds an extra space at the beginning - write(message_out, *) message - call write_message(message_out(2:), level) - end subroutine write_message_from_c - end module error diff --git a/src/error.cpp b/src/error.cpp index fdb42d269..38001b72a 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -1,11 +1,13 @@ #include "openmc/error.h" #include "openmc/message_passing.h" +#include "openmc/settings.h" #if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) #include // for isatty #endif +#include // for exit #include // for setw #include @@ -18,21 +20,10 @@ void abort_mpi(int code) } #endif -void warning(const std::string& message) +void output(const std::string& message, std::ostream& out, int indent) { -#ifdef _POSIX_VERSION - // Make output yellow if user is in a terminal - if (isatty(STDERR_FILENO)) { - std::cerr << "\033[0;33m"; - } -#endif - - // Write warning at beginning - std::cerr << " WARNING: "; - // Set line wrapping and indentation int line_wrap = 80; - int indent = 10; // Determine length of message int length = message.size(); @@ -57,6 +48,20 @@ void warning(const std::string& message) i_start += (pos == std::string::npos) ? line_len : pos + 1; } } +} + +void warning(const std::string& message) +{ +#ifdef _POSIX_VERSION + // Make output yellow if user is in a terminal + if (isatty(STDERR_FILENO)) { + std::cerr << "\033[0;33m"; + } +#endif + + // Write warning + std::cerr << " WARNING: "; + output(message, std::cerr, 10); #ifdef _POSIX_VERSION // Reset color for terminal @@ -66,4 +71,43 @@ void warning(const std::string& message) #endif } +void write_message(const std::string& message, int level) +{ + // Only allow master to print to screen + if (!mpi::master) return; + + if (level <= settings::verbosity) { + std::cout << " "; + output(message, std::cout, 1); + } +} + +void fatal_error(const std::string& message, int err) +{ +#ifdef _POSIX_VERSION + // Make output red if user is in a terminal + if (isatty(STDERR_FILENO)) { + std::cerr << "\033[0;31m"; + } +#endif + + // Write error message + std::cerr << " ERROR: "; + output(message, std::cerr, 8); + +#ifdef _POSIX_VERSION + // Reset color for terminal + if (isatty(STDERR_FILENO)) { + std::cerr << "\033[0m"; + } +#endif + +#ifdef OPENMC_MPI + MPI_Abort(mpi::intracomm, err); +#endif + + // Abort the program + std::exit(err); +} + } // namespace openmc From ab0b9eb0bc4fa39e687b466052cfe85140ea0585 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Feb 2019 23:39:22 -0600 Subject: [PATCH 07/16] Translate most of load_state_point to C++ --- include/openmc/eigenvalue.h | 4 + include/openmc/hdf5_interface.h | 13 ++ include/openmc/state_point.h | 9 +- src/eigenvalue.cpp | 2 +- src/simulation.cpp | 1 - src/state_point.F90 | 205 ++++---------------------------- src/state_point.cpp | 157 +++++++++++++++++++++--- src/string.F90 | 19 --- 8 files changed, 190 insertions(+), 220 deletions(-) diff --git a/include/openmc/eigenvalue.h b/include/openmc/eigenvalue.h index f89bdc8bf..d29f404b9 100644 --- a/include/openmc/eigenvalue.h +++ b/include/openmc/eigenvalue.h @@ -83,6 +83,10 @@ extern "C" double ufs_get_weight(const Particle* p); //! \param[in] group HDF5 group void write_eigenvalue_hdf5(hid_t group); +//! Read data related to k-eigenvalue from statepoint +//! \param[in] group HDF5 group +void read_eigenvalue_hdf5(hid_t group); + } // namespace openmc #endif // OPENMC_EIGENVALUE_H diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 6881cac77..398f03b09 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -229,6 +229,19 @@ void read_dataset(hid_t obj_id, const char* name, T& buffer, bool indep=false) read_dataset(obj_id, name, H5TypeMap::type_id, &buffer, indep); } +// overload for std::string +inline void +read_dataset(hid_t obj_id, const char* name, std::string& str, bool indep=false) +{ + // Create buffer to read data into + auto n = attribute_typesize(obj_id, name); + char buffer[n]; + + // Read attribute and set string + read_string(obj_id, name, n, buffer, indep); + str = std::string{buffer, n}; +} + template void read_dataset(hid_t dset, std::vector& vec, bool indep=false) { diff --git a/include/openmc/state_point.h b/include/openmc/state_point.h index 0c1db86f3..e44c57f1a 100644 --- a/include/openmc/state_point.h +++ b/include/openmc/state_point.h @@ -9,11 +9,12 @@ namespace openmc { +void load_state_point(); void write_source_point(const char* filename); -extern "C" void write_source_bank(hid_t group_id); -extern "C" void read_source_bank(hid_t group_id); -extern "C" void write_tally_results_nr(hid_t file_id); -extern "C" void restart_set_keff(); +void write_source_bank(hid_t group_id); +void read_source_bank(hid_t group_id); +void write_tally_results_nr(hid_t file_id); +void restart_set_keff(); } // namespace openmc #endif // OPENMC_STATE_POINT_H diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index 446052fbb..0f52649d8 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -638,7 +638,7 @@ void write_eigenvalue_hdf5(hid_t group) write_dataset(group, "k_combined", k_combined); } -extern "C" void read_eigenvalue_hdf5(hid_t group) +void read_eigenvalue_hdf5(hid_t group) { read_dataset(group, "generations_per_batch", settings::gen_per_batch); int n = simulation::restart_batch*settings::gen_per_batch; diff --git a/src/simulation.cpp b/src/simulation.cpp index cf6000398..7eba7f628 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -30,7 +30,6 @@ extern "C" void accumulate_tallies(); extern "C" void allocate_tally_results(); extern "C" void check_triggers(); extern "C" void init_tally_routines(); -extern "C" void load_state_point(); extern "C" void setup_active_tallies(); extern "C" void simulation_init_f(); extern "C" void simulation_finalize_f(); diff --git a/src/state_point.F90 b/src/state_point.F90 index 04e354142..113ce1749 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -13,7 +13,6 @@ module state_point use, intrinsic :: ISO_C_BINDING - use bank_header, only: Bank use constants use endf, only: reaction_name use error, only: fatal_error, warning, write_message @@ -21,11 +20,9 @@ module state_point use message_passing use mgxs_interface use nuclide_header, only: nuclides - use output, only: time_stamp - use random_lcg, only: openmc_get_seed, openmc_set_seed use settings use simulation_header - use string, only: to_str, count_digits, zero_padded, to_f_string + use string, only: to_str, zero_padded use tally_header use tally_filter_header use tally_derivative_header, only: tally_derivs @@ -33,18 +30,6 @@ module state_point implicit none - interface - subroutine write_source_bank(group_id) bind(C) - import HID_T - integer(HID_T), value :: group_id - end subroutine write_source_bank - - subroutine read_source_bank(group_id) bind(C) - import HID_T - integer(HID_T), value :: group_id - end subroutine read_source_bank - end interface - contains !=============================================================================== @@ -248,181 +233,39 @@ contains ! LOAD_STATE_POINT !=============================================================================== - subroutine load_state_point() bind(C) + subroutine load_state_point_f(file_id) bind(C) + integer(HID_T), value :: file_id integer :: i - integer :: int_array(3) - integer, allocatable :: array(:) - integer(C_INT64_T) :: seed - integer(HID_T) :: file_id + integer :: temp integer(HID_T) :: tallies_group integer(HID_T) :: tally_group - logical :: source_present - character(MAX_WORD_LEN) :: word - interface - subroutine read_eigenvalue_hdf5(group) bind(C) - import HID_T - integer(HID_T), value :: group - end subroutine + ! Read global tally data + call read_dataset(global_tallies, file_id, "global_tallies") - subroutine restart_set_keff() bind(C) - end subroutine - end interface + ! Check if tally results are present + call read_attribute(temp, file_id, "tallies_present") - ! Write message - call write_message("Loading state point " // trim(path_state_point) & - // "...", 5) + ! Read in sum and sum squared + if (temp == 1) then + tallies_group = open_group(file_id, "tallies") - ! Open file for reading - file_id = file_open(path_state_point, 'r', parallel=.true.) + TALLY_RESULTS: do i = 1, n_tallies + associate (t => tallies(i) % obj) + ! Read sum, sum_sq, and N for each bin + tally_group = open_group(tallies_group, "tally " // & + trim(to_str(t % id))) + call t % read_results_hdf5(tally_group) + call read_dataset(t % n_realizations, tally_group, & + "n_realizations") + call close_group(tally_group) + end associate + end do TALLY_RESULTS - ! Read filetype - call read_attribute(word, file_id, "filetype") - if (word /= 'statepoint') then - call fatal_error("OpenMC tried to restart from a non-statepoint file.") + call close_group(tallies_group) end if - ! Read revision number for state point file and make sure it matches with - ! current version - call read_attribute(array, file_id, "version") - if (any(array /= VERSION_STATEPOINT)) then - call fatal_error("State point version does not match current version & - &in OpenMC.") - end if - - ! Read and overwrite random number seed - call read_dataset(seed, file_id, "seed") - call openmc_set_seed(seed) - - ! It is not impossible for a state point to be generated from a CE run but - ! to be loaded in to an MG run (or vice versa), check to prevent that. - call read_dataset(word, file_id, "energy_mode") - if (word == "multi-group" .and. run_CE) then - call fatal_error("State point file is from multi-group run but & - & current run is continous-energy!") - else if (word == "continuous-energy" .and. .not. run_CE) then - call fatal_error("State point file is from continuous-energy run but & - & current run is multi-group!") - end if - - ! Read and overwrite run information except number of batches - call read_dataset(word, file_id, "run_mode") - select case(word) - case ('fixed source') - run_mode = MODE_FIXEDSOURCE - case ('eigenvalue') - run_mode = MODE_EIGENVALUE - end select - call read_attribute(int_array(1), file_id, "photon_transport") - if (int_array(1) == 1) then - photon_transport = .true. - else - photon_transport = .false. - end if - call read_dataset(n_particles, file_id, "n_particles") - call read_dataset(int_array(1), file_id, "n_batches") - - ! Take maximum of statepoint n_batches and input n_batches - n_batches = max(n_batches, int_array(1)) - - ! Read batch number to restart at - call read_dataset(restart_batch, file_id, "current_batch") - - ! Check for source in statepoint if needed - call read_attribute(int_array(1), file_id, "source_present") - if (int_array(1) == 1) then - source_present = .true. - else - source_present = .false. - end if - - if (restart_batch > n_batches) then - call fatal_error("The number batches specified in settings.xml is fewer & - & than the number of batches in the given statepoint file.") - end if - - ! Read information specific to eigenvalue run - if (run_mode == MODE_EIGENVALUE) then - call read_dataset(int_array(1), file_id, "n_inactive") - call read_eigenvalue_hdf5(file_id) - - ! Take maximum of statepoint n_inactive and input n_inactive - n_inactive = max(n_inactive, int_array(1)) - end if - - ! Read number of realizations for global tallies - call read_dataset(n_realizations, file_id, "n_realizations", indep=.true.) - - ! Set k_sum, keff, and current_batch based on whether restart file is part - ! of active cycle or inactive cycle - call restart_set_keff() - current_batch = restart_batch - - ! Check to make sure source bank is present - if (path_source_point == path_state_point .and. .not. source_present) then - call fatal_error("Source bank must be contained in statepoint restart & - &file") - end if - - ! Read tallies to master. If we are using Parallel HDF5, all processes - ! need to be included in the HDF5 calls. -#ifdef PHDF5 - if (.true.) then -#else - if (master) then -#endif - ! Read global tally data - call read_dataset(global_tallies, file_id, "global_tallies") - - ! Check if tally results are present - call read_attribute(int_array(1), file_id, "tallies_present") - - ! Read in sum and sum squared - if (int_array(1) == 1) then - tallies_group = open_group(file_id, "tallies") - - TALLY_RESULTS: do i = 1, n_tallies - associate (t => tallies(i) % obj) - ! Read sum, sum_sq, and N for each bin - tally_group = open_group(tallies_group, "tally " // & - trim(to_str(t % id))) - call t % read_results_hdf5(tally_group) - call read_dataset(t % n_realizations, tally_group, & - "n_realizations") - call close_group(tally_group) - end associate - end do TALLY_RESULTS - - call close_group(tallies_group) - end if - end if - - ! Read source if in eigenvalue mode - if (run_mode == MODE_EIGENVALUE) then - - ! Check if source was written out separately - if (.not. source_present) then - - ! Close statepoint file - call file_close(file_id) - - ! Write message - call write_message("Loading source file " // trim(path_source_point) & - // "...", 5) - - ! Open source file - file_id = file_open(path_source_point, 'r', parallel=.true.) - end if - - ! Read source - call read_source_bank(file_id) - - end if - - ! Close file - call file_close(file_id) - - end subroutine load_state_point + end subroutine load_state_point_f end module state_point diff --git a/src/state_point.cpp b/src/state_point.cpp index 3668b7b7c..6dc8eafdd 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -1,6 +1,7 @@ #include "openmc/state_point.h" #include +#include // for int64_t #include // for setfill, setw #include #include @@ -26,6 +27,7 @@ namespace openmc { extern "C" void statepoint_write_f(hid_t file_id); +extern "C" void load_state_point_f(hid_t file_id); extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) @@ -160,6 +162,147 @@ openmc_statepoint_write(const char* filename, bool* write_source) return 0; } +void restart_set_keff() +{ + if (simulation::restart_batch > settings::n_inactive) { + for (int i = settings::n_inactive; i < simulation::restart_batch; ++i) { + simulation::k_sum[0] += simulation::k_generation[i]; + simulation::k_sum[1] += std::pow(simulation::k_generation[i], 2); + } + int n = settings::gen_per_batch*n_realizations; + simulation::keff = simulation::k_sum[0] / n; + } else { + simulation::keff = simulation::k_generation.back(); + } +} + +void load_state_point() +{ + // Write message + write_message("Loading state point " + settings::path_statepoint + "...", 5); + + // Open file for reading + hid_t file_id = file_open(settings::path_statepoint.c_str(), 'r', true); + + // Read filetype + std::string word; + read_attribute(file_id, "filetype", word); + if (word != "statepoint") { + fatal_error("OpenMC tried to restart from a non-statepoint file."); + } + + // Read revision number for state point file and make sure it matches with + // current version + std::array array; + read_attribute(file_id, "version", array); + if (array != VERSION_STATEPOINT) { + fatal_error("State point version does not match current version in OpenMC."); + } + + // Read and overwrite random number seed + int64_t seed; + read_dataset(file_id, "seed", seed); + openmc_set_seed(seed); + + // It is not impossible for a state point to be generated from a CE run but + // to be loaded in to an MG run (or vice versa), check to prevent that. + read_dataset(file_id, "energy_mode", word); + if (word == "multi-group" && settings::run_CE) { + fatal_error("State point file is from multigroup run but current run is " + "continous energy."); + } else if (word == "continuous-energy" && !settings::run_CE) { + fatal_error("State point file is from continuous-energy run but current " + "run is multigroup!"); + } + + // Read and overwrite run information except number of batches + read_dataset(file_id, "run_mode", word); + if (word == "fixed source") { + settings::run_mode = RUN_MODE_FIXEDSOURCE; + } else if (word == "eigenvalue") { + settings::run_mode = RUN_MODE_EIGENVALUE; + } + read_attribute(file_id, "photon_transport", settings::photon_transport); + read_dataset(file_id, "n_particles", settings::n_particles); + int temp; + read_dataset(file_id, "n_batches", temp); + + // Take maximum of statepoint n_batches and input n_batches + settings::n_batches = std::max(settings::n_batches, temp); + + // Read batch number to restart at + read_dataset(file_id, "current_batch", simulation::restart_batch); + + // Check for source in statepoint if needed + bool source_present; + read_attribute(file_id, "source_present", source_present); + + if (simulation::restart_batch > settings::n_batches) { + fatal_error("The number batches specified in settings.xml is fewer " + " than the number of batches in the given statepoint file."); + } + + // Read information specific to eigenvalue run + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + read_dataset(file_id, "n_inactive", temp); + read_eigenvalue_hdf5(file_id); + + // Take maximum of statepoint n_inactive and input n_inactive + settings::n_inactive = std::max(settings::n_inactive, temp); + } + + // Read number of realizations for global tallies + read_dataset(file_id, "n_realizations", n_realizations); + + // Set k_sum, keff, and current_batch based on whether restart file is part + // of active cycle or inactive cycle + restart_set_keff(); + simulation::current_batch = simulation::restart_batch; + + // Check to make sure source bank is present + if (settings::path_sourcepoint == settings::path_statepoint && + !source_present) { + fatal_error("Source bank must be contained in statepoint restart file"); + } + + // Read tallies to master. If we are using Parallel HDF5, all processes + // need to be included in the HDF5 calls. +#ifdef PHDF5 + if (true) { +#else + if (mpi::master) { +#endif + // Read tally results + load_state_point_f(file_id); + } + + // Read source if in eigenvalue mode + if (settings::run_mode == RUN_MODE_EIGENVALUE) { + + // Check if source was written out separately + if (!source_present) { + + // Close statepoint file + file_close(file_id); + + // Write message + write_message("Loading source file " + settings::path_sourcepoint + + "...", 5); + + // Open source file + file_id = file_open(settings::path_source.c_str(), 'r', true); + } + + // Read source + read_source_bank(file_id); + + } + + // Close file + file_close(file_id); +} + + hid_t h5banktype() { // Create type for array of 3 reals hsize_t dims[] {3}; @@ -455,18 +598,4 @@ void write_tally_results_nr(hid_t file_id) } } -void restart_set_keff() -{ - if (simulation::restart_batch > settings::n_inactive) { - for (int i = settings::n_inactive; i < simulation::restart_batch; ++i) { - simulation::k_sum[0] += simulation::k_generation[i]; - simulation::k_sum[1] += std::pow(simulation::k_generation[i], 2); - } - int n = settings::gen_per_batch*n_realizations; - simulation::keff = simulation::k_sum[0] / n; - } else { - simulation::keff = simulation::k_generation.back(); - } -} - } // namespace openmc diff --git a/src/string.F90 b/src/string.F90 index 7e1ca41ba..6a2b3ae90 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -247,25 +247,6 @@ contains end function ends_with -!=============================================================================== -! COUNT_DIGITS returns the number of digits needed to represent the input -! integer. -!=============================================================================== - - pure function count_digits(num) result(n_digits) - integer, intent(in) :: num - integer :: n_digits - - n_digits = 1 - do while (num / 10**(n_digits) /= 0 .and. abs(num / 10 **(n_digits-1)) /= 1& - &.and. n_digits /= 10) - ! Note that 10 digits is the maximum needed to represent an integer(4) so - ! the loop automatically exits when n_digits = 10. - n_digits = n_digits + 1 - end do - - end function count_digits - !=============================================================================== ! INT4_TO_STR converts an integer(4) to a string. !=============================================================================== From a99b732592e1d11ab51b3440e9ef0cd68616cb55 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Feb 2019 23:52:09 -0600 Subject: [PATCH 08/16] Remove unused Fortran code/data --- CMakeLists.txt | 1 - include/openmc/output.h | 14 --- include/openmc/settings.h | 5 +- src/algorithm.F90 | 134 -------------------------- src/constants.F90 | 51 ---------- src/endf_header.F90 | 191 -------------------------------------- src/geometry_header.F90 | 4 - src/initialize.F90 | 16 ---- src/input_xml.F90 | 5 +- src/math.F90 | 47 ---------- src/nuclide_header.F90 | 3 +- src/output.F90 | 1 - src/random_lcg.F90 | 25 ----- src/settings.F90 | 5 - src/settings.cpp | 3 +- src/state_point.F90 | 3 +- src/string.F90 | 94 +------------------ src/tallies/tally.F90 | 2 - src/timer_header.F90 | 54 ----------- 19 files changed, 8 insertions(+), 650 deletions(-) delete mode 100644 src/endf_header.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f9572dce..328504199 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,7 +311,6 @@ add_library(libopenmc SHARED src/dict_header.F90 src/eigenvalue.F90 src/endf.F90 - src/endf_header.F90 src/error.F90 src/geometry.F90 src/geometry_header.F90 diff --git a/include/openmc/output.h b/include/openmc/output.h index 0f26caa4f..385ef08a9 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -13,65 +13,51 @@ namespace openmc { //! \brief Display the main title banner as well as information about the //! program developers, version, and date/time which the problem was run. - void title(); //! Display a header block. // //! \param msg The main text of the header //! \param level The lowest verbosity level at which this header is printed - void header(const char* msg, int level); //! Retrieve a time stamp. // //! \return current time stamp (format: "yyyy-mm-dd hh:mm:ss") - std::string time_stamp(); //! Display the attributes of a particle. - extern "C" void print_particle(Particle* p); //! Display plot information. - void print_plot(); //! Display information regarding cell overlap checking. - void print_overlap_check(); //! Display information about command line usage of OpenMC - void print_usage(); //! Display current version and copright/license information - void print_version(); //! Display header listing what physical values will displayed - void print_columns(); //! Display information about a generation of neutrons - void print_generation(); //! \brief Display last batch's tallied value of the neutron multiplication //! factor as well as the average value if we're in active batches - void print_batch_keff(); //! Display time elapsed for various stages of a run - void print_runtime(); //! Display results for global tallies including k-effective estimators - void print_results(); //! Calculate the mean and standard deviation for a tally result - std::pair mean_stdev(const double* x, int n); } // namespace openmc diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 79db8032d..1e2b85c15 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -25,12 +25,12 @@ namespace settings { // Boolean flags extern "C" bool assume_separate; //!< assume tallies are spatially separate? extern "C" bool check_overlaps; //!< check overlaps in geometry? -extern "C" bool cmfd_run; //!< use CMFD? extern "C" bool confidence_intervals; //!< use confidence intervals for results? extern "C" bool create_fission_neutrons; //!< create fission neutrons (fixed source)? +extern "C" bool dagmc; //!< indicator of DAGMC geometry extern "C" bool entropy_on; //!< calculate Shannon entropy? extern "C" bool legendre_to_tabular; //!< convert Legendre distributions to tabular? -extern "C" bool output_summary; //!< write summary.h5? +extern bool output_summary; //!< write summary.h5? extern "C" bool output_tallies; //!< write tallies.out? extern "C" bool particle_restart_run; //!< particle restart run? extern "C" bool photon_transport; //!< photon transport turned on? @@ -49,7 +49,6 @@ extern bool ufs_on; //!< uniform fission site method on? extern bool urr_ptables_on; //!< use unresolved resonance prob. tables? extern "C" bool write_all_tracks; //!< write track files for every particle? extern "C" bool write_initial_source; //!< write out initial source file? -extern "C" bool dagmc; //!< indicator of DAGMC geometry // Paths to various files extern std::string path_cross_sections; //!< path to cross_sections.xml diff --git a/src/algorithm.F90 b/src/algorithm.F90 index 101b11b9a..d9f9e2e22 100644 --- a/src/algorithm.F90 +++ b/src/algorithm.F90 @@ -5,12 +5,6 @@ module algorithm implicit none - integer, parameter :: MAX_ITERATION = 64 - - interface binary_search - module procedure binary_search_real, binary_search_int4, binary_search_int8 - end interface binary_search - interface sort module procedure sort_int, sort_real, sort_vector_int, sort_vector_real end interface sort @@ -21,134 +15,6 @@ module algorithm contains -!=============================================================================== -! BINARY_SEARCH performs a binary search of an array to find where a specific -! value lies in the array. This is used extensively for energy grid searching -!=============================================================================== - - pure function binary_search_real(array, n, val) result(array_index) - - integer, intent(in) :: n - real(8), intent(in) :: array(n) - real(8), intent(in) :: val - integer :: array_index - - integer :: L - integer :: R - integer :: n_iteration - - L = 1 - R = n - - if (val < array(L) .or. val > array(R)) then - array_index = -1 - return - end if - - n_iteration = 0 - do while (R - L > 1) - ! Find values at midpoint - array_index = L + (R - L)/2 - if (val >= array(array_index)) then - L = array_index - else - R = array_index - end if - - ! check for large number of iterations - n_iteration = n_iteration + 1 - if (n_iteration == MAX_ITERATION) then - array_index = -2 - return - end if - end do - - array_index = L - - end function binary_search_real - - pure function binary_search_int4(array, n, val) result(array_index) - - integer, intent(in) :: n - integer, intent(in) :: array(n) - integer, intent(in) :: val - integer :: array_index - - integer :: L - integer :: R - integer :: n_iteration - - L = 1 - R = n - - if (val < array(L) .or. val > array(R)) then - array_index = -1 - return - end if - - n_iteration = 0 - do while (R - L > 1) - ! Find values at midpoint - array_index = L + (R - L)/2 - if (val >= array(array_index)) then - L = array_index - else - R = array_index - end if - - ! check for large number of iterations - n_iteration = n_iteration + 1 - if (n_iteration == MAX_ITERATION) then - array_index = -2 - return - end if - end do - - array_index = L - - end function binary_search_int4 - - pure function binary_search_int8(array, n, val) result(array_index) - - integer, intent(in) :: n - integer(8), intent(in) :: array(n) - integer(8), intent(in) :: val - integer :: array_index - - integer :: L - integer :: R - integer :: n_iteration - - L = 1 - R = n - - if (val < array(L) .or. val > array(R)) then - array_index = -1 - return - end if - - n_iteration = 0 - do while (R - L > 1) - ! Find values at midpoint - array_index = L + (R - L)/2 - if (val >= array(array_index)) then - L = array_index - else - R = array_index - end if - - ! check for large number of iterations - n_iteration = n_iteration + 1 - if (n_iteration == MAX_ITERATION) then - array_index = -2 - return - end if - end do - - array_index = L - - end function binary_search_int8 - !=============================================================================== ! SORT sorts an array in place using an insertion sort. !=============================================================================== diff --git a/src/constants.F90 b/src/constants.F90 index 0b3927f03..602a4e249 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -14,20 +14,9 @@ module constants integer, parameter :: & VERSION(3) = [VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE] - ! HDF5 data format - integer, parameter :: HDF5_VERSION(2) = [2, 0] - - ! WMP data format - integer, parameter :: WMP_VERSION(2) = [1, 1] - ! Version numbers for binary files - integer, parameter :: VERSION_STATEPOINT(2) = [17, 0] - integer, parameter :: VERSION_PARTICLE_RESTART(2) = [2, 0] integer, parameter :: VERSION_TRACK(2) = [2, 0] - integer, parameter :: VERSION_SUMMARY(2) = [6, 0] integer, parameter :: VERSION_VOLUME(2) = [1, 0] - integer, parameter :: VERSION_VOXEL(2) = [1, 0] - integer, parameter :: VERSION_MGXS_LIBRARY(2) = [1, 0] ! ============================================================================ ! ADJUSTABLE PARAMETERS @@ -41,21 +30,14 @@ module constants ! Used for surface current tallies real(8), parameter :: TINY_BIT = 1e-8_8 - ! User for precision in geometry - real(C_DOUBLE), bind(C, name='FP_PRECISION') :: FP_PRECISION = 1e-14_8 - real(C_DOUBLE), bind(C, name='FP_REL_PRECISION') :: FP_REL_PRECISION = 1e-5_8 - real(C_DOUBLE), bind(C, name='FP_COINCIDENT') :: FP_COINCIDENT = 1e-12_8 - ! Maximum number of collisions/crossings integer, parameter :: MAX_EVENTS = 1000000 - integer, parameter :: MAX_SAMPLE = 100000 ! Maximum number of secondary particles created integer, parameter :: MAX_SECONDARY = 1000 ! Maximum number of words in a single line, length of line, and length of ! single word - integer, parameter :: MAX_WORDS = 500 integer, parameter :: MAX_LINE_LEN = 250 integer, parameter :: MAX_WORD_LEN = 150 integer, parameter :: MAX_FILE_LEN = 255 @@ -70,9 +52,7 @@ module constants PI = 3.1415926535898_8, & ! pi MASS_NEUTRON = 1.00866491588_8, & ! mass of a neutron in amu MASS_NEUTRON_EV = 939.5654133e6_8, & ! mass of a neutron in eV/c^2 - AMU = 1.660539040e-27_8, & ! 1 amu in kg C_LIGHT = 2.99792458e8_8, & ! speed of light in m/s - N_AVOGADRO = 0.6022140857_8, & ! Avogadro's number in 10^24/mol K_BOLTZMANN = 8.6173303e-5_8, & ! Boltzmann constant in eV/K INFINITY = huge(0.0_8), & ! positive infinity ZERO = 0.0_8, & @@ -112,14 +92,6 @@ module constants ! ============================================================================ ! CROSS SECTION RELATED CONSTANTS - ! Interpolation flag - integer, parameter :: & - HISTOGRAM = 1, & ! y is constant in x - LINEAR_LINEAR = 2, & ! y is linear in x - LINEAR_LOG = 3, & ! y is linear in ln(x) - LOG_LINEAR = 4, & ! ln(y) is linear in x - LOG_LOG = 5 ! ln(y) is linear in ln(x) - ! Particle type integer, parameter :: & NEUTRON = 0, & @@ -127,17 +99,6 @@ module constants ELECTRON = 2, & POSITRON = 3 - ! Angular distribution type - integer, parameter :: & - ANGLE_ISOTROPIC = 1, & ! Isotropic angular distribution (CE) - ANGLE_32_EQUI = 2, & ! 32 equiprobable bins (CE) - ANGLE_TABULAR = 3, & ! Tabular angular distribution (CE or MG) - ANGLE_LEGENDRE = 4, & ! Legendre angular distribution (MG) - ANGLE_HISTOGRAM = 5 ! Histogram angular distribution (MG) - - ! Number of mu bins to use when converting Legendres to tabular type - integer, parameter :: DEFAULT_NMU = 33 - ! Reaction types integer, parameter :: & TOTAL_XS = 1, ELASTIC = 2, N_NONELASTIC = 3, N_LEVEL = 4, MISC = 5, & @@ -173,24 +134,12 @@ module constants MGXS_ISOTROPIC = 1, & ! Isotropically Weighted Data MGXS_ANGLE = 2 ! Data by Angular Bins - ! Flag to denote this was a macroscopic data object - real(8), parameter :: & - MACROSCOPIC_AWR = -TWO - ! Secondary particle emission type integer, parameter :: & EMISSION_PROMPT = 1, & ! Prompt emission of secondary particle EMISSION_DELAYED = 2, & ! Delayed emission of secondary particle EMISSION_TOTAL = 3 ! Yield represents total emission (prompt + delayed) - ! Library types - integer, parameter :: & - LIBRARY_NEUTRON = 1, & - LIBRARY_THERMAL = 2, & - LIBRARY_PHOTON = 3, & - LIBRARY_MULTIGROUP = 4, & - LIBRARY_WMP = 5 - ! Maximum number of partial fission reactions integer, parameter :: PARTIAL_FISSION_MAX = 4 diff --git a/src/endf_header.F90 b/src/endf_header.F90 deleted file mode 100644 index d45fbe68f..000000000 --- a/src/endf_header.F90 +++ /dev/null @@ -1,191 +0,0 @@ -module endf_header - - use algorithm, only: binary_search - use constants, only: ZERO, HISTOGRAM, LINEAR_LINEAR, LINEAR_LOG, & - LOG_LINEAR, LOG_LOG - use hdf5_interface - - implicit none - - type, abstract :: Function1D - contains - procedure(function1d_evaluate_), deferred :: evaluate - procedure(function1d_from_hdf5_), deferred :: from_hdf5 - end type Function1D - - abstract interface - pure function function1d_evaluate_(this, x) result(y) - import Function1D - class(Function1D), intent(in) :: this - real(8), intent(in) :: x - real(8) :: y - end function function1d_evaluate_ - - subroutine function1d_from_hdf5_(this, dset_id) - import Function1D, HID_T - class(Function1D), intent(inout) :: this - integer(HID_T), intent(in) :: dset_id - end subroutine function1d_from_hdf5_ - end interface - -!=============================================================================== -! POLYNOMIAL represents a one-dimensional function expressed as a polynomial -!=============================================================================== - - type, extends(Function1D) :: Polynomial - real(8), allocatable :: coef(:) ! coefficients - contains - procedure :: from_hdf5 => polynomial_from_hdf5 - procedure :: evaluate => polynomial_evaluate - end type Polynomial - -!=============================================================================== -! TABULATED1D represents a one-dimensional interpolable function -!=============================================================================== - - type, extends(Function1D) :: Tabulated1D - integer :: n_regions = 0 ! # of interpolation regions - integer, allocatable :: nbt(:) ! values separating interpolation regions - integer, allocatable :: int(:) ! interpolation scheme - integer :: n_pairs ! # of pairs of (x,y) values - real(8), allocatable :: x(:) ! values of abscissa - real(8), allocatable :: y(:) ! values of ordinate - contains - procedure :: from_hdf5 => tabulated1d_from_hdf5 - procedure :: evaluate => tabulated1d_evaluate - end type Tabulated1D - -contains - -!=============================================================================== -! Polynomial implementation -!=============================================================================== - - subroutine polynomial_from_hdf5(this, dset_id) - class(Polynomial), intent(inout) :: this - integer(HID_T), intent(in) :: dset_id - - integer(HSIZE_T) :: dims(1) - - call get_shape(dset_id, dims) - allocate(this % coef(dims(1))) - call read_dataset(this % coef, dset_id) - end subroutine polynomial_from_hdf5 - - pure function polynomial_evaluate(this, x) result(y) - class(Polynomial), intent(in) :: this - real(8), intent(in) :: x - real(8) :: y - - integer :: i - - ! Use Horner's rule to evaluate polynomial. Note that coefficients are - ! ordered in increasing powers of x. - y = ZERO - do i = size(this % coef), 1, -1 - y = y*x + this % coef(i) - end do - end function polynomial_evaluate - -!=============================================================================== -! Tabulated1D implementation -!=============================================================================== - - subroutine tabulated1d_from_hdf5(this, dset_id) - class(Tabulated1D), intent(inout) :: this - integer(HID_T), intent(in) :: dset_id - - real(8), allocatable :: xy(:,:) - integer(HSIZE_T) :: dims(2) - - call read_attribute(this % nbt, dset_id, 'breakpoints') - call read_attribute(this % int, dset_id, 'interpolation') - this % n_regions = size(this % nbt) - - call get_shape(dset_id, dims) - this % n_pairs = int(dims(1), 4) - allocate(this % x(this % n_pairs)) - allocate(this % y(this % n_pairs)) - - allocate(xy(dims(1), dims(2))) - call read_dataset(xy, dset_id) - this % x(:) = xy(:,1) - this % y(:) = xy(:,2) - end subroutine tabulated1d_from_hdf5 - - pure function tabulated1d_evaluate(this, x) result(y) - class(Tabulated1D), intent(in) :: this - real(8), intent(in) :: x ! x value to find y at - real(8) :: y ! y(x) - - integer :: i ! bin in which to interpolate - integer :: j ! index for interpolation region - integer :: n_regions ! number of interpolation regions - integer :: n_pairs ! number of tabulated values - integer :: interp ! ENDF interpolation scheme - real(8) :: r ! interpolation factor - real(8) :: x0, x1 ! bounding x values - real(8) :: y0, y1 ! bounding y values - - ! determine number of interpolation regions and pairs - n_regions = this % n_regions - n_pairs = this % n_pairs - - ! find which bin the abscissa is in -- if the abscissa is outside the - ! tabulated range, the first or last point is chosen, i.e. no interpolation - ! is done outside the energy range - if (x < this % x(1)) then - y = this % y(1) - return - elseif (x > this % x(n_pairs)) then - y = this % y(n_pairs) - return - else - i = binary_search(this % x, n_pairs, x) - end if - - ! determine interpolation scheme - if (n_regions == 0) then - interp = LINEAR_LINEAR - elseif (n_regions == 1) then - interp = this % int(1) - elseif (n_regions > 1) then - do j = 1, n_regions - if (i < this % nbt(j)) then - interp = this % int(j) - exit - end if - end do - end if - - ! handle special case of histogram interpolation - if (interp == HISTOGRAM) then - y = this % y(i) - return - end if - - ! determine bounding values - x0 = this % x(i) - x1 = this % x(i + 1) - y0 = this % y(i) - y1 = this % y(i + 1) - - ! determine interpolation factor and interpolated value - select case (interp) - case (LINEAR_LINEAR) - r = (x - x0)/(x1 - x0) - y = y0 + r*(y1 - y0) - case (LINEAR_LOG) - r = log(x/x0)/log(x1/x0) - y = y0 + r*(y1 - y0) - case (LOG_LINEAR) - r = (x - x0)/(x1 - x0) - y = y0*exp(r*log(y1/y0)) - case (LOG_LOG) - r = log(x/x0)/log(x1/x0) - y = y0*exp(r*log(y1/y0)) - end select - - end function tabulated1d_evaluate - -end module endf_header diff --git a/src/geometry_header.F90 b/src/geometry_header.F90 index 1ac6ba423..8c18a4030 100644 --- a/src/geometry_header.F90 +++ b/src/geometry_header.F90 @@ -2,12 +2,8 @@ module geometry_header use, intrinsic :: ISO_C_BINDING - use algorithm, only: find - use constants, only: K_BOLTZMANN, MATERIAL_VOID use dict_header, only: DictIntInt use nuclide_header - use stl_vector, only: VectorReal - use string, only: to_lower implicit none diff --git a/src/initialize.F90 b/src/initialize.F90 index 45ed2047e..b51d81b5b 100644 --- a/src/initialize.F90 +++ b/src/initialize.F90 @@ -20,14 +20,6 @@ module initialize import C_PTR type(C_PTR) :: ptr end function - function path_statepoint_c() result(ptr) bind(C) - import C_PTR - type(C_PTR) :: ptr - end function - function path_sourcepoint_c() result(ptr) bind(C) - import C_PTR - type(C_PTR) :: ptr - end function end interface contains @@ -55,14 +47,6 @@ contains else path_input = '' end if - if (.not. is_null(path_statepoint_c())) then - call c_f_pointer(path_statepoint_c(), string, [255]) - path_state_point = to_f_string(string) - end if - if (.not. is_null(path_sourcepoint_c())) then - call c_f_pointer(path_sourcepoint_c(), string, [255]) - path_source_point = to_f_string(string) - end if if (.not. is_null(path_particle_restart_c())) then call c_f_pointer(path_particle_restart_c(), string, [255]) path_particle_restart = to_f_string(string) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 1e2a03a45..bf661fcdb 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -22,9 +22,8 @@ module input_xml use surface_header use settings use stl_vector, only: VectorInt, VectorReal, VectorChar - use string, only: to_lower, to_str, str_to_int, str_to_real, & - starts_with, ends_with, split_string, & - zero_padded, to_c_string + use string, only: to_lower, to_str, str_to_int, & + starts_with, ends_with, to_c_string use tally use tally_header, only: openmc_extend_tallies use tally_derivative_header diff --git a/src/math.F90 b/src/math.F90 index 5a0a582a4..81856c93c 100644 --- a/src/math.F90 +++ b/src/math.F90 @@ -5,9 +5,6 @@ module math implicit none private public :: t_percentile - public :: calc_pn - public :: calc_rn - public :: rotate_angle interface @@ -18,50 +15,6 @@ module math integer(C_INT), value, intent(in) :: df real(C_DOUBLE) :: t end function t_percentile - - pure subroutine calc_pn(n, x, pnx) bind(C, name='calc_pn_c') - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: n - real(C_DOUBLE), value, intent(in) :: x - real(C_DOUBLE), intent(out) :: pnx(n + 1) - end subroutine calc_pn - - pure subroutine calc_rn(n, uvw, rn) bind(C, name='calc_rn_c') - use ISO_C_BINDING - implicit none - integer(C_INT), value, intent(in) :: n - real(C_DOUBLE), intent(in) :: uvw(3) - real(C_DOUBLE), intent(out) :: rn(2 * n + 1) - end subroutine calc_rn - - subroutine rotate_angle_c_intfc(uvw, mu, phi) bind(C, name='rotate_angle_c') - use ISO_C_BINDING - implicit none - real(C_DOUBLE), intent(inout) :: uvw(3) - real(C_DOUBLE), value, intent(in) :: mu - real(C_DOUBLE), optional, intent(in) :: phi - end subroutine rotate_angle_c_intfc end interface -contains - -!=============================================================================== -! ROTATE_ANGLE rotates direction cosines through a polar angle whose cosine is -! mu and through an azimuthal angle sampled uniformly. Note that this is done -! with direct sampling rather than rejection as is done in MCNP and SERPENT. -!=============================================================================== - - function rotate_angle(uvw0, mu, phi) result(uvw) - real(C_DOUBLE), intent(in) :: uvw0(3) ! directional cosine - real(C_DOUBLE), intent(in) :: mu ! cosine of angle in lab or CM - real(C_DOUBLE), intent(in), optional :: phi ! azimuthal angle - - real(C_DOUBLE) :: uvw(3) ! rotated directional cosine - - uvw = uvw0 - call rotate_angle_c_intfc(uvw, mu, phi) - - end function rotate_angle - end module math diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 78d436bdd..d020de7e2 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -3,10 +3,9 @@ module nuclide_header use, intrinsic :: ISO_FORTRAN_ENV use, intrinsic :: ISO_C_BINDING - use algorithm, only: sort, find, binary_search + use algorithm, only: sort, find use constants use endf, only: is_fission, is_disappearance - use endf_header, only: Function1D, Polynomial, Tabulated1D use error use hdf5_interface use message_passing diff --git a/src/output.F90 b/src/output.F90 index 209d588b2..bfab4ddbf 100644 --- a/src/output.F90 +++ b/src/output.F90 @@ -22,7 +22,6 @@ module output use tally_filter use tally_filter_mesh, only: MeshFilter use tally_filter_header, only: TallyFilterMatch - use timer_header implicit none diff --git a/src/random_lcg.F90 b/src/random_lcg.F90 index d64717cf4..84dac0a1b 100644 --- a/src/random_lcg.F90 +++ b/src/random_lcg.F90 @@ -11,41 +11,16 @@ module random_lcg real(C_DOUBLE) :: pseudo_rn end function prn - function future_prn(n) result(pseudo_rn) bind(C) - use ISO_C_BINDING - implicit none - integer(C_INT64_T), value :: n - real(C_DOUBLE) :: pseudo_rn - end function future_prn - subroutine set_particle_seed(id) bind(C) use ISO_C_BINDING implicit none integer(C_INT64_T), value :: id end subroutine set_particle_seed - subroutine advance_prn_seed(n) bind(C) - use ISO_C_BINDING - implicit none - integer(C_INT64_T), value :: n - end subroutine advance_prn_seed - subroutine prn_set_stream(n) bind(C) use ISO_C_BINDING implicit none integer(C_INT), value :: n end subroutine prn_set_stream - - function openmc_get_seed() result(seed) bind(C) - use ISO_C_BINDING - implicit none - integer(C_INT64_T) :: seed - end function openmc_get_seed - - subroutine openmc_set_seed(new_seed) bind(C) - use ISO_C_BINDING - implicit none - integer(C_INT64_T), value :: new_seed - end subroutine openmc_set_seed end interface end module random_lcg diff --git a/src/settings.F90 b/src/settings.F90 index f0b6a131f..71cb70449 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -88,14 +88,9 @@ module settings character(MAX_FILE_LEN) :: path_input ! Path to input file character(MAX_FILE_LEN) :: path_cross_sections = '' ! Path to cross_sections.xml - character(MAX_FILE_LEN) :: path_state_point ! Path to binary state point - character(MAX_FILE_LEN) :: path_source_point ! Path to binary source point character(MAX_FILE_LEN) :: path_particle_restart ! Path to particle restart character(MAX_FILE_LEN) :: path_output = '' ! Path to output directory - ! Various output options - logical(C_BOOL), bind(C) :: output_summary - ! No reduction at end of batch logical(C_BOOL), bind(C) :: reduce_tallies diff --git a/src/settings.cpp b/src/settings.cpp index 78f90082c..3d40eaea3 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -38,9 +38,9 @@ namespace settings { // Default values for boolean flags bool assume_separate {false}; bool check_overlaps {false}; -bool cmfd_run {false}; bool confidence_intervals {false}; bool create_fission_neutrons {true}; +bool dagmc {false}; bool entropy_on {false}; bool legendre_to_tabular {true}; bool output_summary {true}; @@ -62,7 +62,6 @@ bool ufs_on {false}; bool urr_ptables_on {true}; bool write_all_tracks {false}; bool write_initial_source {false}; -bool dagmc {false}; std::string path_cross_sections; std::string path_input; diff --git a/src/state_point.F90 b/src/state_point.F90 index 113ce1749..217e31c05 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -22,11 +22,10 @@ module state_point use nuclide_header, only: nuclides use settings use simulation_header - use string, only: to_str, zero_padded + use string, only: to_str use tally_header use tally_filter_header use tally_derivative_header, only: tally_derivs - use timer_header implicit none diff --git a/src/string.F90 b/src/string.F90 index 6a2b3ae90..f0419e2c1 100644 --- a/src/string.F90 +++ b/src/string.F90 @@ -2,7 +2,7 @@ module string use, intrinsic :: ISO_C_BINDING - use constants, only: MAX_WORDS, MAX_LINE_LEN, ERROR_INT, ERROR_REAL + use constants, only: ERROR_INT, ERROR_REAL use error, only: fatal_error, warning use stl_vector, only: VectorInt @@ -14,81 +14,6 @@ module string contains -!=============================================================================== -! SPLIT_STRING takes a sentence and splits it into separate words much like the -! Python string.split() method. -! -! Arguments: -! string = input line -! words = array of words -! n = total number of words -!=============================================================================== - - subroutine split_string(string, words, n) - character(*), intent(in) :: string - character(*), intent(out) :: words(MAX_WORDS) - integer, intent(out) :: n - - character(1) :: chr ! current character - integer :: i ! current index - integer :: i_start ! starting index of word - integer :: i_end ! ending index of word - - i_start = 0 - i_end = 0 - n = 0 - do i = 1, len_trim(string) - chr = string(i:i) - - ! Note that ACHAR(9) is a horizontal tab - if ((i_start == 0) .and. (chr /= ' ') .and. (chr /= achar(9))) then - i_start = i - end if - if (i_start > 0) then - if ((chr == ' ') .or. (chr == achar(9))) i_end = i - 1 - if (i == len_trim(string)) i_end = i - if (i_end > 0) then - n = n + 1 - if (i_end - i_start + 1 > len(words(n))) then - call warning("The word '" // string(i_start:i_end) & - // "' is longer than the space allocated for it.") - end if - words(n) = string(i_start:i_end) - ! reset indices - i_start = 0 - i_end = 0 - end if - end if - end do - - end subroutine split_string - -!=============================================================================== -! CONCATENATE takes an array of words and concatenates them together in one -! string with a single space between words -! -! Arguments: -! words = array of words -! n_words = total number of words -! string = concatenated string -!=============================================================================== - - pure function concatenate(words, n_words) result(string) - - integer, intent(in) :: n_words - character(*), intent(in) :: words(n_words) - character(MAX_LINE_LEN) :: string - - integer :: i ! index - - string = words(1) - if (n_words == 1) return - do i = 2, n_words - string = trim(string) // ' ' // words(i) - end do - - end function concatenate - !=============================================================================== ! TO_LOWER converts a string to all lower case characters !=============================================================================== @@ -300,23 +225,6 @@ contains end function str_to_int -!=============================================================================== -! STR_TO_REAL converts an arbitrary string to a real(8) -!=============================================================================== - - pure function str_to_real(string) result(num) - - character(*), intent(in) :: string - real(8) :: num - - integer :: ioError - - ! Read string - read(UNIT=string, FMT=*, IOSTAT=ioError) num - if (ioError > 0) num = ERROR_REAL - - end function str_to_real - !=============================================================================== ! REAL_TO_STR converts a real(8) to a string based on how large the value is and ! how many significant digits are desired. By default, six significants digits diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 20087eab7..75072d644 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -2,14 +2,12 @@ module tally use, intrinsic :: ISO_C_BINDING - use algorithm, only: binary_search use bank_header use constants use dict_header, only: EMPTY use error, only: fatal_error use geometry_header use material_header - use math, only: t_percentile use message_passing use mgxs_interface use nuclide_header diff --git a/src/timer_header.F90 b/src/timer_header.F90 index f1c89242e..3bbc20762 100644 --- a/src/timer_header.F90 +++ b/src/timer_header.F90 @@ -4,57 +4,6 @@ module timer_header use constants, only: ZERO - implicit none - - interface - function time_active_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_bank_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_bank_sample_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_bank_sendrecv_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_finalize_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_inactive_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_initialize_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_read_xs_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_tallies_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_total_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - function time_transport_elapsed() result(t) bind(C) - import C_DOUBLE - real(C_DOUBLE) :: t - end function - subroutine reset_timers() bind(C) - end subroutine - end interface - !=============================================================================== ! TIMER represents a timer that can be started and stopped to measure how long ! different routines run. The intrinsic routine system_clock is used to measure @@ -73,9 +22,6 @@ module timer_header procedure :: reset => timer_reset end type Timer - ! ============================================================================ - ! TIMING VARIABLES - contains !=============================================================================== From 6e2a601fe96e20a58188d736cd7ba4e107fec4ae Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 6 Feb 2019 17:44:16 -0600 Subject: [PATCH 09/16] Adding vacuum BCs to graveyard volumes automatically. --- src/dagmc.cpp | 23 ++++++++++++++++++++++- tests/regression_tests/dagmc/dagmc.h5m | Bin 1233584 -> 1233372 bytes tests/regression_tests/uwuw/dagmc.h5m | Bin 1244548 -> 1244336 bytes 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 1acef1262..a86f3c3e0 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -134,7 +134,7 @@ void load_dagmc_geometry() // initialize cell objects model::n_cells = model::DAG->num_entities(3); - + moab::EntityHandle graveyard = 0; for (int i = 0; i < model::n_cells; i++) { moab::EntityHandle vol_handle = model::DAG->entity_by_index(3, i+1); @@ -199,6 +199,11 @@ void load_dagmc_geometry() std::string cmp_str = mat_value; to_lower(cmp_str); + + if (cmp_str.find("graveyard") != std::string::npos) { + graveyard = vol_handle; + } + // material void checks if (cmp_str.find("void") != std::string::npos || cmp_str.find("vacuum") != std::string::npos || @@ -231,6 +236,11 @@ void load_dagmc_geometry() model::overlap_check_count.resize(model::cells.size(), 0); } + if (!graveyard) { + std::cout << "WARNING: No graveyard volume found in the DagMC model.\n"; + std::cout << "This may result in lost particles and rapid simulation failure.\n"; + } + /// Surfaces \\\ // initialize surface objects @@ -271,6 +281,17 @@ void load_dagmc_geometry() s->bc_ = BC_TRANSMIT; } + // graveyard check + moab::Range parent_vols; + rval = model::DAG->moab_instance()->get_parent_meshsets(surf_handle, parent_vols); + MB_CHK_ERR_CONT(rval); + + // if this surface belongs to the graveyard + if (graveyard && parent_vols.find(graveyard) != parent_vols.end()) { + // set BC to vacuum + s->bc_ = BC_VACUUM; + } + // add to global array and map model::surfaces[i] = s; model::surface_map[s->id_] = s->id_; diff --git a/tests/regression_tests/dagmc/dagmc.h5m b/tests/regression_tests/dagmc/dagmc.h5m index 49c28c4f5e32f9d72c4603b128c3fc1fb1a00e4e..a55e061dcac9f0bf284ecd0741d62c1bafb6a77c 100644 GIT binary patch delta 953 zcmdn6)cek2?+F@AcP?(!nkUUTfAdLcWkzPz!syBGWgf{J=^L2o8(K0kKmZ4nHZ->~ zF}5-`-uyu}MgXLEv%g*}Cz!F`T$Tf@{k;85&S0o|mg$1V0^*Z99E_M}=m|`gEtCf< zx$iKOQ$PWtMqqNIqa$+z1LNe{C~>e!_Z@k`4%z(P3Cj5ITr9@)!(wttlmbM*=6^i%Dun_BIjTSH+iyr%FN9PNwXN49#l>KlMFU% zvwVs%6L-T-L9jsq2xov53#3OdPQFnfHMuHLlXIsKSd97BechtXGb`q^fV41*Oy=%Y1X~5tkyNL_C36B@$L95Qm)RI?P*i5M zX)wCLMeGX~ZjNZ*#LDOc7t-&2%@_jXZMN^TW@CyuF}Y?6#Ch|lyk=rKIeAS6BplaI zRc2!fIW_suVu-Z-lGjWwr{P@vrH3b{KWoHIS}gpfLrS_q_;zc?YpIsL;$A&2P#mxNe2-HQ^-QY#aSQYLN`o?dWC$N>Pt C2{g_C delta 1063 zcmaiyT}V@57{||h=1x1u)U!h$n#v3>whA^)WIJ259lbE}A`KB)MoonlVYX6AbeaV1 zq7Rf;IWE%8Y%(u$t8=kT1fjrLhOTau0;MZqgrln>!CuchH|wSYKi-e$|NPJMJm-8J zuMP*Q`*mda)63(d`M@tNo4^G1tbD%9z;1i4EMBvDX|4#XIM^o$ihcq> zxBal}xh7=EB}tnV$<21IVPQHv@0{0PvMyD zbjlfOTD;QbrYC@8yWm!{>?LVh%E-*{v|6sFCS8UsX0J2=dbh1Q=yIajynzpgaO#rt z7X_Wp1F+Gkr)y?7*-!8-gsj;q_rU0zCA83J)I z2lFTJi>woU6iwlOiJ)Muk!R*&*tF#Dai&G9FL)-A6wReYsONhtQ=XM6fFKbHL&8;PW^vEJ7V|Sh!FxP(-q3I3Ef8k-#ih#fXdZoDPhL-{(1PPE%XQ^%lp?PIJAZ zxuc_1{4&qwq1eIbp4cTEi=2pZY8v>(@)%d8{U$36bbYf{>l)TAw&Hq#3+`GgmycO<@#v74^67=Je1 zu4=;GUgiZ^ww${EKC&dLcoMB5>ysGk6j^IW}EM0w7q0egynHQ zczGZ=)W0smvLN#Wc-W#@K`*O<2zC5 z+v!~mKMIj;z9YGL4%xZ#MypOLMQHvIs5;HH*Lr#m6%2#RCEOgl&cun(owtCeg9}T~ z&!IWDeXsIw2f(dw;<3~_Tx+~F^RdtuTk?cRDsXpjKD@ab>}zu8pvkBUY>-x6s1aep z<)I6`L&w8LxuWr_6PnUoS_4h~kd9|8Lv5=N^jtU5*)Y+GK%r24C;^lZN(AKx*2f=ka9L+$Utcfa-ogW}t`M)~651BN6C`n}Qp$ zwelJ1_KWDesdfC?t_U6h3kJuU8l#A_5MW0FHBnxZ_3iG?p z$b!MB^3YmvpBBadzs@fgSb(w<_7rBS|sH(2i8S~R%uq#Bx6nkn9 zyTY$C22YL3Df#=P$4@-nG*4+fO%|wxTq=)3&Ks ze4nXwn4fnoKJN^Mz CUNDUS delta 1565 zcmaJ>eN0nV6z_Ybr7d6Wl~18Q3|U~BQ9w;w%4lo1X=0|RWWmZ*)Qv6@AJRw3lGIZVX^%4}H6LAs%rg%O9?ni!;&7)(q- znDwvkfQw0gVws|>Euu^*%Ag-kV9k(bXJuw@-b{Feh5Y4YVpsb6T*~MY3po^hSZ)^N z2l7J#Yd$=sQ1Y&&^C`cU2leWBDtSg>=7MB83&1+1lG(sOV3j(K(wtF7P$dzITLZ>R z)rnX%O$tw{lWD&4I#lf6%4?F*(h?*n{ZiFNY%f%^!tUkJF-2}r8DdAx#G%7qA}GHS z`j1dr1a@>28rIz_psLARErUwt7Z)JhmA3MsRzuF_2K>B{rVeYKu%Sj14GYET+`OBB zl4ydJ>V#mG8qHd`^hp|X?iPTz6d2W?T&rZ^;iG_qps-DqjSc|3Z3(P__3H2y-b&b9 zA!QZ}0Qg%HMTK3}mkG1Z5<M>KseeZFua{ zRKye9k!#zC0^@fq#24HWeKC(R2BE%+Zdra_#zr}$f02F@mW%V`eLB}jDH2_cDQuMS zEA(HXquAH;sAts`wf_R|TuS4*hUif-UKy2%xYn|Vg}C6eD|B_s+?iNdV_WQJG1|xVEW|Y@oNt*ap%JT%0?5jy+&!@*bjpLmN36unr zLkWQ#9}Ox@kt15MKaJ;gD`CoH-QC3T5avOz&0K})DO~-OZcOHkQ#OP zczNm3qOw!j?-d;>FE7FW=m!a8EN0-9*g-mG+c*FOT%;A>avyBl@E>AeR;x=%(aC_O z$r_6{-v^h`?nzuR0+N}H zd0qb2m?W}h@r5y?JGampflq3~07|B-aW5jBoLrnG#d};#Zph`d9umoal8I#~Z zJbKx0BRv5pKCk)k8w(4aqPyoj70Quj$JEfi=|Ka31n+$c)as9NP8WNVTKdCu0+IWJ z=ASm|V!GVreRYJyDE7uqJ7v1KMR%3HHp(l=b*B2FE$$QgI*~W#2dCHSR1Alq&r{hiN@V!g>{<_ZlB(N z<{NE9r=z@Qo!Irxl;JCFSgE6=M_A$7Id$fyHfq69)q_R3lsN{Ym$S}sM3=PdfGfJ? z_FmoEVb{JK<3lgHbN1~%1McM=a2(SKkGtOOJ7e=kPCF`f80J#x4HvxJTt~4lsrW|5 pL@4g#9h^ Date: Fri, 8 Feb 2019 08:58:42 -0600 Subject: [PATCH 10/16] Using warning output function instead of cout. --- src/dagmc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index a86f3c3e0..e1e56a785 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -237,8 +237,8 @@ void load_dagmc_geometry() } if (!graveyard) { - std::cout << "WARNING: No graveyard volume found in the DagMC model.\n"; - std::cout << "This may result in lost particles and rapid simulation failure.\n"; + warning("No graveyard volume found in the DagMC model."); + warning("This may result in lost particles and rapid simulation failure."); } /// Surfaces \\\ From 0adad96bf05a91b14fb6846f8347ecd4a9b0a366 Mon Sep 17 00:00:00 2001 From: Jingang Liang Date: Fri, 8 Feb 2019 12:02:51 -0800 Subject: [PATCH 11/16] fix capi: make sure capi.nuclides works after calling capi.load_nuclide --- src/nuclide.cpp | 7 +++++++ tests/unit_tests/test_capi.py | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/nuclide.cpp b/src/nuclide.cpp index b64a1681a..ee1a35111 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -893,6 +893,8 @@ void check_data_version(hid_t file_id) //============================================================================== extern "C" void extend_nuclides(); +extern "C" void nuclide_from_hdf5(hid_t group, const Nuclide* ptr, + const double* temps, int n, int n_nuclide); extern "C" int openmc_load_nuclide(const char* name) { @@ -917,6 +919,11 @@ extern "C" int openmc_load_nuclide(const char* name) int i_nuclide = data::nuclides.size(); data::nuclides.push_back(std::make_unique( group, temperature, i_nuclide)); + + // Read from Fortran too + nuclide_from_hdf5(group, data::nuclides.back().get(), + &temperature.front(), temperature.size(), i_nuclide + 1); + close_group(group); file_close(file_id); diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index e69d15a27..eb9a577a5 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -390,7 +390,11 @@ def test_restart(capi_init): def test_load_nuclide(capi_init): + # load multiple nuclides openmc.capi.load_nuclide('H3') + assert 'H3' in openmc.capi.nuclides openmc.capi.load_nuclide('Pu239') + assert 'Pu239' in openmc.capi.nuclides + # load non-existent nuclide with pytest.raises(exc.DataError): openmc.capi.load_nuclide('Pu3') From f8c8e4e9725e053140575f00321eac858f887277 Mon Sep 17 00:00:00 2001 From: Jingang Liang Date: Fri, 8 Feb 2019 12:03:50 -0800 Subject: [PATCH 12/16] updated depletion test to perform loading of new nuclides from the chain --- .../deplete/example_geometry.py | 4 ---- .../deplete/test_reference.h5 | Bin 162944 -> 162944 bytes tests/unit_tests/test_deplete_resultslist.py | 14 +++++--------- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/tests/regression_tests/deplete/example_geometry.py b/tests/regression_tests/deplete/example_geometry.py index ca10c1f72..e54c087f6 100644 --- a/tests/regression_tests/deplete/example_geometry.py +++ b/tests/regression_tests/deplete/example_geometry.py @@ -47,10 +47,8 @@ def generate_initial_number_density(): fuel_dict['U238'] = 2.21371e22 fuel_dict['O16'] = 4.62954e22 fuel_dict['O17'] = 1.127684e20 - fuel_dict['I135'] = 1.0e10 fuel_dict['Xe135'] = 1.0e10 fuel_dict['Xe136'] = 1.0e10 - fuel_dict['Cs135'] = 1.0e10 fuel_dict['Gd156'] = 1.0e10 fuel_dict['Gd157'] = 1.0e10 # fuel_dict['O18'] = 9.51352e19 # Does not exist in ENDF71, merged into 17 @@ -62,10 +60,8 @@ def generate_initial_number_density(): fuel_gd_dict['Gd156'] = 3.95517E+10 fuel_gd_dict['Gd157'] = 1.08156e20 fuel_gd_dict['O16'] = 4.64035e22 - fuel_dict['I135'] = 1.0e10 fuel_dict['Xe136'] = 1.0e10 fuel_dict['Xe135'] = 1.0e10 - fuel_dict['Cs135'] = 1.0e10 # There are a whole bunch of 1e-10 stuff here. # Concentration to be used for cladding diff --git a/tests/regression_tests/deplete/test_reference.h5 b/tests/regression_tests/deplete/test_reference.h5 index 8750924b113a357b3c880dc04000a5eb1a077710..2f1ef375a96765688cba8e9cbafe98d6b6eedf3f 100644 GIT binary patch literal 162944 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

JF|%HB(*jv~T<5j?Q{??FF-W8zxHU7Q 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 tXh#pD@Xg7-?c+hKP-x{{aAOy`=yE diff --git a/tests/unit_tests/test_deplete_resultslist.py b/tests/unit_tests/test_deplete_resultslist.py index 994ee531a..5a066be6e 100644 --- a/tests/unit_tests/test_deplete_resultslist.py +++ b/tests/unit_tests/test_deplete_resultslist.py @@ -20,8 +20,7 @@ def test_get_atoms(res): t, n = res.get_atoms("1", "Xe135") t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0] - n_ref = [6.674732823364922e+08, 4.022377919003244e+14, - 3.469325382312551e+14, 3.639463751297369e+14] + n_ref = [6.67473282e+08, 3.76986925e+14, 3.68587383e+14, 3.91338675e+14] np.testing.assert_allclose(t, t_ref) np.testing.assert_allclose(n, n_ref) @@ -32,13 +31,11 @@ def test_get_reaction_rate(res): t, r = res.get_reaction_rate("1", "Xe135", "(n,gamma)") t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0] - n_ref = [6.674732823364922e+08, 4.022377919003244e+14, - 3.469325382312551e+14, 3.639463751297369e+14] - xs_ref = np.array([3.272630849911638e-05, 2.663333206501429e-05, - 3.378999816491878e-05, 3.277013860196171e-05]) + n_ref = [6.67473282e+08, 3.76986925e+14, 3.68587383e+14, 3.91338675e+14] + xs_ref = [3.32282266e-05, 2.76207120e-05, 4.10986677e-05, 3.72453665e-05] np.testing.assert_allclose(t, t_ref) - np.testing.assert_allclose(r, n_ref * xs_ref) + np.testing.assert_allclose(r, np.array(n_ref) * xs_ref) def test_get_eigenvalue(res): @@ -46,8 +43,7 @@ def test_get_eigenvalue(res): t, k = res.get_eigenvalue() t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0] - k_ref = [1.2162584685809341, 1.1021840248590875, 1.223040353281542, - 1.2360979537312164] + k_ref = [1.16984322, 1.19097427, 1.03012572, 1.20045627] np.testing.assert_allclose(t, t_ref) np.testing.assert_allclose(k, k_ref) From 4c4d871c86d1e2c073e1b926531bbb5173a2d684 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 9 Feb 2019 14:09:10 -0600 Subject: [PATCH 13/16] Allowing for an implicit complement material in legacy DAGMC formats. --- src/dagmc.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index e1e56a785..85ea79153 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -175,10 +175,22 @@ void load_dagmc_geometry() if (model::DAG->is_implicit_complement(vol_handle)) { if (model::DAG->has_prop(vol_handle, "mat")) { // if the implicit complement has been assigned a material, use it - std::string comp_mat = DMD.volume_material_property_data_eh[vol_handle]; - // Note: material numbers are set by UWUW - int mat_number = uwuw.material_library[comp_mat].metadata["mat_number"].asInt(); - c->material_.push_back(mat_number); + if (using_uwuw) { + std::string comp_mat = DMD.volume_material_property_data_eh[vol_handle]; + // Note: material numbers are set by UWUW + int mat_number = uwuw.material_library[comp_mat].metadata["mat_number"].asInt(); + c->material_.push_back(mat_number); + } else { + std::string mat_value; + rval= model::DAG->prop_value(vol_handle, "mat", mat_value); + MB_CHK_ERR_CONT(rval); + // remove _comp + std::string _comp = "_comp"; + size_t _comp_pos = mat_value.find(_comp); + if (_comp_pos != std::string::npos) { mat_value.erase(_comp_pos, _comp.length()); } + // assign IC material by id + c->material_.push_back(std::stoi(mat_value)); + } } else { // if no material is found, the implicit complement is void c->material_.push_back(MATERIAL_VOID); From 73a9011e609a18c95f5fd5a5afda242a67299c13 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 10 Feb 2019 08:56:21 -0600 Subject: [PATCH 14/16] Removing additional warning call. --- src/dagmc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 85ea79153..22f9d392a 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -249,8 +249,8 @@ void load_dagmc_geometry() } if (!graveyard) { - warning("No graveyard volume found in the DagMC model."); - warning("This may result in lost particles and rapid simulation failure."); + warning("No graveyard volume found in the DagMC model." + "This may result in lost particles and rapid simulation failure."); } /// Surfaces \\\ From 20fa6fa5daa2cd6ce549d20537716a966252b427 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 11 Feb 2019 13:20:06 -0600 Subject: [PATCH 15/16] Respond to @smharper and @pshriwise comments on #1154 --- include/openmc/output.h | 4 --- src/output.cpp | 55 ++++++++++++++++++++++------------------- src/state_point.cpp | 2 -- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/include/openmc/output.h b/include/openmc/output.h index 385ef08a9..e2387dd27 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -5,7 +5,6 @@ #define OPENMC_OUTPUT_H #include -#include // for pair #include "openmc/particle.h" @@ -57,8 +56,5 @@ void print_runtime(); //! Display results for global tallies including k-effective estimators void print_results(); -//! Calculate the mean and standard deviation for a tally result -std::pair mean_stdev(const double* x, int n); - } // namespace openmc #endif // OPENMC_OUTPUT_H diff --git a/src/output.cpp b/src/output.cpp index 567a588fa..2acd50efd 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -2,11 +2,12 @@ #include // for std::transform #include // for strlen -#include // for setw, setprecision +#include // for time, localtime +#include // for setw, setprecision, put_time #include // for fixed, scientific, left #include #include -#include +#include // for pair #include #include "xtensor/xview.hpp" @@ -414,16 +415,20 @@ void print_batch_keff() //============================================================================== -void show_time(const char* label, double value) +void show_time(const char* label, double secs, int indent_level=0) { - std::cout << " " << std::setw(33) << std::left << label << " = " - << std::setw(10) << std::right << value << " seconds\n"; + for (int i = 0; i < indent_level; ++i) { + std::cout << " "; + } + int width = 33 - indent_level*2; + std::cout << " " << std::setw(width) << std::left << label << " = " + << std::setw(10) << std::right << secs << " seconds\n"; } -void show_rate(const char* label, double value) +void show_rate(const char* label, double particles_per_sec) { std::cout << " " << std::setw(33) << std::left << label << " = " << - value << " particles/second\n"; + particles_per_sec << " particles/second\n"; } void print_runtime() @@ -439,20 +444,20 @@ void print_runtime() // display time elapsed for various sections std::cout << std::scientific << std::setprecision(4); show_time("Total time for initialization", time_initialize.elapsed()); - show_time(" Reading cross sections", time_read_xs.elapsed()); + show_time("Reading cross sections", time_read_xs.elapsed(), 1); show_time("Total time in simulation", time_inactive.elapsed() + time_active.elapsed()); - show_time(" Time in transport only", time_transport.elapsed()); + show_time("Time in transport only", time_transport.elapsed(), 1); if (settings::run_mode == RUN_MODE_EIGENVALUE) { - show_time(" Time in inactive batches", time_inactive.elapsed()); + show_time("Time in inactive batches", time_inactive.elapsed(), 1); } - show_time(" Time in active batches", time_active.elapsed()); + show_time("Time in active batches", time_active.elapsed(), 1); if (settings::run_mode == RUN_MODE_EIGENVALUE) { - show_time(" Time synchronizing fission bank", time_bank.elapsed()); - show_time(" Sampling source sites", time_bank_sample.elapsed()); - show_time(" SEND/RECV source sites", time_bank_sendrecv.elapsed()); + show_time("Time synchronizing fission bank", time_bank.elapsed(), 1); + show_time("Sampling source sites", time_bank_sample.elapsed(), 2); + show_time("SEND/RECV source sites", time_bank_sendrecv.elapsed(), 2); } - show_time(" Time accumulating tallies", time_tallies.elapsed()); + show_time("Time accumulating tallies", time_tallies.elapsed(), 1); show_time("Total time for finalization", time_finalize.elapsed()); show_time("Total time elapsed", time_total.elapsed()); @@ -499,6 +504,16 @@ void print_runtime() //============================================================================== +std::pair mean_stdev(const double* x, int n) +{ + double mean = x[RESULT_SUM] / n; + double stdev = n > 1 ? std::sqrt((x[RESULT_SUM_SQ]/n + - mean*mean)/(n - 1)) : 0.0; + return {mean, stdev}; +} + +//============================================================================== + void print_results() { // Save state of cout @@ -567,14 +582,4 @@ void print_results() std::cout.flags(f); } -//============================================================================== - -std::pair mean_stdev(const double* x, int n) -{ - double mean = x[RESULT_SUM] / n; - double stdev = n > 1 ? std::sqrt((x[RESULT_SUM_SQ]/n - - mean*mean)/(n - 1)) : 0.0; - return {mean, stdev}; -} - } // namespace openmc diff --git a/src/state_point.cpp b/src/state_point.cpp index 6dc8eafdd..6ed26dda4 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -114,11 +114,9 @@ openmc_statepoint_write(const char* filename, bool* write_source) if (!settings::reduce_tallies) { // If using the no-tally-reduction method, we need to collect tally // results before writing them to the state point file. - write_tally_results_nr(file_id); } else if (mpi::master) { - // Write number of global realizations write_dataset(file_id, "n_realizations", n_realizations); From 2ad4726c2352d00e49a0e92655c3a7ea4ecba206 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 11 Feb 2019 19:46:40 -0600 Subject: [PATCH 16/16] Small improvement suggested by @pshriwise --- src/output.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index 2acd50efd..98398af15 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -417,9 +417,7 @@ void print_batch_keff() void show_time(const char* label, double secs, int indent_level=0) { - for (int i = 0; i < indent_level; ++i) { - std::cout << " "; - } + std::cout << std::string(2*indent_level, ' '); int width = 33 - indent_level*2; std::cout << " " << std::setw(width) << std::left << label << " = " << std::setw(10) << std::right << secs << " seconds\n";