Skip to content

Commit

Permalink
+*Non-Boussinesq internal tide drag uses density
Browse files Browse the repository at this point in the history
  Use the in situ near bottom density to calculate the internal tide drag,
energy input and energy loss terms when in non-Boussinesq mode.  This change
includes the addition of an argument containing the near-bottom density to
propagate_int_tide, itidal_lowmode_loss and find_N2_bottom.  The recently added
routine find_rho_bottom is used to calculate this near-bottom density.

  Several instances where the Boussinesq reference density or GV%Z_to_H were
used have been eliminated from use in non-Boussinesq cases by this change,  to
simplify the code and reduce the dependence on the value of GV%Rho_0 in
non-Boussinesq mode.  This involved changing the units of 4 internal variables
in find_N2_bottom to use thickness units or related units.  In some places,
GV%Rho0 was replaced with GV%H_to_RZ.  It also includes the rescaling of a
variable in int_tide_CS, and a new element with the bottom drag in the
int_tide_input_type.

 All answers are bitwise identical in Boussinesq mode, but some solutions will
change in non-Boussinesq mode with this change, and there are new arguments to
publicly visible subroutines and a new element in a transparent type.
  • Loading branch information
Hallberg-NOAA committed Jul 20, 2023
1 parent e62a930 commit c0e9b26
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 69 deletions.
91 changes: 55 additions & 36 deletions src/parameterizations/lateral/MOM_internal_tides.F90
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ module MOM_internal_tides
real, allocatable, dimension(:,:,:,:,:) :: TKE_Froude_loss
!< energy lost due to wave breaking [R Z3 T-3 ~> W m-2]
real, allocatable, dimension(:,:) :: TKE_itidal_loss_fixed
!< Fixed part of the energy lost due to small-scale drag [R L-2 Z3 ~> kg m-2] here;
!! This will be multiplied by N and the squared near-bottom velocity to get
!! the energy losses in [R Z3 T-3 ~> W m-2]
!< Fixed part of the energy lost due to small-scale drag [R Z3 L-2 ~> kg m-2] here;
!! This will be multiplied by N and the squared near-bottom velocity (and by
!! the near-bottom density in non-Boussinesq mode) to get the energy losses
!! in [R Z4 H-1 L-2 ~> kg m-2 or m]
real, allocatable, dimension(:,:,:,:,:) :: TKE_itidal_loss
!< energy lost due to small-scale wave drag [R Z3 T-3 ~> W m-2]
real, allocatable, dimension(:,:,:,:,:) :: TKE_residual_loss
Expand Down Expand Up @@ -120,7 +121,7 @@ module MOM_internal_tides
real :: cdrag !< The bottom drag coefficient [nondim].
real :: drag_min_depth !< The minimum total ocean thickness that will be used in the denominator
!! of the quadratic drag terms for internal tides when
!! INTERNAL_TIDE_QUAD_DRAG is true [Z ~> m]
!! INTERNAL_TIDE_QUAD_DRAG is true [H ~> m or kg m-2]
logical :: apply_background_drag
!< If true, apply a drag due to background processes as a sink.
logical :: apply_bottom_drag
Expand Down Expand Up @@ -187,7 +188,7 @@ module MOM_internal_tides

