Skip to content

Commit

Permalink
merge latest dev/ncar and resolve new conflicts in MOM_mixed_layer_re…
Browse files Browse the repository at this point in the history
…strat
  • Loading branch information
alperaltuntas committed Jan 10, 2025
2 parents 0d828a2 + ea1b4f0 commit 1fc274d
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 63 deletions.
2 changes: 1 addition & 1 deletion pkg/CVMix-src
172 changes: 113 additions & 59 deletions src/parameterizations/lateral/MOM_mixed_layer_restrat.F90
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ module MOM_mixed_layer_restrat
logical :: MLE_use_PBL_MLD !< If true, use the MLD provided by the PBL parameterization.
!! if false, MLE will calculate a MLD based on a density difference
!! based on the parameter MLE_DENSITY_DIFF.
logical :: Bodner_detect_MLD !< If true, detect the MLD based on given density difference criterion
!! (MLE_DENSITY_DIFF) in the Bodner et al. parameterization.
real :: vonKar !< The von Karman constant as used for mixed layer viscosity [nondim]
real :: MLE_MLD_decay_time !< Time-scale to use in a running-mean when MLD is retreating [T ~> s].
real :: MLE_MLD_decay_time2 !< Time-scale to use in a running-mean when filtered MLD is retreating [T ~> s].
Expand Down Expand Up @@ -249,14 +251,9 @@ subroutine mixedlayer_restrat_OM4(h, uhtr, vhtr, tv, forces, dt, h_MLD, VarMix,
real :: vtimescale_diag(SZI_(G),SZJB_(G)) ! Meridional restratification timescale [T ~> s], stored for diagnostics.
real :: uDml_diag(SZIB_(G),SZJ_(G)) ! A 2D copy of uDml for diagnostics [H L2 T-1 ~> m3 s-1 or kg s-1]
real :: vDml_diag(SZI_(G),SZJB_(G)) ! A 2D copy of vDml for diagnostics [H L2 T-1 ~> m3 s-1 or kg s-1]
real, dimension(SZI_(G)) :: rhoSurf, deltaRhoAtKm1, deltaRhoAtK ! Densities and density differences [R ~> kg m-3]
real, dimension(SZI_(G)) :: dK, dKm1 ! Depths of layer centers [H ~> m or kg m-2].
real, dimension(SZI_(G)) :: pRef_MLD ! A reference pressure for calculating the mixed layer
! densities [R L2 T-2 ~> Pa].
real, dimension(SZI_(G)) :: covTS, & ! SGS TS covariance in Stanley param; currently 0 [C S ~> degC ppt]
varS ! SGS S variance in Stanley param; currently 0 [S2 ~> ppt2]
real :: aFac, bFac ! Nondimensional ratios [nondim]
real :: ddRho ! A density difference [R ~> kg m-3]
real :: hAtVel ! Thickness at the velocity points [H ~> m or kg m-2]
real :: zpa ! Fractional position within the mixed layer of the interface above a layer [nondim]
real :: zpb ! Fractional position within the mixed layer of the interface below a layer [nondim]
Expand Down Expand Up @@ -291,48 +288,7 @@ subroutine mixedlayer_restrat_OM4(h, uhtr, vhtr, tv, forces, dt, h_MLD, VarMix,
call find_ustar(forces, tv, U_star_2d, G, GV, US, halo=1, H_T_units=.true.)

if (CS%MLE_density_diff > 0.) then ! We need to calculate a mixed layer depth, MLD.
!! TODO: use derivatives and mid-MLD pressure. Currently this is sigma-0. -AJA
pRef_MLD(:) = 0.
EOSdom(:) = EOS_domain(G%HI, halo=1)
do j=js-1,je+1
dK(:) = 0.5 * h(:,j,1) ! Depth of center of surface layer
if (CS%use_Stanley_ML) then
call calculate_density(tv%T(:,j,1), tv%S(:,j,1), pRef_MLD, tv%varT(:,j,1), covTS, varS, &
rhoSurf, tv%eqn_of_state, EOSdom)
else
call calculate_density(tv%T(:,j,1), tv%S(:,j,1), pRef_MLD, rhoSurf, tv%eqn_of_state, EOSdom)
endif
deltaRhoAtK(:) = 0.
MLD_fast(:,j) = 0.
do k=2,nz
dKm1(:) = dK(:) ! Depth of center of layer K-1
dK(:) = dK(:) + 0.5 * ( h(:,j,k) + h(:,j,k-1) ) ! Depth of center of layer K
! Mixed-layer depth, using sigma-0 (surface reference pressure)
deltaRhoAtKm1(:) = deltaRhoAtK(:) ! Store value from previous iteration of K
if (CS%use_Stanley_ML) then
call calculate_density(tv%T(:,j,k), tv%S(:,j,k), pRef_MLD, tv%varT(:,j,k), covTS, varS, &
deltaRhoAtK, tv%eqn_of_state, EOSdom)
else
call calculate_density(tv%T(:,j,k), tv%S(:,j,k), pRef_MLD, deltaRhoAtK, tv%eqn_of_state, EOSdom)
endif
do i=is-1,ie+1
deltaRhoAtK(i) = deltaRhoAtK(i) - rhoSurf(i) ! Density difference between layer K and surface
enddo
do i=is-1,ie+1
ddRho = deltaRhoAtK(i) - deltaRhoAtKm1(i)
if ((MLD_fast(i,j)==0.) .and. (ddRho>0.) .and. &
(deltaRhoAtKm1(i)<CS%MLE_density_diff) .and. (deltaRhoAtK(i)>=CS%MLE_density_diff)) then
aFac = ( CS%MLE_density_diff - deltaRhoAtKm1(i) ) / ddRho
MLD_fast(i,j) = dK(i) * aFac + dKm1(i) * (1. - aFac)
endif
enddo ! i-loop
enddo ! k-loop
do i=is-1,ie+1
MLD_fast(i,j) = CS%MLE_MLD_stretch * MLD_fast(i,j)
if ((MLD_fast(i,j)==0.) .and. (deltaRhoAtK(i)<CS%MLE_density_diff)) &
MLD_fast(i,j) = dK(i) ! Assume mixing to the bottom
enddo
enddo ! j-loop
call detect_mld(h, tv, MLD_fast, G, GV, CS)
elseif (CS%MLE_use_PBL_MLD) then
do j=js-1,je+1 ; do i=is-1,ie+1
MLD_fast(i,j) = CS%MLE_MLD_stretch * h_MLD(i,j)
Expand Down Expand Up @@ -793,6 +749,7 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d
real, dimension(SZI_(G),SZJ_(G)) :: &
little_h, & ! "Little h" representing active mixing layer depth [H ~> m or kg m-2]
big_H, & ! "Big H" representing the mixed layer depth [H ~> m or kg m-2]
mld, & ! The mixed layer depth returned by detect_mld [H ~> m or kg m-2]
htot, & ! The sum of the thicknesses of layers in the mixed layer [H ~> m or kg m-2]
buoy_av, & ! g_Rho0 times the average mixed layer density or G_Earth
! times the average specific volume [L2 H-1 T-2 ~> m s-2 or m4 kg-1 s-2]
Expand Down Expand Up @@ -859,14 +816,19 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d

if (.not.associated(tv%eqn_of_state)) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// &
"An equation of state must be used with this module.")
if (.not.CS%MLE_use_PBL_MLD) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// &
"To use the Bodner et al., 2023, MLE parameterization, MLE_USE_PBL_MLD must be True.")
if (CS%MLE_density_diff > 0.) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// &
"MLE_density_diff is +ve and should not be in mixedlayer_restrat_Bodner.")
if (.not.associated(bflux)) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// &
"Surface buoyancy flux was not associated.")
if (CS%MLE_use_PBL_MLD) then
if (CS%MLE_density_diff > 0.) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// &
"MLE_density_diff is +ve and should not be in mixedlayer_restrat_Bodner.")
if (.not.associated(bflux)) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// &
"Surface buoyancy flux was not associated.")
else
if (.not.CS%Bodner_detect_MLD) call MOM_error(FATAL, "mixedlayer_restrat_Bodner: "// &
"To use the Bodner et al., 2023, MLE parameterization, either MLE_USE_PBL_MLD or "// &
"Bodner_detect_MLD must be True.")
endif

