MOM6
mom_internal_tides Module Reference

Detailed Description

Subroutines that use the ray-tracing equations to propagate the internal tide energy density.

Author
Benjamin Mater & Robert Hallberg, 2015

Data Types

type  int_tide_cs
 This control structure has parameters for the MOM_internal_tides module. More...
 
type  loop_bounds_type
 A structure with the active energy loop bounds. More...
 

Functions/Subroutines

subroutine, public propagate_int_tide (h, tv, cn, TKE_itidal_input, vel_btTide, Nb, dt, G, GV, US, CS)
 Calls subroutines in this file that are needed to refract, propagate, and dissipate energy density of the internal tide. More...
 
subroutine sum_en (G, CS, En, label)
 Checks for energy conservation on computational domain. More...
 
subroutine itidal_lowmode_loss (G, US, CS, Nb, Ub, En, TKE_loss_fixed, TKE_loss, dt, full_halos)
 Calculates the energy lost from the propagating internal tide due to scattering over small-scale roughness along the lines of Jayne & St. Laurent (2001). More...
 
subroutine, public get_lowmode_loss (i, j, G, CS, mechanism, TKE_loss_sum)
 This subroutine extracts the energy lost from the propagating internal which has been summed across all angles, frequencies, and modes for a given mechanism and location. More...
 
subroutine refract (En, cn, freq, dt, G, US, NAngle, use_PPMang)
 Implements refraction on the internal waves at a single frequency. More...
 
subroutine ppm_angular_advect (En2d, CFL_ang, Flux_En, NAngle, dt, halo_ang)
 This subroutine calculates the 1-d flux for advection in angular space using a monotonic piecewise parabolic scheme. This needs to be called from within i and j spatial loops. More...
 
subroutine propagate (En, cn, freq, dt, G, US, CS, NAngle)
 Propagates internal waves at a single frequency. More...
 
subroutine propagate_corner_spread (En, energized_wedge, NAngle, speed, dt, G, CS, LB)
 This subroutine does first-order corner advection. It was written with the hopes of smoothing out the garden sprinkler effect, but is too numerically diffusive to be of much use as of yet. It is not yet compatible with reflection schemes (BDM). More...
 
subroutine propagate_x (En, speed_x, Cgx_av, dCgx, dt, G, US, Nangle, CS, LB)
 Propagates the internal wave energy in the logical x-direction. More...
 
subroutine propagate_y (En, speed_y, Cgy_av, dCgy, dt, G, US, Nangle, CS, LB)
 Propagates the internal wave energy in the logical y-direction. More...
 
subroutine zonal_flux_en (u, h, hL, hR, uh, dt, G, US, j, ish, ieh, vol_CFL)
 Evaluates the zonal mass or volume fluxes in a layer. More...
 
subroutine merid_flux_en (v, h, hL, hR, vh, dt, G, US, J, ish, ieh, vol_CFL)
 Evaluates the meridional mass or volume fluxes in a layer. More...
 
subroutine reflect (En, NAngle, CS, G, LB)
 Reflection of the internal waves at a single frequency. More...
 
subroutine teleport (En, NAngle, CS, G, LB)
 Moves energy across lines of partial reflection to prevent reflection of energy that is supposed to get across. More...
 
subroutine correct_halo_rotation (En, test, G, NAngle)
 Rotates points in the halos where required to accommodate changes in grid orientation, such as at the tripolar fold. More...
 
subroutine ppm_reconstruction_x (h_in, h_l, h_r, G, LB, simple_2nd)
 Calculates left/right edge values for PPM reconstruction in x-direction. More...
 
subroutine ppm_reconstruction_y (h_in, h_l, h_r, G, LB, simple_2nd)
 Calculates left/right edge valus for PPM reconstruction in y-direction. More...
 
subroutine ppm_limit_pos (h_in, h_L, h_R, h_min, G, iis, iie, jis, jie)
 Limits the left/right edge values of the PPM reconstruction to give a reconstruction that is positive-definite. Here this is reinterpreted as giving a constant thickness if the mean thickness is less than h_min, with a minimum of h_min otherwise. More...
 
subroutine, public internal_tides_init (Time, G, GV, US, param_file, diag, CS)
 This subroutine initializes the internal tides module. More...
 
subroutine, public internal_tides_end (CS)
 This subroutine deallocates the memory associated with the internal tides control structure. More...
 

Function/Subroutine Documentation

◆ correct_halo_rotation()

subroutine mom_internal_tides::correct_halo_rotation ( real, dimension(:,:,:,:,:), intent(inout)  En,
real, dimension(szi_(g),szj_(g),2), intent(in)  test,
type(ocean_grid_type), intent(in)  G,
integer, intent(in)  NAngle 
)
private

Rotates points in the halos where required to accommodate changes in grid orientation, such as at the tripolar fold.

Parameters
[in]gThe ocean's grid structure
[in,out]enThe internal gravity wave energy density as a function of space, angular orientation, frequency, and vertical mode [R Z3 T-2 ~> J m-2].
[in]testAn x-unit vector that has been passed through
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.

Definition at line 1812 of file MOM_internal_tides.F90.

1812  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1813  real, dimension(:,:,:,:,:), intent(inout) :: En !< The internal gravity wave energy density as a
1814  !! function of space, angular orientation, frequency,
1815  !! and vertical mode [R Z3 T-2 ~> J m-2].
1816  real, dimension(SZI_(G),SZJ_(G),2), &
1817  intent(in) :: test !< An x-unit vector that has been passed through
1818  !! the halo updates, to enable the rotation of the
1819  !! wave energies in the halo region to be corrected.
1820  integer, intent(in) :: NAngle !< The number of wave orientations in the
1821  !! discretized wave energy spectrum.
1822  ! Local variables
1823  real, dimension(G%isd:G%ied,NAngle) :: En2d
1824  integer, dimension(G%isd:G%ied) :: a_shift
1825  integer :: i_first, i_last, a_new
1826  integer :: a, i, j, isd, ied, jsd, jed, m, fr
1827  character(len=160) :: mesg ! The text of an error message
1828  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1829 
1830  do j=jsd,jed
1831  i_first = ied+1 ; i_last = isd-1
1832  do i=isd,ied
1833  a_shift(i) = 0
1834  if (test(i,j,1) /= 1.0) then
1835  if (i<i_first) i_first = i
1836  if (i>i_last) i_last = i
1837 
1838  if (test(i,j,1) == -1.0) then ; a_shift(i) = nangle/2
1839  elseif (test(i,j,2) == 1.0) then ; a_shift(i) = -nangle/4
1840  elseif (test(i,j,2) == -1.0) then ; a_shift(i) = nangle/4
1841  else
1842  write(mesg,'("Unrecognized rotation test vector ",2ES9.2," at ",F7.2," E, ",&
1843  &F7.2," N; i,j=",2i4)') &
1844  test(i,j,1), test(i,j,2), g%GeoLonT(i,j), g%GeoLatT(i,j), i, j
1845  call mom_error(fatal, mesg)
1846  endif
1847  endif
1848  enddo
1849 
1850  if (i_first <= i_last) then
1851  ! At least one point in this row needs to be rotated.
1852  do m=1,size(en,5) ; do fr=1,size(en,4)
1853  do a=1,nangle ; do i=i_first,i_last ; if (a_shift(i) /= 0) then
1854  a_new = a + a_shift(i)
1855  if (a_new < 1) a_new = a_new + nangle
1856  if (a_new > nangle) a_new = a_new - nangle
1857  en2d(i,a_new) = en(i,j,a,fr,m)
1858  endif ; enddo ; enddo
1859  do a=1,nangle ; do i=i_first,i_last ; if (a_shift(i) /= 0) then
1860  en(i,j,a,fr,m) = en2d(i,a)
1861  endif ; enddo ; enddo
1862  enddo ; enddo
1863  endif
1864  enddo

◆ get_lowmode_loss()

subroutine, public mom_internal_tides::get_lowmode_loss ( integer, intent(in)  i,
integer, intent(in)  j,
type(ocean_grid_type), intent(in)  G,
type(int_tide_cs), pointer  CS,
character(len=*), intent(in)  mechanism,
real, intent(out)  TKE_loss_sum 
)

This subroutine extracts the energy lost from the propagating internal which has been summed across all angles, frequencies, and modes for a given mechanism and location.

It can be called from another module to get values from this module's (private) CS.

Parameters
[in]iThe i-index of the value to be reported.
[in]jThe j-index of the value to be reported.
[in]gThe ocean's grid structure
csThe control structure returned by a previous call to int_tide_init.
[in]mechanismThe named mechanism of loss to return
[out]tke_loss_sumTotal energy loss rate due to specified mechanism [R Z3 T-3 ~> W m-2].

Definition at line 728 of file MOM_internal_tides.F90.

728  integer, intent(in) :: i !< The i-index of the value to be reported.
729  integer, intent(in) :: j !< The j-index of the value to be reported.
730  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
731  type(int_tide_CS), pointer :: CS !< The control structure returned by a
732  !! previous call to int_tide_init.
733  character(len=*), intent(in) :: mechanism !< The named mechanism of loss to return
734  real, intent(out) :: TKE_loss_sum !< Total energy loss rate due to specified
735  !! mechanism [R Z3 T-3 ~> W m-2].
736 
737  if (mechanism == 'LeakDrag') tke_loss_sum = cs%tot_leak_loss(i,j) ! not used for mixing yet
738  if (mechanism == 'QuadDrag') tke_loss_sum = cs%tot_quad_loss(i,j) ! not used for mixing yet
739  if (mechanism == 'WaveDrag') tke_loss_sum = cs%tot_itidal_loss(i,j) ! currently used for mixing
740  if (mechanism == 'Froude') tke_loss_sum = cs%tot_Froude_loss(i,j) ! not used for mixing yet
741 

◆ internal_tides_end()

subroutine, public mom_internal_tides::internal_tides_end ( type(int_tide_cs), pointer  CS)

This subroutine deallocates the memory associated with the internal tides control structure.

Parameters
csA pointer to the control structure returned by a previous call to internal_tides_init, it will be deallocated here.

Definition at line 2549 of file MOM_internal_tides.F90.

2549  type(int_tide_CS), pointer :: CS !< A pointer to the control structure returned by a previous
2550  !! call to internal_tides_init, it will be deallocated here.
2551 
2552  if (associated(cs)) then
2553  if (associated(cs%En)) deallocate(cs%En)
2554  if (allocated(cs%frequency)) deallocate(cs%frequency)
2555  if (allocated(cs%id_En_mode)) deallocate(cs%id_En_mode)
2556  if (allocated(cs%id_Ub_mode)) deallocate(cs%id_Ub_mode)
2557  if (allocated(cs%id_cp_mode)) deallocate(cs%id_cp_mode)
2558  deallocate(cs)
2559  endif
2560  cs => null()

◆ internal_tides_init()

subroutine, public mom_internal_tides::internal_tides_init ( type(time_type), intent(in), target  Time,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(param_file_type), intent(in)  param_file,
type(diag_ctrl), intent(in), target  diag,
type(int_tide_cs), pointer  CS 
)

This subroutine initializes the internal tides module.

Parameters
[in]timeThe current model time.
[in,out]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in]param_fileA structure to parse for run-time parameters.
[in]diagA structure that is used to regulate diagnostic output.
csA pointer that is set to point to the control structure for this module.

Definition at line 2102 of file MOM_internal_tides.F90.

