Skip to content

Commit 83cd133

Browse files
authored
Stochastic GM+E efficiency & docs (#378)
This PR does two things It pre-calculates some coefficients in the stochastic GM+E parameterization, which reduces computational cost. This will change answers when stochastic GM+E is in use, but only due to roundoff. It adds docs to the MOM_stochastics module. Originally this was aimed at Bob's fork, to go in with his PR #367 (see comment). Since that PR has been merged, I'm re-directing this PR directly to dev/ncar.
1 parent 52bdeec commit 83cd133

1 file changed

Lines changed: 62 additions & 29 deletions

File tree

src/parameterizations/stochastic/MOM_stochastics.F90

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ module MOM_stochastics
6565
real, allocatable :: sppt_wts(:,:) !< Random pattern for ocean SPPT
6666
!! tendencies with a number between 0 and 2 [nondim]
6767
real, allocatable :: skeb_wts(:,:) !< Random pattern of lengthscales for ocean SKEB in mks units [m]
68-
! Note that SKEB_wts is set via external code in mks units.
68+
!! Note that SKEB_wts is set via external code in mks units.
6969
real, allocatable :: epbl1_wts(:,:) !< Random pattern for K.E. generation [nondim]
7070
real, allocatable :: epbl2_wts(:,:) !< Random pattern for K.E. dissipation [nondim]
7171
type(time_type), pointer :: Time !< Pointer to model time (needed for sponges)
@@ -77,11 +77,15 @@ module MOM_stochastics
7777
real, allocatable :: taperCv(:,:) !< Taper applied to v component of stochastic
7878
!! velocity increment range [0,1], [nondim]
7979

80+
! Weights for smoothing skeb_diss
81+
real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: Isum_area_wts, & !< One over the 3x3 sum of area_wt [L-2 ~> m-2]
82+
area_wt !< Masked h cell areas. [L2 ~> m2]
83+
8084
end type stochastic_CS
8185

8286
contains
8387

84-
!! This subroutine initializes the stochastics physics control structure.
88+
!> This subroutine initializes the stochastics physics control structure.
8589
subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time)
8690
real, intent(in) :: dt !< time step [T ~> s]
8791
type(ocean_grid_type), intent(in) :: grid !< horizontal grid information
@@ -102,9 +106,11 @@ subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time)
102106
integer :: nyT, nyB ! number of y-points including halo
103107
integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags.
104108
integer :: i, j, k ! loop indices
105-
real :: tmp(grid%isdB:grid%iedB,grid%jsdB:grid%jedB) ! Used to construct tapers
109+
real :: tmp(grid%isdB:grid%iedB,grid%jsdB:grid%jedB) ! Used to construct tapers and weights
106110
integer :: taper_width ! Width (in cells) of the taper that brings the stochastic velocity
107111
! increments to 0 at the boundary.
112+
real :: sum_area_wts ! A rotationally symmetric sum of the surrounding area weights
113+
! that are used to filter skeb_diss [L2 ~> m2]
108114

109115
! This include declares and sets the variable "version".
110116
# include "version_variable.h"
@@ -257,18 +263,29 @@ subroutine stochastics_init(dt, grid, GV, US, CS, param_file, diag, Time)
257263
if (CS%id_skeb_taperu > 0) call post_data(CS%id_skeb_taperu, CS%taperCu, CS%diag, .true.)
258264
if (CS%id_skeb_taperv > 0) call post_data(CS%id_skeb_taperv, CS%taperCv, CS%diag, .true.)
259265

266+
! Initialize the smoothing weights
267+
if ((CS%do_skeb) .and. CS%skeb_npass >= 1) then
268+
ALLOC_(CS%area_wt(grid%isd:grid%ied,grid%jsd:grid%jed)) ; CS%area_wt(:,:) = 0.0
269+
ALLOC_(CS%Isum_area_wts(grid%isd:grid%ied,grid%jsd:grid%jed)) ; CS%Isum_area_wts(:,:) = 0.0
270+
do j=grid%jsc-2,grid%jec+2 ; do i=grid%isc-2,grid%iec+2
271+
CS%area_wt(i,j) = grid%mask2dT(i,j)*grid%areaT(i,j)
272+
enddo ; enddo
273+
do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1
274+
sum_area_wts = CS%area_wt(i,j) + &
275+
(((CS%area_wt(i-1,j) + CS%area_wt(i+1,j)) + (CS%area_wt(i,j-1) + CS%area_wt(i,j+1))) + &
276+
((CS%area_wt(i-1,j-1) + CS%area_wt(i+1,j+1)) + (CS%area_wt(i-1,j+1) + CS%area_wt(i+1,j-1))))
277+
CS%Isum_area_wts(i,j) = 1.0 / (sum_area_wts + 1.e-16*US%m_to_L**2)
278+
enddo ; enddo
279+
endif
280+
260281
if (CS%do_sppt .OR. CS%pert_epbl .OR. CS%do_skeb) &
261282
call MOM_mesg(' === COMPLETED MOM STOCHASTIC INITIALIZATION =====')
262283

