Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds option to override (ignore) checksum test when reading restarts #889

Merged
merged 6 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions fms2_io/blackboxio.F90
Original file line number Diff line number Diff line change
Expand Up @@ -561,13 +561,14 @@ end subroutine save_domain_restart_wrap
!> @brief Loop through registered restart variables and read them from
!! a netcdf file.
subroutine restore_domain_state_wrap(fileobj, unlim_dim_level, directory, timestamp, &
filename)
filename, ignore_checksum)

type(FmsNetcdfDomainFile_t), intent(in), target :: fileobj !< File object.
integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension level.
character(len=*), intent(in), optional :: directory !< Directory to write restart file to.
character(len=*), intent(in), optional :: timestamp !< Model time.
character(len=*), intent(in), optional :: filename !< New name for the file.
logical, intent(in), optional :: ignore_checksum !< Checksum data integrity flag.

character(len=256) :: new_name
type(FmsNetcdfDomainFile_t), target :: new_fileobj
Expand All @@ -583,7 +584,7 @@ subroutine restore_domain_state_wrap(fileobj, unlim_dim_level, directory, timest
p => new_fileobj
close_new_file = .true.
endif
call restore_domain_state(p, unlim_dim_level)
call restore_domain_state(p, unlim_dim_level, ignore_checksum=ignore_checksum)
if (close_new_file) then
call close_domain_file(p)
endif
Expand Down
73 changes: 42 additions & 31 deletions fms2_io/fms_netcdf_domain_io.F90
Original file line number Diff line number Diff line change
Expand Up @@ -627,16 +627,21 @@ end subroutine save_domain_restart

!> @brief Loop through registered restart variables and read them from
!! a netcdf file.
subroutine restore_domain_state(fileobj, unlim_dim_level)
subroutine restore_domain_state(fileobj, unlim_dim_level, ignore_checksum)

type(FmsNetcdfDomainFile_t), intent(inout) :: fileobj !< File object.
integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension level.
logical, intent(in), optional :: ignore_checksum !< Checksum data integrity flag.

integer :: i
character(len=32) :: chksum_in_file
character(len=32) :: chksum
logical :: chksum_ignore = .FALSE. !< local variable for data integrity checks
!! default: .FALSE. - checks enabled
logical :: is_decomposed

if (PRESENT(ignore_checksum)) chksum_ignore = ignore_checksum

if (.not. fileobj%is_restart) then
call error("file "//trim(fileobj%path)//" is not a restart file. You must set is_restart=.true. in your open_file call.")
endif
Expand All @@ -650,46 +655,52 @@ subroutine restore_domain_state(fileobj, unlim_dim_level)
elseif (associated(fileobj%restart_vars(i)%data2d)) then
call domain_read_2d(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data2d, unlim_dim_level=unlim_dim_level)
chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data2d, is_decomposed)
if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
is_decomposed) then
call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
"checksum", chksum_in_file)
if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"//trim(fileobj%restart_vars(i)%varname)//&
&" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
&" from data:"//trim(adjustl(chksum)))
if (.not.chksum_ignore) then
chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data2d, is_decomposed)
if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
is_decomposed) then
call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
"checksum", chksum_in_file)
if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"//trim(fileobj%restart_vars(i)%varname)//&
&" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
&" from data:"//trim(adjustl(chksum)))
endif
endif
endif
elseif (associated(fileobj%restart_vars(i)%data3d)) then
call domain_read_3d(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data3d, unlim_dim_level=unlim_dim_level)
chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data3d, is_decomposed)
if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
is_decomposed) then
call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
"checksum", chksum_in_file(1:len(chksum_in_file)))
if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"//trim(fileobj%restart_vars(i)%varname)//&
&" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
&" from data:"//trim(adjustl(chksum)))
if (.not.chksum_ignore) then
chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data3d, is_decomposed)
if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
is_decomposed) then
call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
"checksum", chksum_in_file(1:len(chksum_in_file)))
if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"//trim(fileobj%restart_vars(i)%varname)//&
&" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
&" from data:"//trim(adjustl(chksum)))
endif
endif
endif
elseif (associated(fileobj%restart_vars(i)%data4d)) then
call domain_read_4d(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data4d, unlim_dim_level=unlim_dim_level)
chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data4d, is_decomposed)
if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
is_decomposed) then
call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
"checksum", chksum_in_file)
if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"//trim(fileobj%restart_vars(i)%varname)//&
&" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
&" from data:"//trim(adjustl(chksum)))
if (.not.chksum_ignore) then
chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data4d, is_decomposed)
if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
is_decomposed) then
call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
"checksum", chksum_in_file)
if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"//trim(fileobj%restart_vars(i)%varname)//&
&" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
&" from data:"//trim(adjustl(chksum)))
endif
endif
endif
else
Expand Down
28 changes: 18 additions & 10 deletions fms2_io/include/scatter_data_bc.inc
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
!> @ingroup fms2_io

