From 311076110e81f3dbfada14a2fcc6bffb27cd61ee Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 24 Oct 2024 09:14:26 -0600 Subject: [PATCH 1/5] add restart at end of run feature --- model/src/wav_comp_nuopc.F90 | 53 ++++++++++---------- model/src/wav_shr_mod.F90 | 94 +++++++++++++++++++++++++++++++++--- 2 files changed, 114 insertions(+), 33 deletions(-) diff --git a/model/src/wav_comp_nuopc.F90 b/model/src/wav_comp_nuopc.F90 index 8b9ff5a5a..f734bb275 100644 --- a/model/src/wav_comp_nuopc.F90 +++ b/model/src/wav_comp_nuopc.F90 @@ -1160,7 +1160,7 @@ end subroutine ModelAdvance !> @author mvertens@ucar.edu, Denise.Worthen@noaa.gov !> @date 01-05-2022 subroutine ModelSetRunClock(gcomp, rc) - + use wav_shr_mod, only : dtime_drv, get_minimum_timestep ! input/output variables type(ESMF_GridComp) :: gcomp integer, intent(out) :: rc @@ -1219,7 +1219,9 @@ subroutine ModelSetRunClock(gcomp, rc) call ESMF_ClockGetAlarmList(mclock, alarmlistflag=ESMF_ALARMLIST_ALL, alarmCount=alarmCount, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - + dtime_drv = get_minimum_timestep(gcomp, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (alarmCount == 0) then call ESMF_ClockGet(mclock, startTime=mStartTime, rc=rc) @@ -1228,6 +1230,29 @@ subroutine ModelSetRunClock(gcomp, rc) call ESMF_GridCompGet(gcomp, name=name, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_LogWrite(trim(subname)//'setting alarms for ' // trim(name), ESMF_LOGMSG_INFO) + !---------------- + ! Stop alarm + !---------------- + call NUOPC_CompAttributeGet(gcomp, name="stop_option", value=stop_option, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="stop_n", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_n + + call NUOPC_CompAttributeGet(gcomp, name="stop_ymd", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_ymd + + call alarmInit(mclock, stop_alarm, stop_option, & + opt_n = stop_n, & + opt_ymd = stop_ymd, & + RefTime = mCurrTime, & + alarmname = 'alarm_stop', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_AlarmSet(stop_alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return !---------------- ! Restart alarm @@ -1263,30 +1288,6 @@ subroutine ModelSetRunClock(gcomp, rc) user_restalarm = .false. end if - !---------------- - ! Stop alarm - !---------------- - call NUOPC_CompAttributeGet(gcomp, name="stop_option", value=stop_option, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - call NUOPC_CompAttributeGet(gcomp, name="stop_n", value=cvalue, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) stop_n - - call NUOPC_CompAttributeGet(gcomp, name="stop_ymd", value=cvalue, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) stop_ymd - - call alarmInit(mclock, stop_alarm, stop_option, & - opt_n = stop_n, & - opt_ymd = stop_ymd, & - RefTime = mCurrTime, & - alarmname = 'alarm_stop', rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - call ESMF_AlarmSet(stop_alarm, clock=mclock, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - !---------------- ! History alarm !---------------- diff --git a/model/src/wav_shr_mod.F90 b/model/src/wav_shr_mod.F90 index 9bddd503e..2862944fb 100644 --- a/model/src/wav_shr_mod.F90 +++ b/model/src/wav_shr_mod.F90 @@ -26,6 +26,7 @@ module wav_shr_mod use ESMF , only : ESMF_Time, ESMF_TimeGet, ESMF_TimeSet use ESMF , only : ESMF_TimeInterval, ESMF_TimeIntervalSet, ESMF_TimeIntervalGet use ESMF , only : ESMF_VM, ESMF_VMGet, ESMF_VMBroadcast, ESMF_VMGetCurrent + use ESMF , only : ESMF_ClockGetAlarm, ESMF_AlarmGet, MOD use NUOPC , only : NUOPC_CompAttributeGet use NUOPC_Model , only : NUOPC_ModelGet use wav_kind_mod , only : r8 => shr_kind_r8, i8 => shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs @@ -47,7 +48,7 @@ module wav_shr_mod private :: field_getfldptr !< @private obtain a pointer to a field public :: diagnose_mesh !< @public write out info about mesh public :: write_meshdecomp !< @public write the mesh decomposition to a file - + public :: get_minimum_timestep !< @public used to set nstep based alarms interface state_getfldptr module procedure state_getfldptr_1d module procedure state_getfldptr_2d @@ -74,8 +75,8 @@ module wav_shr_mod logical , public :: merge_import = .false. !< @public logical to specify whether import fields will !! be merged with a field provided from a file logical , public :: multigrid = .false. !< @public logical to control whether wave model is run - !! as multigrid - + !! as multigrid + integer , public :: dtime_drv !! used for nstep(s) alarm option setting interface ymd2date module procedure ymd2date_int module procedure ymd2date_long @@ -102,6 +103,7 @@ module wav_shr_mod optMonthly = "monthly" , & !< alarm option monthly optYearly = "yearly" , & !< alarm option yearly optDate = "date" , & !< alarm option date + optEnd = "end" , & !< alarm option end optIfdays0 = "ifdays0" !< alarm option for number of days 0 ! Module data @@ -893,6 +895,7 @@ subroutine alarmInit( clock, alarm, option, & type(ESMF_Time) :: CurrTime ! Current Time type(ESMF_Time) :: NextAlarm ! Next restart alarm time type(ESMF_TimeInterval) :: AlarmInterval ! Alarm interval + type(ESMF_TimeInterval) :: TimeStepInterval ! Timestep interval integer :: sec character(len=*), parameter :: subname = ' (wav_shr_mod:set_alarmInit) ' @@ -940,6 +943,14 @@ subroutine alarmInit( clock, alarm, option, & if (chkerr(rc,__LINE__,u_FILE_u)) return update_nextalarm = .false. + case (optEnd) + call ESMF_TimeIntervalSet(AlarmInterval, yy=9999, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGetAlarm(clock, alarmname="alarm_stop", alarm=alarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_AlarmGet(alarm, ringTime=NextAlarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case (optDate) if (.not. present(opt_ymd)) then call ESMF_LogWrite(trim(subname)//trim(option)//' requires opt_ymd', & @@ -990,10 +1001,22 @@ subroutine alarmInit( clock, alarm, option, & ESMF_LOGMSG_INFO, rc=rc) rc = ESMF_FAILURE end if - call ESMF_ClockGet(clock, TimeStep=AlarmInterval, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGet(clock, TimeStep=TimestepInterval, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeIntervalSet(AlarmInterval, s=dtime_drv, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return AlarmInterval = AlarmInterval * opt_n + ! timestepinterval*0 is 0 of kind ESMF_TimeStepInterval + if (mod(AlarmInterval, TimestepInterval) /= (timestepinterval*0)) then + call ESMF_LogWrite(subname//'illegal Alarm setting for '//trim(alarmname), ESMF_LOGMSG_ERROR) + rc = ESMF_FAILURE + return + endif update_nextalarm = .true. +! call ESMF_ClockGet(clock, TimeStep=AlarmInterval, rc=rc) +! if (chkerr(rc,__LINE__,u_FILE_u)) return +! AlarmInterval = AlarmInterval * opt_n +! update_nextalarm = .true. case (optNStep) if (.not.present(opt_n)) then @@ -1006,10 +1029,22 @@ subroutine alarmInit( clock, alarm, option, & ESMF_LOGMSG_INFO, rc=rc) rc = ESMF_FAILURE end if - call ESMF_ClockGet(clock, TimeStep=AlarmInterval, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGet(clock, TimeStep=TimestepInterval, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeIntervalSet(AlarmInterval, s=dtime_drv, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return AlarmInterval = AlarmInterval * opt_n + ! timestepinterval*0 is 0 of kind ESMF_TimeStepInterval + if (mod(AlarmInterval, TimestepInterval) /= (timestepinterval*0)) then + call ESMF_LogWrite(subname//'illegal Alarm setting for '//trim(alarmname), ESMF_LOGMSG_ERROR) + rc = ESMF_FAILURE + return + endif update_nextalarm = .true. +! call ESMF_ClockGet(clock, TimeStep=AlarmInterval, rc=rc) +! if (chkerr(rc,__LINE__,u_FILE_u)) return +! AlarmInterval = AlarmInterval * opt_n +! update_nextalarm = .true. case (optNSeconds) if (.not.present(opt_n)) then @@ -1343,6 +1378,51 @@ subroutine ymd2date_long(year,month,day,date) if (year < 0) date = -date end subroutine ymd2date_long + integer function get_minimum_timestep(gcomp, rc) + ! Get the minimum timestep interval in seconds based on the nuopc.config variables *_cpl_dt, + ! if none of these variables are defined this routine will throw an error + type(ESMF_GridComp), intent(in) :: gcomp + integer, intent(out) :: rc + + character(len=CS) :: cvalue + integer :: comp_dt ! coupling interval of component + integer, parameter :: ncomps = 8 + character(len=3),parameter :: compname(ncomps) = (/"atm", "lnd", "ice", "ocn","glc","rof", "wav", "esp"/) + character(len=10) :: comp + integer :: i + logical :: is_present, is_set ! determine if these variables are used + + !--------------------------------------------------------------------------- + ! Determine driver clock timestep + !--------------------------------------------------------------------------- + get_minimum_timestep = huge(1) + + do i=1,ncomps + comp = compname(i)//"_cpl_dt" + + call NUOPC_CompAttributeGet(gcomp, name=comp, isPresent=is_present, isSet=is_set, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (is_present .and. is_set) then + call NUOPC_CompAttributeGet(gcomp, name=comp, value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) comp_dt + get_minimum_timestep = min(comp_dt, get_minimum_timestep) + endif + enddo + + if(get_minimum_timestep == huge(1)) then + call ESMF_LogWrite('minimum_timestep_error: this option is not supported ', ESMF_LOGMSG_ERROR) + rc = ESMF_FAILURE + return + endif + if(get_minimum_timestep <= 0) then + call ESMF_LogWrite('minimum_timestep_error ERROR ', ESMF_LOGMSG_ERROR) + rc = ESMF_FAILURE + return + endif + end function get_minimum_timestep + !=============================================================================== !> Return a logical true if ESMF_LogFoundError detects an error !! From 2a926a44cb8fe92ac5e57f0063d719c377d8983f Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 24 Oct 2024 09:21:17 -0600 Subject: [PATCH 2/5] cleanup whitespace --- model/src/wav_comp_nuopc.F90 | 2 +- model/src/wav_shr_mod.F90 | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/model/src/wav_comp_nuopc.F90 b/model/src/wav_comp_nuopc.F90 index f734bb275..6608bc9b1 100644 --- a/model/src/wav_comp_nuopc.F90 +++ b/model/src/wav_comp_nuopc.F90 @@ -1221,7 +1221,7 @@ subroutine ModelSetRunClock(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return dtime_drv = get_minimum_timestep(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - + if (alarmCount == 0) then call ESMF_ClockGet(mclock, startTime=mStartTime, rc=rc) diff --git a/model/src/wav_shr_mod.F90 b/model/src/wav_shr_mod.F90 index 2862944fb..75104f612 100644 --- a/model/src/wav_shr_mod.F90 +++ b/model/src/wav_shr_mod.F90 @@ -75,8 +75,8 @@ module wav_shr_mod logical , public :: merge_import = .false. !< @public logical to specify whether import fields will !! be merged with a field provided from a file logical , public :: multigrid = .false. !< @public logical to control whether wave model is run - !! as multigrid - integer , public :: dtime_drv !! used for nstep(s) alarm option setting + !! as multigrid + integer , public :: dtime_drv !! used for nstep(s) alarm option setting interface ymd2date module procedure ymd2date_int module procedure ymd2date_long @@ -948,9 +948,9 @@ subroutine alarmInit( clock, alarm, option, & if (chkerr(rc,__LINE__,u_FILE_u)) return call ESMF_ClockGetAlarm(clock, alarmname="alarm_stop", alarm=alarm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_AlarmGet(alarm, ringTime=NextAlarm, rc=rc) + call ESMF_AlarmGet(alarm, ringTime=NextAlarm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - + case (optDate) if (.not. present(opt_ymd)) then call ESMF_LogWrite(trim(subname)//trim(option)//' requires opt_ymd', & @@ -1041,10 +1041,6 @@ subroutine alarmInit( clock, alarm, option, & return endif update_nextalarm = .true. -! call ESMF_ClockGet(clock, TimeStep=AlarmInterval, rc=rc) -! if (chkerr(rc,__LINE__,u_FILE_u)) return -! AlarmInterval = AlarmInterval * opt_n -! update_nextalarm = .true. case (optNSeconds) if (.not.present(opt_n)) then @@ -1399,7 +1395,7 @@ integer function get_minimum_timestep(gcomp, rc) do i=1,ncomps comp = compname(i)//"_cpl_dt" - + call NUOPC_CompAttributeGet(gcomp, name=comp, isPresent=is_present, isSet=is_set, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return From fb42cacdd11944441d0932183c0514026d09a9d9 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Tue, 29 Oct 2024 07:12:13 -0600 Subject: [PATCH 3/5] remove routine copied from share code --- model/src/wav_comp_nuopc.F90 | 7 ++--- model/src/wav_shr_mod.F90 | 50 ------------------------------------ 2 files changed, 2 insertions(+), 55 deletions(-) diff --git a/model/src/wav_comp_nuopc.F90 b/model/src/wav_comp_nuopc.F90 index 6608bc9b1..01d90ed9a 100644 --- a/model/src/wav_comp_nuopc.F90 +++ b/model/src/wav_comp_nuopc.F90 @@ -531,6 +531,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) !-------------------------------------------------------------------- ! IO set-up !-------------------------------------------------------------------- + if (.not. multigrid) call set_shel_io(stdout,mds,ntrace) if (cesmcoupled) then shrlogunit = 6 @@ -547,8 +548,6 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) stdout = 6 end if - if (.not. multigrid) call set_shel_io(stdout,mds,ntrace) - if ( root_task ) then write(stdout,'(a)')' *** WAVEWATCH III Program shell *** ' write(stdout,'(a)')'===============================================' @@ -1012,7 +1011,6 @@ subroutine ModelAdvance(gcomp, rc) integer :: imod integer :: ymd ! current year-month-day integer :: tod ! current time of day (sec) - integer :: shrlogunit ! original log unit and level character(ESMF_MAXSTR) :: msgString character(len=*),parameter :: subname = '(wav_comp_nuopc:ModelAdvance) ' !------------------------------------------------------- @@ -1160,7 +1158,7 @@ end subroutine ModelAdvance !> @author mvertens@ucar.edu, Denise.Worthen@noaa.gov !> @date 01-05-2022 subroutine ModelSetRunClock(gcomp, rc) - use wav_shr_mod, only : dtime_drv, get_minimum_timestep + use nuopc_shr_methods, only : dtime_drv, get_minimum_timestep ! input/output variables type(ESMF_GridComp) :: gcomp integer, intent(out) :: rc @@ -1410,7 +1408,6 @@ subroutine waveinit_cesm(gcomp, ntrace, mpi_comm, mds, rc) ! local variables integer :: ierr integer :: unitn ! namelist unit number - integer :: shrlogunit logical :: isPresent, isSet real(r8) :: dtmax_in ! Maximum overall time step. real(r8) :: dtmin_in ! Minimum dynamic time step for source diff --git a/model/src/wav_shr_mod.F90 b/model/src/wav_shr_mod.F90 index 75104f612..e8f7b5c09 100644 --- a/model/src/wav_shr_mod.F90 +++ b/model/src/wav_shr_mod.F90 @@ -48,7 +48,6 @@ module wav_shr_mod private :: field_getfldptr !< @private obtain a pointer to a field public :: diagnose_mesh !< @public write out info about mesh public :: write_meshdecomp !< @public write the mesh decomposition to a file - public :: get_minimum_timestep !< @public used to set nstep based alarms interface state_getfldptr module procedure state_getfldptr_1d module procedure state_getfldptr_2d @@ -1013,10 +1012,6 @@ subroutine alarmInit( clock, alarm, option, & return endif update_nextalarm = .true. -! call ESMF_ClockGet(clock, TimeStep=AlarmInterval, rc=rc) -! if (chkerr(rc,__LINE__,u_FILE_u)) return -! AlarmInterval = AlarmInterval * opt_n -! update_nextalarm = .true. case (optNStep) if (.not.present(opt_n)) then @@ -1374,51 +1369,6 @@ subroutine ymd2date_long(year,month,day,date) if (year < 0) date = -date end subroutine ymd2date_long - integer function get_minimum_timestep(gcomp, rc) - ! Get the minimum timestep interval in seconds based on the nuopc.config variables *_cpl_dt, - ! if none of these variables are defined this routine will throw an error - type(ESMF_GridComp), intent(in) :: gcomp - integer, intent(out) :: rc - - character(len=CS) :: cvalue - integer :: comp_dt ! coupling interval of component - integer, parameter :: ncomps = 8 - character(len=3),parameter :: compname(ncomps) = (/"atm", "lnd", "ice", "ocn","glc","rof", "wav", "esp"/) - character(len=10) :: comp - integer :: i - logical :: is_present, is_set ! determine if these variables are used - - !--------------------------------------------------------------------------- - ! Determine driver clock timestep - !--------------------------------------------------------------------------- - get_minimum_timestep = huge(1) - - do i=1,ncomps - comp = compname(i)//"_cpl_dt" - - call NUOPC_CompAttributeGet(gcomp, name=comp, isPresent=is_present, isSet=is_set, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - if (is_present .and. is_set) then - call NUOPC_CompAttributeGet(gcomp, name=comp, value=cvalue, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) comp_dt - get_minimum_timestep = min(comp_dt, get_minimum_timestep) - endif - enddo - - if(get_minimum_timestep == huge(1)) then - call ESMF_LogWrite('minimum_timestep_error: this option is not supported ', ESMF_LOGMSG_ERROR) - rc = ESMF_FAILURE - return - endif - if(get_minimum_timestep <= 0) then - call ESMF_LogWrite('minimum_timestep_error ERROR ', ESMF_LOGMSG_ERROR) - rc = ESMF_FAILURE - return - endif - end function get_minimum_timestep - !=============================================================================== !> Return a logical true if ESMF_LogFoundError detects an error !! From b6ab49ae73ba4a0b63378efa61d0e8b7cf95d483 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Fri, 1 Nov 2024 07:40:27 -0600 Subject: [PATCH 4/5] fix issue with initializing log file --- model/src/wav_comp_nuopc.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/model/src/wav_comp_nuopc.F90 b/model/src/wav_comp_nuopc.F90 index 88277cfd9..d100f83f1 100644 --- a/model/src/wav_comp_nuopc.F90 +++ b/model/src/wav_comp_nuopc.F90 @@ -546,7 +546,6 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) !-------------------------------------------------------------------- ! IO set-up !-------------------------------------------------------------------- - if (.not. multigrid) call set_shel_io(stdout,mds,ntrace) if (cesmcoupled) then shrlogunit = 6 @@ -562,7 +561,8 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) else stdout = 6 end if - + if (.not. multigrid) call set_shel_io(stdout,mds,ntrace) + if ( root_task ) then write(stdout,'(a)')' *** WAVEWATCH III Program shell *** ' write(stdout,'(a)')'===============================================' From d634a5c8208b123c67b373d6da8f9cb2f24593a6 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Fri, 1 Nov 2024 07:43:23 -0600 Subject: [PATCH 5/5] fix whitespace --- model/src/wav_comp_nuopc.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/src/wav_comp_nuopc.F90 b/model/src/wav_comp_nuopc.F90 index d100f83f1..bb42fde8f 100644 --- a/model/src/wav_comp_nuopc.F90 +++ b/model/src/wav_comp_nuopc.F90 @@ -562,7 +562,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) stdout = 6 end if if (.not. multigrid) call set_shel_io(stdout,mds,ntrace) - + if ( root_task ) then write(stdout,'(a)')' *** WAVEWATCH III Program shell *** ' write(stdout,'(a)')'==============================================='