263284
call callTree_leave("stochastic_init(), MOM_stochastics.F90")
264285

265286
end subroutine stochastics_init
266287

267-
!> update_ocean_model uses the forcing in Ice_ocean_boundary to advance the
268-
!! ocean model's state from the input value of Ocean_state (which must be for
269-
!! time time_start_update) for a time interval of Ocean_coupling_time_step,
270-
!! returning the publicly visible ocean surface properties in Ocean_sfc and
271-
!! storing the new ocean properties in Ocean_state.
288+
!> Advances the stochastic patterns one time step
272289
subroutine update_stochastics(CS)
273290
type(stochastic_CS), intent(inout) :: CS !< diabatic control structure
274291
call callTree_enter("update_stochastics(), MOM_stochastics.F90")
@@ -280,6 +297,7 @@ subroutine update_stochastics(CS)
280297

281298
end subroutine update_stochastics
282299

300+
!> Adds a stochastic increment (backscatter) to the input velocity field
283301
subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end)
284302

285303
type(ocean_grid_type), intent(in) :: grid !< ocean grid structure
@@ -300,7 +318,6 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end)
300318
real, dimension(SZI_(grid) ,SZJB_(grid),SZK_(GV)) :: vstar !< Stochastic v velocity increment [L T-1 ~> m s-1]
301319
real, dimension(SZI_(grid),SZJ_(grid)) :: diss_tmp !< Temporary array used in smoothing skeb_diss
302320
!! [L2 T-3 ~> m2 s-2]
303-
real, dimension(SZI_(grid),SZJ_(grid)) :: area_wt !< Masked cell areas used in spatial filter [L2 ~> m2]
304321
real, dimension(3,3) :: local_weights !< 3x3 stencil weights used in smoothing skeb_diss
305322
!! [L2 ~> m2]
306323

@@ -310,8 +327,6 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end)
310327
real :: kh ! A smooothing factor [nondim]
311328
real :: sum_wtd_skeb_diss ! The rotationally symmetric sum of the surrounding values of skeb times
312329
! the area weights used to filter skeb_diss [L4 T-3 ~> m4 s-3]
313-
real :: sum_area_wts ! A rotationally symmetric sum of the surrounding area weights
314-
! that are used to filter skeb_diss [L2 ~> m2]
315330
integer :: i, j, k, iter
316331
integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
317332

@@ -358,36 +373,27 @@ subroutine apply_skeb(grid, GV, US, CS, uc, vc, thickness, tv, dt, Time_end)
358373
endif
359374
endif ! Sets CS%skeb_diss in [L2 T-3 ~> m2 s-3] without GM or FrictWork
360375

