Skip to content

Commit

Permalink
Stochastic GM+E (NCAR#280)
Browse files Browse the repository at this point in the history
* SKEB+GM

This commit adds a Stochastic Kinetic Energy Backscatter Scheme (SKEBS)
where the amplitude of the backscatter is based on either the GM
work rate and/or the viscous work rate (FrictWork). Each of these
can be multiplied by a coefficient so that, e.g. the backscatter rate
could be 50% of the GM work rate plus 20% of the viscous work rate.
The vertical structure of the backscatter rate associated with GM has
vertical structure given by the EBT profile. This code was developed
starting from Phil Pegion's branch, and it builds on the stochastic
physics package (external) developed by Phil Pegion, Niraj Agarwal,
and collaborators. This package allows the length and time scales
of the backscatter to be set via namelist parameters. This commit
may break the stochastic EPBL and SPPT schemes developed by P.
Pegion.

* Fix merge

* Whitespace
  • Loading branch information
iangrooms authored Jul 2, 2024
1 parent 2b1201a commit 6ad1530
Show file tree
Hide file tree
Showing 8 changed files with 453 additions and 67 deletions.
11 changes: 9 additions & 2 deletions config_src/external/stochastic_physics/stochastic_physics.F90
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module stochastic_physics

!> Initializes the stochastic physics perturbations.
subroutine init_stochastic_physics_ocn(delt, geoLonT, geoLatT, nx, ny, nz, pert_epbl_in, do_sppt_in, &
mpiroot, mpicomm, iret)
do_skeb_in,mpiroot, mpicomm, iret)
real, intent(in) :: delt !< timestep in seconds between calls to run_stochastic_physics_ocn [s]
integer, intent(in) :: nx !< number of gridpoints in the x-direction of the compute grid
integer, intent(in) :: ny !< number of gridpoints in the y-direction of the compute grid
Expand All @@ -25,6 +25,7 @@ subroutine init_stochastic_physics_ocn(delt, geoLonT, geoLatT, nx, ny, nz, pert_
real, intent(in) :: geoLatT(nx,ny) !< Latitude in degrees
logical, intent(in) :: pert_epbl_in !< logical flag, if true generate random pattern for ePBL perturbations
logical, intent(in) :: do_sppt_in !< logical flag, if true generate random pattern for SPPT perturbations
logical, intent(in) :: do_skeb_in !< logical flag, if true generate random pattern for SKEB perturbations
integer, intent(in) :: mpiroot !< root processor
integer, intent(in) :: mpicomm !< mpi communicator
integer, intent(out) :: iret !< return code
Expand All @@ -38,14 +39,20 @@ subroutine init_stochastic_physics_ocn(delt, geoLonT, geoLatT, nx, ny, nz, pert_
call MOM_error(WARNING, 'init_stochastic_physics_ocn: do_sppt needs to be false if using the stub')
iret=-1
endif
if (do_skeb_in) then
call MOM_error(WARNING, 'init_stochastic_physics_ocn: do_skeb needs to be false if using the stub')
iret=-1
endif

! This stub function does not actually do anything.
return
end subroutine init_stochastic_physics_ocn


!> Determines the stochastic physics perturbations.
subroutine run_stochastic_physics_ocn(sppt_wts, t_rp1, t_rp2)
subroutine run_stochastic_physics_ocn(sppt_wts, skeb_wts, t_rp1, t_rp2)
real, intent(inout) :: sppt_wts(:,:) !< array containing random weights for SPPT range [0,2]
real, intent(inout) :: skeb_wts(:,:) !< array containing random weights for SKEB
real, intent(inout) :: t_rp1(:,:) !< array containing random weights for ePBL
!! perturbations (KE generation) range [0,2]
real, intent(inout) :: t_rp2(:,:) !< array containing random weights for ePBL
Expand Down
22 changes: 15 additions & 7 deletions src/core/MOM.F90
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ module MOM
use MOM_diabatic_driver, only : diabatic, diabatic_driver_init, diabatic_CS, extract_diabatic_member
use MOM_diabatic_driver, only : adiabatic, adiabatic_driver_init, diabatic_driver_end
use MOM_diabatic_driver, only : register_diabatic_restarts
use MOM_stochastics, only : stochastics_init, update_stochastics, stochastic_CS
use MOM_stochastics, only : stochastics_init, update_stochastics, stochastic_CS, apply_skeb
use MOM_diagnostics, only : calculate_diagnostic_fields, MOM_diagnostics_init
use MOM_diagnostics, only : register_transport_diags, post_transport_diagnostics
use MOM_diagnostics, only : register_surface_diags, write_static_fields
Expand Down Expand Up @@ -741,7 +741,8 @@ subroutine step_MOM(forces_in, fluxes_in, sfc_state, Time_start, time_int_in, CS
endif
endif
! advance the random pattern if stochastic physics is active
if (CS%stoch_CS%do_sppt .OR. CS%stoch_CS%pert_epbl) call update_stochastics(CS%stoch_CS)
if (CS%stoch_CS%do_sppt .OR. CS%stoch_CS%pert_epbl .OR. CS%stoch_CS%do_skeb) &
call update_stochastics(CS%stoch_CS)

if (do_dyn) then
if (nonblocking_p_surf_update) &
Expand Down Expand Up @@ -1151,7 +1152,8 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_thermo, &
if (CS%VarMix%use_variable_mixing) &
call calc_slope_functions(h, CS%tv, dt, G, GV, US, CS%VarMix, OBC=CS%OBC)
call thickness_diffuse(h, CS%uhtr, CS%vhtr, CS%tv, dt_thermo, G, GV, US, &
CS%MEKE, CS%VarMix, CS%CDp, CS%thickness_diffuse_CSp)
CS%MEKE, CS%VarMix, CS%CDp, CS%thickness_diffuse_CSp, &
CS%stoch_CS)
call cpu_clock_end(id_clock_thick_diff)
call pass_var(h, G%Domain, clock=id_clock_pass, halo=max(2,CS%cont_stencil))
if (showCallTree) call callTree_waypoint("finished thickness_diffuse_first (step_MOM)")
Expand Down Expand Up @@ -1223,7 +1225,7 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_thermo, &
call step_MOM_dyn_split_RK2(u, v, h, CS%tv, CS%visc, Time_local, dt, forces, &
p_surf_begin, p_surf_end, CS%uh, CS%vh, CS%uhtr, CS%vhtr, &
CS%eta_av_bc, G, GV, US, CS%dyn_split_RK2_CSp, calc_dtbt, CS%VarMix, &
CS%MEKE, CS%thickness_diffuse_CSp, CS%pbv, waves=waves)
CS%MEKE, CS%thickness_diffuse_CSp, CS%pbv, CS%stoch_CS, waves=waves)
if (showCallTree) call callTree_waypoint("finished step_MOM_dyn_split (step_MOM)")

elseif (CS%do_dynamics) then ! ------------------------------------ not SPLIT
Expand All @@ -1237,11 +1239,13 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_thermo, &
if (CS%use_RK2) then
call step_MOM_dyn_unsplit_RK2(u, v, h, CS%tv, CS%visc, Time_local, dt, forces, &
p_surf_begin, p_surf_end, CS%uh, CS%vh, CS%uhtr, CS%vhtr, &
CS%eta_av_bc, G, GV, US, CS%dyn_unsplit_RK2_CSp, CS%VarMix, CS%MEKE, CS%pbv)
CS%eta_av_bc, G, GV, US, CS%dyn_unsplit_RK2_CSp, CS%VarMix, CS%MEKE, CS%pbv, &
CS%stoch_CS)
else
call step_MOM_dyn_unsplit(u, v, h, CS%tv, CS%visc, Time_local, dt, forces, &
p_surf_begin, p_surf_end, CS%uh, CS%vh, CS%uhtr, CS%vhtr, &
CS%eta_av_bc, G, GV, US, CS%dyn_unsplit_CSp, CS%VarMix, CS%MEKE, CS%pbv, Waves=Waves)
CS%eta_av_bc, G, GV, US, CS%dyn_unsplit_CSp, CS%VarMix, CS%MEKE, CS%pbv, &
CS%stoch_CS, Waves=Waves)
endif
if (showCallTree) call callTree_waypoint("finished step_MOM_dyn_unsplit (step_MOM)")

