@@ -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+
8084end type stochastic_CS
8185
8286contains
8387
84- ! ! This subroutine initializes the stochastics physics control structure.
88+ ! > This subroutine initializes the stochastics physics control structure.
8589subroutine 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
265286end 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
272289subroutine 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
281298end subroutine update_stochastics
282299
300+ ! > Adds a stochastic increment (backscatter) to the input velocity field
283301subroutine 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
511517end 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>.
513547end module MOM_stochastics
514-
0 commit comments