361-
if (CS%skeb_npass >= 1) then
362-
do j=grid%jsc-2,grid%jec+2 ; do i=grid%isc-2,grid%iec+2
363-
area_wt(i,j) = grid%mask2dT(i,j)*grid%areaT(i,j)
364-
enddo ; enddo
365-
endif
366-
367376
! smooth dissipation skeb_npass times
368377
do iter=1,CS%skeb_npass
369378
if (mod(iter,2) == 1) call pass_var(CS%skeb_diss, grid%domain)
370379
do k=1,GV%ke
371380
if (CS%answer_date < 20250701) then
372381
! Do the filter with expressions that do not preserve rotational symmetry.
373382
do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1
374-
local_weights(:,:) = area_wt(i-1:i+1,j-1:j+1)
383+
local_weights(:,:) = CS%area_wt(i-1:i+1,j-1:j+1)
375384
diss_tmp(i,j) = sum(local_weights(:,:)*CS%skeb_diss(i-1:i+1,j-1:j+1,k)) / &
376385
(sum(local_weights) + 1.e-16*US%m_to_L**2)
377386
enddo ; enddo
378387
else
379388
! This spatial filter preserves rotational symmeetry (including with FMAs), but is
380389
! mathematically equivalent to the older sum-based form above
381390
do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1
382-
sum_area_wts = area_wt(i,j) + &
383-
(((area_wt(i-1,j) + area_wt(i+1,j)) + (area_wt(i,j-1) + area_wt(i,j+1))) + &
384-
((area_wt(i-1,j-1) + area_wt(i+1,j+1)) + (area_wt(i-1,j+1) + area_wt(i+1,j-1))))
385-
sum_wtd_skeb_diss = CS%skeb_diss(i,j,k) * area_wt(i+1,j) + &
386-
((( (CS%skeb_diss(i-1,j,k) * area_wt(i-1,j)) + (CS%skeb_diss(i+1,j,k) * area_wt(i+1,j)) ) + &
387-
( (CS%skeb_diss(i,j-1,k) * area_wt(i,j-1)) + (CS%skeb_diss(i,j+1,k) * area_wt(i,j+1)) )) + &
388-
(( (CS%skeb_diss(i-1,j-1,k) * area_wt(i-1,j-1)) + (CS%skeb_diss(i-1,j-1,k) * area_wt(i+1,j+1)) ) + &
389-
( (CS%skeb_diss(i-1,j+1,k) * area_wt(i-1,j+1)) + (CS%skeb_diss(i+1,j-1,k) * area_wt(i+1,j-1)) )))
390-
diss_tmp(i,j) = sum_wtd_skeb_diss / (sum_area_wts + 1.e-16*US%m_to_L**2)
391+
sum_wtd_skeb_diss = CS%skeb_diss(i,j,k) * CS%area_wt(i+1,j) + &
392+
((( (CS%skeb_diss(i-1,j,k) * CS%area_wt(i-1,j)) + (CS%skeb_diss(i+1,j,k) * CS%area_wt(i+1,j)) ) + &
393+
( (CS%skeb_diss(i,j-1,k) * CS%area_wt(i,j-1)) + (CS%skeb_diss(i,j+1,k) * CS%area_wt(i,j+1)) )) + &
394+
(( (CS%skeb_diss(i-1,j-1,k) * CS%area_wt(i-1,j-1)) + (CS%skeb_diss(i-1,j-1,k) * CS%area_wt(i+1,j+1)) ) + &
395+
( (CS%skeb_diss(i-1,j+1,k) * CS%area_wt(i-1,j+1)) + (CS%skeb_diss(i+1,j-1,k) * CS%area_wt(i+1,j-1)) )))
396+
diss_tmp(i,j) = sum_wtd_skeb_diss * CS%Isum_area_wts(i,j)
391397
enddo ; enddo
392398
endif
393399
do j=grid%jsc-1,grid%jec+1 ; do i=grid%isc-1,grid%iec+1
@@ -509,6 +515,33 @@ subroutine smooth_x9_uv(G, field_u, field_v, zero_land)
509515
enddo
510516

511517
end subroutine smooth_x9_uv
512-
518+
!> \namespace mom_stochastics
519+
!!
520+
!! This file contains subroutines that implement some stochastic parameterizations in MOM6.
521+
!! SPPT perturbations of the tendencies of S and T are turned on using <code>DO_SPPT=True</code>.
522+
!! Stochastic perturbations in ePBL are turned on using <code>PERT_EPBL=True</code>.
523+
!! Stochastic kinetic energy backscatter (SKEB) via the Stochastic GM+E scheme is turned on using
524+
!! <code>DO_SKEB=True</code>. For all three schemes the spatial and temporal correlation structure
525+
!! of the associated random fields is controlled from the <code>nam_stochy</code> namelist used by
526+
!! the external <code>stochastic_physics</code> package, which is called by subroutines in this
527+
!! module.
528+
!!
529+
!! The SKEB backscatter can be set in a variety of ways. If <code>SKEB_USE_GM=True</code> then
530+
!! <code>SKEB_GM_COEF</code> times the GM work rate will be added to the backscatter rate. (The
531+
!! vertical structure for this component of backscatter is the so-called EBT struct.) If
532+
!! <code>SKEB_USE_FRICT=True</code> then <code>SKEB_FRICT_COEF</code> times the work rate from
533+
!! lateral viscosity will be added to the backscatter rate. The code uses the total contribution
534+
!! from Laplacian and biharmonic viscosities as computed within the horizontal viscosity module.
535+
!! If neither <code>SKEB_USE_GM</code> nor <code>SKEB_USE_FRICT</code> is true, then the code
536+
!! computes the dissipation rate as if it came from a lateral harmonic viscosity with
537+
!! coefficient 1 (MKS units). The only thoroughly tested SKEB option at this point is
538+
!! <code>SKEB_USE_GM</code>.
539+
!!
540+
!! The contributions to the backscatter rate are smoothed before use. One smoothing pass uses a
541+
!! 3x3 moving average with weights proportional to the h-cell areas. The number of smoothing passes
542+
!! is controlled by <code>SKEB_NPASS</code>.
543+
!!
544+
!! A taper is applied to the SKEB velocity increments (equivalently to the SKEB stochastic forcing).
545+
!! The taper zeros out the increments near land cells. The width of this taper can be controlled using
546+
!! <code>SKEB_TAPER_WIDTH</code>.
513547
end module MOM_stochastics
514-

0 commit comments

Comments
 (0)