Expand Down Expand Up @@ -1282,7 +1286,7 @@ subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_thermo, &
if (CS%VarMix%use_variable_mixing) &
call calc_slope_functions(h, CS%tv, dt, G, GV, US, CS%VarMix, OBC=CS%OBC)
call thickness_diffuse(h, CS%uhtr, CS%vhtr, CS%tv, dt, G, GV, US, &
CS%MEKE, CS%VarMix, CS%CDp, CS%thickness_diffuse_CSp)
CS%MEKE, CS%VarMix, CS%CDp, CS%thickness_diffuse_CSp, CS%stoch_CS)

if (CS%debug) call hchksum(h,"Post-thickness_diffuse h", G%HI, haloshift=1, scale=GV%H_to_MKS)
call cpu_clock_end(id_clock_thick_diff)
Expand Down Expand Up @@ -1584,6 +1588,10 @@ subroutine step_MOM_thermo(CS, G, GV, US, u, v, h, tv, fluxes, dtdia, &
Time_end_thermo, G, GV, US, CS%diabatic_CSp, CS%stoch_CS, CS%OBC, Waves)
fluxes%fluxes_used = .true.

if (CS%stoch_CS%do_skeb) then
call apply_skeb(CS%G,CS%GV,CS%stoch_CS,CS%u,CS%v,CS%h,CS%tv,dtdia,Time_end_thermo)
endif