!> Calls subroutines in this file that are needed to refract, propagate,
!! and dissipate energy density of the internal tide.
subroutine propagate_int_tide(h, tv, TKE_itidal_input, vel_btTide, Nb, dt, &
subroutine propagate_int_tide(h, tv, TKE_itidal_input, vel_btTide, Nb, Rho_bot, dt, &
G, GV, US, CS)
type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
Expand All @@ -203,6 +204,8 @@ subroutine propagate_int_tide(h, tv, TKE_itidal_input, vel_btTide, Nb, dt, &
real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: Nb !< Near-bottom buoyancy frequency [T-1 ~> s-1].
!! In some cases the input values are used, but in
!! others this is set along with the wave speeds.
real, dimension(SZI_(G),SZJ_(G)), intent(in) :: Rho_bot !< Near-bottom density or the Boussinesq
!! reference density [R ~> kg m-3].
real, intent(in) :: dt !< Length of time over which to advance
!! the internal tides [T ~> s].
type(int_tide_CS), intent(inout) :: CS !< Internal tide control structure
Expand All @@ -228,8 +231,8 @@ subroutine propagate_int_tide(h, tv, TKE_itidal_input, vel_btTide, Nb, dt, &
real :: frac_per_sector ! The inverse of the number of angular, modal and frequency bins [nondim]
real :: f2 ! The squared Coriolis parameter interpolated to a tracer point [T-2 ~> s-2]
real :: Kmag2 ! A squared horizontal wavenumber [L-2 ~> m-2]
real :: I_D_here ! The inverse of the local depth [Z-1 ~> m-1]
real :: I_rho0 ! The inverse fo the Boussinesq density [R-1 ~> m3 kg-1]
real :: I_D_here ! The inverse of the local water column thickness [H-1 ~> m-1 or m2 kg-1]
real :: I_mass ! The inverse of the local water mass [R-1 Z-1 ~> m2 kg-1]
real :: freq2 ! The frequency squared [T-2 ~> s-2]
real :: PE_term ! total potential energy of profile [R Z ~> kg m-2]
real :: KE_term ! total kinetic energy of profile [R Z ~> kg m-2]
Expand All @@ -244,16 +247,15 @@ subroutine propagate_int_tide(h, tv, TKE_itidal_input, vel_btTide, Nb, dt, &
real :: En_initial, Delta_E_check ! Energies for debugging [R Z3 T-2 ~> J m-2]
real :: TKE_Froude_loss_check, TKE_Froude_loss_tot ! Energy losses for debugging [R Z3 T-3 ~> W m-2]
character(len=160) :: mesg ! The text of an error message
integer :: a, m, fr, i, j, k, is, ie, js, je, isd, ied, jsd, jed, nAngle, nzm
integer :: a, m, fr, i, j, k, is, ie, js, je, isd, ied, jsd, jed, nAngle
integer :: id_g, jd_g ! global (decomp-invar) indices (for debugging)
type(group_pass_type), save :: pass_test, pass_En
type(time_type) :: time_end
logical:: avg_enabled

is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed ; nAngle = CS%NAngle
nzm = GV%ke
I_rho0 = 1.0 / GV%Rho0

cn_subRO = 1e-30*US%m_s_to_L_T
en_subRO = 1e-30*US%W_m2_to_RZ3_T3*US%s_to_T

Expand Down Expand Up @@ -429,11 +431,20 @@ subroutine propagate_int_tide(h, tv, TKE_itidal_input, vel_btTide, Nb, dt, &
do k=1,GV%ke ; do j=jsd,jed ; do i=isd,ied
htot(i,j) = htot(i,j) + h(i,j,k)
enddo ; enddo ; enddo
do j=jsd,jed ; do i=isd,ied
I_D_here = 1.0 / (max(GV%H_to_Z*htot(i,j), CS%drag_min_depth))
drag_scale(i,j) = CS%cdrag * sqrt(max(0.0, US%L_to_Z**2*vel_btTide(i,j)**2 + &
tot_En(i,j) * I_rho0 * I_D_here)) * I_D_here
enddo ; enddo
if (GV%Boussinesq) then
! This is mathematically equivalent to the form in the option below, but they differ at roundoff.
do j=jsd,jed ; do i=isd,ied
I_D_here = 1.0 / (max(htot(i,j), CS%drag_min_depth))
drag_scale(i,j) = CS%cdrag * sqrt(max(0.0, US%L_to_Z**2*vel_btTide(i,j)**2 + &
tot_En(i,j) * GV%RZ_to_H * I_D_here)) * GV%Z_to_H*I_D_here
enddo ; enddo
else
do j=jsd,jed ; do i=isd,ied
I_mass = GV%RZ_to_H / (max(htot(i,j), CS%drag_min_depth))
drag_scale(i,j) = (CS%cdrag * (Rho_bot(i,j)*I_mass)) * &
sqrt(max(0.0, US%L_to_Z**2*vel_btTide(i,j)**2 + tot_En(i,j) * I_mass))
enddo ; enddo
endif
do m=1,CS%nMode ; do fr=1,CS%nFreq ; do a=1,CS%nAngle ; do j=jsd,jed ; do i=isd,ied
! Calculate loss rate and apply loss over the time step ; apply the same drag timescale
! to each En component (technically not correct; fix later)
Expand Down Expand Up @@ -504,7 +515,7 @@ subroutine propagate_int_tide(h, tv, TKE_itidal_input, vel_btTide, Nb, dt, &
! Finally, apply loss
if (CS%apply_wave_drag) then
! Calculate loss rate and apply loss over the time step
call itidal_lowmode_loss(G, US, CS, Nb, Ub, CS%En, CS%TKE_itidal_loss_fixed, &
call itidal_lowmode_loss(G, GV, US, CS, Nb, Rho_bot, Ub, CS%En, CS%TKE_itidal_loss_fixed, &
CS%TKE_itidal_loss, dt, full_halos=.false.)
endif
! Check for En<0 - for debugging, delete later
Expand Down Expand Up @@ -782,18 +793,21 @@ end subroutine sum_En

!> Calculates the energy lost from the propagating internal tide due to
!! scattering over small-scale roughness along the lines of Jayne & St. Laurent (2001).
subroutine itidal_lowmode_loss(G, US, CS, Nb, Ub, En, TKE_loss_fixed, TKE_loss, dt, full_halos)
subroutine itidal_lowmode_loss(G, GV, US, CS, Nb, Rho_bot, Ub, En, TKE_loss_fixed, TKE_loss, dt, full_halos)
type(ocean_grid_type), intent(in) :: 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
type(int_tide_CS), intent(in) :: CS !< Internal tide control structure
real, dimension(G%isd:G%ied,G%jsd:G%jed), &
intent(in) :: Nb !< Near-bottom stratification [T-1 ~> s-1].
real, dimension(G%isd:G%ied,G%jsd:G%jed), &
intent(in) :: Rho_bot !< Near-bottom density [R ~> kg m-3].
real, dimension(G%isd:G%ied,G%jsd:G%jed,CS%nFreq,CS%nMode), &
intent(inout) :: Ub !< RMS (over one period) near-bottom horizontal
!! mode velocity [L T-1 ~> m s-1].
real, dimension(G%isd:G%ied,G%jsd:G%jed), &
intent(in) :: TKE_loss_fixed !< Fixed part of energy loss [R L-2 Z3 ~> kg m-2]
!! (rho*kappa*h^2).
intent(in) :: TKE_loss_fixed !< Fixed part of energy loss [R Z4 H-1 L-2 ~> kg m-2 or m]
!! (rho*kappa*h^2) or (kappa*h^2).
real, dimension(G%isd:G%ied,G%jsd:G%jed,CS%NAngle,CS%nFreq,CS%nMode), &
intent(inout) :: En !< Energy density of the internal waves [R Z3 T-2 ~> J m-2].
real, dimension(G%isd:G%ied,G%jsd:G%jed,CS%NAngle,CS%nFreq,CS%nMode), &
Expand Down Expand Up @@ -830,14 +844,18 @@ subroutine itidal_lowmode_loss(G, US, CS, Nb, Ub, En, TKE_loss_fixed, TKE_loss,
enddo

! Calculate TKE loss rate; units of [R Z3 T-3 ~> W m-2] here.
TKE_loss_tot = q_itides * TKE_loss_fixed(i,j) * Nb(i,j) * Ub(i,j,fr,m)**2
if (GV%Boussinesq .or. GV%semi_Boussinesq) then
TKE_loss_tot = q_itides * GV%Z_to_H * TKE_loss_fixed(i,j) * Nb(i,j) * Ub(i,j,fr,m)**2
else
TKE_loss_tot = q_itides * (GV%RZ_to_H * Rho_bot(i,j)) * TKE_loss_fixed(i,j) * Nb(i,j) * Ub(i,j,fr,m)**2
endif

! Update energy remaining (this is a pseudo implicit calc)
! (E(t+1)-E(t))/dt = -TKE_loss(E(t+1)/E(t)), which goes to zero as E(t+1) goes to zero
if (En_tot > 0.0) then
do a=1,CS%nAngle
frac_per_sector = En(i,j,a,fr,m)/En_tot
TKE_loss(i,j,a,fr,m) = frac_per_sector*TKE_loss_tot ! Wm-2
TKE_loss(i,j,a,fr,m) = frac_per_sector*TKE_loss_tot ! [R Z3 T-3 ~> W m-2]
loss_rate = TKE_loss(i,j,a,fr,m) / (En(i,j,a,fr,m) + En_negl) ! [T-1 ~> s-1]
En(i,j,a,fr,m) = En(i,j,a,fr,m) / (1.0 + dt*loss_rate)
enddo
Expand Down Expand Up @@ -2458,8 +2476,8 @@ subroutine internal_tides_init(Time, G, GV, US, param_file, diag, CS)
call get_param(param_file, mdl, "INTERNAL_TIDE_DRAG_MIN_DEPTH", CS%drag_min_depth, &
"The minimum total ocean thickness that will be used in the denominator "//&
"of the quadratic drag terms for internal tides.", &
units="m", default=1.0, scale=US%m_to_Z, do_not_log=.not.CS%apply_bottom_drag)
CS%drag_min_depth = MAX(CS%drag_min_depth, GV%H_subroundoff * GV%H_to_Z)
units="m", default=1.0, scale=GV%m_to_H, do_not_log=.not.CS%apply_bottom_drag)
CS%drag_min_depth = MAX(CS%drag_min_depth, GV%H_subroundoff)
call get_param(param_file, mdl, "INTERNAL_TIDE_FROUDE_DRAG", CS%apply_Froude_drag, &
"If true, apply wave breaking as a sink.", &
default=.false.)
Expand Down Expand Up @@ -2543,9 +2561,10 @@ subroutine internal_tides_init(Time, G, GV, US, param_file, diag, CS)
else
h2(i,j) = max(h2(i,j), 0.0)
endif
! Compute the fixed part; units are [R L-2 Z3 ~> kg m-2] here
! will be multiplied by N and the squared near-bottom velocity to get into [R Z3 T-3 ~> W m-2]
CS%TKE_itidal_loss_fixed(i,j) = 0.5*kappa_h2_factor*GV%Rho0 * US%L_to_Z*kappa_itides * h2(i,j)
! Compute the fixed part; units are [R Z4 H-1 L-2 ~> kg m-2 or m] here
! will be multiplied by N and the squared near-bottom velocity (and by the
! near-bottom density in non-Boussinesq mode) to get into [R Z3 T-3 ~> W m-2]
CS%TKE_itidal_loss_fixed(i,j) = 0.5*kappa_h2_factor* GV%H_to_RZ * US%L_to_Z*kappa_itides * h2(i,j)
enddo ; enddo

deallocate(h2)
Expand Down Expand Up @@ -2644,16 +2663,16 @@ subroutine internal_tides_init(Time, G, GV, US, param_file, diag, CS)
enddo
call pass_var(CS%residual,G%domain)

CS%id_cg1 = register_diag_field('ocean_model', 'cn1', diag%axesT1, &
Time, 'First baroclinic mode (eigen) speed', 'm s-1', conversion=US%L_T_to_m_s)
allocate(CS%id_cn(CS%nMode), source=-1)
do m=1,CS%nMode
write(var_name, '("cn_mode",i1)') m
write(var_descript, '("Baroclinic (eigen) speed of mode ",i1)') m
CS%id_cn(m) = register_diag_field('ocean_model',var_name, diag%axesT1, &
Time, var_descript, 'm s-1', conversion=US%L_T_to_m_s)
call MOM_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
enddo
CS%id_cg1 = register_diag_field('ocean_model', 'cn1', diag%axesT1, &
Time, 'First baroclinic mode (eigen) speed', 'm s-1', conversion=US%L_T_to_m_s)
allocate(CS%id_cn(CS%nMode), source=-1)
do m=1,CS%nMode
write(var_name, '("cn_mode",i1)') m
write(var_descript, '("Baroclinic (eigen) speed of mode ",i1)') m
CS%id_cn(m) = register_diag_field('ocean_model',var_name, diag%axesT1, &
Time, var_descript, 'm s-1', conversion=US%L_T_to_m_s)
call MOM_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
enddo


! Register maps of reflection parameters
Expand Down
2 changes: 1 addition & 1 deletion src/parameterizations/vertical/MOM_diabatic_driver.F90
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ subroutine diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, &
CS%int_tide_input_CSp)

call propagate_int_tide(h, tv, CS%int_tide_input%TKE_itidal_input, CS%int_tide_input%tideamp, &
CS%int_tide_input%Nb, dt, G, GV, US, CS%int_tide)
CS%int_tide_input%Nb, CS%int_tide_input%Rho_bot, dt, G, GV, US, CS%int_tide)
if (showCallTree) call callTree_waypoint("done with propagate_int_tide (diabatic)")
endif ! end CS%use_int_tides

Expand Down
Loading

0 comments on commit c0e9b26

Please sign in to comment.