diff --git a/src/DEPENDENCIES b/src/DEPENDENCIES index 27080cd2b..8cafde3f4 100644 --- a/src/DEPENDENCIES +++ b/src/DEPENDENCIES @@ -332,13 +332,13 @@ source.o: output.o source.o: particle_header.o source.o: physics.o source.o: random_lcg.o +source.o: state_point.o source.o: string.o state_point.o: error.o state_point.o: global.o state_point.o: math.o state_point.o: output.o -state_point.o: source.o state_point.o: string.o state_point.o: tally_header.o diff --git a/src/source.F90 b/src/source.F90 index 6d33344cf..407542236 100644 --- a/src/source.F90 +++ b/src/source.F90 @@ -9,6 +9,7 @@ module source use particle_header, only: deallocate_coord use physics, only: maxwell_spectrum, watt_spectrum use random_lcg, only: prn, set_particle_seed + use state_point, only: read_source_binary use string, only: to_str #ifdef MPI @@ -229,175 +230,4 @@ contains end subroutine initialize_particle -!=============================================================================== -! WRITE_SOURCE writes out the final source distribution to a binary file that -! can be used as a starting source in a new simulation -!=============================================================================== - - subroutine write_source_binary() - -#ifdef MPI - integer :: fh ! file handle - integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file) - - ! ========================================================================== - ! PARALLEL I/O USING MPI-2 ROUTINES - - ! Open binary source file for reading - call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_CREATE + & - MPI_MODE_WRONLY, MPI_INFO_NULL, fh, mpi_err) - - if (master) then - offset = 0 - call MPI_FILE_WRITE_AT(fh, offset, n_particles, 1, MPI_INTEGER8, & - MPI_STATUS_IGNORE, mpi_err) - end if - - ! Set proper offset for source data on this processor - offset = 8*(1 + rank*maxwork*8) - - ! Write all source sites - call MPI_FILE_WRITE_AT(fh, offset, source_bank(1), work, MPI_BANK, & - MPI_STATUS_IGNORE, mpi_err) - - ! Close binary source file - call MPI_FILE_CLOSE(fh, mpi_err) - -#else - ! ========================================================================== - ! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES - - ! Open binary source file for writing - open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='replace', & - ACCESS='stream') - - ! Write the number of particles - write(UNIT=UNIT_SOURCE) n_particles - - ! Write information from the source bank - write(UNIT=UNIT_SOURCE) source_bank(1:work) - - ! Close binary source file - close(UNIT=UNIT_SOURCE) -#endif - - end subroutine write_source_binary - - !=============================================================================== - ! READ_SOURCE_BINARY reads a source distribution from a source.binary file and - ! initializes the source bank - !=============================================================================== - - subroutine read_source_binary() - - integer :: i ! loop over repeating sites - integer(8) :: n_sites ! number of sites in binary file - integer :: n_repeat ! number of times to repeat a site -#ifdef MPI - integer :: fh ! file handle - integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file) - integer :: n_read ! number of sites to read on a single process -#endif - -#ifdef MPI - ! ========================================================================== - ! PARALLEL I/O USING MPI-2 ROUTINES - - ! Open binary source file for reading - call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_RDONLY, & - MPI_INFO_NULL, fh, mpi_err) - - ! Read number of source sites in file - offset = 0 - call MPI_FILE_READ_AT(fh, offset, n_sites, 1, MPI_INTEGER8, & - MPI_STATUS_IGNORE, mpi_err) - - if (n_particles > n_sites) then - ! Determine number of sites to read and offset - if (rank <= mod(n_sites,int(n_procs,8)) - 1) then - n_read = int(n_sites/n_procs) + 1 - offset = 8*(1 + rank*n_read*8) - else - n_read = int(n_sites/n_procs) - offset = 8*(1 + (rank*n_read + mod(n_sites,int(n_procs,8)))*8) - end if - - ! Read source sites - call MPI_FILE_READ_AT(fh, offset, source_bank(1), n_read, MPI_BANK, & - MPI_STATUS_IGNORE, mpi_err) - - ! Let's say we have 30 sites and we need to fill in 200. This do loop - ! will fill in sites 31 - 180. - - n_repeat = int(work / n_read) - do i = 1, n_repeat - 1 - source_bank(i*n_read + 1:(i+1)*n_read) = & - source_bank((i-1)*n_read + 1:i*n_read) - end do - - ! This final statement would fill sites 181 - 200 in the above example. - - if (mod(work, int(n_repeat*n_read,8)) > 0) then - source_bank(n_repeat*n_read + 1:work) = & - source_bank(1:work - n_repeat * n_read) - end if - - else - ! Set proper offset for source data on this processor - offset = 8*(1 + rank*maxwork*8) - - ! Read all source sites - call MPI_FILE_READ_AT(fh, offset, source_bank(1), work, MPI_BANK, & - MPI_STATUS_IGNORE, mpi_err) - - ! Close binary source file - call MPI_FILE_CLOSE(fh, mpi_err) - end if - -#else - ! ========================================================================== - ! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES - - ! Open binary source file for reading - open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='old', & - ACCESS='stream') - - ! Read number of source sites in file - read(UNIT=UNIT_SOURCE) n_sites - - if (n_particles > n_sites) then - ! The size of the source file is smaller than the number of particles we - ! need. Thus, read all sites and then duplicate sites as necessary. - - read(UNIT=UNIT_SOURCE) source_bank(1:n_sites) - - ! Let's say we have 300 sites and we need to fill in 1000. This do loop - ! will fill in sites 301 - 900. - - n_repeat = int(n_particles / n_sites) - do i = 1, n_repeat - 1 - source_bank(i*n_sites + 1:(i+1)*n_sites) = & - source_bank((i-1)*n_sites + 1:i*n_sites) - end do - - ! This final statement would fill sites 901 - 1000 in the above example. - - source_bank(n_repeat*n_sites + 1:n_particles) = & - source_bank(1:n_particles - n_repeat * n_sites) - - else - ! The size of the source file is bigger than or equal to the number of - ! particles we need for one generation. Thus, we can just read as many - ! sites as we need. - - read(UNIT=UNIT_SOURCE) source_bank(1:n_particles) - - end if - - ! Close binary source file - close(UNIT=UNIT_SOURCE) -#endif - - end subroutine read_source_binary - end module source diff --git a/src/state_point.F90 b/src/state_point.F90 index 904dea643..e75084c48 100644 --- a/src/state_point.F90 +++ b/src/state_point.F90 @@ -22,7 +22,6 @@ module state_point use global use math, only: t_percentile use output, only: write_message, print_batch_keff, time_stamp - use source, only: write_source_binary use string, only: to_str use tally_header, only: TallyObject @@ -1112,4 +1111,175 @@ contains end subroutine replay_batch_history +!=============================================================================== +! WRITE_SOURCE writes out the final source distribution to a binary file that +! can be used as a starting source in a new simulation +!=============================================================================== + + subroutine write_source_binary() + +#ifdef MPI + integer :: fh ! file handle + integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file) + + ! ========================================================================== + ! PARALLEL I/O USING MPI-2 ROUTINES + + ! Open binary source file for reading + call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_CREATE + & + MPI_MODE_WRONLY, MPI_INFO_NULL, fh, mpi_err) + + if (master) then + offset = 0 + call MPI_FILE_WRITE_AT(fh, offset, n_particles, 1, MPI_INTEGER8, & + MPI_STATUS_IGNORE, mpi_err) + end if + + ! Set proper offset for source data on this processor + offset = 8*(1 + rank*maxwork*8) + + ! Write all source sites + call MPI_FILE_WRITE_AT(fh, offset, source_bank(1), work, MPI_BANK, & + MPI_STATUS_IGNORE, mpi_err) + + ! Close binary source file + call MPI_FILE_CLOSE(fh, mpi_err) + +#else + ! ========================================================================== + ! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES + + ! Open binary source file for writing + open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='replace', & + ACCESS='stream') + + ! Write the number of particles + write(UNIT=UNIT_SOURCE) n_particles + + ! Write information from the source bank + write(UNIT=UNIT_SOURCE) source_bank(1:work) + + ! Close binary source file + close(UNIT=UNIT_SOURCE) +#endif + + end subroutine write_source_binary + +!=============================================================================== +! READ_SOURCE_BINARY reads a source distribution from a source.binary file and +! initializes the source bank +!=============================================================================== + + subroutine read_source_binary() + + integer :: i ! loop over repeating sites + integer(8) :: n_sites ! number of sites in binary file + integer :: n_repeat ! number of times to repeat a site +#ifdef MPI + integer :: fh ! file handle + integer(MPI_OFFSET_KIND) :: offset ! offset in memory (0=beginning of file) + integer :: n_read ! number of sites to read on a single process +#endif + +#ifdef MPI + ! ========================================================================== + ! PARALLEL I/O USING MPI-2 ROUTINES + + ! Open binary source file for reading + call MPI_FILE_OPEN(MPI_COMM_WORLD, path_source, MPI_MODE_RDONLY, & + MPI_INFO_NULL, fh, mpi_err) + + ! Read number of source sites in file + offset = 0 + call MPI_FILE_READ_AT(fh, offset, n_sites, 1, MPI_INTEGER8, & + MPI_STATUS_IGNORE, mpi_err) + + if (n_particles > n_sites) then + ! Determine number of sites to read and offset + if (rank <= mod(n_sites,int(n_procs,8)) - 1) then + n_read = int(n_sites/n_procs) + 1 + offset = 8*(1 + rank*n_read*8) + else + n_read = int(n_sites/n_procs) + offset = 8*(1 + (rank*n_read + mod(n_sites,int(n_procs,8)))*8) + end if + + ! Read source sites + call MPI_FILE_READ_AT(fh, offset, source_bank(1), n_read, MPI_BANK, & + MPI_STATUS_IGNORE, mpi_err) + + ! Let's say we have 30 sites and we need to fill in 200. This do loop + ! will fill in sites 31 - 180. + + n_repeat = int(work / n_read) + do i = 1, n_repeat - 1 + source_bank(i*n_read + 1:(i+1)*n_read) = & + source_bank((i-1)*n_read + 1:i*n_read) + end do + + ! This final statement would fill sites 181 - 200 in the above example. + + if (mod(work, int(n_repeat*n_read,8)) > 0) then + source_bank(n_repeat*n_read + 1:work) = & + source_bank(1:work - n_repeat * n_read) + end if + + else + ! Set proper offset for source data on this processor + offset = 8*(1 + rank*maxwork*8) + + ! Read all source sites + call MPI_FILE_READ_AT(fh, offset, source_bank(1), work, MPI_BANK, & + MPI_STATUS_IGNORE, mpi_err) + + ! Close binary source file + call MPI_FILE_CLOSE(fh, mpi_err) + end if + +#else + ! ========================================================================== + ! SERIAL I/O USING FORTRAN INTRINSIC ROUTINES + + ! Open binary source file for reading + open(UNIT=UNIT_SOURCE, FILE=path_source, STATUS='old', & + ACCESS='stream') + + ! Read number of source sites in file + read(UNIT=UNIT_SOURCE) n_sites + + if (n_particles > n_sites) then + ! The size of the source file is smaller than the number of particles we + ! need. Thus, read all sites and then duplicate sites as necessary. + + read(UNIT=UNIT_SOURCE) source_bank(1:n_sites) + + ! Let's say we have 300 sites and we need to fill in 1000. This do loop + ! will fill in sites 301 - 900. + + n_repeat = int(n_particles / n_sites) + do i = 1, n_repeat - 1 + source_bank(i*n_sites + 1:(i+1)*n_sites) = & + source_bank((i-1)*n_sites + 1:i*n_sites) + end do + + ! This final statement would fill sites 901 - 1000 in the above example. + + source_bank(n_repeat*n_sites + 1:n_particles) = & + source_bank(1:n_particles - n_repeat * n_sites) + + else + ! The size of the source file is bigger than or equal to the number of + ! particles we need for one generation. Thus, we can just read as many + ! sites as we need. + + read(UNIT=UNIT_SOURCE) source_bank(1:n_particles) + + end if + + ! Close binary source file + close(UNIT=UNIT_SOURCE) +#endif + + end subroutine read_source_binary + end module state_point