2102  type(time_type), target, intent(in) :: Time !< The current model time.
2103  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
2104  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2105  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2106  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
2107  !! parameters.
2108  type(diag_ctrl), target, intent(in) :: diag !< A structure that is used to regulate
2109  !! diagnostic output.
2110  type(int_tide_CS),pointer :: CS !< A pointer that is set to point to the control
2111  !! structure for this module.
2112  ! Local variables
2113  real :: Angle_size ! size of wedges, rad
2114  real, allocatable :: angles(:) ! orientations of wedge centers, rad
2115  real, allocatable, dimension(:,:) :: h2 ! topographic roughness scale, m^2
2116  real :: kappa_itides, kappa_h2_factor
2117  ! characteristic topographic wave number
2118  ! and a scaling factor
2119  real, allocatable :: ridge_temp(:,:)
2120  ! array for temporary storage of flags
2121  ! of cells with double-reflecting ridges
2122  logical :: use_int_tides, use_temperature
2123  real :: period_1 ! The period of the gravest modeled mode [T ~> s]
2124  integer :: num_angle, num_freq, num_mode, m, fr
2125  integer :: isd, ied, jsd, jed, a, id_ang, i, j
2126  type(axes_grp) :: axes_ang
2127  ! This include declares and sets the variable "version".
2128 #include "version_variable.h"
2129  character(len=40) :: mdl = "MOM_internal_tides" ! This module's name.
2130  character(len=16), dimension(8) :: freq_name
2131  character(len=40) :: var_name
2132  character(len=160) :: var_descript
2133  character(len=200) :: filename
2134  character(len=200) :: refl_angle_file, land_mask_file
2135  character(len=200) :: refl_pref_file, refl_dbl_file
2136  character(len=200) :: dy_Cu_file, dx_Cv_file
2137  character(len=200) :: h2_file
2138 
2139  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
2140 
2141  if (associated(cs)) then
2142  call mom_error(warning, "internal_tides_init called "//&
2143  "with an associated control structure.")
2144  return
2145  else
2146  allocate(cs)
2147  endif
2148 
2149  use_int_tides = .false.
2150  call read_param(param_file, "INTERNAL_TIDES", use_int_tides)
2151  cs%do_int_tides = use_int_tides
2152  if (.not.use_int_tides) return
2153 
2154  use_temperature = .true.
2155  call read_param(param_file, "ENABLE_THERMODYNAMICS", use_temperature)
2156  if (.not.use_temperature) call mom_error(fatal, &
2157  "register_int_tide_restarts: internal_tides only works with "//&
2158  "ENABLE_THERMODYNAMICS defined.")
2159 
2160  ! Set number of frequencies, angles, and modes to consider
2161  num_freq = 1 ; num_angle = 24 ; num_mode = 1
2162  call read_param(param_file, "INTERNAL_TIDE_FREQS", num_freq)
2163  call read_param(param_file, "INTERNAL_TIDE_ANGLES", num_angle)
2164  call read_param(param_file, "INTERNAL_TIDE_MODES", num_mode)
2165  if (.not.((num_freq > 0) .and. (num_angle > 0) .and. (num_mode > 0))) return
2166  cs%nFreq = num_freq ; cs%nAngle = num_angle ; cs%nMode = num_mode
2167 
2168  ! Allocate energy density array
2169  allocate(cs%En(isd:ied, jsd:jed, num_angle, num_freq, num_mode))
2170  cs%En(:,:,:,:,:) = 0.0
2171 
2172  ! Allocate phase speed array
2173  allocate(cs%cp(isd:ied, jsd:jed, num_freq, num_mode))
2174  cs%cp(:,:,:,:) = 0.0
2175 
2176  ! Allocate and populate frequency array (each a multiple of first for now)
2177  allocate(cs%frequency(num_freq))
2178  call get_param(param_file, mdl, "FIRST_MODE_PERIOD", period_1, units="s", scale=us%s_to_T)
2179  do fr=1,num_freq
2180  cs%frequency(fr) = (8.0*atan(1.0) * (real(fr)) / period_1) ! ADDED BDM
2181  enddo
2182 
2183  ! Read all relevant parameters and write them to the model log.
2184 
2185  cs%Time => time ! direct a pointer to the current model time target
2186 
2187  call get_param(param_file, mdl, "INPUTDIR", cs%inputdir, default=".")
2188  cs%inputdir = slasher(cs%inputdir)
2189 
2190  call log_version(param_file, mdl, version, "")
2191 
2192  call get_param(param_file, mdl, "INTERNAL_TIDE_FREQS", num_freq, &
2193  "The number of distinct internal tide frequency bands "//&
2194  "that will be calculated.", default=1)
2195  call get_param(param_file, mdl, "INTERNAL_TIDE_MODES", num_mode, &
2196  "The number of distinct internal tide modes "//&
2197  "that will be calculated.", default=1)
2198  call get_param(param_file, mdl, "INTERNAL_TIDE_ANGLES", num_angle, &
2199  "The number of angular resolution bands for the internal "//&
2200  "tide calculations.", default=24)
2201 
2202  if (use_int_tides) then
2203  if ((num_freq <= 0) .and. (num_mode <= 0) .and. (num_angle <= 0)) then
2204  call mom_error(warning, "Internal tides were enabled, but the number "//&
2205  "of requested frequencies, modes and angles were not all positive.")
2206  return
2207  endif
2208  else
2209  if ((num_freq > 0) .and. (num_mode > 0) .and. (num_angle > 0)) then
2210  call mom_error(warning, "Internal tides were not enabled, even though "//&
2211  "the number of requested frequencies, modes and angles were all "//&
2212  "positive.")
2213  return
2214  endif
2215  endif
2216 
2217  if (cs%NFreq /= num_freq) call mom_error(fatal, "Internal_tides_init: "//&
2218  "Inconsistent number of frequencies.")
2219  if (cs%NAngle /= num_angle) call mom_error(fatal, "Internal_tides_init: "//&
2220  "Inconsistent number of angles.")
2221  if (cs%NMode /= num_mode) call mom_error(fatal, "Internal_tides_init: "//&
2222  "Inconsistent number of modes.")
2223  if (4*(num_angle/4) /= num_angle) call mom_error(fatal, &
2224  "Internal_tides_init: INTERNAL_TIDE_ANGLES must be a multiple of 4.")
2225 
2226  cs%diag => diag
2227 
2228  call get_param(param_file, mdl, "INTERNAL_TIDE_DECAY_RATE", cs%decay_rate, &
2229  "The rate at which internal tide energy is lost to the "//&
2230  "interior ocean internal wave field.", &
2231  units="s-1", default=0.0, scale=us%T_to_s)
2232  call get_param(param_file, mdl, "INTERNAL_TIDE_VOLUME_BASED_CFL", cs%vol_CFL, &
2233  "If true, use the ratio of the open face lengths to the "//&
2234  "tracer cell areas when estimating CFL numbers in the "//&
2235  "internal tide code.", default=.false.)
2236  call get_param(param_file, mdl, "INTERNAL_TIDE_CORNER_ADVECT", cs%corner_adv, &
2237  "If true, internal tide ray-tracing advection uses a "//&
2238  "corner-advection scheme rather than PPM.", default=.false.)
2239  call get_param(param_file, mdl, "INTERNAL_TIDE_SIMPLE_2ND_PPM", cs%simple_2nd, &
2240  "If true, CONTINUITY_PPM uses a simple 2nd order "//&
2241  "(arithmetic mean) interpolation of the edge values. "//&
2242  "This may give better PV conservation properties. While "//&
2243  "it formally reduces the accuracy of the continuity "//&
2244  "solver itself in the strongly advective limit, it does "//&
2245  "not reduce the overall order of accuracy of the dynamic "//&
2246  "core.", default=.false.)
2247  call get_param(param_file, mdl, "INTERNAL_TIDE_UPWIND_1ST", cs%upwind_1st, &
2248  "If true, the internal tide ray-tracing advection uses "//&
2249  "1st-order upwind advection. This scheme is highly "//&
2250  "continuity solver. This scheme is highly "//&
2251  "diffusive but may be useful for debugging.", default=.false.)
2252  call get_param(param_file, mdl, "INTERNAL_TIDE_BACKGROUND_DRAG", &
2253  cs%apply_background_drag, "If true, the internal tide "//&
2254  "ray-tracing advection uses a background drag term as a sink.",&
2255  default=.false.)
2256  call get_param(param_file, mdl, "INTERNAL_TIDE_QUAD_DRAG", cs%apply_bottom_drag, &
2257  "If true, the internal tide ray-tracing advection uses "//&
2258  "a quadratic bottom drag term as a sink.", default=.false.)
2259  call get_param(param_file, mdl, "INTERNAL_TIDE_WAVE_DRAG", cs%apply_wave_drag, &
2260  "If true, apply scattering due to small-scale roughness as a sink.", &
2261  default=.false.)
2262  call get_param(param_file, mdl, "INTERNAL_TIDE_FROUDE_DRAG", cs%apply_Froude_drag, &
2263  "If true, apply wave breaking as a sink.", &
2264  default=.false.)
2265  call get_param(param_file, mdl, "CDRAG", cs%cdrag, &
2266  "CDRAG is the drag coefficient relating the magnitude of "//&
2267  "the velocity field to the bottom stress.", units="nondim", &
2268  default=0.003)
2269  call get_param(param_file, mdl, "INTERNAL_TIDE_ENERGIZED_ANGLE", cs%energized_angle, &
2270  "If positive, only one angular band of the internal tides "//&
2271  "gets all of the energy. (This is for debugging.)", default=-1)
2272  call get_param(param_file, mdl, "USE_PPM_ANGULAR", cs%use_PPMang, &
2273  "If true, use PPM for advection of energy in angular space.", &
2274  default=.false.)
2275  call get_param(param_file, mdl, "GAMMA_ITIDES", cs%q_itides, &
2276  "The fraction of the internal tidal energy that is "//&
2277  "dissipated locally with INT_TIDE_DISSIPATION. "//&
2278  "THIS NAME COULD BE BETTER.", &
2279  units="nondim", default=0.3333)
2280  call get_param(param_file, mdl, "KAPPA_ITIDES", kappa_itides, &
2281  "A topographic wavenumber used with INT_TIDE_DISSIPATION. "//&
2282  "The default is 2pi/10 km, as in St.Laurent et al. 2002.", &
2283  units="m-1", default=8.e-4*atan(1.0), scale=us%L_to_m)
2284  call get_param(param_file, mdl, "KAPPA_H2_FACTOR", kappa_h2_factor, &
2285  "A scaling factor for the roughness amplitude with n"//&
2286  "INT_TIDE_DISSIPATION.", units="nondim", default=1.0)
2287 
2288  ! Allocate various arrays needed for loss rates
2289  allocate(h2(isd:ied,jsd:jed)) ; h2(:,:) = 0.0
2290  allocate(cs%TKE_itidal_loss_fixed(isd:ied,jsd:jed))
2291  cs%TKE_itidal_loss_fixed = 0.0
2292  allocate(cs%TKE_leak_loss(isd:ied,jsd:jed,num_angle,num_freq,num_mode))
2293  cs%TKE_leak_loss(:,:,:,:,:) = 0.0
2294  allocate(cs%TKE_quad_loss(isd:ied,jsd:jed,num_angle,num_freq,num_mode))
2295  cs%TKE_quad_loss(:,:,:,:,:) = 0.0
2296  allocate(cs%TKE_itidal_loss(isd:ied,jsd:jed,num_angle,num_freq,num_mode))
2297  cs%TKE_itidal_loss(:,:,:,:,:) = 0.0
2298  allocate(cs%TKE_Froude_loss(isd:ied,jsd:jed,num_angle,num_freq,num_mode))
2299  cs%TKE_Froude_loss(:,:,:,:,:) = 0.0
2300  allocate(cs%tot_leak_loss(isd:ied,jsd:jed)) ; cs%tot_leak_loss(:,:) = 0.0
2301  allocate(cs%tot_quad_loss(isd:ied,jsd:jed) ) ; cs%tot_quad_loss(:,:) = 0.0
2302  allocate(cs%tot_itidal_loss(isd:ied,jsd:jed)) ; cs%tot_itidal_loss(:,:) = 0.0
2303  allocate(cs%tot_Froude_loss(isd:ied,jsd:jed)) ; cs%tot_Froude_loss(:,:) = 0.0
2304 
2305  ! Compute the fixed part of the bottom drag loss from baroclinic modes
2306  call get_param(param_file, mdl, "H2_FILE", h2_file, &
2307  "The path to the file containing the sub-grid-scale "//&
2308  "topographic roughness amplitude with INT_TIDE_DISSIPATION.", &
2309  fail_if_missing=.true.)
2310  filename = trim(cs%inputdir) // trim(h2_file)
2311  call log_param(param_file, mdl, "INPUTDIR/H2_FILE", filename)
2312  call mom_read_data(filename, 'h2', h2, g%domain, timelevel=1, scale=us%m_to_Z)
2313  do j=g%jsc,g%jec ; do i=g%isc,g%iec
2314  ! Restrict rms topo to 10 percent of column depth.
2315  h2(i,j) = min(0.01*(g%bathyT(i,j))**2, h2(i,j))
2316  ! Compute the fixed part; units are [R L-2 Z3 ~> kg m-2] here
2317  ! will be multiplied by N and the squared near-bottom velocity to get into [R Z3 T-3 ~> W m-2]
2318  cs%TKE_itidal_loss_fixed(i,j) = 0.5*kappa_h2_factor*gv%Rho0 * us%L_to_Z*kappa_itides * h2(i,j)
2319  enddo ; enddo
2320 
2321  deallocate(h2)
2322 
2323  ! Read in prescribed coast/ridge/shelf angles from file
2324  call get_param(param_file, mdl, "REFL_ANGLE_FILE", refl_angle_file, &
2325  "The path to the file containing the local angle of "//&
2326  "the coastline/ridge/shelf with respect to the equator.", &
2327  fail_if_missing=.false., default='')
2328  filename = trim(cs%inputdir) // trim(refl_angle_file)
2329  allocate(cs%refl_angle(isd:ied,jsd:jed)) ; cs%refl_angle(:,:) = cs%nullangle
2330  if (file_exists(filename, g%domain)) then
2331  call log_param(param_file, mdl, "INPUTDIR/REFL_ANGLE_FILE", filename)
2332  call mom_read_data(filename, 'refl_angle', cs%refl_angle, &
2333  g%domain, timelevel=1)
2334  else
2335  if (trim(refl_angle_file) /= '' ) call mom_error(fatal, &
2336  "REFL_ANGLE_FILE: "//trim(filename)//" not found")
2337  endif
2338  ! replace NANs with null value
2339  do j=g%jsc,g%jec ; do i=g%isc,g%iec
2340  if (is_nan(cs%refl_angle(i,j))) cs%refl_angle(i,j) = cs%nullangle
2341  enddo ; enddo
2342  call pass_var(cs%refl_angle,g%domain)
2343 
2344  ! Read in prescribed partial reflection coefficients from file
2345  call get_param(param_file, mdl, "REFL_PREF_FILE", refl_pref_file, &
2346  "The path to the file containing the reflection coefficients.", &
2347  fail_if_missing=.false., default='')
2348  filename = trim(cs%inputdir) // trim(refl_pref_file)
2349  allocate(cs%refl_pref(isd:ied,jsd:jed)) ; cs%refl_pref(:,:) = 1.0
2350  if (file_exists(filename, g%domain)) then
2351  call log_param(param_file, mdl, "INPUTDIR/REFL_PREF_FILE", filename)
2352  call mom_read_data(filename, 'refl_pref', cs%refl_pref, g%domain, timelevel=1)
2353  else
2354  if (trim(refl_pref_file) /= '' ) call mom_error(fatal, &
2355  "REFL_PREF_FILE: "//trim(filename)//" not found")
2356  endif
2357  !CS%refl_pref = CS%refl_pref*1 ! adjust partial reflection if desired
2358  call pass_var(cs%refl_pref,g%domain)
2359 
2360  ! Tag reflection cells with partial reflection (done here for speed)
2361  allocate(cs%refl_pref_logical(isd:ied,jsd:jed)) ; cs%refl_pref_logical(:,:) = .false.
2362  do j=jsd,jed
2363  do i=isd,ied
2364  ! flag cells with partial reflection
2365  if (cs%refl_angle(i,j) /= cs%nullangle .and. &
2366  cs%refl_pref(i,j) < 1.0 .and. cs%refl_pref(i,j) > 0.0) then
2367  cs%refl_pref_logical(i,j) = .true.
2368  endif
2369  enddo
2370  enddo
2371 
2372  ! Read in double-reflective (ridge) tags from file
2373  call get_param(param_file, mdl, "REFL_DBL_FILE", refl_dbl_file, &
2374  "The path to the file containing the double-reflective ridge tags.", &
2375  fail_if_missing=.false., default='')
2376  filename = trim(cs%inputdir) // trim(refl_dbl_file)
2377  allocate(ridge_temp(isd:ied,jsd:jed)) ; ridge_temp(:,:) = 0.0
2378  if (file_exists(filename, g%domain)) then
2379  call log_param(param_file, mdl, "INPUTDIR/REFL_DBL_FILE", filename)
2380  call mom_read_data(filename, 'refl_dbl', ridge_temp, g%domain, timelevel=1)
2381  else
2382  if (trim(refl_dbl_file) /= '' ) call mom_error(fatal, &
2383  "REFL_DBL_FILE: "//trim(filename)//" not found")
2384  endif
2385  call pass_var(ridge_temp,g%domain)
2386  allocate(cs%refl_dbl(isd:ied,jsd:jed)) ; cs%refl_dbl(:,:) = .false.
2387  do i=isd,ied; do j=jsd,jed
2388  if (ridge_temp(i,j) == 1) then; cs%refl_dbl(i,j) = .true.
2389  else ; cs%refl_dbl(i,j) = .false. ; endif
2390  enddo ; enddo
2391 
2392  ! Read in prescribed land mask from file (if overwriting -BDM).
2393  ! This should be done in MOM_initialize_topography subroutine
2394  ! defined in MOM_fixed_initialization.F90 (BDM)
2395  !call get_param(param_file, mdl, "LAND_MASK_FILE", land_mask_file, &
2396  ! "The path to the file containing the land mask.", &
2397  ! fail_if_missing=.false.)
2398  !filename = trim(CS%inputdir) // trim(land_mask_file)
2399  !call log_param(param_file, mdl, "INPUTDIR/LAND_MASK_FILE", filename)
2400  !G%mask2dCu(:,:) = 1 ; G%mask2dCv(:,:) = 1 ; G%mask2dT(:,:) = 1
2401  !call MOM_read_data(filename, 'land_mask', G%mask2dCu, G%domain, timelevel=1)
2402  !call MOM_read_data(filename, 'land_mask', G%mask2dCv, G%domain, timelevel=1)
2403  !call MOM_read_data(filename, 'land_mask', G%mask2dT, G%domain, timelevel=1)
2404  !call pass_vector(G%mask2dCu, G%mask2dCv, G%domain, To_All+Scalar_Pair, CGRID_NE)
2405  !call pass_var(G%mask2dT,G%domain)
2406 
2407  ! Read in prescribed partial east face blockages from file (if overwriting -BDM)
2408  !call get_param(param_file, mdl, "dy_Cu_FILE", dy_Cu_file, &
2409  ! "The path to the file containing the east face blockages.", &
2410  ! fail_if_missing=.false.)
2411  !filename = trim(CS%inputdir) // trim(dy_Cu_file)
2412  !call log_param(param_file, mdl, "INPUTDIR/dy_Cu_FILE", filename)
2413  !G%dy_Cu(:,:) = 0.0
2414  !call MOM_read_data(filename, 'dy_Cu', G%dy_Cu, G%domain, timelevel=1, scale=US%m_to_L)
2415 
2416  ! Read in prescribed partial north face blockages from file (if overwriting -BDM)
2417  !call get_param(param_file, mdl, "dx_Cv_FILE", dx_Cv_file, &
2418  ! "The path to the file containing the north face blockages.", &
2419  ! fail_if_missing=.false.)
2420  !filename = trim(CS%inputdir) // trim(dx_Cv_file)
2421  !call log_param(param_file, mdl, "INPUTDIR/dx_Cv_FILE", filename)
2422  !G%dx_Cv(:,:) = 0.0
2423  !call MOM_read_data(filename, 'dx_Cv', G%dx_Cv, G%domain, timelevel=1, scale=US%m_to_L)
2424  !call pass_vector(G%dy_Cu, G%dx_Cv, G%domain, To_All+Scalar_Pair, CGRID_NE)
2425 
2426  ! Register maps of reflection parameters
2427  cs%id_refl_ang = register_diag_field('ocean_model', 'refl_angle', diag%axesT1, &
2428  time, 'Local angle of coastline/ridge/shelf with respect to equator', 'rad')
2429  cs%id_refl_pref = register_diag_field('ocean_model', 'refl_pref', diag%axesT1, &
2430  time, 'Partial reflection coefficients', '')
2431  cs%id_dx_Cv = register_diag_field('ocean_model', 'dx_Cv', diag%axesT1, &
2432  time, 'North face unblocked width', 'm', conversion=us%L_to_m)
2433  cs%id_dy_Cu = register_diag_field('ocean_model', 'dy_Cu', diag%axesT1, &
2434  time, 'East face unblocked width', 'm', conversion=us%L_to_m)
2435  cs%id_land_mask = register_diag_field('ocean_model', 'land_mask', diag%axesT1, &
2436  time, 'Land mask', 'logical') ! used if overriding (BDM)
2437  ! Output reflection parameters as diags here (not needed every timestep)
2438  if (cs%id_refl_ang > 0) call post_data(cs%id_refl_ang, cs%refl_angle, cs%diag)
2439  if (cs%id_refl_pref > 0) call post_data(cs%id_refl_pref, cs%refl_pref, cs%diag)
2440  if (cs%id_dx_Cv > 0) call post_data(cs%id_dx_Cv, g%dx_Cv, cs%diag)
2441  if (cs%id_dy_Cu > 0) call post_data(cs%id_dy_Cu, g%dy_Cu, cs%diag)
2442  if (cs%id_land_mask > 0) call post_data(cs%id_land_mask, g%mask2dT, cs%diag)
2443 
2444  ! Register 2-D energy density (summed over angles, freq, modes)
2445  cs%id_tot_En = register_diag_field('ocean_model', 'ITide_tot_En', diag%axesT1, &
2446  time, 'Internal tide total energy density', &
2447  'J m-2', conversion=us%RZ3_T3_to_W_m2*us%T_to_s)
2448  ! Register 2-D drag scale used for quadratic bottom drag
2449  cs%id_itide_drag = register_diag_field('ocean_model', 'ITide_drag', diag%axesT1, &
2450  time, 'Interior and bottom drag internal tide decay timescale', 's-1', conversion=us%s_to_T)
2451  !Register 2-D energy input into internal tides
2452  cs%id_TKE_itidal_input = register_diag_field('ocean_model', 'TKE_itidal_input', diag%axesT1, &
2453  time, 'Conversion from barotropic to baroclinic tide, '//&
2454  'a fraction of which goes into rays', &
2455  'W m-2', conversion=us%RZ3_T3_to_W_m2)
2456  ! Register 2-D energy losses (summed over angles, freq, modes)
2457  cs%id_tot_leak_loss = register_diag_field('ocean_model', 'ITide_tot_leak_loss', diag%axesT1, &
2458  time, 'Internal tide energy loss to background drag', &
2459  'W m-2', conversion=us%RZ3_T3_to_W_m2)
2460  cs%id_tot_quad_loss = register_diag_field('ocean_model', 'ITide_tot_quad_loss', diag%axesT1, &
2461  time, 'Internal tide energy loss to bottom drag', &
2462  'W m-2', conversion=us%RZ3_T3_to_W_m2)
2463  cs%id_tot_itidal_loss = register_diag_field('ocean_model', 'ITide_tot_itidal_loss', diag%axesT1, &
2464  time, 'Internal tide energy loss to wave drag', &
2465  'W m-2', conversion=us%RZ3_T3_to_W_m2)
2466  cs%id_tot_Froude_loss = register_diag_field('ocean_model', 'ITide_tot_Froude_loss', diag%axesT1, &
2467  time, 'Internal tide energy loss to wave breaking', &
2468  'W m-2', conversion=us%RZ3_T3_to_W_m2)
2469  cs%id_tot_allprocesses_loss = register_diag_field('ocean_model', 'ITide_tot_allprocesses_loss', diag%axesT1, &
2470  time, 'Internal tide energy loss summed over all processes', &
2471  'W m-2', conversion=us%RZ3_T3_to_W_m2)
2472 
2473  allocate(cs%id_En_mode(cs%nFreq,cs%nMode)) ; cs%id_En_mode(:,:) = -1
2474  allocate(cs%id_En_ang_mode(cs%nFreq,cs%nMode)) ; cs%id_En_ang_mode(:,:) = -1
2475  allocate(cs%id_itidal_loss_mode(cs%nFreq,cs%nMode)) ; cs%id_itidal_loss_mode(:,:) = -1
2476  allocate(cs%id_allprocesses_loss_mode(cs%nFreq,cs%nMode)) ; cs%id_allprocesses_loss_mode(:,:) = -1
2477  allocate(cs%id_itidal_loss_ang_mode(cs%nFreq,cs%nMode)) ; cs%id_itidal_loss_ang_mode(:,:) = -1
2478  allocate(cs%id_Ub_mode(cs%nFreq,cs%nMode)) ; cs%id_Ub_mode(:,:) = -1
2479  allocate(cs%id_cp_mode(cs%nFreq,cs%nMode)) ; cs%id_cp_mode(:,:) = -1
2480 
2481  allocate(angles(cs%NAngle)) ; angles(:) = 0.0
2482  angle_size = (8.0*atan(1.0)) / (real(num_angle))
2483  do a=1,num_angle ; angles(a) = (real(a) - 1) * Angle_size ; enddo
2484 
2485  id_ang = diag_axis_init("angle", angles, "Radians", "N", "Angular Orienation of Fluxes")
2486  call define_axes_group(diag, (/ diag%axesT1%handles(1), diag%axesT1%handles(2), id_ang /), axes_ang)
2487 
2488  do fr=1,cs%nFreq ; write(freq_name(fr), '("freq",i1)') fr ; enddo
2489  do m=1,cs%nMode ; do fr=1,cs%nFreq
2490  ! Register 2-D energy density (summed over angles) for each freq and mode
2491  write(var_name, '("Itide_En_freq",i1,"_mode",i1)') fr, m
2492  write(var_descript, '("Internal tide energy density in frequency ",i1," mode ",i1)') fr, m
2493  cs%id_En_mode(fr,m) = register_diag_field('ocean_model', var_name, &
2494  diag%axesT1, time, var_descript, 'J m-2', conversion=us%RZ3_T3_to_W_m2*us%T_to_s)
2495  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
2496 
2497  ! Register 3-D (i,j,a) energy density for each freq and mode
2498  write(var_name, '("Itide_En_ang_freq",i1,"_mode",i1)') fr, m
2499  write(var_descript, '("Internal tide angular energy density in frequency ",i1," mode ",i1)') fr, m
2500  cs%id_En_ang_mode(fr,m) = register_diag_field('ocean_model', var_name, &
2501  axes_ang, time, var_descript, 'J m-2 band-1', conversion=us%RZ3_T3_to_W_m2*us%T_to_s)
2502  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
2503 
2504  ! Register 2-D energy loss (summed over angles) for each freq and mode
2505  ! wave-drag only
2506  write(var_name, '("Itide_wavedrag_loss_freq",i1,"_mode",i1)') fr, m
2507  write(var_descript, '("Internal tide energy loss due to wave-drag from frequency ",i1," mode ",i1)') fr, m
2508  cs%id_itidal_loss_mode(fr,m) = register_diag_field('ocean_model', var_name, &
2509  diag%axesT1, time, var_descript, 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2510  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
2511  ! all loss processes
2512  write(var_name, '("Itide_allprocesses_loss_freq",i1,"_mode",i1)') fr, m
2513  write(var_descript, '("Internal tide energy loss due to all processes from frequency ",i1," mode ",i1)') fr, m
2514  cs%id_allprocesses_loss_mode(fr,m) = register_diag_field('ocean_model', var_name, &
2515  diag%axesT1, time, var_descript, 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2516  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
2517 
2518  ! Register 3-D (i,j,a) energy loss for each freq and mode
2519  ! wave-drag only
2520  write(var_name, '("Itide_wavedrag_loss_ang_freq",i1,"_mode",i1)') fr, m
2521  write(var_descript, '("Internal tide energy loss due to wave-drag from frequency ",i1," mode ",i1)') fr, m
2522  cs%id_itidal_loss_ang_mode(fr,m) = register_diag_field('ocean_model', var_name, &
2523  axes_ang, time, var_descript, 'W m-2 band-1', conversion=us%RZ3_T3_to_W_m2)
2524  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
2525 
2526  ! Register 2-D period-averaged near-bottom horizonal velocity for each freq and mode
2527  write(var_name, '("Itide_Ub_freq",i1,"_mode",i1)') fr, m
2528  write(var_descript, '("Near-bottom horizonal velocity for frequency ",i1," mode ",i1)') fr, m
2529  cs%id_Ub_mode(fr,m) = register_diag_field('ocean_model', var_name, &
2530  diag%axesT1, time, var_descript, 'm s-1', conversion=us%L_T_to_m_s)
2531  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
2532 
2533  ! Register 2-D horizonal phase velocity for each freq and mode
2534  write(var_name, '("Itide_cp_freq",i1,"_mode",i1)') fr, m
2535  write(var_descript, '("Horizonal phase velocity for frequency ",i1," mode ",i1)') fr, m
2536  cs%id_cp_mode(fr,m) = register_diag_field('ocean_model', var_name, &
2537  diag%axesT1, time, var_descript, 'm s-1', conversion=us%L_T_to_m_s)
2538  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
2539 
2540  enddo ; enddo
2541 
2542  ! Initialize wave_structure (not sure if this should be here - BDM)
2543  call wave_structure_init(time, g, param_file, diag, cs%wave_structure_CSp)
2544 

◆ itidal_lowmode_loss()

subroutine mom_internal_tides::itidal_lowmode_loss ( type(ocean_grid_type), intent(in)  G,
type(unit_scale_type), intent(in)  US,
type(int_tide_cs), pointer  CS,
real, dimension(g%isd:g%ied,g%jsd:g%jed), intent(in)  Nb,
real, dimension(g%isd:g%ied,g%jsd:g%jed,cs%nfreq,cs%nmode), intent(inout)  Ub,
real, dimension(g%isd:g%ied,g%jsd:g%jed,cs%nangle,cs%nfreq,cs%nmode), intent(inout)  En,
real, dimension(g%isd:g%ied,g%jsd:g%jed), intent(in)  TKE_loss_fixed,
real, dimension(g%isd:g%ied,g%jsd:g%jed,cs%nangle,cs%nfreq,cs%nmode), intent(out)  TKE_loss,
real, intent(in)  dt,
logical, intent(in), optional  full_halos 
)
private

Calculates the energy lost from the propagating internal tide due to scattering over small-scale roughness along the lines of Jayne & St. Laurent (2001).

Parameters
[in]gThe ocean's grid structure.
[in]usA dimensional unit scaling type
csThe control structure returned by a previous call to int_tide_init.
[in]nbNear-bottom stratification [T-1 ~> s-1].
[in,out]ubRMS (over one period) near-bottom horizontal
[in]tke_loss_fixedFixed part of energy loss [R L-2 Z3 ~> kg m-2]
[in,out]enEnergy density of the internal waves [R Z3 T-2 ~> J m-2].
[out]tke_lossEnergy loss rate [R Z3 T-3 ~> W m-2]
[in]dtTime increment [T ~> s].
[in]full_halosIf true, do the calculation over the entirecomputational domain.

Definition at line 636 of file MOM_internal_tides.F90.

636  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
637  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
638  type(int_tide_CS), pointer :: CS !< The control structure returned by a
639  !! previous call to int_tide_init.
640  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
641  intent(in) :: Nb !< Near-bottom stratification [T-1 ~> s-1].
642  real, dimension(G%isd:G%ied,G%jsd:G%jed,CS%nFreq,CS%nMode), &
643  intent(inout) :: Ub !< RMS (over one period) near-bottom horizontal
644  !! mode velocity [L T-1 ~> m s-1].
645  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
646  intent(in) :: TKE_loss_fixed !< Fixed part of energy loss [R L-2 Z3 ~> kg m-2]
647  !! (rho*kappa*h^2).
648  real, dimension(G%isd:G%ied,G%jsd:G%jed,CS%NAngle,CS%nFreq,CS%nMode), &
649  intent(inout) :: En !< Energy density of the internal waves [R Z3 T-2 ~> J m-2].
650  real, dimension(G%isd:G%ied,G%jsd:G%jed,CS%NAngle,CS%nFreq,CS%nMode), &
651  intent(out) :: TKE_loss !< Energy loss rate [R Z3 T-3 ~> W m-2]
652  !! (q*rho*kappa*h^2*N*U^2).
653  real, intent(in) :: dt !< Time increment [T ~> s].
654  logical,optional, intent(in) :: full_halos !< If true, do the calculation over the
655  !! entirecomputational domain.
656  ! Local variables
657  integer :: j,i,m,fr,a, is, ie, js, je
658  real :: En_tot ! energy for a given mode, frequency, and point summed over angles [R Z3 T-2 ~> J m-2]
659  real :: TKE_loss_tot ! dissipation for a given mode, frequency, and point summed over angles [R Z3 T-3 ~> W m-2]
660  real :: TKE_sum_check ! temporary for check summing
661  real :: frac_per_sector ! fraction of energy in each wedge
662  real :: q_itides ! fraction of energy actually lost to mixing (remainder, 1-q, is
663  ! assumed to stay in propagating mode for now - BDM)
664  real :: loss_rate ! approximate loss rate for implicit calc [T-1 ~> s-1]
665  real :: En_negl ! negilibly small number to prevent division by zero
666 
667  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
668 
669  q_itides = cs%q_itides
670  en_negl = 1e-30*us%kg_m3_to_R*us%m_to_Z**3*us%T_to_s**2
671 
672  if (present(full_halos)) then ; if (full_halos) then
673  is = g%isd ; ie = g%ied ; js = g%jsd ; je = g%jed
674  endif ; endif
675 
676  do j=js,je ; do i=is,ie ; do m=1,cs%nMode ; do fr=1,cs%nFreq
677 
678  ! Sum energy across angles
679  en_tot = 0.0
680  do a=1,cs%nAngle
681  en_tot = en_tot + en(i,j,a,fr,m)
682  enddo
683 
684  ! Calculate TKE loss rate; units of [R Z3 T-3 ~> W m-2] here.
685  tke_loss_tot = q_itides * tke_loss_fixed(i,j) * nb(i,j) * ub(i,j,fr,m)**2
686 
687  ! Update energy remaining (this is a pseudo implicit calc)
688  ! (E(t+1)-E(t))/dt = -TKE_loss(E(t+1)/E(t)), which goes to zero as E(t+1) goes to zero
689  if (en_tot > 0.0) then
690  do a=1,cs%nAngle
691  frac_per_sector = en(i,j,a,fr,m)/en_tot
692  tke_loss(i,j,a,fr,m) = frac_per_sector*tke_loss_tot ! Wm-2
693  loss_rate = tke_loss(i,j,a,fr,m) / (en(i,j,a,fr,m) + en_negl) ! [T-1 ~> s-1]
694  en(i,j,a,fr,m) = en(i,j,a,fr,m) / (1.0 + dt*loss_rate)
695  enddo
696  else
697  ! no loss if no energy
698  tke_loss(i,j,:,fr,m) = 0.0
699  endif
700 
701  ! Update energy remaining (this is the old explicit calc)
702  !if (En_tot > 0.0) then
703  ! do a=1,CS%nAngle
704  ! frac_per_sector = En(i,j,a,fr,m)/En_tot
705  ! TKE_loss(i,j,a,fr,m) = frac_per_sector*TKE_loss_tot
706  ! if (TKE_loss(i,j,a,fr,m)*dt <= En(i,j,a,fr,m))then
707  ! En(i,j,a,fr,m) = En(i,j,a,fr,m) - TKE_loss(i,j,a,fr,m)*dt
708  ! else
709  ! call MOM_error(WARNING, "itidal_lowmode_loss: energy loss greater than avalable, "// &
710  ! " setting En to zero.", all_print=.true.)
711  ! En(i,j,a,fr,m) = 0.0
712  ! endif
713  ! enddo
714  !else
715  ! ! no loss if no energy
716  ! TKE_loss(i,j,:,fr,m) = 0.0
717  !endif
718 
719  enddo ; enddo ; enddo ; enddo
720 

◆ merid_flux_en()

subroutine mom_internal_tides::merid_flux_en ( real, dimension( g %isd: g %ied), intent(in)  v,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  h,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  hL,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  hR,
real, dimension( g %isd: g %ied), intent(inout)  vh,
real, intent(in)  dt,
type(ocean_grid_type), intent(in)  G,
type(unit_scale_type), intent(in)  US,
integer, intent(in)  J,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, intent(in)  vol_CFL 
)
private

Evaluates the meridional mass or volume fluxes in a layer.

Parameters
[in]gThe ocean's grid structure.
[in]vThe meridional velocity [L T-1 ~> m s-1].
[in]hEnergy density used to calculate the fluxes [R Z3 T-2 ~> J m-2].
[in]hlLeft- Energy densities in the reconstruction [R Z3 T-2 ~> J m-2].
[in]hrRight- Energy densities in the reconstruction [R Z3 T-2 ~> J m-2].
[in,out]vhThe meridional energy transport [R Z3 L2 T-3 ~> J s-1].
[in]dtTime increment [T ~> s].
[in]usA dimensional unit scaling type
[in]jThe j-index to work on.
[in]ishThe start i-index range to work on.
[in]iehThe end i-index range to work on.
[in]vol_cflIf true, rescale the ratio of face areas to the cell areas when estimating the CFL number.

Definition at line 1559 of file MOM_internal_tides.F90.

1559  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1560  real, dimension(SZI_(G)), intent(in) :: v !< The meridional velocity [L T-1 ~> m s-1].
1561  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h !< Energy density used to calculate the
1562  !! fluxes [R Z3 T-2 ~> J m-2].
1563  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: hL !< Left- Energy densities in the
1564  !! reconstruction [R Z3 T-2 ~> J m-2].
1565  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: hR !< Right- Energy densities in the
1566  !! reconstruction [R Z3 T-2 ~> J m-2].
1567  real, dimension(SZI_(G)), intent(inout) :: vh !< The meridional energy transport [R Z3 L2 T-3 ~> J s-1].
1568  real, intent(in) :: dt !< Time increment [T ~> s].
1569  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1570  integer, intent(in) :: J !< The j-index to work on.
1571  integer, intent(in) :: ish !< The start i-index range to work on.
1572  integer, intent(in) :: ieh !< The end i-index range to work on.
1573  logical, intent(in) :: vol_CFL !< If true, rescale the ratio of face
1574  !! areas to the cell areas when estimating
1575  !! the CFL number.
1576  ! Local variables
1577  real :: CFL ! The CFL number based on the local velocity and grid spacing [nondim].
1578  real :: curv_3 ! A measure of the energy density curvature over a grid length [R Z3 T-2 ~> J m-2]
1579  integer :: i
1580 
1581  do i=ish,ieh
1582  if (v(i) > 0.0) then
1583  if (vol_cfl) then ; cfl = (v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j))
1584  else ; cfl = v(i) * dt * g%IdyT(i,j) ; endif
1585  curv_3 = hl(i,j) + hr(i,j) - 2.0*h(i,j)
1586  vh(i) = g%dx_Cv(i,j) * v(i) * ( hr(i,j) + cfl * &
1587  (0.5*(hl(i,j) - hr(i,j)) + curv_3*(cfl - 1.5)) )
1588  elseif (v(i) < 0.0) then
1589  if (vol_cfl) then ; cfl = (-v(i) * dt) * (g%dx_Cv(i,j) * g%IareaT(i,j+1))
1590  else ; cfl = -v(i) * dt * g%IdyT(i,j+1) ; endif
1591  curv_3 = hl(i,j+1) + hr(i,j+1) - 2.0*h(i,j+1)
1592  vh(i) = g%dx_Cv(i,j) * v(i) * ( hl(i,j+1) + cfl * &
1593  (0.5*(hr(i,j+1)-hl(i,j+1)) + curv_3*(cfl - 1.5)) )
1594  else
1595  vh(i) = 0.0
1596  endif
1597  enddo

◆ ppm_angular_advect()

subroutine mom_internal_tides::ppm_angular_advect ( real, dimension(1-halo_ang:nangle+halo_ang), intent(in)  En2d,
real, dimension(1-halo_ang:nangle+halo_ang), intent(in)  CFL_ang,
real, dimension(0:nangle), intent(out)  Flux_En,
integer, intent(in)  NAngle,
real, intent(in)  dt,
integer, intent(in)  halo_ang 
)
private

This subroutine calculates the 1-d flux for advection in angular space using a monotonic piecewise parabolic scheme. This needs to be called from within i and j spatial loops.

Parameters
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in]dtTime increment [T ~> s].
[in]halo_angThe halo size in angular space
[in]en2dThe internal gravity wave energy density as a
[in]cfl_angThe CFL number of the energy advection across angles
[out]flux_enThe time integrated internal wave energy flux across angles [R Z3 T-2 ~> J m-2].

Definition at line 876 of file MOM_internal_tides.F90.

876  integer, intent(in) :: NAngle !< The number of wave orientations in the
877  !! discretized wave energy spectrum.
878  real, intent(in) :: dt !< Time increment [T ~> s].
879  integer, intent(in) :: halo_ang !< The halo size in angular space
880  real, dimension(1-halo_ang:NAngle+halo_ang), &
881  intent(in) :: En2d !< The internal gravity wave energy density as a
882  !! function of angular resolution [R Z3 T-2 ~> J m-2].
883  real, dimension(1-halo_ang:NAngle+halo_ang), &
884  intent(in) :: CFL_ang !< The CFL number of the energy advection across angles
885  real, dimension(0:NAngle), intent(out) :: Flux_En !< The time integrated internal wave energy flux
886  !! across angles [R Z3 T-2 ~> J m-2].
887  ! Local variables
888  real :: flux
889  real :: u_ang ! Angular propagation speed [Rad T-1 ~> Rad s-1]
890  real :: Angle_size ! The size of each orientation wedge in radians [Rad]
891  real :: I_Angle_size ! The inverse of the the orientation wedges [Rad-1]
892  real :: I_dt ! The inverse of the timestep [T-1 ~> s-1]
893  real :: aR, aL ! Left and right edge estimates of energy density [R Z3 T-2 rad-1 ~> J m-2 rad-1]
894  real :: dMx, dMn
895  real :: Ep, Ec, Em ! Mean angular energy density for three successive wedges in angular
896  ! orientation [R Z3 T-2 rad-1 ~> J m-2 rad-1]
897  real :: dA, curv_3 ! Difference and curvature of energy density [R Z3 T-2 rad-1 ~> J m-2 rad-1]
898  real, parameter :: oneSixth = 1.0/6.0 ! One sixth [nondim]
899  integer :: a
900 
901  i_dt = 1 / dt
902  angle_size = (8.0*atan(1.0)) / (real(NAngle))
903  i_angle_size = 1 / angle_size
904  flux_en(:) = 0
905 
906  do a=0,nangle
907  u_ang = cfl_ang(a)*angle_size*i_dt
908  if (u_ang >= 0.0) then
909  ! Implementation of PPM-H3
910  ! Convert wedge-integrated energy density into angular energy densities for three successive
911  ! wedges around the source wedge for this flux [R Z3 T-2 rad-1 ~> J m-2 rad-1].
912  ep = en2d(a+1)*i_angle_size
913  ec = en2d(a) *i_angle_size
914  em = en2d(a-1)*i_angle_size
915  ! Calculate and bound edge values of energy density.
916  al = ( 5.*ec + ( 2.*em - ep ) ) * onesixth ! H3 estimate
917  al = max( min(ec,em), al) ; al = min( max(ec,em), al) ! Bound
918  ar = ( 5.*ec + ( 2.*ep - em ) ) * onesixth ! H3 estimate
919  ar = max( min(ec,ep), ar) ; ar = min( max(ec,ep), ar) ! Bound
920  da = ar - al
921  if ((ep-ec)*(ec-em) <= 0.) then
922  al = ec ; ar = ec ! use PCM for local extremum
923  elseif ( 3.0*da*(2.*ec - (ar + al)) > (da*da) ) then
924  al = 3.*ec - 2.*ar ! Flatten the profile to move the extremum to the left edge
925  elseif ( 3.0*da*(2.*ec - (ar + al)) < - (da*da) ) then
926  ar = 3.*ec - 2.*al ! Flatten the profile to move the extremum to the right edge
927  endif
928  curv_3 = (ar + al) - 2.0*ec ! Curvature
929  ! Calculate angular flux rate [R Z3 T-3 ~> W m-2]
930  flux = u_ang*( ar + cfl_ang(a) * ( 0.5*(al - ar) + curv_3 * (cfl_ang(a) - 1.5) ) )
931  ! Calculate amount of energy fluxed between wedges [R Z3 T-2 ~> J m-2]
932  flux_en(a) = dt * flux
933  !Flux_En(A) = (dt * I_Angle_size) * flux
934  else
935  ! Implementation of PPM-H3
936  ! Convert wedge-integrated energy density into angular energy densities for three successive
937  ! wedges around the source wedge for this flux [R Z3 T-2 rad-1 ~> J m-2 rad-1].
938  ep = en2d(a+2)*i_angle_size
939  ec = en2d(a+1)*i_angle_size
940  em = en2d(a) *i_angle_size
941  ! Calculate and bound edge values of energy density.
942  al = ( 5.*ec + ( 2.*em - ep ) ) * onesixth ! H3 estimate
943  al = max( min(ec,em), al) ; al = min( max(ec,em), al) ! Bound
944  ar = ( 5.*ec + ( 2.*ep - em ) ) * onesixth ! H3 estimate
945  ar = max( min(ec,ep), ar) ; ar = min( max(ec,ep), ar) ! Bound
946  da = ar - al
947  if ((ep-ec)*(ec-em) <= 0.) then
948  al = ec ; ar = ec ! use PCM for local extremum
949  elseif ( 3.0*da*(2.*ec - (ar + al)) > (da*da) ) then
950  al = 3.*ec - 2.*ar ! Flatten the profile to move the extremum to the left edge
951  elseif ( 3.0*da*(2.*ec - (ar + al)) < - (da*da) ) then
952  ar = 3.*ec - 2.*al ! Flatten the profile to move the extremum to the right edge
953  endif
954  curv_3 = (ar + al) - 2.0*ec ! Curvature
955  ! Calculate angular flux rate [R Z3 T-3 ~> W m-2]
956  ! Note that CFL_ang is negative here, so it looks odd compared with equivalent expressions.
957  flux = u_ang*( al - cfl_ang(a) * ( 0.5*(ar - al) + curv_3 * (-cfl_ang(a) - 1.5) ) )
958  ! Calculate amount of energy fluxed between wedges [R Z3 T-2 ~> J m-2]
959  flux_en(a) = dt * flux
960  !Flux_En(A) = (dt * I_Angle_size) * flux
961  endif
962  enddo

◆ ppm_limit_pos()

subroutine mom_internal_tides::ppm_limit_pos ( real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  h_in,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(inout)  h_L,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(inout)  h_R,
real, intent(in)  h_min,
type(ocean_grid_type), intent(in)  G,
integer, intent(in)  iis,
integer, intent(in)  iie,
integer, intent(in)  jis,
integer, intent(in)  jie 
)
private

Limits the left/right edge values of the PPM reconstruction to give a reconstruction that is positive-definite. Here this is reinterpreted as giving a constant thickness if the mean thickness is less than h_min, with a minimum of h_min otherwise.

Parameters
[in]gThe ocean's grid structure.
[in]h_inThickness of layer (2D).
[in,out]h_lLeft edge value (2D).
[in,out]h_rRight edge value (2D).
[in]h_minThe minimum thickness that can be obtained by a concave parabolic fit.
[in]iisStart i-index for computations
[in]iieEnd i-index for computations
[in]jisStart j-index for computations
[in]jieEnd j-index for computations

Definition at line 2022 of file MOM_internal_tides.F90.

2022  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2023  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Thickness of layer (2D).
2024  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_L !< Left edge value (2D).
2025  real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: h_R !< Right edge value (2D).
2026  real, intent(in) :: h_min !< The minimum thickness that can be
2027  !! obtained by a concave parabolic fit.
2028  integer, intent(in) :: iis !< Start i-index for computations
2029  integer, intent(in) :: iie !< End i-index for computations
2030  integer, intent(in) :: jis !< Start j-index for computations
2031  integer, intent(in) :: jie !< End j-index for computations
2032  ! Local variables
2033  real :: curv, dh, scale
2034  character(len=256) :: mesg ! The text of an error message
2035  integer :: i,j
2036 
2037  do j=jis,jie ; do i=iis,iie
2038  ! This limiter prevents undershooting minima within the domain with
2039  ! values less than h_min.
2040  curv = 3.0*(h_l(i,j) + h_r(i,j) - 2.0*h_in(i,j))
2041  if (curv > 0.0) then ! Only minima are limited.
2042  dh = h_r(i,j) - h_l(i,j)
2043  if (abs(dh) < curv) then ! The parabola's minimum is within the cell.
2044  if (h_in(i,j) <= h_min) then
2045  h_l(i,j) = h_in(i,j) ; h_r(i,j) = h_in(i,j)
2046  elseif (12.0*curv*(h_in(i,j) - h_min) < (curv**2 + 3.0*dh**2)) then
2047  ! The minimum value is h_in - (curv^2 + 3*dh^2)/(12*curv), and must
2048  ! be limited in this case. 0 < scale < 1.
2049  scale = 12.0*curv*(h_in(i,j) - h_min) / (curv**2 + 3.0*dh**2)
2050  h_l(i,j) = h_in(i,j) + scale*(h_l(i,j) - h_in(i,j))
2051  h_r(i,j) = h_in(i,j) + scale*(h_r(i,j) - h_in(i,j))
2052  endif
2053  endif
2054  endif
2055  enddo ; enddo

◆ ppm_reconstruction_x()

subroutine mom_internal_tides::ppm_reconstruction_x ( real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(in)  h_in,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(out)  h_l,
real, dimension( g %isd: g %ied, g %jsd: g %jed), intent(out)  h_r,
type(ocean_grid_type), intent(in)  G,
type(loop_bounds_type), intent(in)  LB,
logical, intent(in), optional  simple_2nd 
)
private

Calculates left/right edge values for PPM reconstruction in x-direction.

Parameters
[in]gThe ocean's grid structure.
[in]h_inEnergy density in a sector (2D).
[out]h_lLeft edge value of reconstruction (2D).
[out]h_rRight edge value of reconstruction (2D).
[in]lbA structure with the active loop bounds.
[in]simple_2ndIf true, use the arithmetic mean energy densities as default edge values for a simple 2nd order scheme.

Definition at line 1869 of file MOM_internal_tides.F90.

1869  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1870  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Energy density in a sector (2D).
1871  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_l !< Left edge value of reconstruction (2D).
1872  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_r !< Right edge value of reconstruction (2D).
1873  type(loop_bounds_type), intent(in) :: LB !< A structure with the active loop bounds.
1874  logical, optional, intent(in) :: simple_2nd !< If true, use the arithmetic mean
1875  !! energy densities as default edge values
1876  !! for a simple 2nd order scheme.
1877  ! Local variables
1878  real, dimension(SZI_(G),SZJ_(G)) :: slp ! The slopes.
1879  real, parameter :: oneSixth = 1./6.
1880  real :: h_ip1, h_im1
1881  real :: dMx, dMn
1882  logical :: use_CW84, use_2nd
1883  character(len=256) :: mesg ! The text of an error message
1884  integer :: i, j, isl, iel, jsl, jel, stencil
1885 
1886  use_2nd = .false. ; if (present(simple_2nd)) use_2nd = simple_2nd
1887  isl = lb%ish-1 ; iel = lb%ieh+1 ; jsl = lb%jsh ; jel = lb%jeh
1888 
1889  ! This is the stencil of the reconstruction, not the scheme overall.
1890  stencil = 2 ; if (use_2nd) stencil = 1
1891 
1892  if ((isl-stencil < g%isd) .or. (iel+stencil > g%ied)) then
1893  write(mesg,'("In MOM_internal_tides, PPM_reconstruction_x called with a ", &
1894  & "x-halo that needs to be increased by ",i2,".")') &
1895  stencil + max(g%isd-isl,iel-g%ied)
1896  call mom_error(fatal,mesg)
1897  endif
1898  if ((jsl < g%jsd) .or. (jel > g%jed)) then
1899  write(mesg,'("In MOM_internal_tides, PPM_reconstruction_x called with a ", &
1900  & "y-halo that needs to be increased by ",i2,".")') &
1901  max(g%jsd-jsl,jel-g%jed)
1902  call mom_error(fatal,mesg)
1903  endif
1904 
1905  if (use_2nd) then
1906  do j=jsl,jel ; do i=isl,iel
1907  h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1908  h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1909  h_l(i,j) = 0.5*( h_im1 + h_in(i,j) )
1910  h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) )
1911  enddo ; enddo
1912  else
1913  do j=jsl,jel ; do i=isl-1,iel+1
1914  if ((g%mask2dT(i-1,j) * g%mask2dT(i,j) * g%mask2dT(i+1,j)) == 0.0) then
1915  slp(i,j) = 0.0
1916  else
1917  ! This uses a simple 2nd order slope.
1918  slp(i,j) = 0.5 * (h_in(i+1,j) - h_in(i-1,j))
1919  ! Monotonic constraint, see Eq. B2 in Lin 1994, MWR (132)
1920  dmx = max(h_in(i+1,j), h_in(i-1,j), h_in(i,j)) - h_in(i,j)
1921  dmn = h_in(i,j) - min(h_in(i+1,j), h_in(i-1,j), h_in(i,j))
1922  slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1923  ! * (G%mask2dT(i-1,j) * G%mask2dT(i,j) * G%mask2dT(i+1,j))
1924  endif
1925  enddo ; enddo
1926 
1927  do j=jsl,jel ; do i=isl,iel
1928  ! Neighboring values should take into account any boundaries. The 3
1929  ! following sets of expressions are equivalent.
1930  ! h_im1 = h_in(i-1,j,k) ; if (G%mask2dT(i-1,j) < 0.5) h_im1 = h_in(i,j)
1931  ! h_ip1 = h_in(i+1,j,k) ; if (G%mask2dT(i+1,j) < 0.5) h_ip1 = h_in(i,j)
1932  h_im1 = g%mask2dT(i-1,j) * h_in(i-1,j) + (1.0-g%mask2dT(i-1,j)) * h_in(i,j)
1933  h_ip1 = g%mask2dT(i+1,j) * h_in(i+1,j) + (1.0-g%mask2dT(i+1,j)) * h_in(i,j)
1934  ! Left/right values following Eq. B2 in Lin 1994, MWR (132)
1935  h_l(i,j) = 0.5*( h_im1 + h_in(i,j) ) + onesixth*( slp(i-1,j) - slp(i,j) )
1936  h_r(i,j) = 0.5*( h_ip1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i+1,j) )
1937  enddo ; enddo
1938  endif
1939 
1940  call ppm_limit_pos(h_in, h_l, h_r, 0.0, g, isl, iel, jsl, jel)

