diff --git a/src/io/io.f90 b/src/io/io.f90 index ce1aced7c..e2171b169 100644 --- a/src/io/io.f90 +++ b/src/io/io.f90 @@ -299,6 +299,45 @@ module function io_get_args(integrator, param_file_name) result(ierr) end function io_get_args + module function io_get_old_t_final_system(self, param) result(old_t_final) + !! author: David A. Minton + !! + !! Validates the dump file to check whether the dump file initial conditions duplicate the last frame of the binary output. + !! + implicit none + ! Arguments + class(swiftest_nbody_system), intent(in) :: self + class(swiftest_parameters), intent(in) :: param + ! Result + real(DP) :: old_t_final + ! Internals + class(swiftest_nbody_system), allocatable :: tmpsys + class(swiftest_parameters), allocatable :: tmpparam + integer(I4B), parameter :: LUN = 76 + integer(I4B) :: ierr, iu = LUN + character(len=STRMAX) :: errmsg + + old_t_final = 0.0_DP + allocate(tmpsys, source=self) + allocate(tmpparam, source=param) + + ierr = 0 + open(unit = iu, file = param%outfile, status = 'OLD', form = 'UNFORMATTED', err = 667, iomsg = errmsg) + do + ierr = tmpsys%read_frame(iu, tmpparam) + if (ierr /= 0) exit + end do + if (is_iostat_end(ierr)) then + old_t_final = tmpparam%t + return + end if + + 667 continue + write(*,*) "Error reading binary output file. " // trim(adjustl(errmsg)) + call util_exit(FAILURE) + end function io_get_old_t_final_system + + module function io_get_token(buffer, ifirst, ilast, ierr) result(token) !! author: David A. Minton !! @@ -814,6 +853,7 @@ module subroutine io_read_in_body(self, param) character(len=:), allocatable :: infile real(DP) :: t character(STRMAX) :: errmsg + integer(I4B) :: ierr ! Select the appropriate polymorphic class (test particle or massive body) select type(self) @@ -839,15 +879,15 @@ module subroutine io_read_in_body(self, param) end select call self%setup(nbody, param) + ierr = 0 if (nbody > 0) then - call self%read_frame(iu, param) + ierr = self%read_frame(iu, param) self%status(:) = ACTIVE self%lmask(:) = .true. end if - close(iu, err = 667, iomsg = errmsg) - return + if (ierr == 0) return 667 continue write(*,*) 'Error reading in initial conditions file: ',trim(adjustl(errmsg)) @@ -870,6 +910,7 @@ module subroutine io_read_in_cb(self, param) integer(I4B), parameter :: LUN = 7 !! Unit number of input file integer(I4B) :: iu = LUN character(len=STRMAX) :: errmsg + integer(I4B) :: ierr if (param%in_type == 'ASCII') then open(unit = iu, file = param%incbfile, status = 'old', form = 'FORMATTED', err = 667, iomsg = errmsg) @@ -885,20 +926,22 @@ module subroutine io_read_in_cb(self, param) end if else open(unit = iu, file = param%incbfile, status = 'old', form = 'UNFORMATTED', err = 667, iomsg = errmsg) - call self%read_frame(iu, param) + ierr = self%read_frame(iu, param) end if close(iu, err = 667, iomsg = errmsg) - if (self%j2rp2 /= 0.0_DP) param%loblatecb = .true. - if (param%rmin < 0.0) param%rmin = self%radius - - select type(cb => self) - class is (symba_cb) - cb%M0 = cb%mass - cb%R0 = cb%radius - cb%L0(:) = cb%Ip(3) * cb%mass * cb%radius**2 * cb%rot(:) - end select - + if (ierr == 0) then + + if (self%j2rp2 /= 0.0_DP) param%loblatecb = .true. + if (param%rmin < 0.0) param%rmin = self%radius + + select type(cb => self) + class is (symba_cb) + cb%M0 = cb%mass + cb%R0 = cb%radius + cb%L0(:) = cb%Ip(3) * cb%mass * cb%radius**2 * cb%rot(:) + end select + end if return 667 continue @@ -958,7 +1001,7 @@ function io_read_encounter(t, id1, id2, Gmass1, Gmass2, radius1, radius2, & end function io_read_encounter - module subroutine io_read_frame_body(self, iu, param) + module function io_read_frame_body(self, iu, param) result(ierr) !! author: David A. Minton !! !! Reads a frame of output of either test particle or massive body data from a binary output file @@ -970,11 +1013,15 @@ module subroutine io_read_frame_body(self, iu, param) class(swiftest_body), intent(inout) :: self !! Swiftest particle object integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + ! Result + integer(I4B) :: ierr !! Error code: returns 0 if the read is successful ! Internals character(len=STRMAX) :: errmsg integer(I4B) :: i real(QP) :: val + if (self%nbody == 0) return + if ((param%in_form /= EL) .and. (param%in_form /= XV)) then write(errmsg, *) trim(adjustl(param%in_form)) // " is not a recognized format code for input files." goto 667 @@ -1074,6 +1121,7 @@ module subroutine io_read_frame_body(self, iu, param) end select end associate + ierr = 0 return 667 continue @@ -1086,10 +1134,10 @@ module subroutine io_read_frame_body(self, iu, param) write(*,*) "Error reading body file: " // trim(adjustl(errmsg)) end select call util_exit(FAILURE) - end subroutine io_read_frame_body + end function io_read_frame_body - module subroutine io_read_frame_cb(self, iu, param) + module function io_read_frame_cb(self, iu, param) result(ierr) !! author: David A. Minton !! !! Reads a frame of output of central body data to the binary output file @@ -1101,6 +1149,8 @@ module subroutine io_read_frame_cb(self, iu, param) class(swiftest_cb), intent(inout) :: self !! Swiftest central body object integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + ! Result + integer(I4B) :: ierr !! Error code: returns 0 if the read is successful ! Internals character(len=STRMAX) :: errmsg @@ -1123,15 +1173,17 @@ module subroutine io_read_frame_cb(self, iu, param) read(iu, err = 667, iomsg = errmsg) self%k2 read(iu, err = 667, iomsg = errmsg) self%Q end if + + ierr = 0 return 667 continue write(*,*) "Error reading central body file: " // trim(adjustl(errmsg)) call util_exit(FAILURE) - end subroutine io_read_frame_cb + end function io_read_frame_cb - module subroutine io_read_frame_system(self, iu, param) + module function io_read_frame_system(self, iu, param) result(ierr) !! author: The Purdue Swiftest Team - David A. Minton, Carlisle A. Wishard, Jennifer L.L. Pouplin, and Jacob R. Elliott !! !! Read a frame (header plus records for each massive body and active test particle) from a output binary file @@ -1140,18 +1192,34 @@ module subroutine io_read_frame_system(self, iu, param) class(swiftest_nbody_system), intent(inout) :: self !! Swiftest system object integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + ! Result + integer(I4B) :: ierr !! Error code: returns 0 if the read is successful ! Internals character(len=STRMAX) :: errmsg - integer(I4B) :: ierr ierr = io_read_hdr(iu, param%t, self%pl%nbody, self%tp%nbody, param%out_form, param%out_type) + if (is_iostat_end(ierr)) return ! Reached the end of the frames + if (ierr /= 0) then - write(errmsg, *) "Cannot read header." + write(errmsg, *) "Cannot read frame header." goto 667 end if - call self%cb%read_frame(iu, param) - call self%pl%read_frame(iu, param) - call self%tp%read_frame(iu, param) + ierr = self%cb%read_frame(iu, param) + if (ierr /= 0) then + write(errmsg, *) "Cannot read central body frame." + goto 667 + end if + ierr = self%pl%read_frame(iu, param) + if (ierr /= 0) then + write(errmsg, *) "Cannot read massive body frame." + goto 667 + end if + ierr = self%tp%read_frame(iu, param) + if (ierr /= 0) then + write(errmsg, *) "Cannot read test particle frame." + goto 667 + end if + if (param%in_form == EL) then call self%pl%el2xv(self%cb) call self%tp%el2xv(self%cb) @@ -1161,8 +1229,7 @@ module subroutine io_read_frame_system(self, iu, param) 667 continue write(*,*) "Error reading system frame: " // trim(adjustl(errmsg)) - call util_exit(FAILURE) - end subroutine io_read_frame_system + end function io_read_frame_system function io_read_hdr(iu, t, npl, ntp, out_form, out_type) result(ierr) @@ -1187,10 +1254,10 @@ function io_read_hdr(iu, t, npl, ntp, out_form, out_type) result(ierr) select case (out_type) case (REAL4_TYPE) - read(iu, iostat = ierr, err = 667, iomsg = errmsg) ttmp + read(iu, iostat = ierr, err = 667, iomsg = errmsg, end = 333) ttmp t = ttmp case (REAL8_TYPE) - read(iu, iostat = ierr, err = 667, iomsg = errmsg) t + read(iu, iostat = ierr, err = 667, iomsg = errmsg, end = 333) t case default write(errmsg,*) trim(adjustl(out_type)) // ' is an unrecognized file type' ierr = -1 @@ -1203,6 +1270,8 @@ function io_read_hdr(iu, t, npl, ntp, out_form, out_type) result(ierr) 667 continue write(*,*) "Error reading header: " // trim(adjustl(errmsg)) + 333 continue + return return end function io_read_hdr diff --git a/src/main/swiftest_driver.f90 b/src/main/swiftest_driver.f90 index 0dc7641d1..3a274e596 100644 --- a/src/main/swiftest_driver.f90 +++ b/src/main/swiftest_driver.f90 @@ -19,6 +19,7 @@ program swiftest_driver integer(I8B) :: iout !! Output cadence counter integer(I8B) :: nloops !! Number of steps to take in the simulation integer(I4B) :: iu !! Unit number of binary file + real(DP) :: old_t_final = 0.0_DP !! Output time at which writing should start, in order to prevent duplicate lines being written for restarts ierr = io_get_args(integrator, param_file_name) if (ierr /= 0) then @@ -50,8 +51,15 @@ program swiftest_driver iout = istep_out idump = istep_dump nloops = ceiling(tstop / dt, kind=I8B) - if (istep_out > 0 .and. (.not.param%lrestart)) call nbody_system%write_frame(iu, param) - if (.not.param%lrestart) call nbody_system%dump(param) + ! Prevent duplicate frames from being written if this is a restarted run + if (param%lrestart) then + old_t_final = nbody_system%get_old_t_final(param) + else + old_t_final = t0 + if (istep_out > 0) call nbody_system%write_frame(iu, param) + call nbody_system%dump(param) + end if + !> Define the maximum number of threads nthreads = 1 ! In the *serial* case @@ -73,7 +81,7 @@ program swiftest_driver if (istep_out > 0) then iout = iout - 1 if (iout == 0) then - call nbody_system%write_frame(iu, param) + if (t > old_t_final) call nbody_system%write_frame(iu, param) iout = istep_out end if end if diff --git a/src/modules/swiftest_classes.f90 b/src/modules/swiftest_classes.f90 index 6d450b044..9a674c830 100644 --- a/src/modules/swiftest_classes.f90 +++ b/src/modules/swiftest_classes.f90 @@ -306,6 +306,7 @@ module swiftest_classes procedure :: discard => discard_system !! Perform a discard step on the system procedure :: conservation_report => io_conservation_report !! Compute energy and momentum and print out the change with time procedure :: dump => io_dump_system !! Dump the state of the system to a file + procedure :: get_old_t_final => io_get_old_t_final_system !! Validates the dump file to check whether the dump file initial conditions duplicate the last frame of the binary output. procedure :: read_frame => io_read_frame_system !! Read in a frame of input data from file procedure :: write_discard => io_write_discard !! Write out information about discarded test particles procedure :: write_frame => io_write_frame_system !! Append a frame of output data to file @@ -367,12 +368,13 @@ subroutine abstract_kick_body(self, system, param, t, dt, lbeg) logical, intent(in) :: lbeg !! Logical flag indicating whether this is the beginning of the half step or not. end subroutine abstract_kick_body - subroutine abstract_read_frame(self, iu, param) + function abstract_read_frame(self, iu, param) result(ierr) import DP, I4B, swiftest_base, swiftest_parameters class(swiftest_base), intent(inout) :: self !! Swiftest base object integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - end subroutine abstract_read_frame + integer(I4B) :: ierr !! Error code: returns 0 if the read is successful + end function abstract_read_frame subroutine abstract_set_mu(self, cb) import swiftest_body, swiftest_cb @@ -572,6 +574,13 @@ module function io_get_args(integrator, param_file_name) result(ierr) integer(I4B) :: ierr !! I/O error code end function io_get_args + module function io_get_old_t_final_system(self, param) result(old_t_final) + implicit none + class(swiftest_nbody_system), intent(in) :: self + class(swiftest_parameters), intent(in) :: param + real(DP) :: old_t_final + end function io_get_old_t_final_system + module function io_get_token(buffer, ifirst, ilast, ierr) result(token) implicit none character(len=*), intent(in) :: buffer !! Input string buffer @@ -621,26 +630,29 @@ module subroutine io_read_in_param(self, param_file_name) character(len=*), intent(in) :: param_file_name !! Parameter input file name (i.e. param.in) end subroutine io_read_in_param - module subroutine io_read_frame_body(self, iu, param) + module function io_read_frame_body(self, iu, param) result(ierr) implicit none - class(swiftest_body), intent(inout) :: self !! Swiftest body object - integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - end subroutine io_read_frame_body + class(swiftest_body), intent(inout) :: self !! Swiftest body object + integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + integer(I4B) :: ierr !! Error code: returns 0 if the read is successful + end function io_read_frame_body - module subroutine io_read_frame_cb(self, iu, param) + module function io_read_frame_cb(self, iu, param) result(ierr) implicit none - class(swiftest_cb), intent(inout) :: self !! Swiftest central body object - integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to - class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - end subroutine io_read_frame_cb + class(swiftest_cb), intent(inout) :: self !! Swiftest central body object + integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to + class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters + integer(I4B) :: ierr !! Error code: returns 0 if the read is successful + end function io_read_frame_cb - module subroutine io_read_frame_system(self, iu, param) + module function io_read_frame_system(self, iu, param) result(ierr) implicit none class(swiftest_nbody_system),intent(inout) :: self !! Swiftest system object integer(I4B), intent(inout) :: iu !! Unit number for the output file to write frame to class(swiftest_parameters), intent(inout) :: param !! Current run configuration parameters - end subroutine io_read_frame_system + integer(I4B) :: ierr !! Error code: returns 0 if the read is successful + end function io_read_frame_system module subroutine io_write_discard(self, param) implicit none