Skip to content
52 changes: 42 additions & 10 deletions src/core/MOM_PressureForce_FV.F90
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ module MOM_PressureForce_FV
!! the mean temperature gradient in the deterministic part of
!! the Stanley form of the Brankart correction.
integer :: id_e_tidal = -1 !< Diagnostic identifier
integer :: id_tvar_sgs = -1 !< Diagnostic identifier
type(tidal_forcing_CS), pointer :: tides_CSp => NULL() !< Tides control structure
end type PressureForce_FV_CS

Expand Down Expand Up @@ -479,7 +480,9 @@ subroutine PressureForce_FV_Bouss(h, tv, PFu, PFv, G, GV, US, CS, ALE_CSp, p_atm
logical :: use_ALE ! If true, use an ALE pressure reconstruction.
logical :: use_EOS ! If true, density is calculated from T & S using an equation of state.
type(thermo_var_ptrs) :: tv_tmp! A structure of temporary T & S.
real :: dTdi2, dTdj2 ! Differences in T variance [degC2]
!real :: dTdi2, dTdj2 ! Differences in T variance [degC2]
real :: Tl(5), mn_T, mn_T2 ! copy and moment of local stenil of T [degC or degC2]
real :: Hl(5), mn_H ! Copy of local stencial of H [H ~> m]
real, parameter :: C1_6 = 1.0/6.0
integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb
Expand All @@ -503,15 +506,39 @@ subroutine PressureForce_FV_Bouss(h, tv, PFu, PFv, G, GV, US, CS, ALE_CSp, p_atm
if (CS%Stanley_T2_det_coeff>=0.) then
if (.not. associated(tv%varT)) call safe_alloc_ptr(tv%varT, G%isd, G%ied, G%jsd, G%jed, GV%ke)
do k=1, nz ; do j=js-1,je+1 ; do i=is-1,ie+1
! SGS variance in i-direction [degC2]
dTdi2 = ( ( G%mask2dCu(I ,j) * G%IdxCu(I ,j) * ( tv%T(i+1,j,k) - tv%T(i,j,k) ) &
+ G%mask2dCu(I-1,j) * G%IdxCu(I-1,j) * ( tv%T(i,j,k) - tv%T(i-1,j,k) ) &
) * G%dxT(i,j) * 0.5 )**2
! SGS variance in j-direction [degC2]
dTdj2 = ( ( G%mask2dCv(i,J ) * G%IdyCv(i,J ) * ( tv%T(i,j+1,k) - tv%T(i,j,k) ) &
+ G%mask2dCv(i,J-1) * G%IdyCv(i,J-1) * ( tv%T(i,j,k) - tv%T(i,j-1,k) ) &
) * G%dyT(i,j) * 0.5 )**2
tv%varT(i,j,k) = CS%Stanley_T2_det_coeff * 0.5 * ( dTdi2 + dTdj2 )
! Strictly speaking we should be estimate the horizontal grid-scale variance
! but neither of the following blocks make a rotation to the horizontal
! but work along coordinate

! This block calculates a simple |delta T| along coordinates and does
! not allow vanishing layer thicknesses or layers tracking topography
!! SGS variance in i-direction [degC2]
!dTdi2 = ( ( G%mask2dCu(I ,j) * G%IdxCu(I ,j) * ( tv%T(i+1,j,k) - tv%T(i,j,k) ) &
! + G%mask2dCu(I-1,j) * G%IdxCu(I-1,j) * ( tv%T(i,j,k) - tv%T(i-1,j,k) ) &
! ) * G%dxT(i,j) * 0.5 )**2
!! SGS variance in j-direction [degC2]
!dTdj2 = ( ( G%mask2dCv(i,J ) * G%IdyCv(i,J ) * ( tv%T(i,j+1,k) - tv%T(i,j,k) ) &
! + G%mask2dCv(i,J-1) * G%IdyCv(i,J-1) * ( tv%T(i,j,k) - tv%T(i,j-1,k) ) &
! ) * G%dyT(i,j) * 0.5 )**2
!tv%varT(i,j,k) = CS%Stanley_T2_det_coeff * 0.5 * ( dTdi2 + dTdj2 )

! This block does a thickness weighted variance calculation and helps control for
! extreme gradients along layers which are vanished against topography. It is
! still a poor approximation in the interior when coordinates are strongly tilted.
hl(1) = h(i,j,k) ; hl(2) = h(i-1,j,k) ; hl(3) = h(i+1,j,k) ; hl(4) = h(i,j-1,k) ; hl(5) = h(i,j+1,k)
mn_H = ( hl(1) + ( ( hl(2) + hl(3) ) + ( hl(4) + hl(5) ) ) ) + GV%H_subroundoff
mn_H = 1. / mn_H ! Hereafter, mn_H is the reciprocal of mean h for the stencil
! Mean of T
Tl(1) = tv%T(i,j,k) ; Tl(2) = tv%T(i-1,j,k) ; Tl(3) = tv%T(i+1,j,k) ; Tl(4) = tv%T(i,j-1,k) ; Tl(5) = tv%T(i,j+1,k)
mn_T = ( hl(1)*Tl(1) + ( ( hl(2)*Tl(2) + hl(3)*Tl(3) ) + ( hl(4)*Tl(4) + hl(5)*Tl(5) ) ) ) * mn_H
! Adjust T vectors to have zero mean
Tl(:) = Tl(:) - mn_T ; mn_T = 0.
! Variance of T
mn_T2 = ( hl(1)*Tl(1)*Tl(1) + ( ( hl(2)*Tl(2)*Tl(2) + hl(3)*Tl(3)*Tl(3) ) &
+ ( hl(4)*Tl(4)*Tl(4) + hl(5)*Tl(5)*Tl(5) ) ) ) * mn_H
! Variance should be positive but round-off can violate this. Calculating
! variance directly would fix this but requires more operations.
tv%varT(i,j,k) = CS%Stanley_T2_det_coeff * max(0., mn_T2 - mn_T*mn_T)
enddo ; enddo ; enddo
endif

Expand Down Expand Up @@ -758,6 +785,7 @@ subroutine PressureForce_FV_Bouss(h, tv, PFu, PFv, G, GV, US, CS, ALE_CSp, p_atm
endif

if (CS%id_e_tidal>0) call post_data(CS%id_e_tidal, e_tidal, CS%diag)
if (CS%id_tvar_sgs>0) call post_data(CS%id_tvar_sgs, tv%varT, CS%diag)

end subroutine PressureForce_FV_Bouss

Expand Down Expand Up @@ -826,6 +854,10 @@ subroutine PressureForce_FV_init(Time, G, GV, US, param_file, diag, CS, tides_CS
"the mean temperature gradient in the deterministic part of "// &
"the Stanley form of the Brankart correction. "// &
"Negative values disable the scheme.", units="nondim", default=-1.0)
if (CS%Stanley_T2_det_coeff>=0.) then
CS%id_tvar_sgs = register_diag_field('ocean_model', 'tvar_sgs_pgf', diag%axesTL, &
Time, 'SGS temperature variance used in PGF', 'degC2')
endif
if (CS%tides) then
CS%id_e_tidal = register_diag_field('ocean_model', 'e_tidal', diag%axesT1, &
Time, 'Tidal Forcing Astronomical and SAL Height Anomaly', 'meter', conversion=US%Z_to_m)
Expand Down
15 changes: 11 additions & 4 deletions src/core/MOM_barotropic.F90
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ subroutine btstep(U_in, V_in, eta_in, dt, bc_accel_u, bc_accel_v, forces, pbce,
integer :: is, ie, js, je, nz, Isq, Ieq, Jsq, Jeq
integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
integer :: ioff, joff
integer :: l_seg

if (.not.associated(CS)) call MOM_error(FATAL, &
"btstep: Module MOM_barotropic must be initialized before it is used.")
Expand Down Expand Up @@ -2326,9 +2327,12 @@ subroutine btstep(U_in, V_in, eta_in, dt, bc_accel_u, bc_accel_v, forces, pbce,
if (CS%BT_OBC%apply_u_OBCs) then ! copy back the value for u-points on the boundary.
!GOMP parallel do default(shared)
do j=js,je ; do I=is-1,ie
if (OBC%segment(OBC%segnum_u(I,j))%direction == OBC_DIRECTION_E) then
l_seg = OBC%segnum_u(I,j)
if (l_seg == OBC_NONE) cycle

if (OBC%segment(l_seg)%direction == OBC_DIRECTION_E) then
e_anom(i+1,j) = e_anom(i,j)
elseif (OBC%segment(OBC%segnum_u(I,j))%direction == OBC_DIRECTION_W) then
elseif (OBC%segment(l_seg)%direction == OBC_DIRECTION_W) then
e_anom(i,j) = e_anom(i+1,j)
endif
enddo ; enddo
Expand All @@ -2337,9 +2341,12 @@ subroutine btstep(U_in, V_in, eta_in, dt, bc_accel_u, bc_accel_v, forces, pbce,
if (CS%BT_OBC%apply_v_OBCs) then ! copy back the value for v-points on the boundary.
!GOMP parallel do default(shared)
do J=js-1,je ; do I=is,ie
if (OBC%segment(OBC%segnum_v(i,J))%direction == OBC_DIRECTION_N) then
l_seg = OBC%segnum_v(i,J)
if (l_seg == OBC_NONE) cycle

if (OBC%segment(l_seg)%direction == OBC_DIRECTION_N) then
e_anom(i,j+1) = e_anom(i,j)
elseif (OBC%segment(OBC%segnum_v(i,J))%direction == OBC_DIRECTION_S) then
elseif (OBC%segment(l_seg)%direction == OBC_DIRECTION_S) then
e_anom(i,j) = e_anom(i,j+1)
endif
enddo ; enddo
Expand Down
109 changes: 79 additions & 30 deletions src/core/MOM_continuity_PPM.F90
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, US, CS, LB, uhbt, OBC, &
real :: du_lim ! The velocity change that give a relative CFL of 1 [L T-1 ~> m s-1].
real :: dx_E, dx_W ! Effective x-grid spacings to the east and west [L ~> m].
integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
integer :: l_seg
logical :: local_specified_BC, use_visc_rem, set_BT_cont, any_simple_OBC
logical :: local_Flather_OBC, local_open_BC, is_simple
type(OBC_segment_type), pointer :: segment => NULL()
Expand Down Expand Up @@ -303,7 +304,8 @@ subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, US, CS, LB, uhbt, OBC, &
!$OMP uh,dt,US,G,GV,CS,local_specified_BC,OBC,uhbt,set_BT_cont, &
!$OMP CFL_dt,I_dt,u_cor,BT_cont, local_Flather_OBC) &
!$OMP private(do_I,duhdu,du,du_max_CFL,du_min_CFL,uh_tot_0,duhdu_tot_0, &
!$OMP is_simple,FAuI,visc_rem_max,I_vrm,du_lim,dx_E,dx_W,any_simple_OBC ) &
!$OMP is_simple,FAuI,visc_rem_max,I_vrm,du_lim,dx_E,dx_W, &
!$OMP any_simple_OBC,l_seg) &
!$OMP firstprivate(visc_rem)
do j=jsh,jeh
do I=ish-1,ieh ; do_I(I) = .true. ; visc_rem_max(I) = 0.0 ; enddo
Expand All @@ -318,8 +320,12 @@ subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, US, CS, LB, uhbt, OBC, &
dt, G, US, j, ish, ieh, do_I, CS%vol_CFL, OBC)
if (local_specified_BC) then
do I=ish-1,ieh
if (OBC%segment(OBC%segnum_u(I,j))%specified) &
uh(I,j,k) = OBC%segment(OBC%segnum_u(I,j))%normal_trans(I,j,k)
l_seg = OBC%segnum_u(I,j)

if (l_seg /= OBC_NONE) then
if (OBC%segment(l_seg)%specified) &
uh(I,j,k) = OBC%segment(l_seg)%normal_trans(I,j,k)
endif
enddo
endif
enddo
Expand Down Expand Up @@ -408,9 +414,13 @@ subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, US, CS, LB, uhbt, OBC, &
any_simple_OBC = .false.
if (present(uhbt) .or. set_BT_cont) then
if (local_specified_BC .or. local_Flather_OBC) then ; do I=ish-1,ieh
l_seg = OBC%segnum_u(I,j)

! Avoid reconciling barotropic/baroclinic transports if transport is specified
is_simple = OBC%segment(OBC%segnum_u(I,j))%specified
do_I(I) = .not.(OBC%segnum_u(I,j) /= OBC_NONE .and. is_simple)
is_simple = .false.
if (l_seg /= OBC_NONE) &
is_simple = OBC%segment(l_seg)%specified
do_I(I) = .not. (l_seg /= OBC_NONE .and. is_simple)
any_simple_OBC = any_simple_OBC .or. is_simple
enddo ; else ; do I=ish-1,ieh
do_I(I) = .true.
Expand All @@ -425,8 +435,12 @@ subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, US, CS, LB, uhbt, OBC, &
if (present(u_cor)) then ; do k=1,nz
do I=ish-1,ieh ; u_cor(I,j,k) = u(I,j,k) + du(I) * visc_rem(I,k) ; enddo
if (local_specified_BC) then ; do I=ish-1,ieh
if (OBC%segment(OBC%segnum_u(I,j))%specified) &
u_cor(I,j,k) = OBC%segment(OBC%segnum_u(I,j))%normal_vel(I,j,k)
l_seg = OBC%segnum_u(I,j)

if (l_seg /= OBC_NONE) then
if (OBC%segment(l_seg)%specified) &
u_cor(I,j,k) = OBC%segment(l_seg)%normal_vel(I,j,k)
endif
enddo ; endif
enddo ; endif ! u-corrected

Expand All @@ -438,9 +452,15 @@ subroutine zonal_mass_flux(u, h_in, uh, dt, G, GV, US, CS, LB, uhbt, OBC, &
visc_rem_max, j, ish, ieh, do_I)
if (any_simple_OBC) then
do I=ish-1,ieh
do_I(I) = OBC%segment(OBC%segnum_u(I,j))%specified
l_seg = OBC%segnum_u(I,j)

do_I(I) = .false.
if (l_seg /= OBC_NONE) &
do_I(I) = OBC%segment(l_seg)%specified

if (do_I(I)) FAuI(I) = GV%H_subroundoff*G%dy_Cu(I,j)
enddo
! NOTE: do_I(I) should prevent access to segment OBC_NONE
do k=1,nz ; do I=ish-1,ieh ; if (do_I(I)) then
if ((abs(OBC%segment(OBC%segnum_u(I,j))%normal_vel(I,j,k)) > 0.0) .and. &
(OBC%segment(OBC%segnum_u(I,j))%specified)) &
Expand Down Expand Up @@ -529,6 +549,7 @@ subroutine zonal_flux_layer(u, h, h_L, h_R, uh, duhdu, visc_rem, dt, G, US, j, &
! with the same units as h_in.
real :: h_marg ! The marginal thickness of a flux [H ~> m or kg m-2].
integer :: i
integer :: l_seg
logical :: local_open_BC

local_open_BC = .false.
Expand Down Expand Up @@ -561,13 +582,17 @@ subroutine zonal_flux_layer(u, h, h_L, h_R, uh, duhdu, visc_rem, dt, G, US, j, &

if (local_open_BC) then
do I=ish-1,ieh ; if (do_I(I)) then
if (OBC%segment(OBC%segnum_u(I,j))%open) then
if (OBC%segment(OBC%segnum_u(I,j))%direction == OBC_DIRECTION_E) then
uh(I) = G%dy_Cu(I,j) * u(I) * h(i)
duhdu(I) = G%dy_Cu(I,j) * h(i) * visc_rem(I)
else
uh(I) = G%dy_Cu(I,j) * u(I) * h(i+1)
duhdu(I) = G%dy_Cu(I,j) * h(i+1) * visc_rem(I)
l_seg = OBC%segnum_u(I,j)

if (l_seg /= OBC_NONE) then
if (OBC%segment(l_seg)%open) then
if (OBC%segment(l_seg)%direction == OBC_DIRECTION_E) then
uh(I) = G%dy_Cu(I,j) * u(I) * h(i)
duhdu(I) = G%dy_Cu(I,j) * h(i) * visc_rem(I)
else
uh(I) = G%dy_Cu(I,j) * u(I) * h(i+1)
duhdu(I) = G%dy_Cu(I,j) * h(i+1) * visc_rem(I)
endif
endif
endif
endif ; enddo
Expand Down Expand Up @@ -1062,6 +1087,7 @@ subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, US, CS, LB, vhbt, OBC, &
real :: dv_lim ! The velocity change that give a relative CFL of 1 [L T-1 ~> m s-1].
real :: dy_N, dy_S ! Effective y-grid spacings to the north and south [L ~> m].
integer :: i, j, k, ish, ieh, jsh, jeh, n, nz
integer :: l_seg
logical :: local_specified_BC, use_visc_rem, set_BT_cont, any_simple_OBC
logical :: local_Flather_OBC, is_simple, local_open_BC
type(OBC_segment_type), pointer :: segment => NULL()
Expand Down Expand Up @@ -1103,7 +1129,7 @@ subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, US, CS, LB, vhbt, OBC, &
!$OMP set_BT_cont,CFL_dt,I_dt,v_cor,BT_cont, local_Flather_OBC ) &
!$OMP private(do_I,dvhdv,dv,dv_max_CFL,dv_min_CFL,vh_tot_0, &
!$OMP dvhdv_tot_0,visc_rem_max,I_vrm,dv_lim,dy_N, &
!$OMP is_simple,FAvi,dy_S,any_simple_OBC ) &
!$OMP is_simple,FAvi,dy_S,any_simple_OBC,l_seg) &
!$OMP firstprivate(visc_rem)
do J=jsh-1,jeh
do i=ish,ieh ; do_I(i) = .true. ; visc_rem_max(I) = 0.0 ; enddo
Expand All @@ -1118,8 +1144,12 @@ subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, US, CS, LB, vhbt, OBC, &
dt, G, US, J, ish, ieh, do_I, CS%vol_CFL, OBC)
if (local_specified_BC) then
do i=ish,ieh
if (OBC%segment(OBC%segnum_v(i,J))%specified) &
vh(i,J,k) = OBC%segment(OBC%segnum_v(i,J))%normal_trans(i,J,k)
l_seg = OBC%segnum_v(i,J)

if (l_seg /= OBC_NONE) then
if (OBC%segment(l_seg)%specified) &
vh(i,J,k) = OBC%segment(l_seg)%normal_trans(i,J,k)
endif
enddo
endif
enddo ! k-loop
Expand Down Expand Up @@ -1204,9 +1234,13 @@ subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, US, CS, LB, vhbt, OBC, &
any_simple_OBC = .false.
if (present(vhbt) .or. set_BT_cont) then
if (local_specified_BC .or. local_Flather_OBC) then ; do i=ish,ieh
l_seg = OBC%segnum_v(i,J)

! Avoid reconciling barotropic/baroclinic transports if transport is specified
is_simple = OBC%segment(OBC%segnum_v(i,J))%specified
do_I(i) = .not.(OBC%segnum_v(i,J) /= OBC_NONE .and. is_simple)
is_simple = .false.
if (l_seg /= OBC_NONE) &
is_simple = OBC%segment(l_seg)%specified
do_I(i) = .not.(l_seg /= OBC_NONE .and. is_simple)
any_simple_OBC = any_simple_OBC .or. is_simple
enddo ; else ; do i=ish,ieh
do_I(i) = .true.
Expand All @@ -1221,8 +1255,12 @@ subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, US, CS, LB, vhbt, OBC, &
if (present(v_cor)) then ; do k=1,nz
do i=ish,ieh ; v_cor(i,J,k) = v(i,J,k) + dv(i) * visc_rem(i,k) ; enddo
if (local_specified_BC) then ; do i=ish,ieh
if (OBC%segment(OBC%segnum_v(i,J))%specified) &
v_cor(i,J,k) = OBC%segment(OBC%segnum_v(i,J))%normal_vel(i,J,k)
l_seg = OBC%segnum_v(i,J)

if (l_seg /= OBC_NONE) then
if (OBC%segment(OBC%segnum_v(i,J))%specified) &
v_cor(i,J,k) = OBC%segment(OBC%segnum_v(i,J))%normal_vel(i,J,k)
endif
enddo ; endif
enddo ; endif ! v-corrected
endif
Expand All @@ -1233,9 +1271,15 @@ subroutine meridional_mass_flux(v, h_in, vh, dt, G, GV, US, CS, LB, vhbt, OBC, &
visc_rem_max, J, ish, ieh, do_I)
if (any_simple_OBC) then
do i=ish,ieh
do_I(i) = (OBC%segment(OBC%segnum_v(i,J))%specified)
l_seg = OBC%segnum_v(i,J)

do_I(I) = .false.
if(l_seg /= OBC_NONE) &
do_I(i) = (OBC%segment(l_seg)%specified)

if (do_I(i)) FAvi(i) = GV%H_subroundoff*G%dx_Cv(i,J)
enddo
! NOTE: do_I(I) should prevent access to segment OBC_NONE
do k=1,nz ; do i=ish,ieh ; if (do_I(i)) then
if ((abs(OBC%segment(OBC%segnum_v(i,J))%normal_vel(i,J,k)) > 0.0) .and. &
(OBC%segment(OBC%segnum_v(i,J))%specified)) &
Expand Down Expand Up @@ -1327,6 +1371,7 @@ subroutine merid_flux_layer(v, h, h_L, h_R, vh, dvhdv, visc_rem, dt, G, US, J, &
! with the same units as h, i.e. [H ~> m or kg m-2].
real :: h_marg ! The marginal thickness of a flux [H ~> m or kg m-2].
integer :: i
integer :: l_seg
logical :: local_open_BC

local_open_BC = .false.
Expand Down Expand Up @@ -1360,13 +1405,17 @@ subroutine merid_flux_layer(v, h, h_L, h_R, vh, dvhdv, visc_rem, dt, G, US, J, &

if (local_open_BC) then
do i=ish,ieh ; if (do_I(i)) then
if (OBC%segment(OBC%segnum_v(i,J))%open) then
if (OBC%segment(OBC%segnum_v(i,J))%direction == OBC_DIRECTION_N) then
vh(i) = G%dx_Cv(i,J) * v(i) * h(i,j)
dvhdv(i) = G%dx_Cv(i,J) * h(i,j) * visc_rem(i)
else
vh(i) = G%dx_Cv(i,J) * v(i) * h(i,j+1)
dvhdv(i) = G%dx_Cv(i,J) * h(i,j+1) * visc_rem(i)
l_seg = OBC%segnum_v(i,J)

if (l_seg /= OBC_NONE) then
if (OBC%segment(l_seg)%open) then
if (OBC%segment(l_seg)%direction == OBC_DIRECTION_N) then
vh(i) = G%dx_Cv(i,J) * v(i) * h(i,j)
dvhdv(i) = G%dx_Cv(i,J) * h(i,j) * visc_rem(i)
else
vh(i) = G%dx_Cv(i,J) * v(i) * h(i,j+1)
dvhdv(i) = G%dx_Cv(i,J) * h(i,j+1) * visc_rem(i)
endif
endif
endif
endif ; enddo
Expand Down
Loading