◆ ppm_reconstruction_y()

subroutine mom_internal_tides::ppm_reconstruction_y ( real, dimension(szi_(g),szj_(g)), intent(in)  h_in,
real, dimension(szi_(g),szj_(g)), intent(out)  h_l,
real, dimension(szi_(g),szj_(g)), intent(out)  h_r,
type(ocean_grid_type), intent(in)  G,
type(loop_bounds_type), intent(in)  LB,
logical, intent(in), optional  simple_2nd 
)
private

Calculates left/right edge valus for PPM reconstruction in y-direction.

Parameters
[in]gThe ocean's grid structure.
[in]h_inEnergy density in a sector (2D).
[out]h_lLeft edge value of reconstruction (2D).
[out]h_rRight edge value of reconstruction (2D).
[in]lbA structure with the active loop bounds.
[in]simple_2ndIf true, use the arithmetic mean energy densities as default edge values for a simple 2nd order scheme.

Definition at line 1945 of file MOM_internal_tides.F90.

1945  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1946  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h_in !< Energy density in a sector (2D).
1947  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_l !< Left edge value of reconstruction (2D).
1948  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: h_r !< Right edge value of reconstruction (2D).
1949  type(loop_bounds_type), intent(in) :: LB !< A structure with the active loop bounds.
1950  logical, optional, intent(in) :: simple_2nd !< If true, use the arithmetic mean
1951  !! energy densities as default edge values
1952  !! for a simple 2nd order scheme.
1953  ! Local variables
1954  real, dimension(SZI_(G),SZJ_(G)) :: slp ! The slopes.
1955  real, parameter :: oneSixth = 1./6.
1956  real :: h_jp1, h_jm1
1957  real :: dMx, dMn
1958  logical :: use_2nd
1959  character(len=256) :: mesg ! The text of an error message
1960  integer :: i, j, isl, iel, jsl, jel, stencil
1961 
1962  use_2nd = .false. ; if (present(simple_2nd)) use_2nd = simple_2nd
1963  isl = lb%ish ; iel = lb%ieh ; jsl = lb%jsh-1 ; jel = lb%jeh+1
1964 
1965  ! This is the stencil of the reconstruction, not the scheme overall.
1966  stencil = 2 ; if (use_2nd) stencil = 1
1967 
1968  if ((isl < g%isd) .or. (iel > g%ied)) then
1969  write(mesg,'("In MOM_internal_tides, PPM_reconstruction_y called with a ", &
1970  & "x-halo that needs to be increased by ",i2,".")') &
1971  max(g%isd-isl,iel-g%ied)
1972  call mom_error(fatal,mesg)
1973  endif
1974  if ((jsl-stencil < g%jsd) .or. (jel+stencil > g%jed)) then
1975  write(mesg,'("In MOM_internal_tides, PPM_reconstruction_y called with a ", &
1976  & "y-halo that needs to be increased by ",i2,".")') &
1977  stencil + max(g%jsd-jsl,jel-g%jed)
1978  call mom_error(fatal,mesg)
1979  endif
1980 
1981  if (use_2nd) then
1982  do j=jsl,jel ; do i=isl,iel
1983  h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
1984  h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
1985  h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) )
1986  h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) )
1987  enddo ; enddo
1988  else
1989  do j=jsl-1,jel+1 ; do i=isl,iel
1990  if ((g%mask2dT(i,j-1) * g%mask2dT(i,j) * g%mask2dT(i,j+1)) == 0.0) then
1991  slp(i,j) = 0.0
1992  else
1993  ! This uses a simple 2nd order slope.
1994  slp(i,j) = 0.5 * (h_in(i,j+1) - h_in(i,j-1))
1995  ! Monotonic constraint, see Eq. B2 in Lin 1994, MWR (132)
1996  dmx = max(h_in(i,j+1), h_in(i,j-1), h_in(i,j)) - h_in(i,j)
1997  dmn = h_in(i,j) - min(h_in(i,j+1), h_in(i,j-1), h_in(i,j))
1998  slp(i,j) = sign(1.,slp(i,j)) * min(abs(slp(i,j)), 2. * min(dmx, dmn))
1999  ! * (G%mask2dT(i,j-1) * G%mask2dT(i,j) * G%mask2dT(i,j+1))
2000  endif
2001  enddo ; enddo
2002 
2003  do j=jsl,jel ; do i=isl,iel
2004  ! Neighboring values should take into account any boundaries. The 3
2005  ! following sets of expressions are equivalent.
2006  h_jm1 = g%mask2dT(i,j-1) * h_in(i,j-1) + (1.0-g%mask2dT(i,j-1)) * h_in(i,j)
2007  h_jp1 = g%mask2dT(i,j+1) * h_in(i,j+1) + (1.0-g%mask2dT(i,j+1)) * h_in(i,j)
2008  ! Left/right values following Eq. B2 in Lin 1994, MWR (132)
2009  h_l(i,j) = 0.5*( h_jm1 + h_in(i,j) ) + onesixth*( slp(i,j-1) - slp(i,j) )
2010  h_r(i,j) = 0.5*( h_jp1 + h_in(i,j) ) + onesixth*( slp(i,j) - slp(i,j+1) )
2011  enddo ; enddo
2012  endif
2013 
2014  call ppm_limit_pos(h_in, h_l, h_r, 0.0, g, isl, iel, jsl, jel)

