From 933b148cb141a16d74615092af62c3e8d36777a2 Mon Sep 17 00:00:00 2001 From: Tony Craig Date: Thu, 24 Aug 2023 10:23:56 -0700 Subject: [PATCH] Extend restart output controls, provide multiple frequency options (#850) * Extend restart output controls, provide multiple streams for possible output frequencies. Convert dumpfreq, dumpfreq_n, dumpfreq_base to arrays. Modify histfreq_base to make it an array as well. Now each history stream can have it's own base time (init or zero). Update documentation. * Clean up implementation and documentation * Update PR to check github actions --- cicecore/cicedyn/general/ice_init.F90 | 69 +++++++++-------- .../io/io_netcdf/ice_restart.F90 | 4 +- .../infrastructure/io/io_pio2/ice_restart.F90 | 9 ++- cicecore/shared/ice_calendar.F90 | 77 +++++++++++-------- configuration/scripts/ice_in | 8 +- configuration/scripts/options/set_nml.histall | 2 +- configuration/scripts/options/set_nml.histdbg | 2 +- doc/source/cice_index.rst | 4 +- doc/source/user_guide/ug_case_settings.rst | 15 ++-- doc/source/user_guide/ug_implementation.rst | 5 +- 10 files changed, 110 insertions(+), 85 deletions(-) diff --git a/cicecore/cicedyn/general/ice_init.F90 b/cicecore/cicedyn/general/ice_init.F90 index 4ed128f5e..47fedf538 100644 --- a/cicecore/cicedyn/general/ice_init.F90 +++ b/cicecore/cicedyn/general/ice_init.F90 @@ -322,7 +322,7 @@ subroutine input_data histfreq(4) = 'm' ! output frequency option for different streams histfreq(5) = 'y' ! output frequency option for different streams histfreq_n(:) = 1 ! output frequency - histfreq_base = 'zero' ! output frequency reference date + histfreq_base(:) = 'zero' ! output frequency reference date hist_avg(:) = .true. ! if true, write time-averages (not snapshots) history_format = 'default' ! history file format hist_time_axis = 'end' ! History file time axis averaging interval position @@ -334,9 +334,11 @@ subroutine input_data cpl_bgc = .false. ! couple bgc thru driver incond_dir = history_dir ! write to history dir for default incond_file = 'iceh_ic'! file prefix - dumpfreq='y' ! restart frequency option - dumpfreq_n = 1 ! restart frequency - dumpfreq_base = 'init' ! restart frequency reference date + dumpfreq(:)='x' ! restart frequency option + dumpfreq_n(:) = 1 ! restart frequency + dumpfreq_base(:) = 'init' ! restart frequency reference date + dumpfreq(1)='y' ! restart frequency option + dumpfreq_n(1) = 1 ! restart frequency dump_last = .false. ! write restart on last time step restart_dir = './' ! write to executable dir for default restart_file = 'iced' ! restart file name prefix @@ -901,10 +903,13 @@ subroutine input_data call broadcast_scalar(diag_file, master_task) do n = 1, max_nstrm call broadcast_scalar(histfreq(n), master_task) + call broadcast_scalar(histfreq_base(n), master_task) + call broadcast_scalar(dumpfreq(n), master_task) + call broadcast_scalar(dumpfreq_base(n), master_task) enddo - call broadcast_array(histfreq_n, master_task) - call broadcast_scalar(histfreq_base, master_task) call broadcast_array(hist_avg, master_task) + call broadcast_array(histfreq_n, master_task) + call broadcast_array(dumpfreq_n, master_task) call broadcast_scalar(history_dir, master_task) call broadcast_scalar(history_file, master_task) call broadcast_scalar(history_precision, master_task) @@ -914,9 +919,6 @@ subroutine input_data call broadcast_scalar(cpl_bgc, master_task) call broadcast_scalar(incond_dir, master_task) call broadcast_scalar(incond_file, master_task) - call broadcast_scalar(dumpfreq, master_task) - call broadcast_scalar(dumpfreq_n, master_task) - call broadcast_scalar(dumpfreq_base, master_task) call broadcast_scalar(dump_last, master_task) call broadcast_scalar(restart_file, master_task) call broadcast_scalar(restart, master_task) @@ -1569,33 +1571,32 @@ subroutine input_data abort_list = trim(abort_list)//":22" endif - if(histfreq_base /= 'init' .and. histfreq_base /= 'zero') then - write (nu_diag,*) subname//' ERROR: bad value for histfreq_base, allowed values: init, zero' - abort_list = trim(abort_list)//":24" - endif + do n = 1,max_nstrm + if(histfreq_base(n) /= 'init' .and. histfreq_base(n) /= 'zero') then + write (nu_diag,*) subname//' ERROR: bad value for histfreq_base, allowed values: init, zero: '//trim(histfreq_base(n)) + abort_list = trim(abort_list)//":24" + endif + + if(dumpfreq_base(n) /= 'init' .and. dumpfreq_base(n) /= 'zero') then + write (nu_diag,*) subname//' ERROR: bad value for dumpfreq_base, allowed values: init, zero: '//trim(dumpfreq_base(n)) + abort_list = trim(abort_list)//":25" + endif + + if (.not.(scan(dumpfreq(n)(1:1),'ymdhx1YMDHX') == 1 .and. (dumpfreq(n)(2:2) == '1' .or. dumpfreq(n)(2:2) == ' '))) then + if (my_task == master_task) then + write(nu_diag,*) subname//' WARNING: unrecognized dumpfreq=', trim(dumpfreq(n)) + write(nu_diag,*) subname//' WARNING: No restarts files will be written for this stream' + write(nu_diag,*) subname//' WARNING: Allowed values : y,m,d,h,x,1 followed by an optional 1' + endif + dumpfreq(n) = 'x' + endif + enddo if(trim(hist_time_axis) /= 'begin' .and. trim(hist_time_axis) /= 'middle' .and. trim(hist_time_axis) /= 'end') then write (nu_diag,*) subname//' ERROR: hist_time_axis value not valid = '//trim(hist_time_axis) abort_list = trim(abort_list)//":29" endif - if(dumpfreq_base /= 'init' .and. dumpfreq_base /= 'zero') then - write (nu_diag,*) subname//' ERROR: bad value for dumpfreq_base, allowed values: init, zero' - abort_list = trim(abort_list)//":25" - endif - - if (.not.(trim(dumpfreq) == 'y' .or. trim(dumpfreq) == 'Y' .or. & - trim(dumpfreq) == 'm' .or. trim(dumpfreq) == 'M' .or. & - trim(dumpfreq) == 'd' .or. trim(dumpfreq) == 'D' .or. & - trim(dumpfreq) == 'h' .or. trim(dumpfreq) == 'H' .or. & - trim(dumpfreq) == '1' )) then - if (my_task == master_task) then - write(nu_diag,*) subname//' WARNING: unrecognized dumpfreq=', trim(dumpfreq) - write(nu_diag,*) subname//' WARNING: No restarts files will be written' - write(nu_diag,*) subname//' WARNING: Allowed values : ''y'', ''m'', ''d'', ''h'', ''1''' - endif - endif - ! Implicit solver input validation if (kdyn == 3) then if (.not. (trim(algo_nonlin) == 'picard' .or. trim(algo_nonlin) == 'anderson')) then @@ -2319,7 +2320,7 @@ subroutine input_data write(nu_diag,1021) ' numax = ', numax write(nu_diag,1033) ' histfreq = ', histfreq(:) write(nu_diag,1023) ' histfreq_n = ', histfreq_n(:) - write(nu_diag,1031) ' histfreq_base = ', trim(histfreq_base) + write(nu_diag,1033) ' histfreq_base = ', histfreq_base(:) write(nu_diag,*) ' hist_avg = ', hist_avg(:) write(nu_diag,1031) ' history_dir = ', trim(history_dir) write(nu_diag,1031) ' history_file = ', trim(history_file) @@ -2330,9 +2331,9 @@ subroutine input_data write(nu_diag,1039) ' Initial condition will be written in ', & trim(incond_dir) endif - write(nu_diag,1031) ' dumpfreq = ', trim(dumpfreq) - write(nu_diag,1021) ' dumpfreq_n = ', dumpfreq_n - write(nu_diag,1031) ' dumpfreq_base = ', trim(dumpfreq_base) + write(nu_diag,1033) ' dumpfreq = ', dumpfreq(:) + write(nu_diag,1023) ' dumpfreq_n = ', dumpfreq_n(:) + write(nu_diag,1033) ' dumpfreq_base = ', dumpfreq_base(:) write(nu_diag,1011) ' dump_last = ', dump_last write(nu_diag,1011) ' restart = ', restart write(nu_diag,1031) ' restart_dir = ', trim(restart_dir) diff --git a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 index 8a648f56b..84fcbe5b7 100644 --- a/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_netcdf/ice_restart.F90 @@ -823,7 +823,7 @@ end subroutine write_restart_field subroutine final_restart() - use ice_calendar, only: istep1, idate + use ice_calendar, only: istep1, myear, mmonth, mday, msec integer (kind=int_kind) :: status @@ -833,7 +833,7 @@ subroutine final_restart() status = nf90_close(ncid) if (my_task == master_task) & - write(nu_diag,*) 'Restart read/written ',istep1,idate + write(nu_diag,'(a,i8,4x,i4.4,a,i2.2,a,i2.2,a,i5.5)') 'Restart read/written ',istep1,myear,'-',mmonth,'-',mday,'-',msec #else call abort_ice(subname//'ERROR: USE_NETCDF cpp not defined', & diff --git a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 index 9119fac27..aefcf61f9 100644 --- a/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 +++ b/cicecore/cicedyn/infrastructure/io/io_pio2/ice_restart.F90 @@ -111,7 +111,7 @@ subroutine init_restart_read(ice_ic) ! endif if (my_task == master_task) then - write(nu_diag,*) 'Restart read at istep=',istep0,myear,mmonth,mday,msec + write(nu_diag,'(a,i8,4x,i4.4,a,i2.2,a,i2.2,a,i5.5)') 'Restart read at istep=',istep0,myear,'-',mmonth,'-',mday,'-',msec endif call broadcast_scalar(istep0,master_task) @@ -880,7 +880,7 @@ end subroutine write_restart_field subroutine final_restart() - use ice_calendar, only: istep1, idate, msec + use ice_calendar, only: istep1, myear, mmonth, mday, msec character(len=*), parameter :: subname = '(final_restart)' @@ -888,8 +888,9 @@ subroutine final_restart() call PIO_freeDecomp(File,iodesc3d_ncat) call pio_closefile(File) - if (my_task == master_task) & - write(nu_diag,*) 'Restart read/written ',istep1,idate,msec + if (my_task == master_task) then + write(nu_diag,'(a,i8,4x,i4.4,a,i2.2,a,i2.2,a,i5.5)') 'Restart read/written ',istep1,myear,'-',mmonth,'-',mday,'-',msec + endif end subroutine final_restart diff --git a/cicecore/shared/ice_calendar.F90 b/cicecore/shared/ice_calendar.F90 index 7bd0c73b2..17f18edb2 100644 --- a/cicecore/shared/ice_calendar.F90 +++ b/cicecore/shared/ice_calendar.F90 @@ -102,9 +102,9 @@ module ice_calendar stop_now , & ! if 1, end program execution write_restart, & ! if 1, write restart now diagfreq , & ! diagnostic output frequency (10 = once per 10 dt) - dumpfreq_n , & ! restart output frequency (10 = once per 10 d,m,y) nstreams , & ! number of history output streams - histfreq_n(max_nstrm) ! history output frequency + dumpfreq_n(max_nstrm), & ! restart output frequency (10 = once per 10 d,m,y) + histfreq_n(max_nstrm) ! history output frequency logical (kind=log_kind), public :: & new_year , & ! new year = .true. @@ -126,16 +126,18 @@ module ice_calendar force_restart_now, & ! force a restart now write_history(max_nstrm) ! write history now - character (len=1), public :: & + character (len=2), public :: & npt_unit, & ! run length unit, 'y', 'm', 'd', 'h', 's', '1' npt0_unit, & ! original run length unit, 'y', 'm', 'd', 'h', 's', '1' - histfreq(max_nstrm), & ! history output frequency, 'y','m','d','h','1' - dumpfreq ! restart frequency, 'y','m','d' + histfreq(max_nstrm), & ! history output frequency, 'y','m','d','h','1','x' + dumpfreq(max_nstrm) ! restart frequency, 'y','m','d', h', '1', 'x' followed by optional 1 character (len=char_len), public :: & - dumpfreq_base = 'zero', & ! restart frequency basetime ('zero', 'init') - histfreq_base = 'init', & ! history frequency basetime ('zero', 'init') - calendar_type ! define calendar type + dumpfreq_base(max_nstrm), & ! restart frequency basetime ('zero', 'init') + histfreq_base(max_nstrm), & ! history frequency basetime ('zero', 'init') + calendar_type ! define calendar type + data dumpfreq_base / 'init', 'init', 'init', 'init', 'init' / + data histfreq_base / 'zero', 'zero', 'zero', 'zero', 'zero' / ! PRIVATE @@ -408,10 +410,10 @@ subroutine calendar() ! History writing flags - call compute_relative_elapsed(histfreq_base, elapsed_years, elapsed_months, elapsed_days, elapsed_hours) - do ns = 1, nstreams + call compute_relative_elapsed(histfreq_base(ns), elapsed_years, elapsed_months, elapsed_days, elapsed_hours) + select case (histfreq(ns)) case ("y", "Y") if (new_year .and. histfreq_n(ns)/=0) then @@ -442,27 +444,40 @@ subroutine calendar() enddo - ! Restart writing flag - - call compute_relative_elapsed(dumpfreq_base, elapsed_years, elapsed_months, elapsed_days, elapsed_hours) - - select case (dumpfreq) - case ("y", "Y") - if (new_year .and. mod(elapsed_years, dumpfreq_n)==0) & - write_restart = 1 - case ("m", "M") - if (new_month .and. mod(elapsed_months,dumpfreq_n)==0) & - write_restart = 1 - case ("d", "D") - if (new_day .and. mod(elapsed_days, dumpfreq_n)==0) & - write_restart = 1 - case ("h", "H") - if (new_hour .and. mod(elapsed_hours, dumpfreq_n)==0) & - write_restart = 1 - case ("1") - if (mod(istep1, dumpfreq_n)==0) & - write_restart = 1 - end select + ! Restart writing flag, set dumpfreq to 'x" if stream is written once + + do ns = 1, max_nstrm + + call compute_relative_elapsed(dumpfreq_base(ns), elapsed_years, elapsed_months, elapsed_days, elapsed_hours) + + select case (dumpfreq(ns)(1:1)) + case ("y", "Y") + if (new_year .and. mod(elapsed_years, dumpfreq_n(ns))==0) then + write_restart = 1 + if (dumpfreq(ns)(2:2) == '1') dumpfreq(ns) = 'x' + endif + case ("m", "M") + if (new_month .and. mod(elapsed_months,dumpfreq_n(ns))==0) then + write_restart = 1 + if (dumpfreq(ns)(2:2) == '1') dumpfreq(ns) = 'x' + endif + case ("d", "D") + if (new_day .and. mod(elapsed_days, dumpfreq_n(ns))==0) then + write_restart = 1 + if (dumpfreq(ns)(2:2) == '1') dumpfreq(ns) = 'x' + endif + case ("h", "H") + if (new_hour .and. mod(elapsed_hours, dumpfreq_n(ns))==0) then + write_restart = 1 + if (dumpfreq(ns)(2:2) == '1') dumpfreq(ns) = 'x' + endif + case ("1") + if (mod(istep1, dumpfreq_n(ns))==0) then + write_restart = 1 + if (dumpfreq(ns)(2:2) == '1') dumpfreq(ns) = 'x' + endif + end select + enddo if (force_restart_now) write_restart = 1 diff --git a/configuration/scripts/ice_in b/configuration/scripts/ice_in index e0e317e40..8fff799dc 100644 --- a/configuration/scripts/ice_in +++ b/configuration/scripts/ice_in @@ -21,9 +21,9 @@ restart_dir = './restart/' restart_file = 'iced' pointer_file = './ice.restart_file' - dumpfreq = 'd' - dumpfreq_n = 1 - dumpfreq_base = 'init' + dumpfreq = 'd','x','x','x','x' + dumpfreq_n = 1 , 1 , 1 , 1 , 1 + dumpfreq_base = 'init','init','init','init','init' dump_last = .false. bfbflag = 'off' diagfreq = 24 @@ -47,7 +47,7 @@ lonpnt(2) = -45. histfreq = 'm','x','x','x','x' histfreq_n = 1 , 1 , 1 , 1 , 1 - histfreq_base = 'zero' + histfreq_base = 'zero','zero','zero','zero','zero' hist_avg = .true.,.true.,.true.,.true.,.true. history_dir = './history/' history_file = 'iceh' diff --git a/configuration/scripts/options/set_nml.histall b/configuration/scripts/options/set_nml.histall index 758289099..78932cba8 100644 --- a/configuration/scripts/options/set_nml.histall +++ b/configuration/scripts/options/set_nml.histall @@ -1,6 +1,6 @@ histfreq = 'm','d','1','h','x' histfreq_n = 1,2,6,4,1 - histfreq_base = 'zero' + histfreq_base = 'zero','zero','zero','zero','zero' write_ic = .true. f_tmask = .true. f_blkmask = .true. diff --git a/configuration/scripts/options/set_nml.histdbg b/configuration/scripts/options/set_nml.histdbg index 247d185fd..43ae8e566 100644 --- a/configuration/scripts/options/set_nml.histdbg +++ b/configuration/scripts/options/set_nml.histdbg @@ -1,6 +1,6 @@ histfreq = 'm','d','1','h','x' histfreq_n = 1,1,1,1,1 - histfreq_base = 'zero' + histfreq_base = 'zero','zero','zero','zero','zero' write_ic = .true. f_tmask = .true. f_blkmask = .true. diff --git a/doc/source/cice_index.rst b/doc/source/cice_index.rst index 36c772eff..cf01323d8 100644 --- a/doc/source/cice_index.rst +++ b/doc/source/cice_index.rst @@ -185,7 +185,7 @@ either Celsius or Kelvin units). Deprecated parameters are listed at the end. "dtei", "1/dte, where dte is the EVP subcycling time step", "1/s" "dump_file", "output file for restart dump", "" "dumpfreq", "dump frequency for restarts, y, m, d, h or 1", "" - "dumpfreq_base", "reference date for restart output", "" + "dumpfreq_base", "reference date for restart output, zero or init", "" "dumpfreq_n", "restart output frequency", "" "dump_last", "if true, write restart on last time step of simulation", "" "dwavefreq", "widths of wave frequency bins", "1/s" @@ -316,7 +316,7 @@ either Celsius or Kelvin units). Deprecated parameters are listed at the end. "hin_max", "category thickness limits", "m" "hist_avg", "if true, write averaged data instead of snapshots", "T,T,T,T,T" "histfreq", "units of history output frequency: y, m, w, d or 1", "m,x,x,x,x" - "histfreq_base", "reference date for history output", "" + "histfreq_base", "reference date for history output, zero or init", "" "histfreq_n", "integer output frequency in histfreq units", "1,1,1,1,1" "history_dir", "path to history output files", "" "history_file", "history output file prefix", "" diff --git a/doc/source/user_guide/ug_case_settings.rst b/doc/source/user_guide/ug_case_settings.rst index b60f8f751..ba596863c 100644 --- a/doc/source/user_guide/ug_case_settings.rst +++ b/doc/source/user_guide/ug_case_settings.rst @@ -167,14 +167,19 @@ setup_nml "", "``file``", "write diagnostic output to file", "" "``diag_file``", "string", "diagnostic output file", "'ice_diag.d'" "``dt``", "real", "thermodynamics time step length in seconds", "3600." - "``dumpfreq``", "``d``", "write restart every ``dumpfreq_n`` days", "``y``" + "``dumpfreq``", "``d``", "write restart every ``dumpfreq_n`` days", "'y','x','x','x','x'" + "", "``d1``", "write restart once after ``dumpfreq_n`` days", "" "", "``h``", "write restart every ``dumpfreq_n`` hours", "" + "", "``h1``", "write restart once after ``dumpfreq_n`` hours", "" "", "``m``", "write restart every ``dumpfreq_n`` months", "" + "", "``m1``", "write restart once after ``dumpfreq_n`` months", "" "", "``y``", "write restart every ``dumpfreq_n`` years", "" - "", "``1``", "write restart every ``dumpfreq_n`` time step", "" - "``dumpfreq_base``", "init", "restart output frequency relative to year_init, month_init, day_init", "init" + "", "``y1``", "write restart once after ``dumpfreq_n`` years", "" + "", "``1``", "write restart every ``dumpfreq_n`` time steps", "" + "", "``11``", "write restart once after ``dumpfreq_n`` time steps", "" + "``dumpfreq_base``", "init", "restart output frequency relative to year_init, month_init, day_init", "'init','init','init','init','init'" "", "zero", "restart output frequency relative to year-month-day of 0000-01-01", "" - "``dumpfreq_n``", "integer", "write restart frequency with ``dumpfreq``", "1" + "``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'" @@ -183,7 +188,7 @@ setup_nml "", "``x``", "unused frequency stream (not written)", "" "", "``y``", "write history every ``histfreq_n`` years", "" "", "``1``", "write history every ``histfreq_n`` time step", "" - "``histfreq_base``", "init", "history output frequency relative to year_init, month_init, day_init", "zero" + "``histfreq_base``", "init", "history output frequency relative to year_init, month_init, day_init", "'zero','zero','zero','zero','zero'" "", "zero", "history output frequency relative to year-month-day of 0000-01-01", "" "``histfreq_n``", "integer array", "frequency history output is written with ``histfreq``", "1,1,1,1,1" "``history_dir``", "string", "path to history output directory", "'./'" diff --git a/doc/source/user_guide/ug_implementation.rst b/doc/source/user_guide/ug_implementation.rst index 9bcf205b4..8480eb9aa 100644 --- a/doc/source/user_guide/ug_implementation.rst +++ b/doc/source/user_guide/ug_implementation.rst @@ -891,6 +891,8 @@ will be relative to the model initial date specified by ``year_init``, in setting output frequencies. `init` is the default for ``dumpfreq_base`` and makes it easy to generate restarts 5 or 10 model days after startup as we often do in testing. +Both ``histfreq_base`` and ``dumpfreq_base`` are arrays +and can be set for each stream separately. In general, output is always written at the start of the year, month, day, or hour without @@ -1408,7 +1410,8 @@ The restart files created by CICE contain all of the variables needed for a full, exact restart. The filename begins with the character string ‘iced.’, and the restart dump frequency is given by the namelist variables ``dumpfreq`` and ``dumpfreq_n`` relative to a reference date -specified by ``dumpfreq_base``. The pointer to the filename from +specified by ``dumpfreq_base``. Multiple restart frequencies are supported +in the code with a similar mechanism to history streams. The pointer to the filename from which the restart data is to be read for a continuation run is set in ``pointer_file``. The code assumes that auxiliary binary tracer restart files will be identified using the same pointer and file name prefix,