From 67a2f165741badd9622ce34dd560ee2559fa9849 Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Thu, 4 Apr 2024 09:37:53 -0700 Subject: [PATCH] Add checks that individual history streams have unique filenames (#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. --- .../cicedyn/analysis/ice_history_shared.F90 | 42 +++-- cicecore/cicedyn/general/ice_init.F90 | 2 +- .../io/io_binary/ice_history_write.F90 | 16 +- .../io/io_netcdf/ice_history_write.F90 | 14 +- .../io/io_pio2/ice_history_write.F90 | 12 +- .../scripts/options/set_nml.histinst | 1 + doc/source/user_guide/ug_case_settings.rst | 2 +- doc/source/user_guide/ug_implementation.rst | 150 +++++++++--------- 8 files changed, 130 insertions(+), 109 deletions(-) diff --git a/cicecore/cicedyn/analysis/ice_history_shared.F90 b/cicecore/cicedyn/analysis/ice_history_shared.F90 index 62ee3c2ba..d6fa78542 100644 --- a/cicecore/cicedyn/analysis/ice_history_shared.F90 +++ b/cicecore/cicedyn/analysis/ice_history_shared.F90 @@ -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 @@ -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 @@ -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)') & @@ -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 !======================================================================= @@ -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 @@ -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 @@ -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 /= & @@ -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 diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index 24ac40db3..a7f84e46e 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -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) diff --git a/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 index b16d00f07..dae187eae 100644 --- a/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_binary/ice_history_write.F90 @@ -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 @@ -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 @@ -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 diff --git a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 index 396c52e37..7d29fc4cc 100644 --- a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_history_write.F90 @@ -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 @@ -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 @@ -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__) !----------------------------------------------------------------- @@ -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 diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 index 0281f3721..b8971a872 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_history_write.F90 @@ -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 @@ -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) @@ -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. diff --git a/configuration/scripts/options/set_nml.histinst b/configuration/scripts/options/set_nml.histinst index 31d566d76..34000f635 100644 --- a/configuration/scripts/options/set_nml.histinst +++ b/configuration/scripts/options/set_nml.histinst @@ -1 +1,2 @@ hist_avg = .false.,.false.,.false.,.false.,.false. +hist_suffix = '1','2','3','4','5' diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index b8bde525d..9f1f8a259 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -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", "" @@ -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``" diff --git a/doc/source/user_guide/ug_implementation.rst b/doc/source/user_guide/ug_implementation.rst index c243616d2..7d172e91d 100644 --- a/doc/source/user_guide/ug_implementation.rst +++ b/doc/source/user_guide/ug_implementation.rst @@ -132,11 +132,11 @@ This is shown in Figure :ref:`fig-Cgrid`. The user has several ways to initialize the grid: *popgrid* reads grid lengths and other parameters for a nonuniform grid (including tripole and regional grids), and *rectgrid* creates a regular rectangular grid. -The input files **global\_gx3.grid** and **global\_gx3.kmt** contain the +The input files **global_gx3.grid** and **global_gx3.kmt** contain the :math:`\left<3^\circ\right>` POP grid and land mask; -**global\_gx1.grid** and **global\_gx1.kmt** contain the -:math:`\left<1^\circ\right>` grid and land mask, and **global\_tx1.grid** -and **global\_tx1.kmt** contain the :math:`\left<1^\circ\right>` POP +**global_gx1.grid** and **global_gx1.kmt** contain the +:math:`\left<1^\circ\right>` grid and land mask, and **global_tx1.grid** +and **global_tx1.kmt** contain the :math:`\left<1^\circ\right>` POP tripole grid and land mask. These are binary unformatted, direct access, Big Endian files. @@ -183,7 +183,7 @@ block distribution are ``nx_block`` :math:`\times`\ ``ny_block``. The physical portion of a subdomain is indexed as [``ilo:ihi``, ``jlo:jhi``], with nghost “ghost” or “halo" cells outside the domain used for boundary conditions. These parameters are illustrated in :ref:`fig-grid` in one -dimension. The routines *global\_scatter* and *global\_gather* +dimension. The routines *global_scatter* and *global_gather* distribute information from the global domain to the local domains and back, respectively. If MPI is not being used for grid decomposition in the ice model, these routines simply adjust the indexing on the global @@ -215,7 +215,7 @@ four subdomains. The user sets the ``NTASKS`` and ``NTHRDS`` settings in **cice.settings** and chooses a block size ``block_size_x`` :math:`\times`\ ``block_size_y``, ``max_blocks``, and decomposition information ``distribution_type``, ``processor_shape``, -and ``distribution_type`` in **ice\_in**. That information is used to +and ``distribution_type`` in **ice_in**. That information is used to determine how the blocks are distributed across the processors, and how the processors are distributed across the grid domain. The model is parallelized over blocks @@ -223,18 +223,18 @@ for both MPI and OpenMP. Some suggested combinations for these parameters for best performance are given in Section :ref:`performance`. The script **cice.setup** computes some default decompositions and layouts but the user can overwrite the defaults by manually changing the values in -`ice\_in`. At runtime, the model will print decomposition +`ice_in`. At runtime, the model will print decomposition information to the log file, and if the block size or max blocks is inconsistent with the task and thread size, the model will abort. The code will also print a warning if the maximum number of blocks is too large. Although this is not fatal, it does use extra memory. If ``max_blocks`` is set to -1, the code will compute a tentative ``max_blocks`` on the fly. -A loop at the end of routine *create\_blocks* in module -**ice\_blocks.F90** will print the locations for all of the blocks on +A loop at the end of routine *create_blocks* in module +**ice_blocks.F90** will print the locations for all of the blocks on the global grid if the namelist variable ``debug_blocks`` is set to be true. Likewise, a similar loop at -the end of routine *create\_local\_block\_ids* in module -**ice\_distribution.F90** will print the processor and local block +the end of routine *create_local_block_ids* in module +**ice_distribution.F90** will print the processor and local block number for each block. With this information, the grid decomposition into processors and blocks can be ascertained. This ``debug_blocks`` variable should be used carefully as there may be hundreds or thousands of blocks to print @@ -242,7 +242,7 @@ and this information should be needed only rarely. ``debug_blocks`` can be set to true using the ``debugblocks`` option with **cice.setup**. This information is much easier to look at using a debugger such as Totalview. There is also -an output field that can be activated in `icefields\_nml`, ``f_blkmask``, +an output field that can be activated in `icefields_nml`, ``f_blkmask``, that prints out the variable ``blkmask`` to the history file and which labels the blocks in the grid decomposition according to ``blkmask = my_task + iblk/100``. @@ -427,7 +427,7 @@ restoring timescale ``trestore`` may be used (it is also used for restoring ocean sea surface temperature in stand-alone ice runs). This implementation is only intended to provide the “hooks" for a more sophisticated treatment; the rectangular grid option can be used to test -this configuration. The ‘displaced\_pole’ grid option should not be used +this configuration. The ‘displaced_pole’ grid option should not be used unless the regional grid contains land all along the north and south boundaries. The current form of the boundary condition routines does not allow Neumann boundary conditions, which must be set explicitly. This @@ -470,7 +470,7 @@ The logical masks ``tmask``, ``umask``, ``nmask``, and ``emask`` respectively) are useful in conditional statements. In addition to the land masks, two other masks are implemented in -*dyn\_prep* in order to reduce the dynamics component’s work on a global +*dyn_prep* in order to reduce the dynamics component’s work on a global grid. At each time step the logical masks ``iceTmask`` and ``iceUmask`` are determined from the current ice extent, such that they have the value “true” wherever ice exists. They also include a border of cells around @@ -842,7 +842,7 @@ is the step count at the start of a long multi-restart run, and is continuous across model restarts. In general, the time manager should be advanced by calling -*advance\_timestep*. This subroutine in **ice\_calendar.F90** +*advance_timestep*. This subroutine in **ice_calendar.F90** automatically advances the model time by ``dt``. It also advances the istep numbers and calls subroutine *calendar* to update additional calendar data. @@ -912,7 +912,7 @@ may vary with each run depending on several factors including the model timestep, initial date, and value of ``istep0``. The model year is limited by some integer math. In particular, calculation -of elapsed hours in **ice\_calendar.F90**, and the model year is +of elapsed hours in **ice_calendar.F90**, and the model year is limited to the value of ``myear_max`` set in that file. Currently, that's 200,000 years. @@ -927,10 +927,10 @@ set the namelist variables ``year_init``, ``month_init``, ``day_init``, ``sec_init``, and ``dt`` in conjuction with ``days_per_year`` and ``use_leap_years`` to initialize the model date, timestep, and calendar. To overwrite the default/namelist settings in the coupling layer, -set the **ice\_calendar.F90** variables ``myear``, ``mmonth``, ``mday``, +set the **ice_calendar.F90** variables ``myear``, ``mmonth``, ``mday``, ``msec`` and ``dt`` after the namelists have been read. Subroutine *calendar* should then be called to update all the calendar data. -Finally, subroutine *advance\_timestep* should be used to advance +Finally, subroutine *advance_timestep* should be used to advance the model time manager. It advances the step numbers, advances time by ``dt``, and updates the calendar data. The older method of manually advancing the steps and adding ``dt`` to ``time`` should @@ -945,11 +945,11 @@ Initialization and Restarts The ice model’s parameters and variables are initialized in several steps. Many constants and physical parameters are set in -**ice\_constants.F90**. Namelist variables (:ref:`tabnamelist`), -whose values can be altered at run time, are handled in *input\_data* +**ice_constants.F90**. Namelist variables (:ref:`tabnamelist`), +whose values can be altered at run time, are handled in *input_data* and other initialization routines. These variables are given default values in the code, which may then be changed when the input file -**ice\_in** is read. Other physical constants, numerical parameters, and +**ice_in** is read. Other physical constants, numerical parameters, and variables are first set in initialization routines for each ice model component or module. Then, if the ice model is being restarted from a previous run, core variables are read and reinitialized in @@ -1038,12 +1038,12 @@ An additional namelist option, ``restart_coszen`` specifies whether the cosine of the zenith angle is included in the restart files. This is mainly used in coupled models. -MPI is initialized in *init\_communicate* for both coupled and +MPI is initialized in *init_communicate* for both coupled and stand-alone MPI runs. The ice component communicates with a flux coupler or other climate components via external routines that handle the variables listed in the `Icepack documentation `_. For stand-alone runs, -routines in **ice\_forcing.F90** read and interpolate data from files, +routines in **ice_forcing.F90** read and interpolate data from files, and are intended merely to provide guidance for the user to write his or her own routines. Whether the code is to be run in stand-alone or coupled mode is determined at compile time, as described below. @@ -1232,51 +1232,54 @@ 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 +The data is 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`` -in **ice_in**. These settings for history files are set in the +The files are written to binary or netCDF files prepended by the ``history_file`` +and ``history_suffix`` +namelist setting. The settings for history files are set in the **setup_nml** section of **ice_in** (see :ref:`tabnamelist`). -If ``history_file`` = ‘iceh’ then the -filenames will have the form **iceh.[timeID].nc** or **iceh.[timeID].da**, -depending on the output file format chosen. With binary files, a separate header +The history filenames will have a form like +**[history_file][history_suffix][_freq].[timeID].[nc,da]** +depending on the namelist options chosen. With binary files, a separate header file is written with equivalent information. Standard fields are output -according to settings in the **icefields\_nml** section of **ice\_in** +according to settings in the **icefields_nml** section of **ice_in** (see :ref:`tabnamelist`). The user may add (or subtract) variables not already available in the namelist by following the instructions in section :ref:`addhist`. -The history module has been divided into several +The history implementation has been divided into several modules based on the desired formatting and on the variables themselves. Parameters, variables and routines needed by multiple -modules is in **ice\_history\_shared.F90**, while the primary routines +modules is in **ice_history_shared.F90**, while the primary routines for initializing and accumulating all of the history variables are in -**ice\_history.F90**. These routines call format-specific code in the -**io\_binary**, **io\_netcdf** and **io\_pio** directories. History +**ice_history.F90**. These routines call format-specific code in the +**io_binary**, **io_netcdf** and **io_pio2** directories. History variables specific to certain components or parameterizations are -collected in their own history modules (**ice\_history\_bgc.F90**, -**ice\_history\_drag.F90**, **ice\_history\_mechred.F90**, -**ice\_history\_pond.F90**). +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 +options (``1``, ``h``, ``d``, ``m``, ``y``) are available simultaneously for ``histfreq`` +during a run, and each stream must have a unique value for ``histfreq``. 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 (ie. daily ``d`` and +monthly ``m``) via its namelist flag, `f_` :math:`\left<{var}\right>`, while ``x`` +turns that history variable off. 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**. +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``, @@ -1299,7 +1302,9 @@ For example, in the namelist: Here, ``hi`` will be written to a file on every timestep, ``hs`` will be written once every 6 hours, ``aice`` once a month, ``meltb`` once a month AND -once every 6 hours, and ``Tsfc`` and ``iage`` will not be written. +once every 6 hours, and ``Tsfc`` and ``iage`` will not be written. All streams +are time averaged over the interval although because one stream has ``histfreq=1`` and +``histfreq_n=1``, that is equivalent to instantaneous output each model timestep. From an efficiency standpoint, it is best to set unused frequencies in ``histfreq`` to ‘x’. Having output at all 5 frequencies takes nearly 5 times @@ -1322,19 +1327,14 @@ 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 +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 +directory in **iceh_ic.[timeID].nc(da)**. Several history variables are hard-coded for instantaneous output regardless of the ``hist_avg`` averaging flag, at the frequency given by their namelist flag. The normalized principal components of internal ice stress (``sig1``, ``sig2``) are computed -in *principal\_stress* and written to the history file. This calculation +in *principal_stress* and written to the history file. This calculation is not necessary for the simulation; principal stresses are merely computed for diagnostic purposes and included here for the user’s convenience. @@ -1342,7 +1342,7 @@ convenience. Several history variables are available in two forms, a value representing an average over the sea ice fraction of the grid cell, and another that is multiplied by :math:`a_i`, representing an average over -the grid cell area. Our naming convention attaches the suffix “\_ai" to +the grid cell area. Our naming convention attaches the suffix “_ai" to the grid-cell-mean variable names. Beginning with CICE v6, history variables requested by the Sea Ice Model Intercomparison @@ -1352,9 +1352,9 @@ Project (SIMIP) :cite:`Notz16` have been added as possible history output variab `daily `_ requested SIMIP variables provide the names of possible history fields in CICE. However, each of the additional variables can be output at any temporal frequency -specified in the **icefields\_nml** section of **ice\_in** as detailed above. +specified in the **icefields_nml** section of **ice_in** as detailed above. Additionally, a new history output variable, ``f_CMIP``, has been added. When ``f_CMIP`` -is added to the **icefields\_nml** section of **ice\_in** then all SIMIP variables +is added to the **icefields_nml** section of **ice_in** then all SIMIP variables will be turned on for output at the frequency specified by ``f_CMIP``. It may also be helpful for debugging to increase the precision of the history file @@ -1367,7 +1367,7 @@ Diagnostic files Like ``histfreq``, the parameter ``diagfreq`` can be used to regulate how often output is written to a log file. The log file unit to which diagnostic -output is written is set in **ice\_fileunits.F90**. If ``diag_type`` = +output is written is set in **ice_fileunits.F90**. If ``diag_type`` = ‘stdout’, then it is written to standard out (or to **ice.log.[ID]** if you redirect standard out as in **cice.run**); otherwise it is written to the file given by ``diag_file``. @@ -1381,7 +1381,7 @@ useful for checking global conservation of mass and energy. ``print_points`` writes data for two specific grid points defined by the input namelist ``lonpnt`` and ``latpnt``. By default, one point is near the North Pole and the other is in the Weddell Sea; these -may be changed in **ice\_in**. +may be changed in **ice_in**. The namelist ``debug_model`` prints detailed debug diagnostics for a single point as the model advances. The point is defined @@ -1394,16 +1394,16 @@ namelist, the point associated with ``lonpnt(1)`` and ``latpnt(1)`` is used. in detail at a particular (usually failing) grid point. Memory use diagnostics are controlled by the logical namelist ``memory_stats``. -This feature uses an intrinsic query in C defined in **ice\_memusage\_gptl.c**. +This feature uses an intrinsic query in C defined in **ice_memusage_gptl.c**. Memory diagnostics will be written at the the frequency defined by diagfreq. -Timers are declared and initialized in **ice\_timers.F90**, and the code -to be timed is wrapped with calls to *ice\_timer\_start* and -*ice\_timer\_stop*. Finally, *ice\_timer\_print* writes the results to +Timers are declared and initialized in **ice_timers.F90**, and the code +to be timed is wrapped with calls to *ice_timer_start* and +*ice_timer_stop*. Finally, *ice_timer_print* writes the results to the log file. The optional “stats" argument (true/false) prints additional statistics. The "stats" argument can be set by the ``timer_stats`` -namelist. Calling *ice\_timer\_print\_all* prints all of +namelist. Calling *ice_timer_print_all* prints all of the timings at once, rather than having to call each individually. Currently, the timers are set up as in :ref:`timers`. Section :ref:`addtimer` contains instructions for adding timers. @@ -1415,8 +1415,8 @@ the code, including the dynamics and advection routines. The Dynamics, Advection, and Column timers do not overlap and represent most of the overall model work. -The timers use *MPI\_WTIME* for parallel runs and the F90 intrinsic -*system\_clock* for single-processor runs. +The timers use *MPI_WTIME* for parallel runs and the F90 intrinsic +*system_clock* for single-processor runs. .. _timers: