Skip to content

Commit

Permalink
Add checks that individual history streams have unique filenames. If …
Browse files Browse the repository at this point in the history
…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.

Closes #915
  • Loading branch information
apcraig committed Mar 25, 2024
1 parent 2209749 commit 2b8dcc2
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 57 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
45 changes: 22 additions & 23 deletions doc/source/user_guide/ug_implementation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1232,11 +1232,6 @@ above. In addition, ``history_format`` as well as other history namelist
options control the specific file format as well as features related to
IO performance, see :ref:`iooverview`.

CICE Model history output data can be written as instantaneous or average data as specified
by the ``hist_avg`` namelist array and is customizable by stream. Characters
can be added to the ``history_filename`` to distinguish the streams. This can be changed
by modifying ``hist_suffix`` to something other than "x".

The data written at the period(s) given by ``histfreq`` and
``histfreq_n`` relative to a reference date specified by ``histfreq_base``.
The files are written to binary or netCDF files prepended by ``history_file``
Expand All @@ -1263,20 +1258,29 @@ collected in their own history modules (**ice\_history\_bgc.F90**,
**ice\_history\_drag.F90**, **ice\_history\_mechred.F90**,
**ice\_history\_pond.F90**).

The history modules allow output at different frequencies. Five output
frequencies (``1``, ``h``, ``d``, ``m``, ``y``) are available simultaneously during a run.
The same variable can be output at different frequencies (say daily and
monthly) via its namelist flag, `f\_` :math:`\left<{var}\right>`, which
is a character string corresponding to ``histfreq`` or ‘x’ for none.
(Grid variable flags are logicals, since they are written to all
files, no matter what the frequency is.) If there are no namelist flags
The history modules allow output at different frequencies, ``hist_freq``. Five output
options (``1``, ``h``, ``d``, ``m``, ``y``) are available simultaneously
during a run, and each stream must have a unique value for ``hist_freq``. In other words, ``d``
cannot be used by two different streams. Each stream has an associated frequency
set by ``histfreq_n``. The frequency is
relative to a reference date specified by the corresponding entry in ``histfreq_base``.
Each stream can be instantaneous or time averaged
data over the frequency internal. The ``hist_avg`` namelist turns on time averaging
for each stream individually.
The same model variable can be written to multiple history streams (say daily and
monthly) via its namelist flag, `f\_` :math:`\left<{var}\right>`. The valid
values for the character string `f\_` :math:`\left<{var}\right>` is the ``hist_freq``
values or 'x' for none. For example, ``f_aice = 'md'`` will write aice to the
monthly and daily streams.
Grid variable history output flags are logicals and written to all stream files if
turned on. If there are no namelist flags
with a given ``histfreq`` value, or if an element of ``histfreq_n`` is 0, then
no file will be written at that frequency. The output period can be
discerned from the filenames or the ``hist_suffix`` can be used. Each history stream will be either instantaneous
or averaged as specified by the corresponding entry in the ``hist_avg`` namelist array, and the frequency
will be relative to a reference date specified by the corresponding entry in ``histfreq_base``.
More information about how the frequency is
computed is found in :ref:`timemanager`.
no file will be written at that frequency. The history filenames are set in
the subroutine **construct_filename** in **ice_history_shared.F90**. The stream
filename is a function of the output frequency, and the ``hist_avg`` and ``hist_suffix``
values. In cases where two streams produce the same identical filename, the model will
abort. Use the namelist ``hist_suffix`` to make stream filenames unique.
More information about how the frequency is computed is found in :ref:`timemanager`.
Also, some
Earth Sytem Models require the history file time axis to be centered in the averaging
interval. The flag ``hist_time_axis`` will allow the user to chose ``begin``, ``middle``,
Expand Down Expand Up @@ -1322,11 +1326,6 @@ above, ``meltb`` is called ``meltb`` in the monthly file (for backward
compatibility with the default configuration) and ``meltb_h`` in the
6-hourly file.

Using the same frequency twice in ``histfreq`` will have unexpected
consequences and currently will cause the code to abort. It is not
possible at the moment to output averages once a month and also once
every 3 months, for example.

If ``write_ic`` is set to true in **ice\_in**, a snapshot of the same set
of history fields at the start of the run will be written to the history
directory in **iceh\_ic.[timeID].nc(da)**. Several history variables are
Expand Down

0 comments on commit 2b8dcc2

Please sign in to comment.