Skip to content

Commit 40187b2

Browse files
authored
Prate_avg fix (NOAA-EMC#979), UPP call freq and single restart var (NOAA-EMC#973) combo (NOAA-EMC#996)
* Add fixes for Prate and UPP Call * Add changes to unit test due to fundamental change to output_fh * Reduce restart control variables to one
1 parent 65884b1 commit 40187b2

6 files changed

Lines changed: 88 additions & 85 deletions

File tree

ccpp/CCPP_driver.F90

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ subroutine CCPP_step (step, nblks, ierr)
5959
! Local variables
6060
integer :: nb, nt, ntX
6161
integer :: ierr2
62+
integer :: kdt_iau
63+
logical :: iauwindow_center
6264
! DH* 20210104 - remove kdt_rad when code to clear diagnostic buckets is removed
6365
integer :: kdt_rad
6466

@@ -167,8 +169,17 @@ subroutine CCPP_step (step, nblks, ierr)
167169
endif
168170

169171
!--- determine if physics diagnostics buckets need to be cleared
172+
iauwindow_center = .false.
173+
if (GFS_control%iau_offset > 0) then
174+
kdt_iau = nint(GFS_control%iau_offset*3600./GFS_control%dtp)
175+
if (GFS_control%kdt-1 == kdt_iau) then
176+
iauwindow_center = .true.
177+
if( GFS_control%me == 0)print *,'in ccpp step vary, iauwindow_center=',iauwindow_center,&
178+
'kdt=',GFS_control%kdt,'dtp=',GFS_control%dtp,'iau_offset=',GFS_control%iau_offset
179+
endif
180+
endif
170181
if ((mod(GFS_control%kdt-1,GFS_control%nszero)) == 0) then
171-
call GFS_Intdiag%phys_zero(GFS_control)
182+
call GFS_Intdiag%phys_zero(GFS_control, iauwindow_center=iauwindow_center)
172183
endif
173184

174185
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

fv3/atmos_model.F90

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,8 +1026,10 @@ subroutine update_atmos_model_state (Atmos, rc)
10261026
if (ANY(nint(output_fh(:)*3600.0) == seconds) .or. (GFS_control%kdt == first_kdt)) then
10271027
if (mpp_pe() == mpp_root_pe()) write(6,*) "---isec,seconds",isec,seconds
10281028
time_int = real(isec)
1029-
call InitTimeFromIAUOffset(Atmos, time_int, time_intfull, seconds)
1030-
if (mpp_pe() == mpp_root_pe()) write(6,*) ' gfs diags time since last bucket empty: ',time_int/3600.,'hrs'
1029+
time_intfull = real(seconds)
1030+
call InitTimeFromIAUOffset(Atmos, time_int, time_intfull)
1031+
if (mpp_pe() == mpp_root_pe()) write(6,*) 'gfs diags time since last bucket empty: ',time_int,' time_intfull=', &
1032+
time_intfull,' kdt=',GFS_control%kdt
10311033
call atmosphere_nggps_diag(Atmos%Time)
10321034
call fv3atm_diag_output(Atmos%Time, GFS_Diag, Atm_block, GFS_control%nx, GFS_control%ny, &
10331035
GFS_control%levs, 1, 1, 1.0_GFS_kind_phys, time_int, time_intfull, &
@@ -1069,27 +1071,17 @@ end subroutine update_atmos_model_state
10691071
!> @param[inout] atmos the main atmos model configurations
10701072
!> @param[inout] time_init model initialization time
10711073
!> @param[inout] time_intfull model time remaining
1072-
!> @param seconds time since model initialization
10731074
!>
10741075
!> @author Daniel Sarmiento @date May 16, 2025
1075-
subroutine InitTimeFromIAUOffset(Atmos, time_int, time_intfull, seconds)
1076+
subroutine InitTimeFromIAUOffset(Atmos, time_int, time_intfull)
10761077

10771078
type (atmos_data_type), intent(inout) :: Atmos
10781079
real(kind=GFS_kind_phys), intent(inout) :: time_int, time_intfull
1079-
integer, intent(inout) :: seconds
1080-
integer :: isec_fhzero
10811080

10821081
if(Atmos%iau_offset > zero) then
10831082
if( time_int - Atmos%iau_offset*3600. > zero ) then
10841083
time_int = time_int - Atmos%iau_offset*3600.
1085-
else if(seconds == Atmos%iau_offset*3600) then
1086-
call get_time (Atmos%Time - diag_time_fhzero, isec_fhzero)
1087-
time_int = real(isec_fhzero)
1088-
if (mpp_pe() == mpp_root_pe()) write(6,*) "---iseczero",isec_fhzero
10891084
endif
1090-
endif
1091-
time_intfull = real(seconds)
1092-
if(Atmos%iau_offset > zero) then
10931085
if( time_intfull - Atmos%iau_offset*3600. > zero) then
10941086
time_intfull = time_intfull - Atmos%iau_offset*3600.
10951087
endif

fv3/fv3_cap.F90

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,11 +1005,7 @@ subroutine OutputHours_FrequencyInput(nfhmax, output_startfh, outputfh2)
10051005
if( nfhmax>output_startfh) nfh = nint((nfhmax-output_startfh)/outputfh2(1)) + 1
10061006
if( nfh > 0) then
10071007
allocate(output_fh(nfh))
1008-
if( output_startfh == 0) then
1009-
output_fh(1) = dt_atmos/3600.
1010-
else
1011-
output_fh(1) = output_startfh
1012-
endif
1008+
output_fh(1) = output_startfh + dt_atmos/3600.
10131009
do i=2,nfh
10141010
output_fh(i) = (i-1)*outputfh2(1) + output_startfh
10151011
! Except fh000, which is the first time output, if any other of the

fv3/io/module_wrt_grid_comp.F90

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,7 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc)
17231723
logical :: use_parallel_netcdf
17241724
real, allocatable :: output_fh(:)
17251725
logical :: is_restart_bundle, restart_written
1726+
logical :: lupp_history, lrestart
17261727
integer :: tileCount
17271728
type(ESMF_Info) :: fcstInfo, wrtInfo
17281729
character(len=ESMF_MAXSTR) :: output_grid_name
@@ -1783,7 +1784,30 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc)
17831784
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
17841785