◆ propagate()

subroutine mom_internal_tides::propagate ( real, dimension(g%isd:g%ied,g%jsd:g%jed,nangle), intent(inout)  En,
real, dimension(g%isd:g%ied,g%jsd:g%jed), intent(in)  cn,
real, intent(in)  freq,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(unit_scale_type), intent(in)  US,
type(int_tide_cs), pointer  CS,
integer, intent(in)  NAngle 
)
private

Propagates internal waves at a single frequency.

Parameters
[in,out]gThe ocean's grid structure.
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in,out]enThe internal gravity wave energy density as a
[in]cnBaroclinic mode speed [L T-1 ~> m s-1].
[in]freqWave frequency [T-1 ~> s-1].
[in]dtTime step [T ~> s].
[in]usA dimensional unit scaling type
csThe control structure returned by a previous call to int_tide_init.

Definition at line 967 of file MOM_internal_tides.F90.

967  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
968  integer, intent(in) :: NAngle !< The number of wave orientations in the
969  !! discretized wave energy spectrum.
970  real, dimension(G%isd:G%ied,G%jsd:G%jed,NAngle), &
971  intent(inout) :: En !< The internal gravity wave energy density as a
972  !! function of space and angular resolution,
973  !! [R Z3 T-2 ~> J m-2].
974  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
975  intent(in) :: cn !< Baroclinic mode speed [L T-1 ~> m s-1].
976  real, intent(in) :: freq !< Wave frequency [T-1 ~> s-1].
977  real, intent(in) :: dt !< Time step [T ~> s].
978  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
979  type(int_tide_CS), pointer :: CS !< The control structure returned by a
980  !! previous call to int_tide_init.
981  ! Local variables
982  real, dimension(G%IsdB:G%IedB,G%JsdB:G%JedB) :: &
983  speed ! The magnitude of the group velocity at the q points for corner adv [L T-1 ~> m s-1].
984  integer, parameter :: stencil = 2
985  real, dimension(SZIB_(G),SZJ_(G)) :: &
986  speed_x ! The magnitude of the group velocity at the Cu points [L T-1 ~> m s-1].
987  real, dimension(SZI_(G),SZJB_(G)) :: &
988  speed_y ! The magnitude of the group velocity at the Cv points [L T-1 ~> m s-1].
989  real, dimension(0:NAngle) :: &
990  cos_angle, sin_angle
991  real, dimension(NAngle) :: &
992  Cgx_av, Cgy_av, dCgx, dCgy
993  real :: f2 ! The squared Coriolis parameter [T-2 ~> s-2].
994  real :: Angle_size, I_Angle_size, angle
995  real :: Ifreq ! The inverse of the frequency [T ~> s]
996  real :: freq2 ! The frequency squared [T-2 ~> s-2]
997  type(loop_bounds_type) :: LB
998  integer :: is, ie, js, je, asd, aed, na
999  integer :: ish, ieh, jsh, jeh
1000  integer :: i, j, a
1001 
1002  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; na = size(en,3)
1003  asd = 1-stencil ; aed = nangle+stencil
1004 
1005  ifreq = 1.0 / freq
1006  freq2 = freq**2
1007 
1008  ! Define loop bounds: Need extensions on j-loop so propagate_y
1009  ! (done after propagate_x) will have updated values in the halo
1010  ! for correct PPM reconstruction. Use if no teleporting and
1011  ! no pass_var between propagate_x and propagate_y.
1012  !jsh = js-3 ; jeh = je+3 ; ish = is ; ieh = ie
1013 
1014  ! Define loop bounds: Need 1-pt extensions on loops because
1015  ! teleporting eats up a halo point. Use if teleporting.
1016  ! Also requires pass_var before propagate_y.
1017  jsh = js-1 ; jeh = je+1 ; ish = is-1 ; ieh = ie+1
1018 
1019  angle_size = (8.0*atan(1.0)) / real(NAngle)
1020  i_angle_size = 1.0 / angle_size
1021 
1022  if (cs%corner_adv) then
1023  ! IMPLEMENT CORNER ADVECTION IN HORIZONTAL--------------------
1024  ! FIND AVERAGE GROUP VELOCITY (SPEED) AT CELL CORNERS
1025  ! NOTE: THIS HAS NOT BE ADAPTED FOR REFLECTION YET (BDM)!!
1026  ! Fix indexing here later
1027  speed(:,:) = 0.0
1028  do j=jsh-1,jeh ; do i=ish-1,ieh
1029  f2 = g%CoriolisBu(i,j)**2
1030  speed(i,j) = 0.25*(cn(i,j) + cn(i+1,j) + cn(i+1,j+1) + cn(i,j+1)) * &
1031  sqrt(max(freq2 - f2, 0.0)) * ifreq
1032  enddo ; enddo
1033  do a=1,na
1034  ! Apply the propagation WITH CORNER ADVECTION/FINITE VOLUME APPROACH.
1035  lb%jsh = js ; lb%jeh = je ; lb%ish = is ; lb%ieh = ie
1036  call propagate_corner_spread(en(:,:,a), a, nangle, speed, dt, g, cs, lb)
1037  enddo ! a-loop
1038  else
1039  ! IMPLEMENT PPM ADVECTION IN HORIZONTAL-----------------------
1040  ! These could be in the control structure, as they do not vary.
1041  do a=0,na
1042  ! These are the angles at the cell edges...
1043  angle = (real(A) - 0.5) * Angle_size
1044  cos_angle(a) = cos(angle) ; sin_angle(a) = sin(angle)
1045  enddo
1046 
1047  do a=1,na
1048  cgx_av(a) = (sin_angle(a) - sin_angle(a-1)) * i_angle_size
1049  cgy_av(a) = -(cos_angle(a) - cos_angle(a-1)) * i_angle_size
1050  dcgx(a) = sqrt(0.5 + 0.5*(sin_angle(a)*cos_angle(a) - &
1051  sin_angle(a-1)*cos_angle(a-1)) * i_angle_size - &
1052  cgx_av(a)**2)
1053  dcgy(a) = sqrt(0.5 - 0.5*(sin_angle(a)*cos_angle(a) - &
1054  sin_angle(a-1)*cos_angle(a-1)) * i_angle_size - &
1055  cgy_av(a)**2)
1056  enddo
1057 
1058  do j=jsh,jeh ; do i=ish-1,ieh
1059  f2 = 0.5 * (g%CoriolisBu(i,j)**2 + g%CoriolisBu(i,j-1)**2)
1060  speed_x(i,j) = 0.5*(cn(i,j) + cn(i+1,j)) * g%mask2dCu(i,j) * &
1061  sqrt(max(freq2 - f2, 0.0)) * ifreq
1062  enddo ; enddo
1063  do j=jsh-1,jeh ; do i=ish,ieh
1064  f2 = 0.5 * (g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j)**2)
1065  speed_y(i,j) = 0.5*(cn(i,j) + cn(i,j+1)) * g%mask2dCv(i,j) * &
1066  sqrt(max(freq2 - f2, 0.0)) * ifreq
1067  enddo ; enddo
1068 
1069  ! Apply propagation in x-direction (reflection included)
1070  lb%jsh = jsh ; lb%jeh = jeh ; lb%ish = ish ; lb%ieh = ieh
1071  call propagate_x(en, speed_x, cgx_av, dcgx, dt, g, us, cs%nAngle, cs, lb)
1072 
1073  ! Check for energy conservation on computational domain (for debugging)
1074  !call sum_En(G, CS, En, 'post-propagate_x')
1075 
1076  ! Update halos
1077  call pass_var(en, g%domain)
1078 
1079  ! Apply propagation in y-direction (reflection included)
1080  ! LB%jsh = js ; LB%jeh = je ; LB%ish = is ; LB%ieh = ie ! Use if no teleport
1081  lb%jsh = jsh ; lb%jeh = jeh ; lb%ish = ish ; lb%ieh = ieh
1082  call propagate_y(en, speed_y, cgy_av, dcgy, dt, g, us, cs%nAngle, cs, lb)
1083 
1084  ! Check for energy conservation on computational domain (for debugging)
1085  !call sum_En(G, CS, En, 'post-propagate_y')
1086  endif
1087 

◆ propagate_corner_spread()

subroutine mom_internal_tides::propagate_corner_spread ( real, dimension(g%isd:g%ied,g%jsd:g%jed), intent(inout)  En,
integer, intent(in)  energized_wedge,
integer, intent(in)  NAngle,
real, dimension(g%isdb:g%iedb,g%jsd:g%jed), intent(in)  speed,
real, intent(in)  dt,
type(ocean_grid_type), intent(in)  G,
type(int_tide_cs), pointer  CS,
type(loop_bounds_type), intent(in)  LB 
)
private

This subroutine does first-order corner advection. It was written with the hopes of smoothing out the garden sprinkler effect, but is too numerically diffusive to be of much use as of yet. It is not yet compatible with reflection schemes (BDM).

Parameters
[in]gThe ocean's grid structure.
[in,out]enThe energy density integrated over an angular
[in]speedThe magnitude of the group velocity at the cell
[in]energized_wedgeIndex of current ray direction.
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in]dtTime increment [T ~> s].
csThe control structure returned by a previous call to continuity_PPM_init.
[in]lbA structure with the active energy loop bounds.

Definition at line 1094 of file MOM_internal_tides.F90.

