Skip to content

Commit

Permalink
Add checks that individual history streams have unique filenames (#943)
Browse files Browse the repository at this point in the history
Add checks that individual history streams have unique filenames. If they
do not, then streams will overwrite each other. With this change, abort in that case. Added in ice_history_shared.F90, subroutine construct_filename. The implementation tracks the latest filenames for each stream and checks versus those names. Because the file naming convention relies heavily on the current model date/time, this should be adequate (versus keeping track of all history filenames ever used).

Updated the cstream string in subroutine construct_filename. It was hardwired to len=1 which probably was an error. Made it len=char_len to support longer hist_suffix character strings in filenames.

Updated the ncfile variable implementation in ice_write_hist in io_binary, io_netcdf, and io_pio2. It was defined as an array of length max_nstrm, and was changed to a non-array character string. The array implementation served no purpose.

Modified the set_nml.histinst to add hist_suffix values for each stream. The latest code modifications cause The current test suite to fail with "histall,histinst" because it creates multiple streams with the same filename. Setting hist_suffix for histinst fixes this (and tests hist_suffix).

Clean up abort calls in ice_history_shared.F90, add space before "ERROR:".

Update the documentation describing history streams. Some "_" formatting was changed to simply "_" where the backslash wasn't needed in ug_implementation.rst.

Several namelist settings were tested to make sure the model would abort with identical filenames including the case where a time averaged file with output at each timestep conflicts with an instantaneous history stream of lower output frequency.
  • Loading branch information
apcraig committed Apr 4, 2024
1 parent 12dd204 commit 67a2f16
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 109 deletions.
42 changes: 31 additions & 11 deletions cicecore/cicedyn/analysis/ice_history_shared.F90
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ module ice_history_shared
history_rearranger ! history file rearranger, box or subset for pio

character (len=char_len), public :: &
hist_suffix(max_nstrm) ! appended to 'h' in filename when not 'x'
hist_suffix(max_nstrm) ! appended to history_file in filename

integer (kind=int_kind), public :: &
history_iotasks , & ! iotasks, root, stride defines io pes for pio
Expand Down Expand Up @@ -757,18 +757,22 @@ subroutine construct_filename(ncfile,suffix,ns)
dt
use ice_restart_shared, only: lenstr

character (char_len_long), intent(inout) :: ncfile
character (len=2), intent(in) :: suffix
character (len=*), intent(inout) :: ncfile
character (len=*), intent(in) :: suffix
integer (kind=int_kind), intent(in) :: ns

integer (kind=int_kind) :: iyear, imonth, iday, isec
character (len=1) :: cstream
integer (kind=int_kind) :: n
character (len=char_len) :: cstream
character (len=char_len_long), save :: ncfile_last(max_nstrm) = 'UnDefineD'
character(len=*), parameter :: subname = '(construct_filename)'

iyear = myear
imonth = mmonth
iday = mday
isec = int(msec - dt,int_kind)
cstream = ''
if (hist_suffix(ns) /= 'x') cstream = hist_suffix(ns)

! construct filename
if (write_ic) then
Expand All @@ -793,9 +797,6 @@ subroutine construct_filename(ncfile,suffix,ns)
endif
endif

cstream = ''
if (hist_suffix(ns) /= 'x') cstream = hist_suffix(ns)

if (hist_avg(ns)) then ! write averaged data
if (histfreq(ns) == '1' .and. histfreq_n(ns) == 1) then ! timestep
write(ncfile,'(a,a,i4.4,a,i2.2,a,i2.2,a,i5.5,a,a)') &
Expand Down Expand Up @@ -831,6 +832,25 @@ subroutine construct_filename(ncfile,suffix,ns)

endif

! Check whether the filename is already in use.
! Same filename in multiple history streams leads to files being overwritten (not good).
! The current filename convention means we just have to check latest filename,
! not all filenames ever generated because of use of current model date/time in filename.

! write(nu_diag,'(2a,i2,1x,a)') subname, 'debug ncfile= ',ns,trim(ncfile)
do n = 1,max_nstrm
! write(nu_diag,'(2a,i2,1x,a)') subname, 'debug nfile_last= ',n,trim(ncfile_last(n))
if (ncfile == ncfile_last(n)) then
write(nu_diag,*) subname,' history stream = ',ns
write(nu_diag,*) subname,' history filename = ',trim(ncfile)
write(nu_diag,*) subname,' filename in use for stream ',n
write(nu_diag,*) subname,' filename for stream ',trim(ncfile_last(n))
write(nu_diag,*) subname,' Use namelist hist_suffix so history filenames are unique'
call abort_ice(subname//' ERROR: history filename already used for another history stream '//trim(ncfile))
endif
enddo
ncfile_last(ns) = ncfile

end subroutine construct_filename

!=======================================================================
Expand Down Expand Up @@ -891,7 +911,7 @@ subroutine define_hist_field(id, vname, vunit, vcoord, vcellmeas, &
if(present(mask_ice_free_points)) l_mask_ice_free_points = mask_ice_free_points

if (histfreq(ns) == 'x') then
call abort_ice(subname//'ERROR: define_hist_fields has histfreq x')
call abort_ice(subname//' ERROR: define_hist_fields has histfreq x')
endif

if (ns == 1) id(:) = 0
Expand All @@ -901,7 +921,7 @@ subroutine define_hist_field(id, vname, vunit, vcoord, vcellmeas, &
if (vhistfreq(ns1:ns1) == histfreq(ns)) then

if (ns1 > 1 .and. index(vhistfreq(1:ns1-1),'x') /= 0) then
call abort_ice(subname//'ERROR: history frequency variable f_' // vname // ' can''t contain ''x'' along with active frequencies')
call abort_ice(subname//' ERROR: history frequency variable f_' // vname // ' can''t contain ''x'' along with active frequencies')
endif

num_avail_hist_fields_tot = num_avail_hist_fields_tot + 1
Expand Down Expand Up @@ -931,7 +951,7 @@ subroutine define_hist_field(id, vname, vunit, vcoord, vcellmeas, &
write(nu_diag,*) subname,' num_avail_hist_fields_tot = ',num_avail_hist_fields_tot
write(nu_diag,*) subname,' max_avail_hist_fields = ',max_avail_hist_fields
endif
call abort_ice(subname//'ERROR: Need in computation of max_avail_hist_fields')
call abort_ice(subname//' ERROR: Need in computation of max_avail_hist_fields')
endif

if (num_avail_hist_fields_tot /= &
Expand All @@ -947,7 +967,7 @@ subroutine define_hist_field(id, vname, vunit, vcoord, vcellmeas, &
if (my_task == master_task) then
write(nu_diag,*) subname,' num_avail_hist_fields_tot = ',num_avail_hist_fields_tot
endif
call abort_ice(subname//'ERROR: in num_avail_hist_fields')
call abort_ice(subname//' ERROR: in num_avail_hist_fields')
endif

id(ns) = num_avail_hist_fields_tot
Expand Down
2 changes: 1 addition & 1 deletion cicecore/cicedyn/general/ice_init.F90
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ subroutine input_data
call broadcast_scalar(histfreq_base(n), master_task)
call broadcast_scalar(dumpfreq(n), master_task)
call broadcast_scalar(dumpfreq_base(n), master_task)
call broadcast_scalar(hist_suffix(n), master_task)
call broadcast_scalar(hist_suffix(n), master_task)
enddo
call broadcast_array(hist_avg, master_task)
call broadcast_array(histfreq_n, master_task)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ subroutine ice_write_hist(ns)

integer (kind=int_kind) :: k,n,nn,nrec,nbits
character (char_len) :: title
character (char_len_long) :: ncfile(max_nstrm), hdrfile
character (char_len_long) :: ncfile, hdrfile

integer (kind=int_kind) :: icategory,i_aice

Expand All @@ -85,26 +85,26 @@ subroutine ice_write_hist(ns)

if (my_task == master_task) then

call construct_filename(ncfile(ns),'da',ns)
call construct_filename(ncfile,'da',ns)

! add local directory path name to ncfile
if (write_ic) then
ncfile(ns) = trim(incond_dir)//ncfile(ns)
ncfile = trim(incond_dir)//ncfile
else
ncfile(ns) = trim(history_dir)//ncfile(ns)
ncfile = trim(history_dir)//ncfile
endif
hdrfile = trim(ncfile(ns))//'.hdr'
hdrfile = trim(ncfile)//'.hdr'

!-----------------------------------------------------------------
! create history files
!-----------------------------------------------------------------
call ice_open(nu_history, ncfile(ns), nbits) ! direct access
call ice_open(nu_history, ncfile, nbits) ! direct access
open(nu_hdr,file=hdrfile,form='formatted',status='unknown') ! ascii

title = 'sea ice model: CICE'
write (nu_hdr, 999) 'source',title,' '

write (nu_hdr, 999) 'file name contains model date',trim(ncfile(ns)),' '
write (nu_hdr, 999) 'file name contains model date',trim(ncfile),' '
#ifdef CESMCOUPLED
write (nu_hdr, 999) 'runid',runid,' '
#endif
Expand Down Expand Up @@ -391,7 +391,7 @@ subroutine ice_write_hist(ns)
close (nu_hdr) ! header file
close (nu_history) ! data file
write (nu_diag,*) ' '
write (nu_diag,*) 'Finished writing ',trim(ncfile(ns))
write (nu_diag,*) 'Finished writing ',trim(ncfile)
endif

end subroutine ice_write_hist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ subroutine ice_write_hist (ns)
real (kind=dbl_kind) :: ltime2
character (char_len) :: title, cal_units, cal_att
character (char_len) :: time_period_freq = 'none'
character (char_len_long) :: ncfile(max_nstrm)
character (char_len_long) :: ncfile
real (kind=dbl_kind) :: secday, rad_to_deg

integer (kind=int_kind) :: ind,boundid, lprecision
Expand Down Expand Up @@ -139,13 +139,13 @@ subroutine ice_write_hist (ns)

if (my_task == master_task) then

call construct_filename(ncfile(ns),'nc',ns)
call construct_filename(ncfile,'nc',ns)

! add local directory path name to ncfile
if (write_ic) then
ncfile(ns) = trim(incond_dir)//ncfile(ns)
ncfile = trim(incond_dir)//ncfile
else
ncfile(ns) = trim(history_dir)//ncfile(ns)
ncfile = trim(history_dir)//ncfile
endif

! create file
Expand All @@ -161,8 +161,8 @@ subroutine ice_write_hist (ns)
call abort_ice(subname//' ERROR: history_format not allowed for '//trim(history_format), &
file=__FILE__, line=__LINE__)
endif
status = nf90_create(ncfile(ns), iflag, ncid)
call ice_check_nc(status, subname// ' ERROR: creating history ncfile '//ncfile(ns), &
status = nf90_create(ncfile, iflag, ncid)
call ice_check_nc(status, subname// ' ERROR: creating history ncfile '//ncfile, &
file=__FILE__, line=__LINE__)

!-----------------------------------------------------------------
Expand Down Expand Up @@ -1160,7 +1160,7 @@ subroutine ice_write_hist (ns)
call ice_check_nc(status, subname// ' ERROR: closing netCDF history file', &
file=__FILE__, line=__LINE__)
write(nu_diag,*) ' '
write(nu_diag,*) 'Finished writing ',trim(ncfile(ns))
write(nu_diag,*) 'Finished writing ',trim(ncfile)
endif

#else
Expand Down
12 changes: 6 additions & 6 deletions cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ subroutine ice_write_hist (ns)
character (len=8) :: cdate
character (len=char_len_long) :: title, cal_units, cal_att
character (len=char_len) :: time_period_freq = 'none'
character (len=char_len_long) :: ncfile(max_nstrm)
character (len=char_len_long) :: ncfile

integer (kind=int_kind) :: icategory,ind,i_aice,boundid, lprecision

Expand Down Expand Up @@ -156,15 +156,15 @@ subroutine ice_write_hist (ns)
file=__FILE__, line=__LINE__)

if (my_task == master_task) then
call construct_filename(ncfile(ns),'nc',ns)
call construct_filename(ncfile,'nc',ns)

! add local directory path name to ncfile
if (write_ic) then
ncfile(ns) = trim(incond_dir)//ncfile(ns)
ncfile = trim(incond_dir)//ncfile
else
ncfile(ns) = trim(history_dir)//ncfile(ns)
ncfile = trim(history_dir)//ncfile
endif
filename = ncfile(ns)
filename = ncfile
end if
call broadcast_scalar(filename, master_task)

Expand Down Expand Up @@ -1252,7 +1252,7 @@ subroutine ice_write_hist (ns)
call pio_closefile(File)
if (my_task == master_task) then
write(nu_diag,*) ' '
write(nu_diag,*) 'Finished writing ',trim(ncfile(ns))
write(nu_diag,*) 'Finished writing ',trim(ncfile)
endif

first_call = .false.
Expand Down
1 change: 1 addition & 0 deletions configuration/scripts/options/set_nml.histinst
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
hist_avg = .false.,.false.,.false.,.false.,.false.
hist_suffix = '1','2','3','4','5'
2 changes: 1 addition & 1 deletion doc/source/user_guide/ug_case_settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ setup_nml
"", "zero", "restart output frequency relative to year-month-day of 0000-01-01", ""
"``dumpfreq_n``", "integer array", "write restart frequency with ``dumpfreq``", "1,1,1,1,1"
"``dump_last``", "logical", "write restart on last time step of simulation", "``.false.``"
"``hist_avg``", "logical", "write time-averaged data", "``.true.,.true.,.true.,.true.,.true.``"
"``histfreq``", "``d``", "write history every ``histfreq_n`` days", "'1','h','d','m','y'"
"", "``h``", "write history every ``histfreq_n`` hours", ""
"", "``m``", "write history every ``histfreq_n`` months", ""
Expand Down Expand Up @@ -218,6 +217,7 @@ setup_nml
"", "subset", "subset io rearranger option for history output", ""
"``history_root``", "integer", "pe root task for history output with history_iotasks and history_stride (PIO only), -99=internal default", "-99"
"``history_stride``", "integer", "pe stride for history output with history_iotasks and history_root (PIO only), -99=internal default", "-99"
"``hist_avg``", "logical", "write time-averaged data", "``.true.,.true.,.true.,.true.,.true.``"
"``hist_suffix``", "character array", "appended to history_file when not x", "``x,x,x,x,x``"
"``hist_time_axis``","character","history file time axis interval location: begin, middle, end","end"
"``ice_ic``", "``default``", "equal to internal", "``default``"
Expand Down
Loading

0 comments on commit 67a2f16

Please sign in to comment.