17851786
if (nf_hours < 0) return
1786-
1787+
!
1788+
!*** set up output time on write grid comp:
1789+
!
1790+
call ESMF_TimeIntervalGet(timeinterval=io_currtimediff, s=fcst_seconds, rc=rc)
1791+
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
1792+
1793+
! fcst_seconds is number of seconds in io_currtimediff, which is time interval between currenttime and io_basetime.
1794+
! io_basetime has been adjusted by iau_offset in initialize phase.
1795+
! Since output_fh and frestart and NOT adjusted by iau_offset, in order to compare
1796+
! them with fcst_seconds, we must also adjust fcst_seconds by iau_offset
1797+
if (iau_offset > 0) then
1798+
fcst_seconds = fcst_seconds + iau_offset*3600
1799+
endif
1800+
!
1801+
!--- set up logic variable to run upp/history and restart
1802+
!
1803+
lupp_history = .false.
1804+
lrestart = .false.
1805+
if ( ANY(nint(output_fh(:)*3600) == fcst_seconds) ) lupp_history = .true.
1806+
if ( ANY(frestart(:) == fcst_seconds) ) lrestart = .true.
1807+
if ( .not. (lupp_history .or. lrestart ) ) return
1808+
!
1809+
!--- set up current forecast hours
1810+
!
17871811
if (lflname_fulltime) then
17881812
ndig = max(log10(nf_hours+0.5)+1., 3.)
17891813
write(cform, '("(I",I1,".",I1,",A1,I2.2,A1,I2.2)")') ndig, ndig
@@ -1794,7 +1818,9 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc)
17941818
write(cfhour, cform) nf_hours
17951819
endif
17961820
!
1797-
if(lprnt) print *,'in wrt run, nfhour=',nfhour,' cfhour=',trim(cfhour)
1821+
if(lprnt) print *,'in wrt run, cdate=',cdate(1:4),'fcst_seconds=',fcst_seconds/3600.,'nfhour=',nfhour,&
1822+
'lupp_history=', lupp_history, 'lrestart=',lrestart,'write grid comp not return,cfhour=',trim(cfhour)
1823+
!
17981824
!
17991825
!-----------------------------------------------------------------------
18001826
!*** loop on the "output_" FieldBundles, i.e. files that need to write out
@@ -2020,7 +2046,7 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc)
20202046
!*** do post
20212047
!-----------------------------------------------------------------------
20222048
lmask_fields = .false.
2023-
if( wrt_int_state%write_dopost ) then
2049+
if( wrt_int_state%write_dopost .and. lupp_history ) then
20242050
#ifdef INLINE_POST
20252051
wbeg = MPI_Wtime()
20262052
do n=1,ngrids
@@ -2081,20 +2107,7 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc)
20812107
! ** now loop through output field bundle
20822108
!-----------------------------------------------------------------------
20832109

