Move reading command-line arguments to C++ side

This commit is contained in:
Paul Romano 2018-04-25 12:51:45 -05:00
parent 36dc4a59b1
commit da4999f116
11 changed files with 229 additions and 184 deletions

View file

@ -47,7 +47,7 @@ extern "C" {
int64_t openmc_get_seed();
int openmc_get_tally_index(int32_t id, int32_t* index);
void openmc_hard_reset();
int openmc_init(const void* intracomm);
int openmc_init(int argc, char* argv[], const void* intracomm);
int openmc_init_f(const int* intracomm);
int openmc_legendre_filter_get_order(int32_t index, int* order);
int openmc_legendre_filter_set_order(int32_t index, int order);
@ -146,9 +146,11 @@ extern "C" {
extern bool openmc_simulation_initialized;
extern int openmc_verbosity;
// Variables that are shared by necessity (can be removed later)
// Variables that are shared by necessity (can be removed from public header
// later)
extern bool openmc_master;
extern int openmc_n_procs;
extern int openmc_n_threads;
extern int openmc_rank;
extern int64_t openmc_work;

View file

@ -27,7 +27,7 @@ _dll.openmc_find.argtypes = [POINTER(c_double*3), c_int, POINTER(c_int32),
_dll.openmc_find.restype = c_int
_dll.openmc_find.errcheck = _error_handler
_dll.openmc_hard_reset.restype = None
_dll.openmc_init.argtypes = [c_void_p]
_dll.openmc_init.argtypes = [c_int, POINTER(c_char_p), c_void_p]
_dll.openmc_init.restype = None
_dll.openmc_get_keff.argtypes = [POINTER(c_double*2)]
_dll.openmc_get_keff.restype = c_int
@ -126,7 +126,7 @@ def init(intracomm=None):
address = MPI._addressof(intracomm)
intracomm = c_void_p(address)
_dll.openmc_init(intracomm)
_dll.openmc_init(0, None, intracomm)
def iter_batches():

View file

@ -104,7 +104,9 @@ contains
subroutine openmc_finalize() bind(C)
#ifdef OPENMC_MPI
integer :: err
#endif
! Clear results
call openmc_reset()

View file

@ -1105,7 +1105,7 @@ contains
integer :: i
integer(HSIZE_T) :: dims(1)
integer(C_SIZE_T) :: m
integer(C_SIZE_T) :: m, n
logical(C_BOOL) :: indep_
character(kind=C_CHAR), allocatable :: buffer_(:)
@ -1118,7 +1118,8 @@ contains
m = maxval(len_trim(buffer)) + 1
allocate(buffer_(dims(1)*m))
do i = 0, dims(1) - 1
buffer_(i*m+1 : (i+1)*m) = to_c_string(buffer(i+1))
n = len_trim(buffer(i+1)) + 1
buffer_(i*m+1 : i*m+n) = to_c_string(buffer(i+1))
end do
call write_string_c(group_id, 1, dims, m, to_c_string(name), &

View file

@ -1,6 +1,6 @@
module initialize
use, intrinsic :: ISO_C_BINDING, only: c_loc
use, intrinsic :: ISO_C_BINDING
#ifdef _OPENMP
use omp_lib
@ -8,28 +8,20 @@ module initialize
use bank_header, only: Bank
use constants
use set_header, only: SetInt
use error, only: fatal_error, warning, write_message
use geometry_header, only: Cell, Universe, Lattice, RectLattice, HexLattice,&
root_universe
use hdf5_interface, only: file_open, read_attribute, file_close, HID_T
use input_xml, only: read_input_xml
use material_header, only: Material
use message_passing
use mgxs_data, only: read_mgxs, create_macro_xs
use output, only: print_version, print_usage
use random_lcg, only: openmc_set_seed
use settings
#ifdef _OPENMP
use simulation_header, only: n_threads
#endif
use string, only: to_str, starts_with, ends_with, str_to_int
use tally_header, only: TallyObject
use tally_filter
use string, only: ends_with, to_f_string
use timer_header
implicit none
type(C_PTR), bind(C) :: openmc_path_input
type(C_PTR), bind(C) :: openmc_path_statepoint
type(C_PTR), bind(C) :: openmc_path_sourcepoint
type(C_PTR), bind(C) :: openmc_path_particle_restart
contains
!===============================================================================
@ -43,7 +35,6 @@ contains
integer, intent(in), optional :: intracomm ! MPI intracommunicator
integer(C_INT) :: err
integer :: hdf5_err
#ifdef _OPENMP
character(MAX_WORD_LEN) :: envvar
#endif
@ -161,162 +152,41 @@ contains
!===============================================================================
subroutine read_command_line()
! Arguments were already read on C++ side (initialize.cpp). Here we just
! convert the C-style strings to Fortran style
integer :: i ! loop index
integer :: argc ! number of command line arguments
integer :: last_flag ! index of last flag
character(MAX_WORD_LEN) :: filetype
integer(HID_T) :: file_id
character(MAX_WORD_LEN), allocatable :: argv(:) ! command line arguments
character(kind=C_CHAR), pointer :: string(:)
interface
function is_null(ptr) result(x) bind(C)
import C_PTR, C_BOOL
type(C_PTR), value :: ptr
logical(C_BOOL) :: x
end function is_null
end interface
! Check number of command line arguments and allocate argv
argc = COMMAND_ARGUMENT_COUNT()
! Allocate and retrieve command arguments
allocate(argv(argc))
do i = 1, argc
call GET_COMMAND_ARGUMENT(i, argv(i))
end do
! Process command arguments
last_flag = 0
i = 1
do while (i <= argc)
! Check for flags
if (starts_with(argv(i), "-")) then
select case (argv(i))
case ('-p', '-plot', '--plot')
run_mode = MODE_PLOTTING
check_overlaps = .true.
case ('-n', '-particles', '--particles')
! Read number of particles per cycle
i = i + 1
n_particles = str_to_int(argv(i))
! Check that number specified was valid
if (n_particles == ERROR_INT) then
call fatal_error("Must specify integer after " // trim(argv(i-1)) &
&// " command-line flag.")
end if
case ('-r', '-restart', '--restart')
! Read path for state point/particle restart
i = i + 1
! Check what type of file this is
file_id = file_open(argv(i), 'r', parallel=.true.)
call read_attribute(filetype, file_id, 'filetype')
call file_close(file_id)
! Set path and flag for type of run
select case (trim(filetype))
case ('statepoint')
path_state_point = argv(i)
restart_run = .true.
case ('particle restart')
path_particle_restart = argv(i)
particle_restart_run = .true.
case default
call fatal_error("Unrecognized file after restart flag: " // filetype // ".")
end select
! If its a restart run check for additional source file
if (restart_run .and. i + 1 <= argc) then
! Increment arg
i = i + 1
! Check if it has extension we can read
if (ends_with(argv(i), '.h5')) then
! Check file type is a source file
file_id = file_open(argv(i), 'r', parallel=.true.)
call read_attribute(filetype, file_id, 'filetype')
call file_close(file_id)
if (filetype /= 'source') then
call fatal_error("Second file after restart flag must be a &
&source file")
end if
! It is a source file
path_source_point = argv(i)
else ! Different option is specified not a source file
! Source is in statepoint file
path_source_point = path_state_point
! Set argument back
i = i - 1
end if
else ! No command line arg after statepoint
! Source is assumed to be in statepoint file
path_source_point = path_state_point
end if
case ('-g', '-geometry-debug', '--geometry-debug')
check_overlaps = .true.
case ('-c', '--volume')
run_mode = MODE_VOLUME
case ('-s', '--threads')
! Read number of threads
i = i + 1
#ifdef _OPENMP
! Read and set number of OpenMP threads
n_threads = int(str_to_int(argv(i)), 4)
if (n_threads < 1) then
call fatal_error("Invalid number of threads specified on command &
&line.")
end if
call omp_set_num_threads(n_threads)
#else
if (master) call warning("Ignoring number of threads specified on &
&command line.")
#endif
case ('-?', '-h', '-help', '--help')
call print_usage()
stop
case ('-v', '-version', '--version')
call print_version()
stop
case ('-t', '-track', '--track')
write_all_tracks = .true.
case default
call fatal_error("Unknown command line option: " // argv(i))
end select
last_flag = i
end if
! Increment counter
i = i + 1
end do
! Determine directory where XML input files are
if (argc > 0 .and. last_flag < argc) then
path_input = argv(last_flag + 1)
if (.not. is_null(openmc_path_input)) then
call c_f_pointer(openmc_path_input, string, [255])
path_input = to_f_string(string)
else
path_input = ''
end if
! Add slash at end of directory if it isn't there
if (.not. ends_with(path_input, "/") .and. len_trim(path_input) > 0) then
path_input = trim(path_input) // "/"
if (.not. is_null(openmc_path_statepoint)) then
call c_f_pointer(openmc_path_statepoint, string, [255])
path_state_point = to_f_string(string)
end if
if (.not. is_null(openmc_path_sourcepoint)) then
call c_f_pointer(openmc_path_sourcepoint, string, [255])
path_source_point = to_f_string(string)
end if
if (.not. is_null(openmc_path_particle_restart)) then
call c_f_pointer(openmc_path_particle_restart, string, [255])
path_particle_restart = to_f_string(string)
end if
! Free memory from argv
deallocate(argv)
! TODO: Check that directory exists
! Add slash at end of directory if it isn't there
if (len_trim(path_input) > 0 .and. .not. ends_with(path_input, "/")) then
path_input = trim(path_input) // "/"
end if
end subroutine read_command_line
end module initialize

View file

@ -1,12 +1,38 @@
#include "initialize.h"
#include <cstddef>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include "error.h"
#include "hdf5_interface.h"
#include "message_passing.h"
#include "openmc.h"
#ifdef _OPENMP
#include "omp.h"
#endif
// data/functions from Fortran side
extern "C" bool openmc_check_overlaps;
extern "C" bool openmc_write_all_tracks;
extern "C" bool openmc_particle_restart_run;
extern "C" bool openmc_restart_run;
extern "C" void print_usage();
extern "C" void print_version();
int openmc_init(const void* intracomm)
// Paths to various files
extern "C" {
char* openmc_path_input;
char* openmc_path_statepoint;
char* openmc_path_sourcepoint;
char* openmc_path_particle_restart;
bool is_null(void* ptr) {return !ptr;}
}
int openmc_init(int argc, char* argv[], const void* intracomm)
{
#ifdef OPENMC_MPI
// Check if intracomm was passed
@ -19,13 +45,20 @@ int openmc_init(const void* intracomm)
// Initialize MPI for C++
openmc::initialize_mpi(comm);
#endif
// Parse command-line arguments
int err = openmc::parse_command_line(argc, argv);
if (err) return err;
// Continue with rest of initialization
#ifdef OPENMC_MPI
MPI_Fint fcomm = MPI_Comm_c2f(comm);
openmc_init_f(&fcomm);
#else
openmc_init_f(nullptr);
#endif
return 0;
}
@ -63,6 +96,130 @@ void initialize_mpi(MPI_Comm intracomm)
MPI_Type_create_struct(5, blocks, disp, types, &openmc::mpi::bank);
MPI_Type_commit(&openmc::mpi::bank);
}
#endif // OPENMC_MPI
inline bool ends_with(std::string const& value, std::string const& ending)
{
if (ending.size() > value.size()) return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
int
parse_command_line(int argc, char* argv[])
{
char buffer[256]; // buffer for reading attribute
int last_flag = 0;
for (int i=1; i < argc; ++i) {
std::string arg {argv[i]};
if (arg[0] == '-') {
if (arg == "-p" || arg == "--plot") {
openmc_run_mode = RUN_MODE_PLOTTING;
openmc_check_overlaps = true;
} else if (arg == "-n" || arg == "--particles") {
i += 1;
n_particles = std::stoll(argv[i]);
} else if (arg == "-r" || arg == "--restart") {
i += 1;
// Check what type of file this is
hid_t file_id = file_open(argv[i], 'r', true);
size_t len = attribute_typesize(file_id, "filetype");
read_attr_string(file_id, "filetype", len, buffer);
file_close(file_id);
std::string filetype {buffer};
// Set path and flag for type of run
if (filetype == "statepoint") {
openmc_path_statepoint = argv[i];
openmc_restart_run = true;
} else if (filetype == "particle restart") {
openmc_path_particle_restart = argv[i];
openmc_particle_restart_run = true;
} else {
std::stringstream msg;
msg << "Unrecognized file after restart flag: " << filetype << ".";
strcpy(openmc_err_msg, msg.str().c_str());
return OPENMC_E_INVALID_ARGUMENT;
}
// If its a restart run check for additional source file
if (openmc_restart_run && i + 1 < argc) {
// Check if it has extension we can read
if (ends_with(argv[i+1], ".h5")) {
// Check file type is a source file
file_id = file_open(argv[i+1], 'r', true);
len = attribute_typesize(file_id, "filetype");
read_attr_string(file_id, "filetype", len, buffer);
file_close(file_id);
if (filetype != "source") {
std::string msg {"Second file after restart flag must be a source file"};
strcpy(openmc_err_msg, msg.c_str());
return OPENMC_E_INVALID_ARGUMENT;
}
// It is a source file
openmc_path_sourcepoint = argv[i+1];
i += 1;
} else {
// Source is in statepoint file
openmc_path_sourcepoint = openmc_path_statepoint;
}
} else {
// Source is assumed to be in statepoint file
openmc_path_sourcepoint = openmc_path_statepoint;
}
} else if (arg == "-g" || arg == "--geometry-debug") {
openmc_check_overlaps = true;
} else if (arg == "-c" || arg == "--volume") {
openmc_run_mode = RUN_MODE_VOLUME;
} else if (arg == "-s" || arg == "--threads") {
// Read number of threads
i += 1;
#ifdef _OPENMP
// Read and set number of OpenMP threads
openmc_n_threads = std::stoi(argv[i]);
if (openmc_n_threads < 1) {
std::string msg {"Number of threads must be positive."};
strcpy(openmc_err_msg, msg.c_str());
return OPENMC_E_INVALID_ARGUMENT;
}
omp_set_num_threads(openmc_n_threads);
#endif
} else if (arg == "-?" || arg == "-h" || arg == "--help") {
print_usage();
return OPENMC_E_UNASSIGNED;
} else if (arg == "-v" || arg == "--version") {
print_version();
return OPENMC_E_UNASSIGNED;
} else if (arg == "-t" || arg == "--track") {
openmc_write_all_tracks = true;
} else {
std::cerr << "Unknown option: " << argv[i] << '\n';
print_usage();
return OPENMC_E_UNASSIGNED;
}
last_flag = i;
}
}
// Determine directory where XML input files are
if (argc > 1 && last_flag < argc) openmc_path_input = argv[last_flag + 1];
return 0;
}
} // namespace openmc

View file

@ -5,10 +5,14 @@
#include "mpi.h"
#endif
extern "C" void print_usage();
extern "C" void print_version();
namespace openmc {
int parse_command_line(int argc, char* argv[]);
#ifdef OPENMC_MPI
void initialize_mpi(MPI_Comm intracomm);
void initialize_mpi(MPI_Comm intracomm);
#endif
}

View file

@ -1,19 +1,26 @@
#include "error.h"
#ifdef OPENMC_MPI
#include "mpi.h"
#endif
#include "openmc.h"
int main(int argc, char** argv) {
int main(int argc, char* argv[]) {
int err;
// Initialize run -- when run with MPI, pass communicator
#ifdef OPENMC_MPI
MPI_Comm world {MPI_COMM_WORLD};
openmc_init(&world);
err = openmc_init(argc, argv, &world);
#else
openmc_init(nullptr);
err = openmc_init(argc, argv, nullptr);
#endif
if (err == -1) {
// This happens for the -h and -v flags
return 0;
} else if (err) {
openmc::fatal_error(openmc_err_msg);
}
// start problem based on mode
switch (openmc_run_mode) {

View file

@ -162,7 +162,7 @@ contains
! information
!===============================================================================
subroutine print_version()
subroutine print_version() bind(C)
if (master) then
write(UNIT=OUTPUT_UNIT, FMT='(1X,A,1X,I1,".",I2,".",I1)') &
@ -182,7 +182,7 @@ contains
! PRINT_USAGE displays information about command line usage of OpenMC
!===============================================================================
subroutine print_usage()
subroutine print_usage() bind(C)
if (master) then
write(OUTPUT_UNIT,*) 'Usage: openmc [options] [directory]'

View file

@ -78,13 +78,13 @@ module settings
integer(C_INT), bind(C, name='openmc_run_mode') :: run_mode = NONE
! Restart run
logical :: restart_run = .false.
logical(C_BOOL), bind(C, name='openmc_restart_run') :: restart_run = .false.
! The verbosity controls how much information will be printed to the screen
! and in logs
integer(C_INT), bind(C, name='openmc_verbosity') :: verbosity = 7
logical :: check_overlaps = .false.
logical(C_BOOL), bind(C, name='openmc_check_overlaps') :: check_overlaps = .false.
! Trace for single particle
integer :: trace_batch
@ -92,11 +92,13 @@ module settings
integer(8) :: trace_particle
! Particle tracks
logical :: write_all_tracks = .false.
logical(C_BOOL), bind(C, name='openmc_write_all_tracks') :: &
write_all_tracks = .false.
integer, allocatable :: track_identifiers(:,:)
! Particle restart run
logical :: particle_restart_run = .false.
logical(C_BOOL), bind(C, name='openmc_particle_restart_run') :: &
particle_restart_run = .false.
! Write out initial source
logical :: write_initial_source = .false.

View file

@ -58,7 +58,7 @@ module simulation_header
! PARALLEL PROCESSING VARIABLES
#ifdef _OPENMP
integer :: n_threads = NONE ! number of OpenMP threads
integer(C_INT), bind(C, name='openmc_n_threads') :: n_threads = NONE ! number of OpenMP threads
integer :: thread_id ! ID of a given thread
#endif