Skip to content

Commit a321883

Browse files
authored
Corrections for tipping bucket and nudging in very long simulations (#2063)
TYPE: bug fix KEYWORDS: precipitation, tipping bucket, nudging, spectral nudging, analysis nudging, grid nudging, regional climate, dynamical downscaling, downscaling SOURCE: Tanya Spero (U.S. EPA) DESCRIPTION OF CHANGES: Problem: Several processes in WRF are currently triggered at periodic intervals (such as reading/writing files and managing certain bookkeeping processes). Some of those processes had been coded to identify those time triggers by referencing a variable that contains the time elapsed since the model simulation was initialized. That variable, XTIME, is a Fortran single-precision real variable that counts the number of elapsed minutes since initialization. However, single-precision real numbers become imprecise (i.e., cannot accurately resolve "whole" numbers) after they exceed 2^24, which is 16,777,216. In long simulations, that occurs just before 32 years of simulation period. Solution: Two new variables are introduced based on existing variable CURR_SECS2: CURR_SECS2_R8, and double precision version of CURR_SECS2, to address bucket tipping and CURR_MINS2, based on CURR_SECS2_R8, to address issues in nudging code. LIST OF MODIFIED FILES: M phys/module_diag_misc.F M dyn_em/module_first_rk_step_part1.F M dyn_em/solve_em.F, M phys/module_fdda_psufddagd.F M phys/module_fdda_spnudging.F, M phys/module_fddagd_driver.F M wrftladj/wrftladj/solve_em_ad.F TESTS CONDUCTED: 1. Modified code has been tested extensively using a long simulation (using a restart at more than 31 years into the simulation) with WRFv4.5.1 and with shorter (3-day) simulations using WRFv4.6. 2. The Jenkins tests are all passing. RELEASE NOTE: Corrected algorithms in the tipping bucket for precipitation and in the nudging routines to adjust for imprecision in single-precision real numbers exceeding the resolvable values in long (>23-year) continuous simulations.
1 parent 5fc76c5 commit a321883

File tree

7 files changed

+69
-30
lines changed

7 files changed

+69
-30
lines changed

dyn_em/module_first_rk_step_part1.F

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ SUBROUTINE first_rk_step_part1 ( grid , config_flags &
1919
, ph_tendf, mu_tendf &
2020
, tke_tend &
2121
, adapt_step_flag , curr_secs &
22+
, curr_mins2 &
2223
, psim , psih , gz1oz0 , chklowq &
2324
, cu_act_flag , hol , th_phy &
2425
, pi_phy , p_phy , t_phy &
@@ -77,7 +78,7 @@ SUBROUTINE first_rk_step_part1 ( grid , config_flags &
7778

7879

7980
LOGICAL ,INTENT(IN) :: adapt_step_flag
80-
REAL, INTENT(IN) :: curr_secs
81+
REAL, INTENT(IN) :: curr_secs, curr_mins2
8182

8283
REAL ,DIMENSION(ims:ime,kms:kme,jms:jme,num_moist),INTENT(INOUT) :: moist
8384
REAL ,DIMENSION(ims:ime,kms:kme,jms:jme,num_moist),INTENT(INOUT) :: moist_tend
@@ -1770,7 +1771,7 @@ SUBROUTINE first_rk_step_part1 ( grid , config_flags &
17701771

17711772
BENCH_START(fdda_driver_tim)
17721773
CALL fddagd_driver(itimestep=grid%itimestep,dt=grid%dt,xtime=grid%XTIME, &
1773-
id=grid%id, &
1774+
curr_mins2=curr_mins2, id=grid%id, &
17741775
RUNDGDTEN=grid%rundgdten,RVNDGDTEN=grid%rvndgdten, &
17751776
RTHNDGDTEN=grid%rthndgdten,RPHNDGDTEN=grid%rphndgdten, &
17761777
RQVNDGDTEN=grid%rqvndgdten,RMUNDGDTEN=grid%rmundgdten, &

dyn_em/solve_em.F

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,8 @@ SUBROUTINE solve_em ( grid , config_flags &
183183
LOGICAL :: leapfrog
184184
INTEGER :: l,kte,kk
185185
LOGICAL :: f_flux ! flag for computing averaged fluxes in cu_gd
186-
REAL :: curr_secs, curr_secs2
186+
REAL :: curr_secs, curr_secs2, curr_mins2
187+
REAL(8) :: curr_secs_r8, curr_secs2_r8
187188
INTEGER :: num_sound_steps
188189
INTEGER :: idex, jdex
189190
REAL :: max_msft
@@ -198,6 +199,7 @@ SUBROUTINE solve_em ( grid , config_flags &
198199

199200
TYPE(WRFU_TimeInterval) :: tmpTimeInterval, tmpTimeInterval2
200201
REAL :: real_time
202+
REAL(8) :: real_time_r8
201203
LOGICAL :: adapt_step_flag
202204
LOGICAL :: fill_w_flag
203205

@@ -331,6 +333,9 @@ END SUBROUTINE CMAQ_DRIVER
331333
tmpTimeInterval2 = domain_get_current_time ( grid ) - domain_get_start_time ( grid )
332334
curr_secs = real_time(tmpTimeInterval)
333335
curr_secs2 = real_time(tmpTimeInterval2)
336+
curr_secs_r8 = real_time_r8(tmpTimeInterval)
337+
curr_secs2_r8 = real_time_r8(tmpTimeInterval2)
338+
curr_mins2 = REAL( curr_secs2_r8 / 60.0d0 )
334339

335340
old_dt = grid%dt ! store old time step for flux averaging code at end of RK loop
336341

@@ -811,7 +816,7 @@ END SUBROUTINE CMAQ_DRIVER
811816
, ph_tendf, mu_tendf &
812817
, tke_tend &
813818
, config_flags%use_adaptive_time_step &
814-
, curr_secs &
819+
, curr_secs, curr_mins2 &
815820
, psim , psih , gz1oz0 &
816821
, chklowq &
817822
, cu_act_flag , hol , th_phy &

phys/module_diag_misc.F

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,11 @@ SUBROUTINE diagnostic_output_calc( &
288288
!-----------------------------------------------------------------
289289
! Handle accumulations with buckets to prevent round-off truncation in long runs
290290
! This is done every 360 minutes assuming time step fits exactly into 360 minutes
291-
IF(bucket_mm .gt. 0. .AND. MOD(NINT(XTIME),360) .EQ. 0)THEN
291+
292+
!!!~~ CURR_SECS2 is elapsed seconds since restart. It is preferred to
293+
!!!~~ XTIME here because XTIME goes imprecise at 2^24, just under 32 years.
294+
295+
IF(bucket_mm .gt. 0. .AND. MOD(NINT(CURR_SECS2),3600) .EQ. 0)THEN
292296
! SET START AND END POINTS FOR TILES
293297
! !$OMP PARALLEL DO &
294298
! !$OMP PRIVATE ( ij )

phys/module_fdda_psufddagd.F

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,17 @@
99
! surfance reanalsys
1010
!Reference: Alapaty et al., 2008: Development of the flux-adjusting surface
1111
! data assimilation system for mesoscale models. JAMC, 47, 2331-2350
12-
12+
!
13+
! Changed logic for determining next nudging time to rely on minutes elapsed
14+
! since restart (CURR_MINS2) rather than on minutes since initialization
15+
! (XTIME). The REAL variable, XTIME, will become imprecise after 1 X 2^24
16+
! minutes (just under 32 years of continuous simulation). Cannot remove all
17+
! reliance on XTIME because actual end time is in absolute minutes. Using XTIME
18+
! results in spectral nudging analyses ingested at the wrong times, beginning
19+
! 23 years and 3.5 months into a continous simulation. Purposefully not
20+
! modifying the ramping function because pragmatically we will not get
21+
! very large XTIME values in any situation where the off-ramp for nudging would
22+
! be used. (Tanya Spero, U.S. Environmental Protection Agency -- June 2024)
1323
!
1424
!
1525
MODULE module_fdda_psufddagd
@@ -18,7 +28,7 @@ MODULE module_fdda_psufddagd
1828
!
1929
!-------------------------------------------------------------------
2030
!
21-
SUBROUTINE fddagd(itimestep,dx,dt,xtime, &
31+
SUBROUTINE fddagd(itimestep,dx,dt,xtime, curr_mins2, &
2232
id,analysis_interval, end_fdda_hour, &
2333
if_no_pbl_nudging_uv, if_no_pbl_nudging_t, if_no_pbl_nudging_q, &
2434
if_zfac_uv, k_zfac_uv, if_zfac_t, k_zfac_t, if_zfac_q, k_zfac_q, &
@@ -101,7 +111,7 @@ SUBROUTINE fddagd(itimestep,dx,dt,xtime, &
101111
INTEGER, INTENT(IN) :: if_ramping
102112

103113
INTEGER , INTENT(IN) :: id
104-
REAL, INTENT(IN) :: DT, dx, xtime, dtramp_min
114+
REAL, INTENT(IN) :: DT, dx, xtime, dtramp_min, curr_mins2
105115

106116
INTEGER, INTENT(IN) :: ids,ide, jds,jde, kds,kde, &
107117
ims,ime, jms,jme, kms,kme, &
@@ -243,10 +253,10 @@ SUBROUTINE fddagd(itimestep,dx,dt,xtime, &
243253
ENDIF
244254

245255
IF( analysis_interval <= 0 )CALL wrf_error_fatal('In grid FDDA, gfdda_interval_m must be > 0')
246-
xtime_old = FLOOR(xtime/analysis_interval) * analysis_interval * 1.0
256+
xtime_old = FLOOR(curr_mins2/analysis_interval) * analysis_interval * 1.0
247257
xtime_new = xtime_old + analysis_interval
248258
IF( int4 == 1 ) THEN
249-
coef = (xtime-xtime_old)/(xtime_new-xtime_old)
259+
coef = (curr_mins2-xtime_old)/(xtime_new-xtime_old)
250260
ELSE
251261
coef = 1.0 ! Nudging toward a target value (*_ndg_new values)
252262
ENDIF
@@ -255,7 +265,7 @@ SUBROUTINE fddagd(itimestep,dx,dt,xtime, &
255265

256266
CALL get_wrf_debug_level( dbg_level )
257267

258-
IF( xtime-xtime_old < 0.5*dt/60.0 ) THEN
268+
IF( curr_mins2-xtime_old < 0.5*dt/60.0 ) THEN
259269

260270
IF( xtime < end_fdda_hour*60.0 ) THEN
261271
WRITE(message,'(a,i1,a,f10.3,a)') &
@@ -578,7 +588,7 @@ SUBROUTINE fddagd(itimestep,dx,dt,xtime, &
578588
! Surface Analysis Nudging
579589
!
580590
IF( grid_sfdda >= 1 ) THEN
581-
CALL SFDDAGD(itimestep,dx,dt,xtime, id, &
591+
CALL SFDDAGD(itimestep,dx,dt,xtime, curr_mins2, id, &
582592
analysis_interval_sfc, end_fdda_hour_sfc, guv_sfc, gt_sfc, gq_sfc, &
583593
rinblw, &
584594
u3d,v3d,th3d,t3d, &
@@ -680,7 +690,7 @@ SUBROUTINE fddagd(itimestep,dx,dt,xtime, &
680690
END SUBROUTINE fddagd
681691

682692
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
683-
SUBROUTINE sfddagd(itimestep,dx,dt,xtime, &
693+
SUBROUTINE sfddagd(itimestep,dx,dt,xtime, curr_mins2, &
684694
id, analysis_interval_sfc, end_fdda_hour_sfc, &
685695
guv_sfc, gt_sfc, gq_sfc, rinblw, &
686696
u3d,v3d,th3d,t3d, &
@@ -758,7 +768,7 @@ SUBROUTINE sfddagd(itimestep,dx,dt,xtime, &
758768
INTEGER, INTENT(IN) :: itimestep, analysis_interval_sfc, end_fdda_hour_sfc
759769

760770
INTEGER , INTENT(IN) :: id
761-
REAL, INTENT(IN) :: dx,DT, xtime
771+
REAL, INTENT(IN) :: dx,DT, xtime, curr_mins2
762772

763773
INTEGER, INTENT(IN) :: ids,ide, jds,jde, kds,kde, &
764774
ims,ime, jms,jme, kms,kme, &
@@ -862,10 +872,10 @@ SUBROUTINE sfddagd(itimestep,dx,dt,xtime, &
862872
int4 = 1 ! 1: temporal ionterpolation. else: target nudging toward *_ndg_new values
863873

864874
IF( analysis_interval_sfc <= 0 )CALL wrf_error_fatal('In grid sfc FDDA, sgfdda_interval_m must be > 0')
865-
xtime_old_sfc = FLOOR(xtime/analysis_interval_sfc) * analysis_interval_sfc * 1.0
875+
xtime_old_sfc = FLOOR(curr_mins2/analysis_interval_sfc) * analysis_interval_sfc * 1.0
866876
xtime_new_sfc = xtime_old_sfc + analysis_interval_sfc
867877
IF( int4 == 1 ) THEN
868-
coef = (xtime-xtime_old_sfc)/(xtime_new_sfc-xtime_old_sfc) ! Temporal interpolation
878+
coef = (curr_mins2-xtime_old_sfc)/(xtime_new_sfc-xtime_old_sfc) ! Temporal interpolation
869879
ELSE
870880
coef = 1.0 ! Nudging toward a target value (*_ndg_new values)
871881
ENDIF
@@ -874,7 +884,7 @@ SUBROUTINE sfddagd(itimestep,dx,dt,xtime, &
874884

875885
CALL get_wrf_debug_level( dbg_level )
876886

877-
IF( xtime-xtime_old_sfc < 0.5*dt/60.0 ) THEN
887+
IF( curr_mins2-xtime_old_sfc < 0.5*dt/60.0 ) THEN
878888

879889
IF( xtime < end_fdda_hour_sfc*60.0 ) THEN
880890
WRITE(message,'(a,i1,a,f10.3,a)') &

phys/module_fdda_spnudging.F

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@
55
! Added capability to spectrally nudge water vapor mixing ratio, and added
66
! user-definable lid for nudging potential temperature and water vapor mixing
77
! ratio. (Tanya Spero, U.S. Environmental Protection Agency -- October 2017)
8+
!
9+
! Changed logic for determining next nudging time to rely on minutes elapsed
10+
! since restart (CURR_MINS2) rather than on minutes since initialization
11+
! (XTIME). The REAL variable, XTIME, will become imprecise after 1 X 2^24
12+
! minutes (just under 32 years of continuous simulation). Cannot remove all
13+
! reliance on XTIME because actual end time is in absolute minutes. Using XTIME
14+
! results in spectral nudging analyses ingested at the wrong times, beginning
15+
! 23 years and 3.5 months into a continous simulation. Purposefully not
16+
! modifying the ramping function because pragmatically we will not get
17+
! very large XTIME values in any situation where the off-ramp for nudging would
18+
! be used. (Tanya Spero, U.S. Environmental Protection Agency -- June 2024)
819

920
MODULE module_fdda_spnudging
1021

@@ -17,7 +28,8 @@ MODULE module_fdda_spnudging
1728
!
1829
!-------------------------------------------------------------------
1930
!
20-
SUBROUTINE spectral_nudging(grid,itimestep,dt,xtime,id,analysis_interval, end_fdda_hour, &
31+
SUBROUTINE spectral_nudging(grid,itimestep,dt,xtime,curr_mins2, &
32+
id,analysis_interval, end_fdda_hour, &
2133
if_no_pbl_nudging_uv, if_no_pbl_nudging_t, if_no_pbl_nudging_ph,if_no_pbl_nudging_q,&
2234
if_zfac_uv, k_zfac_uv, dk_zfac_uv, &
2335
if_zfac_t, k_zfac_t, dk_zfac_t, &
@@ -95,7 +107,7 @@ SUBROUTINE spectral_nudging(grid,itimestep,dt,xtime,id,analysis_interval, end_fd
95107
INTEGER, INTENT(IN) :: xwavenum,ywavenum
96108

97109
INTEGER , INTENT(IN) :: id
98-
REAL, INTENT(IN) :: DT, xtime, dtramp_min
110+
REAL, INTENT(IN) :: DT, xtime, dtramp_min, curr_mins2
99111

100112
INTEGER, INTENT(IN) :: ids,ide, jds,jde, kds,kde, &
101113
ims,ime, jms,jme, kms,kme, &
@@ -202,15 +214,15 @@ SUBROUTINE spectral_nudging(grid,itimestep,dt,xtime,id,analysis_interval, end_fd
202214
! IF( if_ramping == 1 .AND. dtramp_min > 0.0 ) &
203215
! actual_end_fdda_min = end_fdda_hour*60.0 + ABS(dtramp_min)
204216

205-
xtime_old = FLOOR(xtime/analysis_interval) * analysis_interval * 1.0
217+
xtime_old = FLOOR(curr_mins2/analysis_interval) * analysis_interval * 1.0
206218
xtime_new = xtime_old + analysis_interval
207-
coef = (xtime-xtime_old)/(xtime_new-xtime_old)
219+
coef = (curr_mins2-xtime_old)/(xtime_new-xtime_old)
208220

209221
IF ( wrf_dm_on_monitor()) THEN
210222

211223
CALL get_wrf_debug_level( dbg_level )
212224

213-
IF( xtime-xtime_old < 0.5*dt/60.0 ) THEN
225+
IF( curr_mins2-xtime_old < 0.5*dt/60.0 ) THEN
214226

215227
IF( xtime < end_fdda_hour*60.0 ) THEN
216228
WRITE(wrf_err_message,FMT='(a,i2.2,a,f15.3,a)') &
@@ -549,7 +561,7 @@ SUBROUTINE spectral_nudging(grid,itimestep,dt,xtime,id,analysis_interval, end_fd
549561
tfac = 1.0
550562
ELSEIF( xtime >= actual_end_fdda_min-ABS(dtramp_min) .AND. xtime <= actual_end_fdda_min )THEN
551563
tfac = ( actual_end_fdda_min - xtime ) / ABS(dtramp_min)
552-
IF( dtramp_min > 0.0 ) coef = (xtime-xtime_old+analysis_interval)/analysis_interval
564+
IF( dtramp_min > 0.0 ) coef = (curr_mins2-xtime_old+analysis_interval)/analysis_interval
553565
ELSE
554566
tfac = 0.0
555567
ENDIF

phys/module_fddagd_driver.F

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ MODULE module_fddagd_driver
66

77
!------------------------------------------------------------------
88
SUBROUTINE fddagd_driver(itimestep,dt,xtime, &
9-
id, &
9+
curr_mins2, id, &
1010
RUNDGDTEN,RVNDGDTEN,RTHNDGDTEN, &
1111
RPHNDGDTEN,RQVNDGDTEN,RMUNDGDTEN, &
1212
SDA_HFX, SDA_QFX, & !fasdas
@@ -143,7 +143,7 @@ SUBROUTINE fddagd_driver(itimestep,dt,xtime, &
143143

144144
INTEGER, INTENT(IN ) :: itimestep,STEPFG
145145
!
146-
REAL, INTENT(IN ) :: DT,DX,XTIME
146+
REAL, INTENT(IN ) :: DT,DX,XTIME, curr_mins2
147147

148148

149149
!
@@ -521,7 +521,7 @@ SUBROUTINE fddagd_driver(itimestep,dt,xtime, &
521521
ENDIF
522522

523523
CALL FDDAGD(itimestep,dx,dt,xtime, &
524-
id, &
524+
curr_mins2, id, &
525525
config_flags%auxinput10_interval_m, &
526526
config_flags%auxinput10_end_h, &
527527
config_flags%if_no_pbl_nudging_uv, &
@@ -570,7 +570,7 @@ SUBROUTINE fddagd_driver(itimestep,dt,xtime, &
570570
CASE (SPNUDGING)
571571
CALL wrf_debug(100,'in SPECTRAL NUDGING scheme')
572572
CALL SPECTRAL_NUDGING(grid,itimestep,dt,xtime, &
573-
id, &
573+
curr_mins2, id, &
574574
config_flags%auxinput10_interval_m, &
575575
config_flags%auxinput10_end_h, &
576576
config_flags%if_no_pbl_nudging_uv, &

wrftladj/solve_em_ad.F

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ SUBROUTINE solve_em_ad ( grid , config_flags &
178178
LOGICAL :: leapfrog
179179
INTEGER :: l,kte,kk
180180
LOGICAL :: f_flux ! flag for computing averaged fluxes in cu_gd
181-
REAL :: curr_secs
181+
REAL :: curr_secs, curr_secs2, curr_mins2
182+
REAL(8) :: curr_secs_r8, curr_secs2_r8
182183
INTEGER :: num_sound_steps
183184
INTEGER :: idex, jdex
184185
REAL :: max_msft
@@ -191,8 +192,9 @@ SUBROUTINE solve_em_ad ( grid , config_flags &
191192
! urban related variables
192193
INTEGER :: NUM_ROOF_LAYERS, NUM_WALL_LAYERS, NUM_ROAD_LAYERS ! urban
193194

194-
TYPE(WRFU_TimeInterval) :: tmpTimeInterval
195+
TYPE(WRFU_TimeInterval) :: tmpTimeInterval, tmpTimeInterval2
195196
REAL :: real_time
197+
REAL(8) :: real_time_r8
196198
LOGICAL :: adapt_step_flag
197199
LOGICAL :: fill_w_flag
198200

@@ -299,7 +301,12 @@ SUBROUTINE solve_em_ad ( grid , config_flags &
299301
! calculate it here--but, this is not clean!!
300302
!
301303
tmpTimeInterval = domain_get_current_time ( grid ) - domain_get_sim_start_time ( grid )
304+
tmpTimeInterval2 = domain_get_current_time ( grid ) - domain_get_start_time ( grid )
302305
curr_secs = real_time(tmpTimeInterval)
306+
curr_secs2 = real_time(tmpTimeInterval2)
307+
curr_secs_r8 = real_time_r8(tmpTimeInterval)
308+
curr_secs2_r8 = real_time_r8(tmpTimeInterval2)
309+
curr_mins2 = REAL( curr_secs2_r8 / 60.0d0 )
303310
304311
old_dt = grid%dt ! store old time step for flux averaging code at end of RK loop
305312
!-----------------------------------------------------------------------------
@@ -672,7 +679,7 @@ SUBROUTINE solve_em_ad ( grid , config_flags &
672679
, ph_tendf, mu_tendf &
673680
, tke_tend &
674681
, config_flags%use_adaptive_time_step &
675-
, curr_secs &
682+
, curr_secs, curr_mins2 &
676683
, psim , psih , gz1oz0 &
677684
, chklowq &
678685
, cu_act_flag , hol , th_phy &

0 commit comments

Comments
 (0)