2084-
call ESMF_TimeIntervalGet(timeinterval=io_currtimediff, s=fcst_seconds, rc=rc)
2085-
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
2086-
2087-
! fcst_seconds is number of seconds in io_currtimediff, which is time interval between currenttime and io_basetime.
2088-
! io_basetime has been adjusted by iau_offset in initialize phase.
2089-
! Since output_fh and frestart and NOT adjusted by iau_offset, in order to compare
2090-
! them with fcst_seconds, we must also adjust fcst_seconds by iau_offset
2091-
if (iau_offset > 0) then
2092-
fcst_seconds = fcst_seconds + iau_offset*3600
2093-
endif
2094-
2095-
if ( (wrt_int_state%output_history .and. ANY(nint(output_fh(:)*3600.0) == fcst_seconds)) .or. ANY(frestart(:) == fcst_seconds) ) then
2096-
2097-
! if (lprnt) write(0,*)'wrt_run: loop over wrt_int_state%FBCount ',wrt_int_state%FBCount, ' nfhour ', nfhour, ' cdate ', cdate(1:6)
2110+
if ( (wrt_int_state%output_history .and. lupp_history) .or. lrestart ) then
20982111
two_phase_loop: do out_phase = 1, 2
20992112

21002113
restart_written = .false.
@@ -2106,9 +2119,9 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc)
21062119
is_restart_bundle = .false.
21072120
if (wrtFBName(1:8) == 'restart_') then
21082121
is_restart_bundle = .true.
2109-
if (.not.(ANY(frestart(:) == fcst_seconds))) cycle
2122+
if (.not.lrestart) cycle
21102123
else
2111-
if (.not.(wrt_int_state%output_history .and. ANY(nint(output_fh(:)*3600.0) == fcst_seconds))) cycle
2124+
if (.not.(wrt_int_state%output_history .and. lupp_history)) cycle
21122125
endif
21132126

21142127
if (out_phase == 1 .and. is_restart_bundle) cycle

fv3/module_fcst_grid_comp.F90

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -595,8 +595,8 @@ subroutine fcst_initialize(fcst_comp, importState, exportState, clock, rc)
595595
logical :: top_parent_is_global
596596
logical :: history_file_on_native_grid
597597

598-
integer :: num_restart_interval, restart_starttime
599-
real,dimension(:),allocatable :: restart_interval
598+
integer :: num_restart_fh, restart_starttime
599+
real,dimension(:),allocatable :: restart_fh
600600

601601
integer :: urc
602602
type(ESMF_State) :: tempState
@@ -634,16 +634,16 @@ subroutine fcst_initialize(fcst_comp, importState, exportState, clock, rc)
634634
call ESMF_ConfigLoadFile(config=CF ,filename='model_configure' ,rc=rc)
635635
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
636636

637-
num_restart_interval = ESMF_ConfigGetLen(config=CF, label ='restart_interval:',rc=rc)
637+
num_restart_fh = ESMF_ConfigGetLen(config=CF, label ='restart_interval:',rc=rc)
638638
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
639-
if (mype == 0) print *,'af ufs config,num_restart_interval=',num_restart_interval
640-
if (num_restart_interval<=0) num_restart_interval = 1
641-
allocate(restart_interval(num_restart_interval))
642-
restart_interval = 0
643-
call ESMF_ConfigGetAttribute(CF,valueList=restart_interval,label='restart_interval:', &
644-
count=num_restart_interval, rc=rc)
639+
if (mype == 0) print *,'af ufs config,num_restart_fh=',num_restart_fh
640+
if (num_restart_fh<=0) num_restart_fh = 1
641+
allocate(restart_fh(num_restart_fh))
642+
restart_fh = 0
643+
call ESMF_ConfigGetAttribute(CF,valueList=restart_fh,label='restart_interval:', &
644+
count=num_restart_fh, rc=rc)
645645
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
646-
if (mype == 0) print *,'af ufs config,restart_interval=',restart_interval
646+
if (mype == 0) print *,'af ufs config,restart_fh=',restart_fh
647647
!
648648
call fms_init(fcst_mpi_comm%mpi_val)
649649
call mpp_init()
@@ -762,8 +762,8 @@ subroutine fcst_initialize(fcst_comp, importState, exportState, clock, rc)
762762
if (mype == 0) write(*,*)'time_init=', date_init,'time=',date,'time_end=',date_end,'dt_atmos=',dt_atmos
763763

764764
call fcst_time_array_setup(Time_init, Time_end, Time_step_restart, &
765-
Time_restart, num_restart_interval, &
766-
restart_interval)
765+
Time_restart, num_restart_fh, &
766+
restart_fh)
767767

768768
!------ initialize component models ------
769769

@@ -1158,51 +1158,41 @@ end subroutine fcst_initialize
11581158
!>
11591159
!> @param[inout] Time_init model initialization time
11601160
!> @param[inout] Time_end model end time
1161-
!> @param[inout] Time_step_restart restart time based on restart_interval
1161+
!> @param[inout] Time_step_restart restart time based on restart_fh
11621162
!> @param[inout] Time_restart calculated restart time
1163-
!> @param[inout] num_restart_interval user defined restart interval
1164-
!> @param[inout] restart_interval restart interval, allocatable
1163+
!> @param[inout] num_restart_fh user defined restart interval
1164+
!> @param[inout] restart_fh restart interval, allocatable
11651165
!>
11661166
!> @author Daniel Sarmiento @date May 16, 2025
11671167
subroutine fcst_time_array_setup(Time_init, Time_end, Time_step_restart, &
1168-
Time_restart, num_restart_interval, &
1169-
restart_interval)
1168+
Time_restart, num_restart_fh, &
1169+
restart_fh)
11701170

