diff --git a/CMakeLists.txt b/CMakeLists.txt index 1797ae5d3..81c16aa48 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -447,7 +447,9 @@ set(LIBOPENMC_CXX_SRC src/pugixml/pugixml.hpp) add_library(libopenmc SHARED ${LIBOPENMC_FORTRAN_SRC} ${LIBOPENMC_CXX_SRC}) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) -add_executable(${program} src/main.F90) + +add_executable(${program} src/main.cpp) +target_include_directories(${program} PUBLIC include) #=============================================================================== # Add compiler/linker flags @@ -460,7 +462,7 @@ target_include_directories(libopenmc PUBLIC ${HDF5_INCLUDE_DIRS}) # The executable and the faddeeva package use only one language. They can be # set via target_compile_options which accepts a list. -target_compile_options(${program} PUBLIC ${f90flags}) +target_compile_options(${program} PUBLIC ${cxxflags}) target_compile_options(faddeeva PRIVATE ${cflags}) # The libopenmc library has both F90 and C++ so the compile flags must be set diff --git a/include/openmc.h b/include/openmc.h index ed3a86054..194545345 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -70,6 +70,7 @@ extern "C" { int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh); int openmc_next_batch(int* status); int openmc_nuclide_name(int index, char** name); + int openmc_particle_restart(); void openmc_plot_geometry(); void openmc_reset(); int openmc_run(); @@ -122,8 +123,9 @@ extern "C" { // Global variables extern char openmc_err_msg[256]; - extern double keff; - extern double keff_std; + extern double openmc_keff; + extern double openmc_keff_std; + extern bool openmc_master; extern int32_t n_batches; extern int32_t n_cells; extern int32_t n_filters; @@ -139,9 +141,16 @@ extern "C" { extern int32_t n_surfaces; extern int32_t n_tallies; extern int32_t n_universes; - extern int run_mode; - extern bool simulation_initialized; - extern int verbosity; + extern int openmc_run_mode; + extern bool openmc_simulation_initialized; + extern int openmc_verbosity; + + // Run modes + constexpr int RUN_MODE_FIXEDSOURCE {1}; + constexpr int RUN_MODE_EIGENVALUE {2}; + constexpr int RUN_MODE_PLOTTING {3}; + constexpr int RUN_MODE_PARTICLE {4}; + constexpr int RUN_MODE_VOLUME {5}; #ifdef __cplusplus } diff --git a/openmc/capi/core.py b/openmc/capi/core.py index f80b5fe54..d35690503 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -178,8 +178,9 @@ def keff(): return tuple(k) else: # Otherwise, return the tracklength estimator - mean = c_double.in_dll(_dll, 'keff').value - std_dev = c_double.in_dll(_dll, 'keff_std').value if n > 1 else np.inf + mean = c_double.in_dll(_dll, 'openmc_keff').value + std_dev = c_double.in_dll(_dll, 'openmc_keff_std').value \ + if n > 1 else np.inf return (mean, std_dev) diff --git a/openmc/capi/settings.py b/openmc/capi/settings.py index 1063d6463..d706112c4 100644 --- a/openmc/capi/settings.py +++ b/openmc/capi/settings.py @@ -20,11 +20,11 @@ class _Settings(object): generations_per_batch = _DLLGlobal(c_int32, 'gen_per_batch') inactive = _DLLGlobal(c_int32, 'n_inactive') particles = _DLLGlobal(c_int64, 'n_particles') - verbosity = _DLLGlobal(c_int, 'verbosity') + verbosity = _DLLGlobal(c_int, 'openmc_verbosity') @property def run_mode(self): - i = c_int.in_dll(_dll, 'run_mode').value + i = c_int.in_dll(_dll, 'openmc_run_mode').value try: return _RUN_MODES[i] except KeyError: @@ -32,7 +32,7 @@ class _Settings(object): @run_mode.setter def run_mode(self, mode): - current_idx = c_int.in_dll(_dll, 'run_mode') + current_idx = c_int.in_dll(_dll, 'openmc_run_mode') for idx, mode_value in _RUN_MODES.items(): if mode_value == mode: current_idx.value = idx diff --git a/src/main.F90 b/src/main.F90 deleted file mode 100644 index 372e993f5..000000000 --- a/src/main.F90 +++ /dev/null @@ -1,51 +0,0 @@ -program main - - use, intrinsic :: ISO_C_BINDING - - use constants - use message_passing - use openmc_api, only: openmc_init, openmc_finalize, openmc_run, & - openmc_plot_geometry, openmc_calculate_volumes - use particle_restart, only: run_particle_restart - use settings, only: run_mode - - implicit none - - integer(C_INT) :: err -#ifdef OPENMC_MPI - integer :: mpi_err ! MPI error code -#endif - - ! Initialize run -- when run with MPI, pass communicator -#ifdef OPENMC_MPI -#ifdef OPENMC_MPIF08 - call openmc_init(MPI_COMM_WORLD % MPI_VAL) -#else - call openmc_init(MPI_COMM_WORLD) -#endif -#else - call openmc_init() -#endif - - ! start problem based on mode - select case (run_mode) - case (MODE_FIXEDSOURCE, MODE_EIGENVALUE) - err = openmc_run() - case (MODE_PLOTTING) - call openmc_plot_geometry() - case (MODE_PARTICLE) - if (master) call run_particle_restart() - case (MODE_VOLUME) - call openmc_calculate_volumes() - end select - - ! finalize run - call openmc_finalize() - -#ifdef OPENMC_MPI - ! If MPI is in use and enabled, terminate it - call MPI_FINALIZE(mpi_err) -#endif - - -end program main diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 000000000..7b2ccb5c3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,40 @@ +#include "openmc.h" + +#ifdef MPI +#include +#else +#define MPI_COMM_WORLD nullptr +#endif + + +int main(int argc, char** argv) { + int err; + + // Initialize run -- when run with MPI, pass communicator + openmc_init(MPI_COMM_WORLD); + + // start problem based on mode + switch (openmc_run_mode) { + case RUN_MODE_FIXEDSOURCE: + case RUN_MODE_EIGENVALUE: + err = openmc_run(); + break; + case RUN_MODE_PLOTTING: + openmc_plot_geometry(); + break; + case RUN_MODE_PARTICLE: + if (openmc_master) err = openmc_particle_restart(); + break; + case RUN_MODE_VOLUME: + openmc_calculate_volumes(); + break; + } + + // Finalize and free up memory + openmc_finalize(); + + // If MPI is in use and enabled, terminate it +#ifdef MPI + err = MPI_Finalize(); +#endif +} diff --git a/src/message_passing.F90 b/src/message_passing.F90 index 7391a632c..f9a16ee75 100644 --- a/src/message_passing.F90 +++ b/src/message_passing.F90 @@ -1,5 +1,7 @@ module message_passing + use, intrinsic :: ISO_C_BINDING + #ifdef OPENMC_MPI #ifdef OPENMC_MPIF08 use mpi_f08 @@ -14,7 +16,7 @@ module message_passing integer :: n_procs = 1 ! number of processes integer :: rank = 0 ! rank of process - logical :: master = .true. ! master process? + logical(C_BOOL), bind(C, name='openmc_master') :: master = .true. ! master process? logical :: mpi_enabled = .false. ! is MPI in use and initialized? #ifdef OPENMC_MPIF08 type(MPI_Datatype) :: MPI_BANK ! MPI datatype for fission bank diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 8362f5d41..76fc26a74 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -277,7 +277,7 @@ contains integer, intent(inout) :: method real(8), intent(in) :: tolerance real(8), intent(in) :: minmax(2) ! range of temperatures - logical, intent(in) :: master ! if this is the master proc + logical(C_BOOL), intent(in) :: master ! if this is the master proc integer, intent(in) :: i_nuclide ! Nuclide index in nuclides integer :: i diff --git a/src/particle_restart.F90 b/src/particle_restart.F90 index 2d15f2ddc..fc8a05277 100644 --- a/src/particle_restart.F90 +++ b/src/particle_restart.F90 @@ -20,20 +20,23 @@ module particle_restart implicit none private - public :: run_particle_restart + public :: openmc_particle_restart contains !=============================================================================== -! RUN_PARTICLE_RESTART is the main routine that runs the particle restart +! OPENMC_PARTICLE_RESTART is the main routine that runs the particle restart !=============================================================================== - subroutine run_particle_restart() + function openmc_particle_restart() result(err) bind(C) + integer(C_INT) :: err integer(8) :: particle_seed integer :: previous_run_mode type(Particle) :: p + err = 0 + ! Set verbosity high verbosity = 10 @@ -66,7 +69,7 @@ contains deallocate(micro_xs) - end subroutine run_particle_restart + end function openmc_particle_restart !=============================================================================== ! READ_PARTICLE_RESTART reads the particle restart file diff --git a/src/settings.F90 b/src/settings.F90 index 83aebce86..4de72e8c4 100644 --- a/src/settings.F90 +++ b/src/settings.F90 @@ -75,14 +75,14 @@ module settings real(8) :: weight_survive = ONE ! Mode to run in (fixed source, eigenvalue, plotting, etc) - integer(C_INT), bind(C) :: run_mode = NONE + integer(C_INT), bind(C, name='openmc_run_mode') :: run_mode = NONE ! Restart run logical :: restart_run = .false. ! The verbosity controls how much information will be printed to the screen ! and in logs - integer(C_INT), bind(C) :: verbosity = 7 + integer(C_INT), bind(C, name='openmc_verbosity') :: verbosity = 7 logical :: check_overlaps = .false. diff --git a/src/simulation_header.F90 b/src/simulation_header.F90 index 11be9bf9c..67bf3062b 100644 --- a/src/simulation_header.F90 +++ b/src/simulation_header.F90 @@ -23,7 +23,8 @@ module simulation_header integer :: current_batch ! current batch integer :: current_gen ! current generation within a batch integer :: total_gen = 0 ! total number of generations simulated - logical(C_BOOL), bind(C) :: simulation_initialized = .false. + logical(C_BOOL), bind(C, name='openmc_simulation_initialized') :: & + simulation_initialized = .false. logical :: need_depletion_rx ! need to calculate depletion reaction rx? ! ============================================================================ @@ -40,8 +41,8 @@ module simulation_header ! Temporary k-effective values type(VectorReal) :: k_generation ! single-generation estimates of k - real(C_DOUBLE), bind(C) :: keff = ONE ! average k over active batches - real(C_DOUBLE), bind(C) :: keff_std ! standard deviation of average k + real(C_DOUBLE), bind(C, name='openmc_keff') :: keff = ONE ! average k over active batches + real(C_DOUBLE), bind(C, name='openmc_keff_std') :: keff_std ! standard deviation of average k real(8) :: k_col_abs = ZERO ! sum over batches of k_collision * k_absorption real(8) :: k_col_tra = ZERO ! sum over batches of k_collision * k_tracklength real(8) :: k_abs_tra = ZERO ! sum over batches of k_absorption * k_tracklength