1094  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1095  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
1096  intent(inout) :: En !< The energy density integrated over an angular
1097  !! band [R Z3 T-2 ~> J m-2].
1098  real, dimension(G%IsdB:G%IedB,G%Jsd:G%Jed), &
1099  intent(in) :: speed !< The magnitude of the group velocity at the cell
1100  !! corner points [L T-1 ~> m s-1].
1101  integer, intent(in) :: energized_wedge !< Index of current ray direction.
1102  integer, intent(in) :: NAngle !< The number of wave orientations in the
1103  !! discretized wave energy spectrum.
1104  real, intent(in) :: dt !< Time increment [T ~> s].
1105  type(int_tide_CS), pointer :: CS !< The control structure returned by a previous
1106  !! call to continuity_PPM_init.
1107  type(loop_bounds_type), intent(in) :: LB !< A structure with the active energy loop bounds.
1108  ! Local variables
1109  integer :: i, j, k, ish, ieh, jsh, jeh, m
1110  real :: TwoPi, Angle_size
1111  real :: energized_angle ! angle through center of current wedge
1112  real :: theta ! angle at edge of wedge
1113  real :: Nsubrays ! number of sub-rays for averaging
1114  ! count includes the two rays that bound the current wedge,
1115  ! i.e. those at -dtheta/2 and +dtheta/2 from energized angle
1116  real :: I_Nsubwedges ! inverse of number of sub-wedges
1117  real :: cos_thetaDT, sin_thetaDT ! cos(theta)*dt, sin(theta)*dt
1118  real :: xNE,xNW,xSW,xSE,yNE,yNW,ySW,ySE ! corner point coordinates of advected fluid parcel
1119  real :: CFL_xNE,CFL_xNW,CFL_xSW,CFL_xSE,CFL_yNE,CFL_yNW,CFL_ySW,CFL_ySE,CFL_max
1120  real :: xN,xS,xE,xW,yN,yS,yE,yW ! intersection point coordinates of parcel edges and grid
1121  real :: xCrn,yCrn ! grid point contained within advected fluid parcel
1122  real :: xg,yg ! grid point of interest
1123  real :: slopeN,slopeW,slopeS,slopeE, bN,bW,bS,bE ! parameters defining parcel sides
1124  real :: aNE,aN,aNW,aW,aSW,aS,aSE,aE,aC ! sub-areas of advected parcel
1125  real :: a_total ! total area of advected parcel
1126  real :: a1,a2,a3,a4 ! areas used in calculating polygon areas (sub-areas) of advected parcel
1127  real, dimension(G%IsdB:G%IedB,G%Jsd:G%Jed) :: x,y ! coordinates of cell corners
1128  real, dimension(G%IsdB:G%IedB,G%Jsd:G%Jed) :: Idx,Idy ! inverse of dx,dy at cell corners
1129  real, dimension(G%IsdB:G%IedB,G%Jsd:G%Jed) :: dx,dy ! dx,dy at cell corners
1130  real, dimension(2) :: E_new ! Energy in cell after advection for subray [R Z3 T-2 ~> J m-2]; set size
1131  ! here to define Nsubrays - this should be made an input option later!
1132 
1133  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh
1134  twopi = (8.0*atan(1.0))
1135  nsubrays = real(size(E_new))
1136  i_nsubwedges = 1./(nsubrays - 1)
1137 
1138  angle_size = twopi / real(NAngle)
1139  energized_angle = angle_size * real(energized_wedge - 1) ! for a=1 aligned with x-axis
1140  !energized_angle = Angle_size * real(energized_wedge - 1) + 2.0*Angle_size !
1141  !energized_angle = Angle_size * real(energized_wedge - 1) + 0.5*Angle_size !
1142  do j=jsh-1,jeh ; do i=ish-1,ieh
1143  ! This will only work for a Cartesian grid for which G%geoLonBu is in the same units has dx.
1144  ! This needs to be extensively revised to work for a general grid.
1145  x(i,j) = g%US%m_to_L*g%geoLonBu(i,j)
1146  y(i,j) = g%US%m_to_L*g%geoLatBu(i,j)
1147  idx(i,j) = g%IdxBu(i,j) ; dx(i,j) = g%dxBu(i,j)
1148  idy(i,j) = g%IdyBu(i,j) ; dy(i,j) = g%dyBu(i,j)
1149  enddo ; enddo
1150 
1151  do j=jsh,jeh ; do i=ish,ieh
1152  do m=1,int(nsubrays)
1153  theta = energized_angle - 0.5*angle_size + real(m - 1)*Angle_size*I_Nsubwedges
1154  if (theta < 0.0) then
1155  theta = theta + twopi
1156  elseif (theta > twopi) then
1157  theta = theta - twopi
1158  endif
1159  cos_thetadt = cos(theta)*dt
1160  sin_thetadt = sin(theta)*dt
1161 
1162  ! corner point coordinates of advected fluid parcel ----------
1163  xg = x(i,j); yg = y(i,j)
1164  xne = xg - speed(i,j)*cos_thetadt
1165  yne = yg - speed(i,j)*sin_thetadt
1166  cfl_xne = (xg-xne)*idx(i,j)
1167  cfl_yne = (yg-yne)*idy(i,j)
1168 
1169  xg = x(i-1,j); yg = y(i-1,j)
1170  xnw = xg - speed(i-1,j)*cos_thetadt
1171  ynw = yg - speed(i-1,j)*sin_thetadt
1172  cfl_xnw = (xg-xnw)*idx(i-1,j)
1173  cfl_ynw = (yg-ynw)*idy(i-1,j)
1174 
1175  xg = x(i-1,j-1); yg = y(i-1,j-1)
1176  xsw = xg - speed(i-1,j-1)*cos_thetadt
1177  ysw = yg - speed(i-1,j-1)*sin_thetadt
1178  cfl_xsw = (xg-xsw)*idx(i-1,j-1)
1179  cfl_ysw = (yg-ysw)*idy(i-1,j-1)
1180 
1181  xg = x(i,j-1); yg = y(i,j-1)
1182  xse = xg - speed(i,j-1)*cos_thetadt
1183  yse = yg - speed(i,j-1)*sin_thetadt
1184  cfl_xse = (xg-xse)*idx(i,j-1)
1185  cfl_yse = (yg-yse)*idy(i,j-1)
1186 
1187  cfl_max = max(abs(cfl_xne),abs(cfl_xnw),abs(cfl_xsw), &
1188  abs(cfl_xse),abs(cfl_yne),abs(cfl_ynw), &
1189  abs(cfl_ysw),abs(cfl_yse))
1190  if (cfl_max > 1.0) then
1191  call mom_error(warning, "propagate_corner_spread: CFL exceeds 1.", .true.)
1192  endif
1193 
1194  ! intersection point coordinates of parcel edges and cell edges ---
1195  if (0.0 <= theta .and. theta < 0.25*twopi) then
1196  xn = x(i-1,j-1)
1197  yw = y(i-1,j-1)
1198  elseif (0.25*twopi <= theta .and. theta < 0.5*twopi) then
1199  xn = x(i,j-1)
1200  yw = y(i,j-1)
1201  elseif (0.5*twopi <= theta .and. theta < 0.75*twopi) then
1202  xn = x(i,j)
1203  yw = y(i,j)
1204  elseif (0.75*twopi <= theta .and. theta <= 1.00*twopi) then
1205  xn = x(i-1,j)
1206  yw = y(i-1,j)
1207  endif
1208  xs = xn
1209  ye = yw
1210 
1211  ! north intersection
1212  slopen = (yne - ynw)/(xne - xnw)
1213  bn = -slopen*xne + yne
1214  yn = slopen*xn + bn
1215  ! west intersection
1216  if (xnw == xsw) then
1217  xw = xnw
1218  else
1219  slopew = (ynw - ysw)/(xnw - xsw)
1220  bw = -slopew*xnw + ynw
1221  xw = (yw - bw)/slopew
1222  endif
1223  ! south intersection
1224  slopes = (ysw - yse)/(xsw - xse)
1225  bs = -slopes*xsw + ysw
1226  ys = slopes*xs + bs
1227  ! east intersection
1228  if (xne == xse) then
1229  xe = xne
1230  else
1231  slopee = (yse - yne)/(xse - xne)
1232  be = -slopee*xse + yse
1233  xe = (ye - be)/slopee
1234  endif
1235 
1236  ! areas --------------------------------------------
1237  ane = 0.0; an = 0.0; anw = 0.0; ! initialize areas
1238  aw = 0.0; asw = 0.0; as = 0.0; ! initialize areas
1239  ase = 0.0; ae = 0.0; ac = 0.0; ! initialize areas
1240  if (0.0 <= theta .and. theta < 0.25*twopi) then
1241  xcrn = x(i-1,j-1); ycrn = y(i-1,j-1)
1242  ! west area
1243  a1 = (yn - ycrn)*(0.5*(xn + xcrn))
1244  a2 = (ycrn - yw)*(0.5*(xcrn + xw))
1245  a3 = (yw - ynw)*(0.5*(xw + xnw))
1246  a4 = (ynw - yn)*(0.5*(xnw + xn))
1247  aw = a1 + a2 + a3 + a4
1248  ! southwest area
1249  a1 = (ycrn - ys)*(0.5*(xcrn + xs))
1250  a2 = (ys - ysw)*(0.5*(xs + xsw))
1251  a3 = (ysw - yw)*(0.5*(xsw + xw))
1252  a4 = (yw - ycrn)*(0.5*(xw + xcrn))
1253  asw = a1 + a2 + a3 + a4
1254  ! south area
1255  a1 = (ye - yse)*(0.5*(xe + xse))
1256  a2 = (yse - ys)*(0.5*(xse + xs))
1257  a3 = (ys - ycrn)*(0.5*(xs + xcrn))
1258  a4 = (ycrn - ye)*(0.5*(xcrn + xe))
1259  as = a1 + a2 + a3 + a4
1260  ! area within cell
1261  a1 = (yne - ye)*(0.5*(xne + xe))
1262  a2 = (ye - ycrn)*(0.5*(xe + xcrn))
1263  a3 = (ycrn - yn)*(0.5*(xcrn + xn))
1264  a4 = (yn - yne)*(0.5*(xn + xne))
1265  ac = a1 + a2 + a3 + a4
1266  elseif (0.25*twopi <= theta .and. theta < 0.5*twopi) then
1267  xcrn = x(i,j-1); ycrn = y(i,j-1)
1268  ! south area
1269  a1 = (ycrn - ys)*(0.5*(xcrn + xs))
1270  a2 = (ys - ysw)*(0.5*(xs + xsw))
1271  a3 = (ysw - yw)*(0.5*(xsw + xw))
1272  a4 = (yw - ycrn)*(0.5*(xw + xcrn))
1273  as = a1 + a2 + a3 + a4
1274  ! southeast area
1275  a1 = (ye - yse)*(0.5*(xe + xse))
1276  a2 = (yse - ys)*(0.5*(xse + xs))
1277  a3 = (ys - ycrn)*(0.5*(xs + xcrn))
1278  a4 = (ycrn - ye)*(0.5*(xcrn + xe))
1279  ase = a1 + a2 + a3 + a4
1280  ! east area
1281  a1 = (yne - ye)*(0.5*(xne + xe))
1282  a2 = (ye - ycrn)*(0.5*(xe + xcrn))
1283  a3 = (ycrn - yn)*(0.5*(xcrn + xn))
1284  a4 = (yn - yne)*(0.5*(xn + xne))
1285  ae = a1 + a2 + a3 + a4
1286  ! area within cell
1287  a1 = (yn - ycrn)*(0.5*(xn + xcrn))
1288  a2 = (ycrn - yw)*(0.5*(xcrn + xw))
1289  a3 = (yw - ynw)*(0.5*(xw + xnw))
1290  a4 = (ynw - yn)*(0.5*(xnw + xn))
1291  ac = a1 + a2 + a3 + a4
1292  elseif (0.5*twopi <= theta .and. theta < 0.75*twopi) then
1293  xcrn = x(i,j); ycrn = y(i,j)
1294  ! east area
1295  a1 = (ye - yse)*(0.5*(xe + xse))
1296  a2 = (yse - ys)*(0.5*(xse + xs))
1297  a3 = (ys - ycrn)*(0.5*(xs + xcrn))
1298  a4 = (ycrn - ye)*(0.5*(xcrn + xe))
1299  ae = a1 + a2 + a3 + a4
1300  ! northeast area
1301  a1 = (yne - ye)*(0.5*(xne + xe))
1302  a2 = (ye - ycrn)*(0.5*(xe + xcrn))
1303  a3 = (ycrn - yn)*(0.5*(xcrn + xn))
1304  a4 = (yn - yne)*(0.5*(xn + xne))
1305  ane = a1 + a2 + a3 + a4
1306  ! north area
1307  a1 = (yn - ycrn)*(0.5*(xn + xcrn))
1308  a2 = (ycrn - yw)*(0.5*(xcrn + xw))
1309  a3 = (yw - ynw)*(0.5*(xw + xnw))
1310  a4 = (ynw - yn)*(0.5*(xnw + xn))
1311  an = a1 + a2 + a3 + a4
1312  ! area within cell
1313  a1 = (ycrn - ys)*(0.5*(xcrn + xs))
1314  a2 = (ys - ysw)*(0.5*(xs + xsw))
1315  a3 = (ysw - yw)*(0.5*(xsw + xw))
1316  a4 = (yw - ycrn)*(0.5*(xw + xcrn))
1317  ac = a1 + a2 + a3 + a4
1318  elseif (0.75*twopi <= theta .and. theta <= 1.00*twopi) then
1319  xcrn = x(i-1,j); ycrn = y(i-1,j)
1320  ! north area
1321  a1 = (yne - ye)*(0.5*(xne + xe))
1322  a2 = (ye - ycrn)*(0.5*(xe + xcrn))
1323  a3 = (ycrn - yn)*(0.5*(xcrn + xn))
1324  a4 = (yn - yne)*(0.5*(xn + xne))
1325  an = a1 + a2 + a3 + a4
1326  ! northwest area
1327  a1 = (yn - ycrn)*(0.5*(xn + xcrn))
1328  a2 = (ycrn - yw)*(0.5*(xcrn + xw))
1329  a3 = (yw - ynw)*(0.5*(xw + xnw))
1330  a4 = (ynw - yn)*(0.5*(xnw + xn))
1331  anw = a1 + a2 + a3 + a4
1332  ! west area
1333  a1 = (ycrn - ys)*(0.5*(xcrn + xs))
1334  a2 = (ys - ysw)*(0.5*(xs + xsw))
1335  a3 = (ysw - yw)*(0.5*(xsw + xw))
1336  a4 = (yw - ycrn)*(0.5*(xw + xcrn))
1337  aw = a1 + a2 + a3 + a4
1338  ! area within cell
1339  a1 = (ye - yse)*(0.5*(xe + xse))
1340  a2 = (yse - ys)*(0.5*(xse + xs))
1341  a3 = (ys - ycrn)*(0.5*(xs + xcrn))
1342  a4 = (ycrn - ye)*(0.5*(xcrn + xe))
1343  ac = a1 + a2 + a3 + a4
1344  endif
1345 
1346  ! energy weighting ----------------------------------------
1347  a_total = ane + an + anw + aw + asw + as + ase + ae + ac
1348  e_new(m) = (ane*en(i+1,j+1) + an*en(i,j+1) + anw*en(i-1,j+1) + &
1349  aw*en(i-1,j) + asw*en(i-1,j-1) + as*en(i,j-1) + &
1350  ase*en(i+1,j-1) + ae*en(i+1,j) + ac*en(i,j)) / (dx(i,j)*dy(i,j))
1351  enddo ! m-loop
1352  ! update energy in cell
1353  en(i,j) = sum(e_new)/nsubrays
1354  enddo ; enddo

◆ propagate_int_tide()

subroutine, public mom_internal_tides::propagate_int_tide ( real, dimension(szi_(g),szj_(g),szk_(g)), intent(in)  h,
type(thermo_var_ptrs), intent(in)  tv,
real, dimension(szi_(g),szj_(g),cs%nmode), intent(in)  cn,
real, dimension(szi_(g),szj_(g)), intent(in)  TKE_itidal_input,
real, dimension(szi_(g),szj_(g)), intent(in)  vel_btTide,
real, dimension(szi_(g),szj_(g)), intent(in)  Nb,
real, intent(in)  dt,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(int_tide_cs), pointer  CS 
)

Calls subroutines in this file that are needed to refract, propagate, and dissipate energy density of the internal tide.

Parameters
[in,out]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in]hLayer thicknesses [H ~> m or kg m-2]
[in]tvPointer to thermodynamic variables (needed for wave structure).
[in]tke_itidal_inputThe energy input to the internal waves [R Z3 T-3 ~> W m-2].
[in]vel_bttideBarotropic velocity read from file [L T-1 ~> m s-1].
[in]nbNear-bottom buoyancy frequency [T-1 ~> s-1].
[in]dtLength of time over which to advance the internal tides [T ~> s].
csThe control structure returned by a previous call to int_tide_init.
[in]cnThe internal wave speeds of each

Definition at line 154 of file MOM_internal_tides.F90.