!< Root pe reads the data in the netcdf file and scatters it to the other pes
subroutine scatter_data_bc_2d(fileobj, varname, vdata, bc_info, unlim_dim_level)
subroutine scatter_data_bc_2d(fileobj, varname, vdata, bc_info, unlim_dim_level, ignore_checksum)
class(FmsNetcdfFile_t), intent(inout) :: fileobj !< Fms2io netcdf fileobj
character(len=*), intent(in) :: varname !< Variable name.
class(*), dimension(:,:), intent(inout) :: vdata !< scattered data
type(bc_information), intent(inout) :: bc_info !< information about the boundary condition variable
integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension
!! level.
integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension level.
logical, intent(in), optional :: ignore_checksum !< Checksum data integrity flag.

real(kind=r8_kind), dimension(:,:), allocatable :: global_buf_r8_kind !< buffer with a data read in from file
real(kind=r8_kind), dimension(:,:), allocatable :: local_buf_r8_kind !< current pe's portion of the data
Expand All @@ -36,6 +36,8 @@ subroutine scatter_data_bc_2d(fileobj, varname, vdata, bc_info, unlim_dim_level)
integer(kind=i8_kind) :: chksum_val !< Checksum value calculated from the read data
character(len=32) :: chksum !< Cheksum value converted to a string
character(len=32) :: chksum_read !< String checksum read in from file
logical :: chksum_ignore = .FALSE. !< local variable for data integrity checks
!! default: .FALSE. - checks enabled

integer :: isc, iec, jsc, jec !< current PE's indices
integer :: i1, i2, j1, j2 !< current PE's indices relative to the global domain
Expand All @@ -44,6 +46,8 @@ subroutine scatter_data_bc_2d(fileobj, varname, vdata, bc_info, unlim_dim_level)
integer :: i_glob !< Size of the global domain in x
integer :: j_glob !< Size of the global domain in y

if (PRESENT(ignore_checksum)) chksum_ignore = ignore_checksum