if (showCallTree) call callTree_waypoint("finished diabatic (step_MOM_thermo)")

! Regridding/remapping is done here, at end of thermodynamics time step
Expand Down
6 changes: 4 additions & 2 deletions src/core/MOM_dynamics_split_RK2.F90
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ module MOM_dynamics_split_RK2
use MOM_PressureForce, only : PressureForce, PressureForce_CS
use MOM_PressureForce, only : PressureForce_init
use MOM_set_visc, only : set_viscous_ML, set_visc_CS
use MOM_stochastics, only : stochastic_CS
use MOM_thickness_diffuse, only : thickness_diffuse_CS
use MOM_self_attr_load, only : SAL_CS
use MOM_self_attr_load, only : SAL_init, SAL_end
Expand Down Expand Up @@ -286,7 +287,7 @@ module MOM_dynamics_split_RK2
!> RK2 splitting for time stepping MOM adiabatic dynamics
subroutine step_MOM_dyn_split_RK2(u, v, h, tv, visc, Time_local, dt, forces, p_surf_begin, p_surf_end, &
uh, vh, uhtr, vhtr, eta_av, G, GV, US, CS, calc_dtbt, VarMix, &
MEKE, thickness_diffuse_CSp, pbv, Waves)
MEKE, thickness_diffuse_CSp, pbv, STOCH, Waves)
type(ocean_grid_type), intent(inout) :: G !< Ocean grid structure
type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
Expand Down Expand Up @@ -326,6 +327,7 @@ subroutine step_MOM_dyn_split_RK2(u, v, h, tv, visc, Time_local, dt, forces, p_s
type(thickness_diffuse_CS), intent(inout) :: thickness_diffuse_CSp !< Pointer to a structure containing
!! interface height diffusivities
type(porous_barrier_type), intent(in) :: pbv !< porous barrier fractional cell metrics
type(stochastic_CS), intent(inout) :: STOCH !< Stochastic control structure
type(wave_parameters_CS), optional, pointer :: Waves !< A pointer to a structure containing
!! fields related to the surface wave conditions

Expand Down Expand Up @@ -851,7 +853,7 @@ subroutine step_MOM_dyn_split_RK2(u, v, h, tv, visc, Time_local, dt, forces, p_s
call horizontal_viscosity(u_av, v_av, h_av, CS%diffu, CS%diffv, &
MEKE, Varmix, G, GV, US, CS%hor_visc, &
OBC=CS%OBC, BT=CS%barotropic_CSp, TD=thickness_diffuse_CSp, &
ADp=CS%ADp)
ADp=CS%ADp, STOCH=STOCH)
call cpu_clock_end(id_clock_horvisc)
if (showCallTree) call callTree_wayPoint("done with horizontal_viscosity (step_MOM_dyn_split_RK2)")

Expand Down
8 changes: 5 additions & 3 deletions src/core/MOM_dynamics_unsplit.F90
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ module MOM_dynamics_unsplit
use MOM_open_boundary, only : open_boundary_zero_normal_flow
use MOM_PressureForce, only : PressureForce, PressureForce_init, PressureForce_CS
use MOM_set_visc, only : set_viscous_ML, set_visc_CS
use MOM_self_attr_load, only : SAL_init, SAL_end, SAL_CS
use MOM_stochastics, only : stochastic_CS
use MOM_tidal_forcing, only : tidal_forcing_init, tidal_forcing_end, tidal_forcing_CS
use MOM_self_attr_load, only : SAL_init, SAL_end, SAL_CS
use MOM_unit_scaling, only : unit_scale_type
use MOM_vert_friction, only : vertvisc, vertvisc_coef, vertvisc_init, vertvisc_CS
use MOM_verticalGrid, only : verticalGrid_type, get_thickness_units
Expand Down Expand Up @@ -189,7 +190,7 @@ module MOM_dynamics_unsplit
!! 3rd order (for the inviscid momentum equations) order scheme
subroutine step_MOM_dyn_unsplit(u, v, h, tv, visc, Time_local, dt, forces, &
p_surf_begin, p_surf_end, uh, vh, uhtr, vhtr, eta_av, G, GV, US, CS, &
VarMix, MEKE, pbv, Waves)
VarMix, MEKE, pbv, STOCH, Waves)
type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
Expand Down Expand Up @@ -223,6 +224,7 @@ subroutine step_MOM_dyn_unsplit(u, v, h, tv, visc, Time_local, dt, forces, &
type(VarMix_CS), intent(inout) :: VarMix !< Variable mixing control structure
type(MEKE_type), intent(inout) :: MEKE !< MEKE fields
type(porous_barrier_type), intent(in) :: pbv !< porous barrier fractional cell metrics
type(stochastic_CS), intent(inout) :: STOCH !< Stochastic control structure
type(wave_parameters_CS), optional, pointer :: Waves !< A pointer to a structure containing
!! fields related to the surface wave conditions

Expand Down Expand Up @@ -263,7 +265,7 @@ subroutine step_MOM_dyn_unsplit(u, v, h, tv, visc, Time_local, dt, forces, &
! diffu = horizontal viscosity terms (u,h)
call enable_averages(dt, Time_local, CS%diag)
call cpu_clock_begin(id_clock_horvisc)
call horizontal_viscosity(u, v, h, CS%diffu, CS%diffv, MEKE, Varmix, G, GV, US, CS%hor_visc)
call horizontal_viscosity(u, v, h, CS%diffu, CS%diffv, MEKE, Varmix, G, GV, US, CS%hor_visc, STOCH=STOCH)
call cpu_clock_end(id_clock_horvisc)
call disable_averaging(CS%diag)

Expand Down
6 changes: 4 additions & 2 deletions src/core/MOM_dynamics_unsplit_RK2.F90
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ module MOM_dynamics_unsplit_RK2
use MOM_PressureForce, only : PressureForce, PressureForce_init, PressureForce_CS
use MOM_set_visc, only : set_viscous_ML, set_visc_CS
use MOM_self_attr_load, only : SAL_init, SAL_end, SAL_CS
use MOM_stochastics, only : stochastic_CS
use MOM_tidal_forcing, only : tidal_forcing_init, tidal_forcing_end, tidal_forcing_CS
use MOM_unit_scaling, only : unit_scale_type
use MOM_vert_friction, only : vertvisc, vertvisc_coef, vertvisc_init, vertvisc_CS
Expand Down Expand Up @@ -192,7 +193,7 @@ module MOM_dynamics_unsplit_RK2
!> Step the MOM6 dynamics using an unsplit quasi-2nd order Runge-Kutta scheme
subroutine step_MOM_dyn_unsplit_RK2(u_in, v_in, h_in, tv, visc, Time_local, dt, forces, &
p_surf_begin, p_surf_end, uh, vh, uhtr, vhtr, eta_av, G, GV, US, CS, &
VarMix, MEKE, pbv)
VarMix, MEKE, pbv, STOCH)
type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
Expand Down Expand Up @@ -237,6 +238,7 @@ subroutine step_MOM_dyn_unsplit_RK2(u_in, v_in, h_in, tv, visc, Time_local, dt,
!! fields related to the Mesoscale
!! Eddy Kinetic Energy.
type(porous_barrier_type), intent(in) :: pbv !< porous barrier fractional cell metrics
type(stochastic_CS), intent(inout) :: STOCH !< Stochastic control structure
! Local variables
real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_av ! Averaged layer thicknesses [H ~> m or kg m-2]
real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: hp ! Predicted layer thicknesses [H ~> m or kg m-2]
Expand Down Expand Up @@ -276,7 +278,7 @@ subroutine step_MOM_dyn_unsplit_RK2(u_in, v_in, h_in, tv, visc, Time_local, dt,
call enable_averages(dt,Time_local, CS%diag)
call cpu_clock_begin(id_clock_horvisc)
call horizontal_viscosity(u_in, v_in, h_in, CS%diffu, CS%diffv, MEKE, VarMix, &
G, GV, US, CS%hor_visc)
G, GV, US, CS%hor_visc, STOCH=STOCH)
call cpu_clock_end(id_clock_horvisc)
call disable_averaging(CS%diag)
call pass_vector(CS%diffu, CS%diffv, G%Domain, clock=id_clock_pass)
Expand Down
18 changes: 15 additions & 3 deletions src/parameterizations/lateral/MOM_hor_visc.F90
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ module MOM_hor_visc
use MOM_MEKE_types, only : MEKE_type
use MOM_open_boundary, only : ocean_OBC_type, OBC_DIRECTION_E, OBC_DIRECTION_W
use MOM_open_boundary, only : OBC_DIRECTION_N, OBC_DIRECTION_S, OBC_NONE
use MOM_stochastics, only : stochastic_CS
use MOM_unit_scaling, only : unit_scale_type
use MOM_verticalGrid, only : verticalGrid_type
use MOM_variables, only : accel_diag_ptrs
Expand Down Expand Up @@ -241,7 +242,7 @@ module MOM_hor_visc
!! v[is-2:ie+2,js-2:je+2]
!! h[is-1:ie+1,js-1:je+1]
subroutine horizontal_viscosity(u, v, h, diffu, diffv, MEKE, VarMix, G, GV, US, &
CS, OBC, BT, TD, ADp)
CS, OBC, BT, TD, ADp, STOCH)
type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
Expand All @@ -265,6 +266,7 @@ subroutine horizontal_viscosity(u, v, h, diffu, diffv, MEKE, VarMix, G, GV, US,
type(barotropic_CS), intent(in), optional :: BT !< Barotropic control structure
type(thickness_diffuse_CS), intent(in), optional :: TD !< Thickness diffusion control structure
type(accel_diag_ptrs), intent(in), optional :: ADp !< Acceleration diagnostics
type(stochastic_CS), intent(inout), optional :: STOCH !< Stochastic control structure

! Local variables
real, dimension(SZIB_(G),SZJ_(G)) :: &
Expand Down Expand Up @@ -395,6 +397,7 @@ subroutine horizontal_viscosity(u, v, h, diffu, diffv, MEKE, VarMix, G, GV, US,
logical :: apply_OBC = .false.
logical :: use_MEKE_Ku
logical :: use_MEKE_Au
logical :: skeb_use_frict
integer :: is_vort, ie_vort, js_vort, je_vort ! Loop ranges for vorticity terms
integer :: is_Kh, ie_Kh, js_Kh, je_Kh ! Loop ranges for thickness point viscosities
integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
Expand Down Expand Up @@ -426,6 +429,9 @@ subroutine horizontal_viscosity(u, v, h, diffu, diffv, MEKE, VarMix, G, GV, US,
inv_PI2 = 1.0/((4.0*atan(1.0))**2)
inv_PI6 = inv_PI3 * inv_PI3

skeb_use_frict = .false.
if (present(STOCH)) skeb_use_frict = STOCH%skeb_use_frict

m_leithy(:,:) = 0.0 ! Initialize

if (present(OBC)) then ; if (associated(OBC)) then ; if (OBC%OBC_pe) then
Expand Down Expand Up @@ -588,12 +594,12 @@ subroutine horizontal_viscosity(u, v, h, diffu, diffv, MEKE, VarMix, G, GV, US,
!$OMP CS, G, GV, US, OBC, VarMix, MEKE, u, v, h, &
!$OMP is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, is_vort, ie_vort, js_vort, je_vort, &
!$OMP is_Kh, ie_Kh, js_Kh, je_Kh, apply_OBC, rescale_Kh, legacy_bound, find_FrictWork, &
!$OMP use_MEKE_Ku, use_MEKE_Au, u_smooth, v_smooth, &
!$OMP use_MEKE_Ku, use_MEKE_Au, u_smooth, v_smooth, skeb_use_frict, &
!$OMP backscat_subround, GME_effic_h, GME_effic_q, &
!$OMP h_neglect, h_neglect3, inv_PI3, inv_PI6, &
!$OMP diffu, diffv, Kh_h, Kh_q, Ah_h, Ah_q, FrictWork, FrictWork_GME, &
!$OMP div_xx_h, sh_xx_h, vort_xy_q, sh_xy_q, GME_coeff_h, GME_coeff_q, &
!$OMP KH_u_GME, KH_v_GME, grid_Re_Kh, grid_Re_Ah, NoSt, ShSt &
!$OMP KH_u_GME, KH_v_GME, grid_Re_Kh, grid_Re_Ah, NoSt, ShSt, STOCH &
!$OMP ) &
!$OMP private( &
!$OMP i, j, k, n, &
Expand Down Expand Up @@ -1786,6 +1792,12 @@ subroutine horizontal_viscosity(u, v, h, diffu, diffv, MEKE, VarMix, G, GV, US,
+ (v(i+1,J-1,k)-v(i,J-1,k))*G%IdxBu(I,J-1)) ) ) )
enddo ; enddo ; endif

if (skeb_use_frict) then ; do j=js,je ; do i=is,ie
! Note that the sign convention is FrictWork < 0 means energy dissipation.
STOCH%skeb_diss(i,j,k) = STOCH%skeb_diss(i,j,k) - STOCH%skeb_frict_coef * &
FrictWork(i,j,k) / (GV%H_to_RZ * (h(i,j,k) + h_neglect))
enddo ; enddo ; endif

! Make a similar calculation as for FrictWork above but accumulating into
! the vertically integrated MEKE source term, and adjusting for any
! energy loss seen as a reduction in the (biharmonic) frictional source term.
Expand Down
Loading

0 comments on commit 6ad1530

Please sign in to comment.