154  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
155  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
156  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
157  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
158  intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2]
159  type(thermo_var_ptrs), intent(in) :: tv !< Pointer to thermodynamic variables
160  !! (needed for wave structure).
161  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: TKE_itidal_input !< The energy input to the
162  !! internal waves [R Z3 T-3 ~> W m-2].
163  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: vel_btTide !< Barotropic velocity read
164  !! from file [L T-1 ~> m s-1].
165  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: Nb !< Near-bottom buoyancy frequency [T-1 ~> s-1].
166  real, intent(in) :: dt !< Length of time over which to advance
167  !! the internal tides [T ~> s].
168  type(int_tide_CS), pointer :: CS !< The control structure returned by a
169  !! previous call to int_tide_init.
170  real, dimension(SZI_(G),SZJ_(G),CS%nMode), &
171  intent(in) :: cn !< The internal wave speeds of each
172  !! mode [L T-1 ~> m s-1].
173  ! Local variables
174  real, dimension(SZI_(G),SZJ_(G),2) :: &
175  test
176  real, dimension(SZI_(G),SZJ_(G),CS%nFreq,CS%nMode) :: &
177  tot_En_mode, & ! energy summed over angles only [R Z3 T-2 ~> J m-2]
178  Ub, & ! near-bottom horizontal velocity of wave (modal) [L T-1 ~> m s-1]
179  Umax ! Maximum horizontal velocity of wave (modal) [L T-1 ~> m s-1]
180  real, dimension(SZI_(G),SZJB_(G)) :: &
181  flux_heat_y, &
182  flux_prec_y
183  real, dimension(SZI_(G),SZJ_(G)) :: &
184  tot_En, & ! energy summed over angles, modes, frequencies [R Z3 T-2 ~> J m-2]
185  tot_leak_loss, tot_quad_loss, tot_itidal_loss, tot_Froude_loss, tot_allprocesses_loss, &
186  ! energy loss rates summed over angle, freq, and mode [R Z3 T-3 ~> W m-2]
187  drag_scale, & ! bottom drag scale [T-1 ~> s-1]
188  itidal_loss_mode, allprocesses_loss_mode
189  ! energy loss rates for a given mode and frequency (summed over angles) [R Z3 T-3 ~> W m-2]
190  real :: frac_per_sector, f2, Kmag2
191  real :: I_D_here ! The inverse of the local depth [Z-1 ~> m-1]
192  real :: I_rho0 ! The inverse fo the Boussinesq density [R-1 ~> m3 kg-1]
193  real :: freq2 ! The frequency squared [T-2 ~> s-2]
194  real :: c_phase ! The phase speed [L T-1 ~> m s-1]
195  real :: loss_rate ! An energy loss rate [T-1 ~> s-1]
196  real :: Fr2_max
197  real :: cn_subRO ! A tiny wave speed to prevent division by zero [L T-1 ~> m s-1]
198  real :: En_new, En_check ! Energies for debugging [R Z3 T-2 ~> J m-2]
199  real :: En_initial, Delta_E_check ! Energies for debugging [R Z3 T-2 ~> J m-2]
200  real :: TKE_Froude_loss_check, TKE_Froude_loss_tot ! Energy losses for debugging [R Z3 T-3 ~> W m-2]
201  character(len=160) :: mesg ! The text of an error message
202  integer :: a, m, fr, i, j, is, ie, js, je, isd, ied, jsd, jed, nAngle, nzm
203  integer :: id_g, jd_g ! global (decomp-invar) indices (for debugging)
204  type(group_pass_type), save :: pass_test, pass_En
205 
206  if (.not.associated(cs)) return
207  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
208  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nangle = cs%NAngle
209  i_rho0 = 1.0 / gv%Rho0
210  cn_subro = 1e-100*us%m_s_to_L_T ! The hard-coded value here might need to increase.
211 
212  ! Set the wave speeds for the modes, using cg(n) ~ cg(1)/n.**********************
213  ! This is wrong, of course, but it works reasonably in some cases.
214  ! Uncomment if wave_speed is not used to calculate the true values (BDM).
215  !do m=1,CS%nMode ; do j=jsd,jed ; do i=isd,ied
216  ! cn(i,j,m) = cn(i,j,1) / real(m)
217  !enddo ; enddo ; enddo
218 
219  ! Add the forcing.***************************************************************
220  if (cs%energized_angle <= 0) then
221  frac_per_sector = 1.0 / real(CS%nAngle * CS%nMode * CS%nFreq)
222  do m=1,cs%nMode ; do fr=1,cs%nFreq ; do a=1,cs%nAngle ; do j=js,je ; do i=is,ie
223  f2 = 0.25*((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
224  (g%CoriolisBu(i-1,j)**2 + g%CoriolisBu(i,j-1)**2))
225  if (cs%frequency(fr)**2 > f2) &
226  cs%En(i,j,a,fr,m) = cs%En(i,j,a,fr,m) + dt*frac_per_sector*(1.0-cs%q_itides) * &
227  tke_itidal_input(i,j)
228  enddo ; enddo ; enddo ; enddo ; enddo
229  elseif (cs%energized_angle <= cs%nAngle) then
230  frac_per_sector = 1.0 / real(CS%nMode * CS%nFreq)
231  a = cs%energized_angle
232  do m=1,cs%nMode ; do fr=1,cs%nFreq ; do j=js,je ; do i=is,ie
233  f2 = 0.25*((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
234  (g%CoriolisBu(i-1,j)**2 + g%CoriolisBu(i,j-1)**2))
235  if (cs%frequency(fr)**2 > f2) &
236  cs%En(i,j,a,fr,m) = cs%En(i,j,a,fr,m) + dt*frac_per_sector*(1.0-cs%q_itides) * &
237  tke_itidal_input(i,j)
238  enddo ; enddo ; enddo ; enddo
239  else
240  call mom_error(warning, "Internal tide energy is being put into a angular "//&
241  "band that does not exist.")
242  endif
243 
244  ! Pass a test vector to check for grid rotation in the halo updates.
245  do j=jsd,jed ; do i=isd,ied ; test(i,j,1) = 1.0 ; test(i,j,2) = 0.0 ; enddo ; enddo
246  do m=1,cs%nMode ; do fr=1,cs%nFreq
247  call create_group_pass(pass_en, cs%En(:,:,:,fr,m), g%domain)
248  enddo ; enddo
249  call create_group_pass(pass_test, test(:,:,1), test(:,:,2), g%domain, stagger=agrid)
250  call start_group_pass(pass_test, g%domain)
251 
252  ! Apply half the refraction.
253  do m=1,cs%nMode ; do fr=1,cs%nFreq
254  call refract(cs%En(:,:,:,fr,m), cn(:,:,m), cs%frequency(fr), 0.5*dt, &
255  g, us, cs%nAngle, cs%use_PPMang)
256  enddo ; enddo
257 
258  ! Check for En<0 - for debugging, delete later
259  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle
260  do j=js,je ; do i=is,ie
261  if (cs%En(i,j,a,fr,m)<0.0) then
262  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset ! for debugging
263  write(mesg,*) 'After first refraction: En<0.0 at ig=', id_g, ', jg=', jd_g, &
264  'En=',cs%En(i,j,a,fr,m)
265  call mom_error(warning, "propagate_int_tide: "//trim(mesg))
266  cs%En(i,j,a,fr,m) = 0.0
267 ! call MOM_error(FATAL, "propagate_int_tide: stopped due to negative energy.")
268  endif
269  enddo ; enddo
270  enddo ; enddo ; enddo
271 
272  call do_group_pass(pass_en, g%domain)
273 
274  call complete_group_pass(pass_test, g%domain)
275 
276  ! Rotate points in the halos as necessary.
277  call correct_halo_rotation(cs%En, test, g, cs%nAngle)
278 
279  ! Propagate the waves.
280  do m=1,cs%NMode ; do fr=1,cs%Nfreq
281  call propagate(cs%En(:,:,:,fr,m), cn(:,:,m), cs%frequency(fr), dt, &
282  g, us, cs, cs%NAngle)
283  enddo ; enddo
284 
285  ! Check for En<0 - for debugging, delete later
286  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle
287  do j=js,je ; do i=is,ie
288  if (cs%En(i,j,a,fr,m)<0.0) then
289  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset
290  if (abs(cs%En(i,j,a,fr,m))>1.0) then ! only print if large
291  write(mesg,*) 'After propagation: En<0.0 at ig=', id_g, ', jg=', jd_g, &
292  'En=', cs%En(i,j,a,fr,m)
293  call mom_error(warning, "propagate_int_tide: "//trim(mesg))
294 ! call MOM_error(FATAL, "propagate_int_tide: stopped due to negative energy.")
295  endif
296  cs%En(i,j,a,fr,m) = 0.0
297  endif
298  enddo ; enddo
299  enddo ; enddo ; enddo
300 
301  ! Apply the other half of the refraction.
302  do m=1,cs%NMode ; do fr=1,cs%Nfreq
303  call refract(cs%En(:,:,:,fr,m), cn(:,:,m), cs%frequency(fr), 0.5*dt, &
304  g, us, cs%NAngle, cs%use_PPMang)
305  enddo ; enddo
306 
307  ! Check for En<0 - for debugging, delete later
308  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle
309  do j=js,je ; do i=is,ie
310  if (cs%En(i,j,a,fr,m)<0.0) then
311  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset ! for debugging
312  write(mesg,*) 'After second refraction: En<0.0 at ig=', id_g, ', jg=', jd_g, &
313  'En=',cs%En(i,j,a,fr,m)
314  call mom_error(warning, "propagate_int_tide: "//trim(mesg))
315  cs%En(i,j,a,fr,m) = 0.0
316 ! call MOM_error(FATAL, "propagate_int_tide: stopped due to negative energy.")
317  endif
318  enddo ; enddo
319  enddo ; enddo ; enddo
320 
321  ! Apply various dissipation mechanisms.
322  if (cs%apply_background_drag .or. cs%apply_bottom_drag &
323  .or. cs%apply_wave_drag .or. cs%apply_Froude_drag &
324  .or. (cs%id_tot_En > 0)) then
325  tot_en(:,:) = 0.0
326  tot_en_mode(:,:,:,:) = 0.0
327  do m=1,cs%NMode ; do fr=1,cs%Nfreq
328  do j=jsd,jed ; do i=isd,ied ; do a=1,cs%nAngle
329  tot_en(i,j) = tot_en(i,j) + cs%En(i,j,a,fr,m)
330  tot_en_mode(i,j,fr,m) = tot_en_mode(i,j,fr,m) + cs%En(i,j,a,fr,m)
331  enddo ; enddo ; enddo
332  enddo ; enddo
333  endif
334 
335  ! Extract the energy for mixing due to misc. processes (background leakage)------
336  if (cs%apply_background_drag) then
337  do m=1,cs%nMode ; do fr=1,cs%nFreq ; do a=1,cs%nAngle ; do j=jsd,jed ; do i=isd,ied
338  ! Calculate loss rate and apply loss over the time step ; apply the same drag timescale
339  ! to each En component (technically not correct; fix later)
340  cs%TKE_leak_loss(i,j,a,fr,m) = cs%En(i,j,a,fr,m) * cs%decay_rate ! loss rate [R Z3 T-3 ~> W m-2]
341  cs%En(i,j,a,fr,m) = cs%En(i,j,a,fr,m) / (1.0 + dt * cs%decay_rate) ! implicit update
342  enddo ; enddo ; enddo ; enddo ; enddo
343  endif
344  ! Check for En<0 - for debugging, delete later
345  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle
346  do j=js,je ; do i=is,ie
347  if (cs%En(i,j,a,fr,m)<0.0) then
348  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset ! for debugging
349  write(mesg,*) 'After leak loss: En<0.0 at ig=', id_g, ', jg=', jd_g, &
350  'En=',cs%En(i,j,a,fr,m)
351  call mom_error(warning, "propagate_int_tide: "//trim(mesg), all_print=.true.)
352  cs%En(i,j,a,fr,m) = 0.0
353 ! call MOM_error(FATAL, "propagate_int_tide: stopped due to negative energy.")
354  endif
355  enddo ; enddo
356  enddo ; enddo ; enddo
357 
358  ! Extract the energy for mixing due to bottom drag-------------------------------
359  if (cs%apply_bottom_drag) then
360  do j=jsd,jed ; do i=isd,ied
361  ! Note the 1 m dimensional scale here. Should this be a parameter?
362  i_d_here = 1.0 / (max(g%bathyT(i,j), 1.0*us%m_to_Z))
363  drag_scale(i,j) = cs%cdrag * sqrt(max(0.0, us%L_to_Z**2*vel_bttide(i,j)**2 + &
364  tot_en(i,j) * i_rho0 * i_d_here)) * i_d_here
365  enddo ; enddo
366  do m=1,cs%nMode ; do fr=1,cs%nFreq ; do a=1,cs%nAngle ; do j=jsd,jed ; do i=isd,ied
367  ! Calculate loss rate and apply loss over the time step ; apply the same drag timescale
368  ! to each En component (technically not correct; fix later)
369  cs%TKE_quad_loss(i,j,a,fr,m) = cs%En(i,j,a,fr,m) * drag_scale(i,j) ! loss rate
370  cs%En(i,j,a,fr,m) = cs%En(i,j,a,fr,m) / (1.0 + dt * drag_scale(i,j)) ! implicit update
371  enddo ; enddo ; enddo ; enddo ; enddo
372  endif
373  ! Check for En<0 - for debugging, delete later
374  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle
375  do j=js,je ; do i=is,ie
376  if (cs%En(i,j,a,fr,m)<0.0) then
377  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset ! for debugging
378  write(mesg,*) 'After bottom loss: En<0.0 at ig=', id_g, ', jg=', jd_g, &
379  'En=',cs%En(i,j,a,fr,m)
380  call mom_error(warning, "propagate_int_tide: "//trim(mesg), all_print=.true.)
381  cs%En(i,j,a,fr,m) = 0.0
382 ! call MOM_error(FATAL, "propagate_int_tide: stopped due to negative energy.")
383  !stop
384  endif
385  enddo ; enddo
386  enddo ; enddo ; enddo
387 
388  ! Extract the energy for mixing due to scattering (wave-drag)--------------------
389  ! still need to allow a portion of the extracted energy to go to higher modes.
390  ! First, find velocity profiles
391  if (cs%apply_wave_drag .or. cs%apply_Froude_drag) then
392  do m=1,cs%NMode ; do fr=1,cs%Nfreq
393  ! Calculate modal structure for given mode and frequency
394  call wave_structure(h, tv, g, gv, us, cn(:,:,m), m, cs%frequency(fr), &
395  cs%wave_structure_CSp, tot_en_mode(:,:,fr,m), full_halos=.true.)
396  ! Pick out near-bottom and max horizontal baroclinic velocity values at each point
397  do j=jsd,jed ; do i=isd,ied
398  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset ! for debugging
399  nzm = cs%wave_structure_CSp%num_intfaces(i,j)
400  ub(i,j,fr,m) = cs%wave_structure_CSp%Uavg_profile(i,j,nzm)
401  umax(i,j,fr,m) = maxval(cs%wave_structure_CSp%Uavg_profile(i,j,1:nzm))
402  enddo ; enddo ! i-loop, j-loop
403  enddo ; enddo ! fr-loop, m-loop
404  endif ! apply_wave or _Froude_drag (Ub or Umax needed)
405  ! Finally, apply loss
406  if (cs%apply_wave_drag) then
407  ! Calculate loss rate and apply loss over the time step
408  call itidal_lowmode_loss(g, us, cs, nb, ub, cs%En, cs%TKE_itidal_loss_fixed, &
409  cs%TKE_itidal_loss, dt, full_halos=.false.)
410  endif
411  ! Check for En<0 - for debugging, delete later
412  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle
413  do j=js,je ; do i=is,ie
414  if (cs%En(i,j,a,fr,m)<0.0) then
415  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset ! for debugging
416  write(mesg,*) 'After wave drag loss: En<0.0 at ig=', id_g, ', jg=', jd_g, &
417  'En=',cs%En(i,j,a,fr,m)
418  call mom_error(warning, "propagate_int_tide: "//trim(mesg), all_print=.true.)
419  cs%En(i,j,a,fr,m) = 0.0
420 ! call MOM_error(FATAL, "propagate_int_tide: stopped due to negative energy.")
421  endif
422  enddo ; enddo
423  enddo ; enddo ; enddo
424 
425  ! Extract the energy for mixing due to wave breaking-----------------------------
426  if (cs%apply_Froude_drag) then
427  ! Pick out maximum baroclinic velocity values; calculate Fr=max(u)/cg
428  do m=1,cs%NMode ; do fr=1,cs%Nfreq
429  freq2 = cs%frequency(fr)**2
430  do j=jsd,jed ; do i=isd,ied
431  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset ! for debugging
432  ! Calculate horizontal phase velocity magnitudes
433  f2 = 0.25*((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
434  (g%CoriolisBu(i-1,j)**2 + g%CoriolisBu(i,j-1)**2))
435  kmag2 = (freq2 - f2) / (cn(i,j,m)**2 + cn_subro**2)
436  c_phase = 0.0
437  if (kmag2 > 0.0) then
438  c_phase = sqrt(freq2/kmag2)
439  nzm = cs%wave_structure_CSp%num_intfaces(i,j)
440  fr2_max = (umax(i,j,fr,m) / c_phase)**2
441  ! Dissipate energy if Fr>1; done here with an arbitrary time scale
442  if (fr2_max > 1.0) then
443  en_initial = sum(cs%En(i,j,:,fr,m)) ! for debugging
444  ! Calculate effective decay rate [T-1 ~> s-1] if breaking occurs over a time step
445  loss_rate = (1.0 - fr2_max) / (fr2_max * dt)
446  do a=1,cs%nAngle
447  ! Determine effective dissipation rate (Wm-2)
448  cs%TKE_Froude_loss(i,j,a,fr,m) = cs%En(i,j,a,fr,m) * abs(loss_rate)
449  ! Update energy
450  en_new = cs%En(i,j,a,fr,m)/fr2_max ! for debugging
451  en_check = cs%En(i,j,a,fr,m) - cs%TKE_Froude_loss(i,j,a,fr,m)*dt ! for debugging
452  ! Re-scale (reduce) energy due to breaking
453  cs%En(i,j,a,fr,m) = cs%En(i,j,a,fr,m)/fr2_max
454  ! Check (for debugging only)
455  if (abs(en_new - en_check) > 1e-10*us%kg_m3_to_R*us%m_to_Z**3*us%T_to_s**2) then
456  call mom_error(warning, "MOM_internal_tides: something is wrong with Fr-breaking.", &
457  all_print=.true.)
458  write(mesg,*) "En_new=", en_new , "En_check=", en_check
459  call mom_error(warning, "MOM_internal_tides: "//trim(mesg), all_print=.true.)
460  endif
461  enddo
462  ! Check (for debugging)
463  delta_e_check = en_initial - sum(cs%En(i,j,:,fr,m))
464  tke_froude_loss_check = abs(delta_e_check)/dt
465  tke_froude_loss_tot = sum(cs%TKE_Froude_loss(i,j,:,fr,m))
466  if (abs(tke_froude_loss_check - tke_froude_loss_tot) > 1e-10) then
467  call mom_error(warning, "MOM_internal_tides: something is wrong with Fr energy update.", &
468  all_print=.true.)
469  write(mesg,*) "TKE_Froude_loss_check=", tke_froude_loss_check, &
470  "TKE_Froude_loss_tot=", tke_froude_loss_tot
471  call mom_error(warning, "MOM_internal_tides: "//trim(mesg), all_print=.true.)
472  endif
473  endif ! Fr2>1
474  endif ! Kmag2>0
475  cs%cp(i,j,fr,m) = c_phase
476  enddo ; enddo
477  enddo ; enddo
478  endif
479  ! Check for En<0 - for debugging, delete later
480  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle
481  do j=js,je ; do i=is,ie
482  if (cs%En(i,j,a,fr,m)<0.0) then
483  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset
484  write(mesg,*) 'After Froude loss: En<0.0 at ig=', id_g, ', jg=', jd_g, &
485  'En=',cs%En(i,j,a,fr,m)
486  call mom_error(warning, "propagate_int_tide: "//trim(mesg), all_print=.true.)
487  cs%En(i,j,a,fr,m) = 0.0
488 ! call MOM_error(FATAL, "propagate_int_tide: stopped due to negative energy.")
489  !stop
490  endif
491  enddo ; enddo
492  enddo ; enddo ; enddo
493 
494  ! Check for energy conservation on computational domain.*************************
495  do m=1,cs%NMode ; do fr=1,cs%Nfreq
496  call sum_en(g,cs,cs%En(:,:,:,fr,m),'prop_int_tide')
497  enddo ; enddo
498 
499  ! Output diagnostics.************************************************************
500  if (query_averaging_enabled(cs%diag)) then
501  ! Output two-dimensional diagnostistics
502  if (cs%id_tot_En > 0) call post_data(cs%id_tot_En, tot_en, cs%diag)
503  if (cs%id_itide_drag > 0) call post_data(cs%id_itide_drag, drag_scale, cs%diag)
504  if (cs%id_TKE_itidal_input > 0) call post_data(cs%id_TKE_itidal_input, &
505  tke_itidal_input, cs%diag)
506 
507  ! Output 2-D energy density (summed over angles) for each freq and mode
508  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; if (cs%id_En_mode(fr,m) > 0) then
509  tot_en(:,:) = 0.0
510  do a=1,cs%nAngle ; do j=js,je ; do i=is,ie
511  tot_en(i,j) = tot_en(i,j) + cs%En(i,j,a,fr,m)
512  enddo ; enddo ; enddo
513  call post_data(cs%id_En_mode(fr,m), tot_en, cs%diag)
514  endif ; enddo ; enddo
515 
516  ! Output 3-D (i,j,a) energy density for each freq and mode
517  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; if (cs%id_En_ang_mode(fr,m) > 0) then
518  call post_data(cs%id_En_ang_mode(fr,m), cs%En(:,:,:,fr,m) , cs%diag)
519  endif ; enddo ; enddo
520 
521  ! Output 2-D energy loss (summed over angles, freq, modes)
522  tot_leak_loss(:,:) = 0.0
523  tot_quad_loss(:,:) = 0.0
524  tot_itidal_loss(:,:) = 0.0
525  tot_froude_loss(:,:) = 0.0
526  tot_allprocesses_loss(:,:) = 0.0
527  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; do a=1,cs%nAngle ; do j=js,je ; do i=is,ie
528  tot_leak_loss(i,j) = tot_leak_loss(i,j) + cs%TKE_leak_loss(i,j,a,fr,m)
529  tot_quad_loss(i,j) = tot_quad_loss(i,j) + cs%TKE_quad_loss(i,j,a,fr,m)
530  tot_itidal_loss(i,j) = tot_itidal_loss(i,j) + cs%TKE_itidal_loss(i,j,a,fr,m)
531  tot_froude_loss(i,j) = tot_froude_loss(i,j) + cs%TKE_Froude_loss(i,j,a,fr,m)
532  enddo ; enddo ; enddo ; enddo ; enddo
533  do j=js,je ; do i=is,ie
534  tot_allprocesses_loss(i,j) = tot_leak_loss(i,j) + tot_quad_loss(i,j) + &
535  tot_itidal_loss(i,j) + tot_froude_loss(i,j)
536  enddo ; enddo
537  cs%tot_leak_loss = tot_leak_loss
538  cs%tot_quad_loss = tot_quad_loss
539  cs%tot_itidal_loss = tot_itidal_loss
540  cs%tot_Froude_loss = tot_froude_loss
541  cs%tot_allprocesses_loss = tot_allprocesses_loss
542  if (cs%id_tot_leak_loss > 0) then
543  call post_data(cs%id_tot_leak_loss, tot_leak_loss, cs%diag)
544  endif
545  if (cs%id_tot_quad_loss > 0) then
546  call post_data(cs%id_tot_quad_loss, tot_quad_loss, cs%diag)
547  endif
548  if (cs%id_tot_itidal_loss > 0) then
549  call post_data(cs%id_tot_itidal_loss, tot_itidal_loss, cs%diag)
550  endif
551  if (cs%id_tot_Froude_loss > 0) then
552  call post_data(cs%id_tot_Froude_loss, tot_froude_loss, cs%diag)
553  endif
554  if (cs%id_tot_allprocesses_loss > 0) then
555  call post_data(cs%id_tot_allprocesses_loss, tot_allprocesses_loss, cs%diag)
556  endif
557 
558  ! Output 2-D energy loss (summed over angles) for each freq and mode
559  do m=1,cs%NMode ; do fr=1,cs%Nfreq
560  if (cs%id_itidal_loss_mode(fr,m) > 0 .or. cs%id_allprocesses_loss_mode(fr,m) > 0) then
561  itidal_loss_mode(:,:) = 0.0 ! wave-drag processes (could do others as well)
562  allprocesses_loss_mode(:,:) = 0.0 ! all processes summed together
563  do a=1,cs%nAngle ; do j=js,je ; do i=is,ie
564  itidal_loss_mode(i,j) = itidal_loss_mode(i,j) + cs%TKE_itidal_loss(i,j,a,fr,m)
565  allprocesses_loss_mode(i,j) = allprocesses_loss_mode(i,j) + &
566  cs%TKE_leak_loss(i,j,a,fr,m) + cs%TKE_quad_loss(i,j,a,fr,m) + &
567  cs%TKE_itidal_loss(i,j,a,fr,m) + cs%TKE_Froude_loss(i,j,a,fr,m)
568  enddo ; enddo ; enddo
569  call post_data(cs%id_itidal_loss_mode(fr,m), itidal_loss_mode, cs%diag)
570  call post_data(cs%id_allprocesses_loss_mode(fr,m), allprocesses_loss_mode, cs%diag)
571  endif ; enddo ; enddo
572 
573  ! Output 3-D (i,j,a) energy loss for each freq and mode
574  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; if (cs%id_itidal_loss_ang_mode(fr,m) > 0) then
575  call post_data(cs%id_itidal_loss_ang_mode(fr,m), cs%TKE_itidal_loss(:,:,:,fr,m) , cs%diag)
576  endif ; enddo ; enddo
577 
578  ! Output 2-D period-averaged horizontal near-bottom mode velocity for each freq and mode
579  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; if (cs%id_Ub_mode(fr,m) > 0) then
580  call post_data(cs%id_Ub_mode(fr,m), ub(:,:,fr,m), cs%diag)
581  endif ; enddo ; enddo
582 
583  ! Output 2-D horizontal phase velocity for each freq and mode
584  do m=1,cs%NMode ; do fr=1,cs%Nfreq ; if (cs%id_cp_mode(fr,m) > 0) then
585  call post_data(cs%id_cp_mode(fr,m), cs%cp(:,:,fr,m), cs%diag)
586  endif ; enddo ; enddo
587 
588  endif
589 

◆ propagate_x()

subroutine mom_internal_tides::propagate_x ( real, dimension(g%isd:g%ied,g%jsd:g%jed,nangle), intent(inout)  En,
real, dimension(g%isdb:g%iedb,g%jsd:g%jed), intent(in)  speed_x,
real, dimension(nangle), intent(in)  Cgx_av,
real, dimension(nangle), intent(in)  dCgx,
real, intent(in)  dt,
type(ocean_grid_type), intent(in)  G,
type(unit_scale_type), intent(in)  US,
integer, intent(in)  Nangle,
type(int_tide_cs), pointer  CS,
type(loop_bounds_type), intent(in)  LB 
)
private

Propagates the internal wave energy in the logical x-direction.

Parameters
[in]gThe ocean's grid structure.
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in,out]enThe energy density integrated over an angular
[in]speed_xThe magnitude of the group velocity at the
[in]cgx_avThe average x-projection in each angular band.
[in]dcgxThe difference in x-projections between the edges of each angular band.
[in]dtTime increment [T ~> s].
[in]usA dimensional unit scaling type
csThe control structure returned by a previous call to continuity_PPM_init.
[in]lbA structure with the active energy loop bounds.

Definition at line 1359 of file MOM_internal_tides.F90.

1359  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1360  integer, intent(in) :: NAngle !< The number of wave orientations in the
1361  !! discretized wave energy spectrum.
1362  real, dimension(G%isd:G%ied,G%jsd:G%jed,Nangle), &
1363  intent(inout) :: En !< The energy density integrated over an angular
1364  !! band [R Z3 T-2 ~> J m-2].
1365  real, dimension(G%IsdB:G%IedB,G%jsd:G%jed), &
1366  intent(in) :: speed_x !< The magnitude of the group velocity at the
1367  !! Cu points [L T-1 ~> m s-1].
1368  real, dimension(Nangle), intent(in) :: Cgx_av !< The average x-projection in each angular band.
1369  real, dimension(Nangle), intent(in) :: dCgx !< The difference in x-projections between the
1370  !! edges of each angular band.
1371  real, intent(in) :: dt !< Time increment [T ~> s].
1372  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1373  type(int_tide_CS), pointer :: CS !< The control structure returned by a previous call
1374  !! to continuity_PPM_init.
1375  type(loop_bounds_type), intent(in) :: LB !< A structure with the active energy loop bounds.
1376  ! Local variables
1377  real, dimension(SZI_(G),SZJ_(G)) :: &
1378  EnL, EnR ! Left and right face energy densities [R Z3 T-2 ~> J m-2].
1379  real, dimension(SZIB_(G),SZJ_(G)) :: &
1380  flux_x ! The internal wave energy flux [J T-1 ~> J s-1].
1381  real, dimension(SZIB_(G)) :: &
1382  cg_p, cg_m, flux1, flux2
1383  !real, dimension(SZI_(G),SZJB_(G),Nangle) :: En_m, En_p
1384  real, dimension(SZI_(G),SZJB_(G),Nangle) :: &
1385  Fdt_m, Fdt_p! Left and right energy fluxes [J]
1386  integer :: i, j, k, ish, ieh, jsh, jeh, a
1387 
1388  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh
1389  do a=1,nangle
1390  ! This sets EnL and EnR.
1391  if (cs%upwind_1st) then
1392  do j=jsh,jeh ; do i=ish-1,ieh+1
1393  enl(i,j) = en(i,j,a) ; enr(i,j) = en(i,j,a)
1394  enddo ; enddo
1395  else
1396  call ppm_reconstruction_x(en(:,:,a), enl, enr, g, lb, simple_2nd=cs%simple_2nd)
1397  endif
1398 
1399  do j=jsh,jeh
1400  ! This is done once with single speed (GARDEN SPRINKLER EFFECT POSSIBLE)
1401  do i=ish-1,ieh
1402  cg_p(i) = speed_x(i,j) * (cgx_av(a))
1403  enddo
1404  call zonal_flux_en(cg_p, en(:,j,a), enl(:,j), enr(:,j), flux1, &
1405  dt, g, us, j, ish, ieh, cs%vol_CFL)
1406  do i=ish-1,ieh ; flux_x(i,j) = flux1(i); enddo
1407  enddo
1408 
1409  do j=jsh,jeh ; do i=ish,ieh
1410  fdt_m(i,j,a) = dt*flux_x(i-1,j) ! left face influx (J)
1411  fdt_p(i,j,a) = -dt*flux_x(i,j) ! right face influx (J)
1412  enddo ; enddo
1413 
1414  enddo ! a-loop
1415 
1416  ! Only reflect newly arrived energy; existing energy in incident wedge is not reflected
1417  ! and will eventually propagate out of cell. (This code only reflects if En > 0.)
1418  call reflect(fdt_m, nangle, cs, g, lb)
1419  call teleport(fdt_m, nangle, cs, g, lb)
1420  call reflect(fdt_p, nangle, cs, g, lb)
1421  call teleport(fdt_p, nangle, cs, g, lb)
1422 
1423  ! Update reflected energy [R Z3 T-2 ~> J m-2]
1424  do a=1,nangle ; do j=jsh,jeh ; do i=ish,ieh
1425  ! if ((En(i,j,a) + G%IareaT(i,j)*(Fdt_m(i,j,a) + Fdt_p(i,j,a))) < 0.0) & ! for debugging
1426  ! call MOM_error(FATAL, "propagate_x: OutFlux>Available")
1427  en(i,j,a) = en(i,j,a) + g%IareaT(i,j)*(fdt_m(i,j,a) + fdt_p(i,j,a))
1428  enddo ; enddo ; enddo
1429 

◆ propagate_y()

subroutine mom_internal_tides::propagate_y ( real, dimension(g%isd:g%ied,g%jsd:g%jed,nangle), intent(inout)  En,
real, dimension(g%isd:g%ied,g%jsdb:g%jedb), intent(in)  speed_y,
real, dimension(nangle), intent(in)  Cgy_av,
real, dimension(nangle), intent(in)  dCgy,
real, intent(in)  dt,
type(ocean_grid_type), intent(in)  G,
type(unit_scale_type), intent(in)  US,
integer, intent(in)  Nangle,
type(int_tide_cs), pointer  CS,
type(loop_bounds_type), intent(in)  LB 
)
private

Propagates the internal wave energy in the logical y-direction.

Parameters
[in]gThe ocean's grid structure.
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in,out]enThe energy density integrated over an angular
[in]speed_yThe magnitude of the group velocity at the
[in]cgy_avThe average y-projection in each angular band.
[in]dcgyThe difference in y-projections between the edges of each angular band.
[in]dtTime increment [T ~> s].
[in]usA dimensional unit scaling type
csThe control structure returned by a previous call to continuity_PPM_init.
[in]lbA structure with the active energy loop bounds.

Definition at line 1434 of file MOM_internal_tides.F90.

1434  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1435  integer, intent(in) :: NAngle !< The number of wave orientations in the
1436  !! discretized wave energy spectrum.
1437  real, dimension(G%isd:G%ied,G%jsd:G%jed,Nangle), &
1438  intent(inout) :: En !< The energy density integrated over an angular
1439  !! band [R Z3 T-2 ~> J m-2].
1440  real, dimension(G%isd:G%ied,G%JsdB:G%JedB), &
1441  intent(in) :: speed_y !< The magnitude of the group velocity at the
1442  !! Cv points [L T-1 ~> m s-1].
1443  real, dimension(Nangle), intent(in) :: Cgy_av !< The average y-projection in each angular band.
1444  real, dimension(Nangle), intent(in) :: dCgy !< The difference in y-projections between the
1445  !! edges of each angular band.
1446  real, intent(in) :: dt !< Time increment [T ~> s].
1447  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1448  type(int_tide_CS), pointer :: CS !< The control structure returned by a previous call
1449  !! to continuity_PPM_init.
1450  type(loop_bounds_type), intent(in) :: LB !< A structure with the active energy loop bounds.
1451  ! Local variables
1452  real, dimension(SZI_(G),SZJ_(G)) :: &
1453  EnL, EnR ! South and north face energy densities [R Z3 T-2 ~> J m-2].
1454  real, dimension(SZI_(G),SZJB_(G)) :: &
1455  flux_y ! The internal wave energy flux [J T-1 ~> J s-1].
1456  real, dimension(SZI_(G)) :: &
1457  cg_p, cg_m, flux1, flux2
1458  !real, dimension(SZI_(G),SZJB_(G),Nangle) :: En_m, En_p
1459  real, dimension(SZI_(G),SZJB_(G),Nangle) :: &
1460  Fdt_m, Fdt_p! South and north energy fluxes [J]
1461  character(len=160) :: mesg ! The text of an error message
1462  integer :: i, j, k, ish, ieh, jsh, jeh, a
1463 
1464  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh
1465  do a=1,nangle
1466  ! This sets EnL and EnR.
1467  if (cs%upwind_1st) then
1468  do j=jsh-1,jeh+1 ; do i=ish,ieh
1469  enl(i,j) = en(i,j,a) ; enr(i,j) = en(i,j,a)
1470  enddo ; enddo
1471  else
1472  call ppm_reconstruction_y(en(:,:,a), enl, enr, g, lb, simple_2nd=cs%simple_2nd)
1473  endif
1474 
1475  do j=jsh-1,jeh
1476  ! This is done once with single speed (GARDEN SPRINKLER EFFECT POSSIBLE)
1477  do i=ish,ieh
1478  cg_p(i) = speed_y(i,j) * (cgy_av(a))
1479  enddo
1480  call merid_flux_en(cg_p, en(:,:,a), enl(:,:), enr(:,:), flux1, &
1481  dt, g, us, j, ish, ieh, cs%vol_CFL)
1482  do i=ish,ieh ; flux_y(i,j) = flux1(i); enddo
1483  enddo
1484 
1485  do j=jsh,jeh ; do i=ish,ieh
1486  fdt_m(i,j,a) = dt*flux_y(i,j-1) ! south face influx (J)
1487  fdt_p(i,j,a) = -dt*flux_y(i,j) ! north face influx (J)
1488  !if ((En(i,j,a) + G%IareaT(i,j)*(Fdt_m(i,j,a) + Fdt_p(i,j,a))) < 0.0) then ! for debugging
1489  ! call MOM_error(WARNING, "propagate_y: OutFlux>Available prior to reflection", .true.)
1490  ! write(mesg,*) "flux_y_south=",flux_y(i,J-1),"flux_y_north=",flux_y(i,J),"En=",En(i,j,a), &
1491  ! "cn_south=", speed_y(i,J-1) * (Cgy_av(a)), "cn_north=", speed_y(i,J) * (Cgy_av(a))
1492  ! call MOM_error(WARNING, mesg, .true.)
1493  !endif
1494  enddo ; enddo
1495 
1496  enddo ! a-loop
1497 
1498  ! Only reflect newly arrived energy; existing energy in incident wedge is not reflected
1499  ! and will eventually propagate out of cell. (This code only reflects if En > 0.)
1500  call reflect(fdt_m, nangle, cs, g, lb)
1501  call teleport(fdt_m, nangle, cs, g, lb)
1502  call reflect(fdt_p, nangle, cs, g, lb)
1503  call teleport(fdt_p, nangle, cs, g, lb)
1504 
1505  ! Update reflected energy [R Z3 T-2 ~> J m-2]
1506  do a=1,nangle ; do j=jsh,jeh ; do i=ish,ieh
1507  ! if ((En(i,j,a) + G%IareaT(i,j)*(Fdt_m(i,j,a) + Fdt_p(i,j,a))) < 0.0) & ! for debugging
1508  ! call MOM_error(FATAL, "propagate_y: OutFlux>Available", .true.)
1509  en(i,j,a) = en(i,j,a) + g%IareaT(i,j)*(fdt_m(i,j,a) + fdt_p(i,j,a))
1510  enddo ; enddo ; enddo
1511 

◆ reflect()

subroutine mom_internal_tides::reflect ( real, dimension(g%isd:g%ied,g%jsd:g%jed,nangle), intent(inout)  En,
integer, intent(in)  NAngle,
type(int_tide_cs), pointer  CS,
type(ocean_grid_type), intent(in)  G,
type(loop_bounds_type), intent(in)  LB 
)
private

Reflection of the internal waves at a single frequency.

Parameters
[in]gThe ocean's grid structure
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in,out]enThe internal gravity wave energy density as a
csThe control structure returned by a previous call to int_tide_init.
[in]lbA structure with the active energy loop bounds.

Definition at line 1602 of file MOM_internal_tides.F90.

1602  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1603  integer, intent(in) :: NAngle !< The number of wave orientations in the
1604  !! discretized wave energy spectrum.
1605  real, dimension(G%isd:G%ied,G%jsd:G%jed,NAngle), &
1606  intent(inout) :: En !< The internal gravity wave energy density as a
1607  !! function of space and angular resolution
1608  !! [R Z3 T-2 ~> J m-2].
1609  type(int_tide_CS), pointer :: CS !< The control structure returned by a
1610  !! previous call to int_tide_init.
1611  type(loop_bounds_type), intent(in) :: LB !< A structure with the active energy loop bounds.
1612  ! Local variables
1613  real, dimension(G%isd:G%ied,G%jsd:G%jed) :: angle_c
1614  ! angle of boundary wrt equator [rad]
1615  real, dimension(G%isd:G%ied,G%jsd:G%jed) :: part_refl
1616  ! fraction of wave energy reflected
1617  ! values should collocate with angle_c [nondim]
1618  logical, dimension(G%isd:G%ied,G%jsd:G%jed) :: ridge
1619  ! tags of cells with double reflection
1620 
1621  real :: TwoPi ! 2*pi = 6.2831853... [nondim]
1622  real :: Angle_size ! size of beam wedge [rad]
1623  real :: angle_wall ! angle of coast/ridge/shelf wrt equator [rad]
1624  real, dimension(1:NAngle) :: angle_i ! angle of incident ray wrt equator [rad]
1625  real :: angle_r ! angle of reflected ray wrt equator [rad]
1626  real, dimension(1:Nangle) :: En_reflected
1627  integer :: i, j, a, a_r, na
1628  !integer :: isd, ied, jsd, jed ! start and end local indices on data domain
1629  ! ! (values include halos)
1630  integer :: isc, iec, jsc, jec ! start and end local indices on PE
1631  ! (values exclude halos)
1632  integer :: ish, ieh, jsh, jeh ! start and end local indices on data domain
1633  ! leaving out outdated halo points (march in)
1634 
1635  !isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
1636  isc = g%isc ; iec = g%iec ; jsc = g%jsc ; jec = g%jec
1637  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh
1638 
1639  twopi = 8.0*atan(1.0)
1640  angle_size = twopi / (real(NAngle))
1641 
1642  do a=1,nangle
1643  ! These are the angles at the cell centers
1644  ! (should do this elsewhere since doesn't change with time)
1645  angle_i(a) = angle_size * real(a - 1) ! for a=1 aligned with x-axis
1646  enddo
1647 
1648  angle_c = cs%refl_angle
1649  part_refl = cs%refl_pref
1650  ridge = cs%refl_dbl
1651  en_reflected(:) = 0.0
1652 
1653  do j=jsh,jeh ; do i=ish,ieh
1654  ! redistribute energy in angular space if ray will hit boundary
1655  ! i.e., if energy is in a reflecting cell
1656  if (angle_c(i,j) /= cs%nullangle) then
1657  do a=1,nangle ; if (en(i,j,a) > 0.0) then
1658  if (sin(angle_i(a) - angle_c(i,j)) >= 0.0) then
1659  ! if ray is incident, keep specified boundary angle
1660  angle_wall = angle_c(i,j)
1661  elseif (ridge(i,j)) then
1662  ! if ray is not incident but in ridge cell, use complementary angle
1663  angle_wall = angle_c(i,j) + 0.5*twopi
1664  if (angle_wall > twopi) then
1665  angle_wall = angle_wall - twopi*floor(abs(angle_wall)/twopi)
1666  elseif (angle_wall < 0.0) then
1667  angle_wall = angle_wall + twopi*ceiling(abs(angle_wall)/twopi)
1668  endif
1669  else
1670  ! if ray is not incident and not in a ridge cell, keep specified angle
1671  angle_wall = angle_c(i,j)
1672  endif
1673 
1674  ! do reflection
1675  if (sin(angle_i(a) - angle_wall) >= 0.0) then
1676  angle_r = 2.0*angle_wall - angle_i(a)
1677  if (angle_r > twopi) then
1678  angle_r = angle_r - twopi*floor(abs(angle_r)/twopi)
1679  elseif (angle_r < 0.0) then
1680  angle_r = angle_r + twopi*ceiling(abs(angle_r)/twopi)
1681  endif
1682  a_r = nint(angle_r/angle_size) + 1
1683  do while (a_r > nangle) ; a_r = a_r - nangle ; enddo
1684  if (a /= a_r) then
1685  en_reflected(a_r) = part_refl(i,j)*en(i,j,a)
1686  en(i,j,a) = (1.0-part_refl(i,j))*en(i,j,a)
1687  endif
1688  endif
1689  endif ; enddo ! a-loop
1690  do a=1,nangle
1691  en(i,j,a) = en(i,j,a) + en_reflected(a)
1692  en_reflected(a) = 0.0
1693  enddo ! a-loop
1694  endif
1695  enddo ; enddo ! i- and j-loops
1696 
1697  ! Check to make sure no energy gets onto land (only run for debugging)
1698  ! do a=1,NAngle ; do j=jsc,jec ; do i=isc,iec
1699  ! if (En(i,j,a) > 0.001 .and. G%mask2dT(i,j) == 0) then
1700  ! write (mesg,*) 'En=', En(i,j,a), 'a=', a, 'ig_g=',i+G%idg_offset, 'jg_g=',j+G%jdg_offset
1701  ! call MOM_error(FATAL, "reflect: Energy detected out of bounds: "//trim(mesg), .true.)
1702  ! endif
1703  ! enddo ; enddo ; enddo
1704 

◆ refract()

subroutine mom_internal_tides::refract ( real, dimension(g%isd:g%ied,g%jsd:g%jed,nangle), intent(inout)  En,
real, dimension(g%isd:g%ied,g%jsd:g%jed), intent(in)  cn,
real, intent(in)  freq,
real, intent(in)  dt,
type(ocean_grid_type), intent(in)  G,
type(unit_scale_type), intent(in)  US,
integer, intent(in)  NAngle,
logical, intent(in)  use_PPMang 
)
private

Implements refraction on the internal waves at a single frequency.

Parameters
[in]gThe ocean's grid structure.
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in,out]enThe internal gravity wave energy density as a
[in]cnBaroclinic mode speed [L T-1 ~> m s-1].
[in]freqWave frequency [T-1 ~> s-1].
[in]dtTime step [T ~> s].
[in]usA dimensional unit scaling type
[in]use_ppmangIf true, use PPM for advection rather than upwind.

Definition at line 746 of file MOM_internal_tides.F90.

746  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
747  integer, intent(in) :: NAngle !< The number of wave orientations in the
748  !! discretized wave energy spectrum.
749  real, dimension(G%isd:G%ied,G%jsd:G%jed,NAngle), &
750  intent(inout) :: En !< The internal gravity wave energy density as a
751  !! function of space and angular resolution,
752  !! [R Z3 T-2 ~> J m-2].
753  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
754  intent(in) :: cn !< Baroclinic mode speed [L T-1 ~> m s-1].
755  real, intent(in) :: freq !< Wave frequency [T-1 ~> s-1].
756  real, intent(in) :: dt !< Time step [T ~> s].
757  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
758  logical, intent(in) :: use_PPMang !< If true, use PPM for advection rather
759  !! than upwind.
760  ! Local variables
761  integer, parameter :: stencil = 2
762  real, dimension(SZI_(G),1-stencil:NAngle+stencil) :: &
763  En2d
764  real, dimension(1-stencil:NAngle+stencil) :: &
765  cos_angle, sin_angle
766  real, dimension(SZI_(G)) :: &
767  Dk_Dt_Kmag, Dl_Dt_Kmag
768  real, dimension(SZI_(G),0:nAngle) :: &
769  Flux_E
770  real, dimension(SZI_(G),SZJ_(G),1-stencil:NAngle+stencil) :: &
771  CFL_ang
772  real :: f2 ! The squared Coriolis parameter [T-2 ~> s-2].
773  real :: favg ! The average Coriolis parameter at a point [T-1 ~> s-1].
774  real :: df_dy, df_dx ! The x- and y- gradients of the Coriolis parameter [T-1 L-1 ~> s-1 m-1].
775  real :: dlnCn_dx ! The x-gradient of the wave speed divided by itself [L-1 ~> m-1].
776  real :: dlnCn_dy ! The y-gradient of the wave speed divided by itself [L-1 ~> m-1].
777  real :: Angle_size, dt_Angle_size, angle
778  real :: Ifreq, Kmag2, I_Kmag
779  real :: cn_subRO ! A tiny wave speed to prevent division by zero [L T-1 ~> m s-1]
780  integer :: is, ie, js, je, asd, aed, na
781  integer :: i, j, a
782 
783  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; na = size(en,3)
784  asd = 1-stencil ; aed = nangle+stencil
785 
786  ifreq = 1.0 / freq
787  cn_subro = 1e-100*us%m_s_to_L_T ! The hard-coded value here might need to increase.
788  angle_size = (8.0*atan(1.0)) / (real(NAngle))
789  dt_angle_size = dt / angle_size
790 
791  do a=asd,aed
792  angle = (real(A) - 0.5) * Angle_size
793  cos_angle(a) = cos(angle) ; sin_angle(a) = sin(angle)
794  enddo
795 
796  !### There should also be refraction due to cn.grad(grid_orientation).
797  cfl_ang(:,:,:) = 0.0
798  do j=js,je
799  ! Copy En into angle space with halos.
800  do a=1,na ; do i=is,ie
801  en2d(i,a) = en(i,j,a)
802  enddo ; enddo
803  do a=asd,0 ; do i=is,ie
804  en2d(i,a) = en2d(i,a+nangle)
805  en2d(i,nangle+stencil+a) = en2d(i,stencil+a)
806  enddo ; enddo
807 
808  ! Do the refraction.
809  do i=is,ie
810  f2 = 0.25* ((g%CoriolisBu(i,j)**2 + g%CoriolisBu(i-1,j-1)**2) + &
811  (g%CoriolisBu(i,j-1)**2 + g%CoriolisBu(i-1,j)**2))
812  favg = 0.25*((g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j-1)) + &
813  (g%CoriolisBu(i,j-1) + g%CoriolisBu(i-1,j)))
814  df_dx = 0.5*((g%CoriolisBu(i,j) + g%CoriolisBu(i,j-1)) - &
815  (g%CoriolisBu(i-1,j) + g%CoriolisBu(i-1,j-1))) * g%IdxT(i,j)
816  dlncn_dx = 0.5*( g%IdxCu(i,j) * (cn(i+1,j) - cn(i,j)) / &
817  (0.5*(cn(i+1,j) + cn(i,j)) + cn_subro) + &
818  g%IdxCu(i-1,j) * (cn(i,j) - cn(i-1,j)) / &
819  (0.5*(cn(i,j) + cn(i-1,j)) + cn_subro) )
820  df_dy = 0.5*((g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j)) - &
821  (g%CoriolisBu(i,j-1) + g%CoriolisBu(i-1,j-1))) * g%IdyT(i,j)
822  dlncn_dy = 0.5*( g%IdyCv(i,j) * (cn(i,j+1) - cn(i,j)) / &
823  (0.5*(cn(i,j+1) + cn(i,j)) + cn_subro) + &
824  g%IdyCv(i,j-1) * (cn(i,j) - cn(i,j-1)) / &
825  (0.5*(cn(i,j) + cn(i,j-1)) + cn_subro) )
826  kmag2 = (freq**2 - f2) / (cn(i,j)**2 + cn_subro**2)
827  if (kmag2 > 0.0) then
828  i_kmag = 1.0 / sqrt(kmag2)
829  dk_dt_kmag(i) = -ifreq * (favg*df_dx + (freq**2 - f2) * dlncn_dx) * i_kmag
830  dl_dt_kmag(i) = -ifreq * (favg*df_dy + (freq**2 - f2) * dlncn_dy) * i_kmag
831  else
832  dk_dt_kmag(i) = 0.0
833  dl_dt_kmag(i) = 0.0
834  endif
835  enddo
836 
837  ! Determine the energy fluxes in angular orientation space.
838  do a=asd,aed ; do i=is,ie
839  cfl_ang(i,j,a) = (cos_angle(a) * dl_dt_kmag(i) - sin_angle(a) * dk_dt_kmag(i)) * dt_angle_size
840  if (abs(cfl_ang(i,j,a)) > 1.0) then
841  call mom_error(warning, "refract: CFL exceeds 1.", .true.)
842  if (cfl_ang(i,j,a) > 0.0) then ; cfl_ang(i,j,a) = 1.0 ; else ; cfl_ang(i,j,a) = -1.0 ; endif
843  endif
844  enddo ; enddo
845 
846  ! Advect in angular space
847  if (.not.use_ppmang) then
848  ! Use simple upwind
849  do a=0,na ; do i=is,ie
850  if (cfl_ang(i,j,a) > 0.0) then
851  flux_e(i,a) = cfl_ang(i,j,a) * en2d(i,a)
852  else
853  flux_e(i,a) = cfl_ang(i,j,a) * en2d(i,a+1)
854  endif
855  enddo ; enddo
856  else
857  ! Use PPM
858  do i=is,ie
859  call ppm_angular_advect(en2d(i,:),cfl_ang(i,j,:),flux_e(i,:),nangle,dt,stencil)
860  enddo
861  endif
862 
863  ! Update and copy back to En.
864  do a=1,na ; do i=is,ie
865  !if (En2d(i,a)+(Flux_E(i,A-1)-Flux_E(i,A)) < 0.0) then ! for debugging
866  ! call MOM_error(FATAL, "refract: OutFlux>Available")
867  !endif
868  en(i,j,a) = en2d(i,a) + (flux_e(i,a-1) - flux_e(i,a))
869  enddo ; enddo
870  enddo ! j-loop

◆ sum_en()

subroutine mom_internal_tides::sum_en ( type(ocean_grid_type), intent(in)  G,
type(int_tide_cs), pointer  CS,
real, dimension(g%isd:g%ied,g%jsd:g%jed,cs%nangle), intent(in)  En,
character(len=*), intent(in)  label 
)
private

Checks for energy conservation on computational domain.

Parameters
[in]gThe ocean's grid structure.
csThe control structure returned by a previous call to int_tide_init.
[in]enThe energy density of the internal tides [R Z3 T-2 ~> J m-2].
[in]labelA label to use in error messages

Definition at line 594 of file MOM_internal_tides.F90.

594  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
595  type(int_tide_CS), pointer :: CS !< The control structure returned by a
596  !! previous call to int_tide_init.
597  real, dimension(G%isd:G%ied,G%jsd:G%jed,CS%NAngle), &
598  intent(in) :: En !< The energy density of the internal tides [R Z3 T-2 ~> J m-2].
599  character(len=*), intent(in) :: label !< A label to use in error messages
600  ! Local variables
601  real :: En_sum ! The total energy [R Z3 T-2 ~> J m-2]
602  real :: tmpForSumming
603  integer :: m,fr,a
604  ! real :: En_sum_diff, En_sum_pdiff
605  ! character(len=160) :: mesg ! The text of an error message
606  ! real :: days
607 
608  en_sum = 0.0
609  tmpforsumming = 0.0
610  do a=1,cs%nAngle
611  tmpforsumming = global_area_mean(en(:,:,a),g)*g%areaT_global
612  en_sum = en_sum + tmpforsumming
613  enddo
614  cs%En_sum = en_sum
615  !En_sum_diff = En_sum - CS%En_sum
616  !if (CS%En_sum /= 0.0) then
617  ! En_sum_pdiff= (En_sum_diff/CS%En_sum)*100.0
618  !else
619  ! En_sum_pdiff= 0.0
620  !endif
621  !! Print to screen
622  !if (is_root_pe()) then
623  ! days = time_type_to_real(CS%Time) / 86400.0
624  ! write(mesg,*) trim(label)//': days =', days, ', En_sum=', En_sum, &
625  ! ', En_sum_diff=', En_sum_diff, ', Percent change=', En_sum_pdiff, '%'
626  ! call MOM_mesg(mesg)
627  !if (is_root_pe() .and. (abs(En_sum_pdiff) > 1.0)) &
628  ! call MOM_error(FATAL, "Run stopped due to excessive internal tide energy change.")
629  !endif
630 

◆ teleport()

subroutine mom_internal_tides::teleport ( real, dimension(g%isd:g%ied,g%jsd:g%jed,nangle), intent(inout)  En,
integer, intent(in)  NAngle,
type(int_tide_cs), pointer  CS,
type(ocean_grid_type), intent(in)  G,
type(loop_bounds_type), intent(in)  LB 
)
private

Moves energy across lines of partial reflection to prevent reflection of energy that is supposed to get across.

Parameters
[in]gThe ocean's grid structure.
[in]nangleThe number of wave orientations in the discretized wave energy spectrum.
[in,out]enThe internal gravity wave energy density as a
csThe control structure returned by a previous call to int_tide_init.
[in]lbA structure with the active energy loop bounds.

Definition at line 1710 of file MOM_internal_tides.F90.

1710  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1711  integer, intent(in) :: NAngle !< The number of wave orientations in the
1712  !! discretized wave energy spectrum.
1713  real, dimension(G%isd:G%ied,G%jsd:G%jed,NAngle), &
1714  intent(inout) :: En !< The internal gravity wave energy density as a
1715  !! function of space and angular resolution
1716  !! [R Z3 T-2 ~> J m-2].
1717  type(int_tide_CS), pointer :: CS !< The control structure returned by a
1718  !! previous call to int_tide_init.
1719  type(loop_bounds_type), intent(in) :: LB !< A structure with the active energy loop bounds.
1720  ! Local variables
1721  real, dimension(G%isd:G%ied,G%jsd:G%jed) :: angle_c
1722  ! angle of boundary wrt equator [rad]
1723  real, dimension(G%isd:G%ied,G%jsd:G%jed) :: part_refl
1724  ! fraction of wave energy reflected
1725  ! values should collocate with angle_c [nondim]
1726  logical, dimension(G%isd:G%ied,G%jsd:G%jed) :: pref_cell
1727  ! flag for partial reflection
1728  logical, dimension(G%isd:G%ied,G%jsd:G%jed) :: ridge
1729  ! tags of cells with double reflection
1730  real :: TwoPi ! 2*pi = 6.2831853... [nondim]
1731  real :: Angle_size ! size of beam wedge [rad]
1732  real, dimension(1:NAngle) :: angle_i ! angle of incident ray wrt equator [rad]
1733  real, dimension(1:NAngle) :: cos_angle, sin_angle
1734  real :: En_tele ! energy to be "teleported" [R Z3 T-2 ~> J m-2]
1735  character(len=160) :: mesg ! The text of an error message
1736  integer :: i, j, a
1737  !integer :: isd, ied, jsd, jed ! start and end local indices on data domain
1738  ! ! (values include halos)
1739  !integer :: isc, iec, jsc, jec ! start and end local indices on PE
1740  ! ! (values exclude halos)
1741  integer :: ish, ieh, jsh, jeh ! start and end local indices on data domain
1742  ! leaving out outdated halo points (march in)
1743  integer :: id_g, jd_g ! global (decomp-invar) indices
1744  integer :: jos, ios ! offsets
1745  real :: cos_normal, sin_normal, angle_wall
1746  ! cos/sin of cross-ridge normal, ridge angle
1747 
1748  !isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
1749  !isc = G%isc ; iec = G%iec ; jsc = G%jsc ; jec = G%jec
1750  ish = lb%ish ; ieh = lb%ieh ; jsh = lb%jsh ; jeh = lb%jeh
1751 
1752  twopi = 8.0*atan(1.0)
1753  angle_size = twopi / (real(NAngle))
1754 
1755  do a=1,nangle
1756  ! These are the angles at the cell centers
1757  ! (should do this elsewhere since doesn't change with time)
1758  angle_i(a) = angle_size * real(a - 1) ! for a=1 aligned with x-axis
1759  cos_angle(a) = cos(angle_i(a)) ; sin_angle(a) = sin(angle_i(a))
1760  enddo
1761 
1762  angle_c = cs%refl_angle
1763  part_refl = cs%refl_pref
1764  pref_cell = cs%refl_pref_logical
1765  ridge = cs%refl_dbl
1766 
1767  do j=jsh,jeh
1768  do i=ish,ieh
1769  id_g = i + g%idg_offset ; jd_g = j + g%jdg_offset
1770  if (pref_cell(i,j)) then
1771  do a=1,nangle
1772  if (en(i,j,a) > 0) then
1773  ! if ray is incident, keep specified boundary angle
1774  if (sin(angle_i(a) - angle_c(i,j)) >= 0.0) then
1775  angle_wall = angle_c(i,j)
1776  ! if ray is not incident but in ridge cell, use complementary angle
1777  elseif (ridge(i,j)) then
1778  angle_wall = angle_c(i,j) + 0.5*twopi
1779  ! if ray is not incident and not in a ridge cell, keep specified angle
1780  else
1781  angle_wall = angle_c(i,j)
1782  endif
1783  ! teleport if incident
1784  if (sin(angle_i(a) - angle_wall) >= 0.0) then
1785  en_tele = en(i,j,a)
1786  cos_normal = cos(angle_wall + 0.25*twopi)
1787  sin_normal = sin(angle_wall + 0.25*twopi)
1788  ! find preferred zonal offset based on shelf/ridge angle
1789  ios = int(sign(1.,cos_normal))
1790  ! find preferred meridional offset based on shelf/ridge angle
1791  jos = int(sign(1.,sin_normal))
1792  ! find receptive ocean cell in direction of offset
1793  if (.not. pref_cell(i+ios,j+jos)) then
1794  en(i,j,a) = en(i,j,a) - en_tele
1795  en(i+ios,j+jos,a) = en(i+ios,j+jos,a) + en_tele
1796  else
1797  write(mesg,*) 'idg=',id_g,'jd_g=',jd_g,'a=',a
1798  call mom_error(fatal, "teleport: no receptive ocean cell at "//trim(mesg), .true.)
1799  endif
1800  endif ! incidence check
1801  endif ! energy check
1802  enddo ! a-loop
1803  endif ! pref check
1804  enddo ! i-loop
1805  enddo ! j-loop
1806 

◆ zonal_flux_en()

subroutine mom_internal_tides::zonal_flux_en ( real, dimension(szib_(g)), intent(in)  u,
real, dimension(szi_(g)), intent(in)  h,
real, dimension(szi_(g)), intent(in)  hL,
real, dimension(szi_(g)), intent(in)  hR,
real, dimension(szib_(g)), intent(inout)  uh,
real, intent(in)  dt,
type(ocean_grid_type), intent(in)  G,
type(unit_scale_type), intent(in)  US,
integer, intent(in)  j,
integer, intent(in)  ish,
integer, intent(in)  ieh,
logical, intent(in)  vol_CFL 
)
private

Evaluates the zonal mass or volume fluxes in a layer.

Parameters
[in]gThe ocean's grid structure.
[in]uThe zonal velocity [L T-1 ~> m s-1].
[in]hEnergy density used to calculate the fluxes [R Z3 T-2 ~> J m-2].
[in]hlLeft- Energy densities in the reconstruction [R Z3 T-2 ~> J m-2].
[in]hrRight- Energy densities in the reconstruction [R Z3 T-2 ~> J m-2].
[in,out]uhThe zonal energy transport [R Z3 L2 T-3 ~> J s-1].
[in]dtTime increment [T ~> s].
[in]usA dimensional unit scaling type
[in]jThe j-index to work on.
[in]ishThe start i-index range to work on.
[in]iehThe end i-index range to work on.
[in]vol_cflIf true, rescale the ratio of face areas to the cell areas when estimating the CFL number.

Definition at line 1516 of file MOM_internal_tides.F90.

1516  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1517  real, dimension(SZIB_(G)), intent(in) :: u !< The zonal velocity [L T-1 ~> m s-1].
1518  real, dimension(SZI_(G)), intent(in) :: h !< Energy density used to calculate the fluxes
1519  !! [R Z3 T-2 ~> J m-2].
1520  real, dimension(SZI_(G)), intent(in) :: hL !< Left- Energy densities in the reconstruction
1521  !! [R Z3 T-2 ~> J m-2].
1522  real, dimension(SZI_(G)), intent(in) :: hR !< Right- Energy densities in the reconstruction
1523  !! [R Z3 T-2 ~> J m-2].
1524  real, dimension(SZIB_(G)), intent(inout) :: uh !< The zonal energy transport [R Z3 L2 T-3 ~> J s-1].
1525  real, intent(in) :: dt !< Time increment [T ~> s].
1526  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1527  integer, intent(in) :: j !< The j-index to work on.
1528  integer, intent(in) :: ish !< The start i-index range to work on.
1529  integer, intent(in) :: ieh !< The end i-index range to work on.
1530  logical, intent(in) :: vol_CFL !< If true, rescale the ratio of face areas to
1531  !! the cell areas when estimating the CFL number.
1532  ! Local variables
1533  real :: CFL ! The CFL number based on the local velocity and grid spacing [nondim].
1534  real :: curv_3 ! A measure of the energy density curvature over a grid length [R Z3 T-2 ~> J m-2]
1535  integer :: i
1536 
1537  do i=ish-1,ieh
1538  ! Set new values of uh and duhdu.
1539  if (u(i) > 0.0) then
1540  if (vol_cfl) then ; cfl = (u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i,j))
1541  else ; cfl = u(i) * dt * g%IdxT(i,j) ; endif
1542  curv_3 = (hl(i) + hr(i)) - 2.0*h(i)
1543  uh(i) = g%dy_Cu(i,j) * u(i) * &
1544  (hr(i) + cfl * (0.5*(hl(i) - hr(i)) + curv_3*(cfl - 1.5)))
1545  elseif (u(i) < 0.0) then
1546  if (vol_cfl) then ; cfl = (-u(i) * dt) * (g%dy_Cu(i,j) * g%IareaT(i+1,j))
1547  else ; cfl = -u(i) * dt * g%IdxT(i+1,j) ; endif
1548  curv_3 = (hl(i+1) + hr(i+1)) - 2.0*h(i+1)
1549  uh(i) = g%dy_Cu(i,j) * u(i) * &
1550  (hl(i+1) + cfl * (0.5*(hr(i+1)-hl(i+1)) + curv_3*(cfl - 1.5)))
1551  else
1552  uh(i) = 0.0
1553  endif
1554  enddo