!> Set the indices
isc = bc_info%indices(1)
iec = bc_info%indices(2)
Expand Down Expand Up @@ -76,7 +80,7 @@ subroutine scatter_data_bc_2d(fileobj, varname, vdata, bc_info, unlim_dim_level)
unlim_dim_level=unlim_dim_level, &
broadcast=.false.)
!> If the checksum exists read it and compare it with the calculated from the data that was read
if (variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
if (.not.chksum_ignore .and. variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
call get_variable_attribute(fileobj, varname, "checksum", chksum_read, broadcast=.false.)
chksum_val = mpp_chksum(global_buf_r4_kind, (/mpp_pe()/))
chksum = ""
Expand Down Expand Up @@ -124,7 +128,7 @@ subroutine scatter_data_bc_2d(fileobj, varname, vdata, bc_info, unlim_dim_level)
unlim_dim_level=unlim_dim_level, &
broadcast=.false.)
!> If the checksum exists read it and compare it with the calculated from the data that was read
if (variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
if (.not.chksum_ignore .and. variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
call get_variable_attribute(fileobj, varname, "checksum", chksum_read, broadcast=.false.)
chksum_val = mpp_chksum(global_buf_r8_kind, (/mpp_pe()/))
chksum = ""
Expand Down Expand Up @@ -168,13 +172,13 @@ subroutine scatter_data_bc_2d(fileobj, varname, vdata, bc_info, unlim_dim_level)
end subroutine scatter_data_bc_2d

!< Root pe reads the data in the netcdf file and scatters it to the other pes
subroutine scatter_data_bc_3d(fileobj, varname, vdata, bc_info, unlim_dim_level)
subroutine scatter_data_bc_3d(fileobj, varname, vdata, bc_info, unlim_dim_level, ignore_checksum)
class(FmsNetcdfFile_t), intent(inout) :: fileobj !< Fms2io netcdf fileobj
character(len=*), intent(in) :: varname !< Variable name.
class(*), dimension(:,:,:), intent(inout) :: vdata !< scattered data
type(bc_information), intent(inout) :: bc_info !< information about the boundary condition variable
integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension
!! level.
integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension level.
logical, intent(in), optional :: ignore_checksum !< Checksum data integrity flag.

real(kind=r8_kind), dimension(:,:,:), allocatable :: global_buf_r8_kind !< buffer with a data read in from file
real(kind=r8_kind), dimension(:,:,:), allocatable :: local_buf_r8_kind !< current pe's portion of the data
Expand All @@ -184,6 +188,8 @@ subroutine scatter_data_bc_3d(fileobj, varname, vdata, bc_info, unlim_dim_level)
integer(kind=i8_kind) :: chksum_val !< Checksum value calculated from the read data
character(len=32) :: chksum !< Cheksum value converted to a string
character(len=32) :: chksum_read !< String checksum read in from file
logical :: chksum_ignore = .FALSE. !< local variable for data integrity checks
!! default: .FALSE. - checks enabled

integer :: isc, iec, jsc, jec !< current PE's indices
integer :: i1, i2, j1, j2 !< current PE's indices relative to the global domain
Expand All @@ -193,6 +199,8 @@ subroutine scatter_data_bc_3d(fileobj, varname, vdata, bc_info, unlim_dim_level)
integer :: j_glob !< Size of the global domain in y
integer :: k_glob !< Size of the z axis

if (PRESENT(ignore_checksum)) chksum_ignore = ignore_checksum

!> Set the indices
isc = bc_info%indices(1)
iec = bc_info%indices(2)
Expand Down Expand Up @@ -227,7 +235,7 @@ subroutine scatter_data_bc_3d(fileobj, varname, vdata, bc_info, unlim_dim_level)
unlim_dim_level=unlim_dim_level, &
broadcast=.false.)
!> If the checksum exists read it and compare it with the calculated from the data that was read
if (variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
if (.not.chksum_ignore .and. variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
call get_variable_attribute(fileobj, varname, "checksum", chksum_read, broadcast=.false.)
chksum_val = mpp_chksum(global_buf_r4_kind, (/mpp_pe()/))
chksum = ""
Expand Down Expand Up @@ -275,7 +283,7 @@ subroutine scatter_data_bc_3d(fileobj, varname, vdata, bc_info, unlim_dim_level)
unlim_dim_level=unlim_dim_level, &
broadcast=.false.)
!> If the checksum exists read it and compare it with the calculated from the data that was read
if (variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
if (.not.chksum_ignore .and. variable_att_exists(fileobj, varname, "checksum", broadcast=.false.)) then
call get_variable_attribute(fileobj, varname, "checksum", chksum_read, broadcast=.false.)
chksum_val = mpp_chksum(global_buf_r8_kind, (/mpp_pe()/))
chksum = ""
Expand Down
10 changes: 7 additions & 3 deletions fms2_io/netcdf_io.F90
Original file line number Diff line number Diff line change
Expand Up @@ -2172,10 +2172,12 @@ end subroutine set_fileobj_time_name

!> @brief Loop through the registered restart variables (including regional
!! variables) and read them from the netcdf file
subroutine read_restart_bc(fileobj, unlim_dim_level)
subroutine read_restart_bc(fileobj, unlim_dim_level, ignore_checksum)
class(FmsNetcdfFile_t), intent(inout) :: fileobj !< File object
integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension
!! level.
logical, intent(in), optional :: ignore_checksum !< Checksum data integrity flag.

integer :: i !< No description

if (.not. fileobj%is_restart) then
Expand All @@ -2190,11 +2192,13 @@ subroutine read_restart_bc(fileobj, unlim_dim_level)
if (associated(fileobj%restart_vars(i)%data2d)) then
call scatter_data_bc (fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data2d, &
fileobj%restart_vars(i)%bc_info)
fileobj%restart_vars(i)%bc_info, &
ignore_checksum=ignore_checksum)
else if (associated(fileobj%restart_vars(i)%data3d)) then
call scatter_data_bc (fileobj, fileobj%restart_vars(i)%varname, &
fileobj%restart_vars(i)%data3d, &
fileobj%restart_vars(i)%bc_info)
fileobj%restart_vars(i)%bc_info, &
ignore_checksum=ignore_checksum)
endif
end do

Expand Down
22 changes: 19 additions & 3 deletions test_fms/fms2_io/test_atmosphere_io.F90
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ program test_atmosphere_io
character(len=256) :: att
character(len=6), dimension(4) :: names
character(len=8) :: timestamp
logical :: ignore_checksum = .false.
logical :: bad_checksum = .false.

namelist /test_atmosphere_io_nml/ bad_checksum, ignore_checksum

!Initialize.
call init(test_params, ntiles)
Expand All @@ -93,6 +97,8 @@ program test_atmosphere_io
call random_seed()
call fms2_io_init()

read(input_nml_file, nml=test_atmosphere_io_nml)

if (test_params%debug) then
if (mpp_pe() .eq. 0) then
write(error_unit,'(/a)') &
Expand Down Expand Up @@ -346,6 +352,12 @@ program test_atmosphere_io
var10_chksum = mpp_chksum(var10, pelist=(/mpp_pe()/))
!var11_chksum = mpp_chksum(var11(isc-isd+1:isc-isd+1+nx, jsc-jsd+1:jsc-jsd+1+ny, :), pelist=(/mpp_pe()/))

!replace var6 checksum with an incorrect checksum
if (bad_checksum) then
var6_chksum = 101010101
call register_variable_attribute(fileobj , "var6", "checksum", "101010101", str_len = 9)
call register_variable_attribute(fileobjv, "var6", "checksum", "101010101", str_len = 9)
endif
!Close the file.
call close_file(fileobj)
call mpi_barrier(mpi_comm_world, err)
Expand Down Expand Up @@ -474,7 +486,7 @@ program test_atmosphere_io
deallocate(dim_sizes)

!Read in the restart data.
call read_restart(fileobj, unlim_dim_level=nt)
call read_restart(fileobj, unlim_dim_level=nt, ignore_checksum = ignore_checksum )


chksum = mpp_chksum(var5, pelist=(/mpp_pe()/))
Expand All @@ -486,7 +498,11 @@ program test_atmosphere_io

chksum = mpp_chksum(var6, pelist=(/mpp_pe()/))
if (chksum .ne. var6_chksum) then
call mpp_error(fatal, "checksum for var 6 does not match.")
if (ignore_checksum) then
call mpp_error(warning, "checksum for var 6 does not match.")
else
call mpp_error(fatal, "checksum for var 6 does not match.")
endif
else
call mpp_error(warning, "checksum for var 6 does match.")
endif
Expand All @@ -513,7 +529,7 @@ program test_atmosphere_io
var6p = 0.
var7p = 0.
var8p = 0.
call read_new_restart(fileobjv, timestamp=timestamp)
call read_new_restart(fileobjv, timestamp=timestamp, ignore_checksum=ignore_checksum)

!Close the file.
call close_file(fileobj)
Expand Down
Loading