call pass_var(bflux, G%domain, halo=1)
if (associated(bflux)) &
call pass_var(bflux, G%domain, halo=1)

! Extract the friction velocity from the forcing type.
call find_ustar(forces, tv, U_star_2d, G, GV, US, halo=1)
Expand Down Expand Up @@ -897,15 +859,22 @@ subroutine mixedlayer_restrat_Bodner(CS, G, GV, US, h, uhtr, vhtr, tv, forces, d
do j=js-1,je+1 ; do i=is-1,ie+1
big_H(i,j) = rmean2ts(little_h(i,j), CS%MLD_filtered_slow(i,j), &
CS%MLD_growing_Tfilt, CS%MLD_Tfilt_space(i,j), dt)
CS%MLD_filtered_slow(i,j) = big_H(i,j)
enddo ; enddo
elseif (CS%Bodner_detect_MLD) then
call detect_mld(h, tv, MLD, G, GV, CS)
do j=js-1,je+1 ; do i=is-1,ie+1
big_H(i,j) = rmean2ts(MLD(i,j), CS%MLD_filtered_slow(i,j), &
CS%MLD_growing_Tfilt, CS%MLD_decaying_Tfilt, dt)
enddo ; enddo
else
do j=js-1,je+1 ; do i=is-1,ie+1
big_H(i,j) = rmean2ts(little_h(i,j), CS%MLD_filtered_slow(i,j), &
CS%MLD_growing_Tfilt, CS%MLD_decaying_Tfilt, dt)
CS%MLD_filtered_slow(i,j) = big_H(i,j)
enddo ; enddo
endif
do j=js-1,je+1 ; do i=is-1,ie+1
CS%MLD_filtered_slow(i,j) = big_H(i,j)
enddo ; enddo

! Estimate w'u' at h-points, with a floor to avoid division by zero later.
if (allocated(tv%SpV_avg) .and. .not.(GV%Boussinesq .or. GV%semi_Boussinesq)) then
Expand Down Expand Up @@ -1499,6 +1468,76 @@ subroutine mixedlayer_restrat_BML(h, uhtr, vhtr, tv, forces, dt, G, GV, US, CS)

end subroutine mixedlayer_restrat_BML

!> Detects the mixed layer depth using a density difference criterion (MLE_DENSITY_DIFF)
subroutine detect_mld(h, tv, MLD_fast, G, GV, CS)
type(mixedlayer_restrat_CS), intent(inout) :: CS !< Module control structure
type(ocean_grid_type), intent(inout) :: G !< Ocean grid structure
type(verticalGrid_type), intent(in) :: GV !< Ocean vertical grid structure
real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< Layer thickness [H ~> m or kg m-2]
real, dimension(SZI_(G),SZJ_(G)), intent(out) :: MLD_fast !< detected mixed layer depth [H ~> m or kg m-2]
type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamic variables structure

! Local variables
real, dimension(SZI_(G)) :: pRef_MLD ! A reference pressure for calculating the mixed layer
! densities [R L2 T-2 ~> Pa].
real, dimension(SZI_(G)) :: rhoSurf, deltaRhoAtKm1, deltaRhoAtK ! Densities and density differences [R ~> kg m-3]
real, dimension(SZI_(G)) :: dK, dKm1 ! Depths of layer centers [H ~> m or kg m-2].
real :: ddRho ! A density difference [R ~> kg m-3]
real :: aFac ! A nondimensional ratio [nondim]
real :: covTS(SZI_(G)) ! SGS TS covariance in Stanley param; currently 0 [C S ~> degC ppt]
real :: varS(SZI_(G)) ! SGS S variance in Stanley param; currently 0 [S2 ~> ppt2]
integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
integer :: i, j, k, is, ie, js, je, nz

is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke

covTS(:) = 0.0 ! Might be in tv% in the future. Not implemented for the time being.
varS(:) = 0.0 ! Ditto.

!! TODO: use derivatives and mid-MLD pressure. Currently this is sigma-0. -AJA
pRef_MLD(:) = 0.
EOSdom(:) = EOS_domain(G%HI, halo=1)
do j=js-1,je+1
dK(:) = 0.5 * h(:,j,1) ! Depth of center of surface layer
if (CS%use_Stanley_ML) then
call calculate_density(tv%T(:,j,1), tv%S(:,j,1), pRef_MLD, tv%varT(:,j,1), covTS, varS, &
rhoSurf, tv%eqn_of_state, EOSdom)
else
call calculate_density(tv%T(:,j,1), tv%S(:,j,1), pRef_MLD, rhoSurf, tv%eqn_of_state, EOSdom)
endif
deltaRhoAtK(:) = 0.
MLD_fast(:,j) = 0.
do k=2,nz
dKm1(:) = dK(:) ! Depth of center of layer K-1
dK(:) = dK(:) + 0.5 * ( h(:,j,k) + h(:,j,k-1) ) ! Depth of center of layer K
! Mixed-layer depth, using sigma-0 (surface reference pressure)
deltaRhoAtKm1(:) = deltaRhoAtK(:) ! Store value from previous iteration of K
if (CS%use_Stanley_ML) then
call calculate_density(tv%T(:,j,k), tv%S(:,j,k), pRef_MLD, tv%varT(:,j,k), covTS, varS, &
deltaRhoAtK, tv%eqn_of_state, EOSdom)
else
call calculate_density(tv%T(:,j,k), tv%S(:,j,k), pRef_MLD, deltaRhoAtK, tv%eqn_of_state, EOSdom)
endif
do i=is-1,ie+1
deltaRhoAtK(i) = deltaRhoAtK(i) - rhoSurf(i) ! Density difference between layer K and surface
enddo
do i=is-1,ie+1
ddRho = deltaRhoAtK(i) - deltaRhoAtKm1(i)
if ((MLD_fast(i,j)==0.) .and. (ddRho>0.) .and. &
(deltaRhoAtKm1(i)<CS%MLE_density_diff) .and. (deltaRhoAtK(i)>=CS%MLE_density_diff)) then
aFac = ( CS%MLE_density_diff - deltaRhoAtKm1(i) ) / ddRho
MLD_fast(i,j) = dK(i) * aFac + dKm1(i) * (1. - aFac)
endif
enddo ! i-loop
enddo ! k-loop
do i=is-1,ie+1
MLD_fast(i,j) = CS%MLE_MLD_stretch * MLD_fast(i,j)
if ((MLD_fast(i,j)==0.) .and. (deltaRhoAtK(i)<CS%MLE_density_diff)) &
MLD_fast(i,j) = dK(i) ! Assume mixing to the bottom
enddo
enddo ! j-loop
end subroutine detect_mld

! NOTE: This function appears to change answers on some platforms, so it is
! currently unused in the model, but we intend to introduce it in the future.

Expand Down Expand Up @@ -1689,9 +1728,15 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS,
"If true, the MLE parameterization will use the mixed-layer "//&
"depth provided by the active PBL parameterization. If false, "//&
"MLE will estimate a MLD based on a density difference with the "//&
"surface using the parameter MLE_DENSITY_DIFF.", default=.false.)
if (.not.CS%MLE_use_PBL_MLD) call MOM_error(FATAL, "mixedlayer_restrat_init: "// &
"To use MLE%USE_BODNER23=True then MLE_USE_PBL_MLD must be True.")
"surface using the parameter MLE_DENSITY_DIFF, unless "//&
"BODNER_DETECT_MLD is true.", default=.false.)
call get_param(param_file, mdl, "BODNER_DETECT_MLD", CS%Bodner_detect_MLD, &
"If true, the Bodner parameterization will use the mixed-layer depth "//&
"detected via the density difference criterion MLE_DENSITY_DIFF.", default=.false.)
if (.not.(CS%MLE_use_PBL_MLD.or.CS%Bodner_detect_MLD)) call MOM_error(FATAL, "mixedlayer_restrat_init: "// &
"To use MLE%USE_BODNER23=True then MLE_USE_PBL_MLD or BODNER_DETECT_MLD must be true.")
if (CS%MLE_use_PBL_MLD.and.CS%Bodner_detect_MLD) call MOM_error(FATAL, "mixedlayer_restrat_init: "// &
"MLE_USE_PBL_MLD and BODNER_DETECT_MLD cannot both be true.")
else
call closeParameterBlock(param_file) ! The remaining parameters do not have MLE% prepended
endif
Expand Down Expand Up @@ -1777,6 +1822,15 @@ logical function mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, CS,
"restratification module. This can be tiny, but if this is greater than 0, "//&
"it will prevent divisions by zero when f and KV_RESTRAT are zero.", &
units="m s-1", default=US%Z_to_m*US%s_to_T*ustar_min_dflt, scale=GV%m_to_H*US%T_to_s)
elseif (CS%Bodner_detect_MLD) then
call get_param(param_file, mdl, "MLE_DENSITY_DIFF", CS%MLE_density_diff, &
"Density difference used to detect the mixed-layer "//&
"depth used for the mixed-layer eddy parameterization "//&
"by Fox-Kemper et al. (2010)", units="kg/m3", default=0.03, scale=US%kg_m3_to_R)
call get_param(param_file, mdl, "MLE_MLD_STRETCH", CS%MLE_MLD_stretch, &
"A scaling coefficient for stretching/shrinking the MLD "//&
"used in the MLE scheme. This simply multiplies MLD wherever used.",&
units="nondim", default=1.0)
endif

