Skip to content

Commit

Permalink
Add checks that individual history streams have unique filenames (CIC…
Browse files Browse the repository at this point in the history
…E-Consortium#943)

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 authored 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.