11711171
type(time_type), intent(inout) :: Time_init, Time_end, &
11721172
Time_step_restart, &
11731173
Time_restart
11741174
type(time_type) :: iautime
1175-
integer, intent(inout) :: num_restart_interval
1175+
integer, intent(inout) :: num_restart_fh
11761176
integer :: total_inttime, tmpvar, &
11771177
i, restart_starttime
11781178
logical :: freq_restart
1179-
real, dimension(:), allocatable, intent(inout) :: restart_interval
1179+
real, dimension(:), allocatable, intent(inout) :: restart_fh
11801180

11811181
! set up forecast time array that controls when to write out restart files
11821182
frestart = 0
11831183
call get_time(Time_end - Time_init, total_inttime)
1184-
! set iau offset time
1185-
Atmos%iau_offset = iau_offset
1186-
if(iau_offset > 0 ) then
1187-
iautime = set_time(iau_offset * 3600, 0)
1188-
endif
11891184
! if the second item is -1, the first number is frequency
11901185
freq_restart = .false.
1191-
if(num_restart_interval == 2) then
1192-
if(restart_interval(2)== -1) freq_restart = .true.
1186+
if(num_restart_fh == 2) then
1187+
if(restart_fh(2)== -1) freq_restart = .true.
11931188
endif
11941189
if(freq_restart) then
1195-
if(restart_interval(1) >= 0) then
1196-
tmpvar = restart_interval(1) * 3600
1190+
if(restart_fh(1) >= 0) then
1191+
tmpvar = restart_fh(1) * 3600
11971192
Time_step_restart = set_time (tmpvar, 0)
1198-
if(iau_offset > 0 ) then
1199-
Time_restart = Time_init + iautime + Time_step_restart
1200-
frestart(1) = tmpvar + iau_offset *3600
1201-
else
1202-
Time_restart = Time_init + Time_step_restart
1203-
frestart(1) = tmpvar
1204-
endif
1205-
if(restart_interval(1) > 0) then
1193+
Time_restart = Time_init + Time_step_restart
1194+
frestart(1) = tmpvar
1195+
if(restart_fh(1) > 0) then
12061196
i = 2
12071197
do while ( Time_restart < Time_end )
12081198
frestart(i) = frestart(i-1) + tmpvar
@@ -1212,17 +1202,13 @@ subroutine fcst_time_array_setup(Time_init, Time_end, Time_step_restart, &
12121202
endif
12131203
endif
12141204
! otherwise it is an array with forecast time at which the restart files will be written out
1215-
else if(num_restart_interval >= 1) then
1216-
if(num_restart_interval == 1 .and. restart_interval(1) == 0 ) then
1205+
else if(num_restart_fh >= 1) then
1206+
if(num_restart_fh == 1 .and. restart_fh(1) == 0 ) then
12171207
frestart(1) = total_inttime
12181208
else
1219-
if(iau_offset > 0 ) then
1220-
restart_starttime = iau_offset *3600
1221-
else
1222-
restart_starttime = 0
1223-
endif
1224-
do i=1,num_restart_interval
1225-
frestart(i) = restart_interval(i) * 3600. + restart_starttime
1209+
restart_starttime = 0
1210+
do i=1,num_restart_fh
1211+
frestart(i) = restart_fh(i) * 3600. + restart_starttime
12261212
enddo
12271213
endif
12281214
endif

tests/test_fv3_cap.F90

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ program test_output_hours
33
use module_fv3_config, only: dt_atmos, output_fh
44
use module_fv3_io_def, only: lflname_fulltime
55

6+
! Test changelog:
7+
! 2025/07/29 - D. Sarmiento: output_fh changed. When first hour is not 0
8+
! (i.e. IAU), then output will now be created at the first
9+
! timestep. This is now aligns with the coldstart functionality.
10+
611
implicit none
712

813
! Test variables
@@ -73,8 +78,8 @@ subroutine test_frequency_input()
7378
stop 4
7479
end if
7580

76-
! First value (should be 6.0)
77-
if (abs(output_fh(1) - 6.0) > 1e-6) then
81+
! First value (should be 6.5)
82+
if (abs(output_fh(1) - (output_startfh + dt_atmos/3600.)) > 1e-6) then
7883
print *, "First output time is incorrect"
7984
stop 5
8085
end if

0 commit comments

Comments
 (0)