CS%diag => diag
Expand Down
9 changes: 6 additions & 3 deletions src/parameterizations/vertical/MOM_set_viscosity.F90
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module MOM_set_visc
use MOM_EOS, only : calculate_density, calculate_density_derivs, calculate_specific_vol_derivs
use MOM_error_handler, only : MOM_error, FATAL, WARNING
use MOM_file_parser, only : get_param, log_param, log_version, param_file_type
use MOM_file_parser, only : openParameterBlock, closeParameterBlock
use MOM_forcing_type, only : forcing, mech_forcing, find_ustar
use MOM_grid, only : ocean_grid_type
use MOM_hor_index, only : hor_index_type
Expand Down Expand Up @@ -2785,8 +2786,12 @@ subroutine set_visc_register_restarts(HI, G, GV, US, param_file, visc, restart_C
default=.false., do_not_log=.true.)
call get_param(param_file, mdl, "USE_IDEAL_AGE_TRACER", use_ideal_age, &
default=.false., do_not_log=.true.)
call openParameterBlock(param_file, 'MLE', do_not_log=.true.)
call get_param(param_file, mdl, "USE_BODNER23", MLE_use_Bodner, &
default=.false., do_not_log=.true.)
call closeParameterBlock(param_file)

if (MLE_use_PBL_MLD) then
if (MLE_use_PBL_MLD .or. MLE_use_Bodner) then
call safe_alloc_ptr(visc%MLD, isd, ied, jsd, jed)
endif
if ((hfreeze >= 0.0) .or. MLE_use_PBL_MLD .or. do_brine_plume .or. use_fpmix .or. &
Expand All @@ -2806,8 +2811,6 @@ subroutine set_visc_register_restarts(HI, G, GV, US, param_file, visc, restart_C
endif

! visc%sfc_buoy_flx is used to communicate the state of the (e)PBL or KPP to the rest of the model
call get_param(param_file, mdl, "MLE%USE_BODNER23", MLE_use_Bodner, &
default=.false., do_not_log=.true.)
if (MLE_use_PBL_MLD .or. MLE_use_Bodner) then
call safe_alloc_ptr(visc%sfc_buoy_flx, isd, ied, jsd, jed)
call register_restart_field(visc%sfc_buoy_flx, "SFC_BFLX", .false., restart_CS, &
Expand Down

0 comments on commit 1fc274d

Please sign in to comment.