MOM6
MOM_internal_tide_input.F90
Go to the documentation of this file.
2 !***********************************************************************
3 !* GNU General Public License *
4 !* This file is a part of MOM. *
5 !* *
6 !* MOM is free software; you can redistribute it and/or modify it and *
7 !* are expected to follow the terms of the GNU General Public License *
8 !* as published by the Free Software Foundation; either version 2 of *
9 !* the License, or (at your option) any later version. *
10 !* *
11 !* MOM is distributed in the hope that it will be useful, but WITHOUT *
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
13 !* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public *
14 !* License for more details. *
15 !* *
16 !* For the full text of the GNU General Public License, *
17 !* write to: Free Software Foundation, Inc., *
18 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
19 !* or see: http://www.gnu.org/licenses/gpl.html *
20 !***********************************************************************
21 
22 !********+*********+*********+*********+*********+*********+*********+**
23 !* *
24 !* By Robert Hallberg, January 2013 *
25 !* *
26 !* This file contains the subroutines that sets the energy input *
27 !* to the internal tides. *
28 !* *
29 !* A small fragment of the grid is shown below: *
30 !* *
31 !* j+1 x ^ x ^ x At x: q *
32 !* j+1 > o > o > At ^: v *
33 !* j x ^ x ^ x At >: u *
34 !* j > o > o > At o: h, buoy, ustar, T, S, Kd, ea, eb, etc. *
35 !* j-1 x ^ x ^ x *
36 !* i-1 i i+1 At x & ^: *
37 !* i i+1 At > & o: *
38 !* *
39 !* The boundaries always run through q grid points (x). *
40 !* *
41 !********+*********+*********+*********+*********+*********+*********+**
42 
43 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
44 use mom_cpu_clock, only : clock_module_driver, clock_module, clock_routine
45 use mom_diag_mediator, only : diag_ctrl, time_type
46 use mom_diag_mediator, only : safe_alloc_ptr, post_data, register_diag_field
48 use mom_debugging, only : hchksum
49 use mom_error_handler, only : mom_error, is_root_pe, fatal, warning, note
51 use mom_forcing_type, only : forcing
52 use mom_grid, only : ocean_grid_type
53 use mom_io, only : slasher, vardesc
58 
59 use fms_mod, only : read_data
60 
61 implicit none ; private
62 
63 #include <MOM_memory.h>
64 
66 
67 type, public :: int_tide_input_cs ; private
68  logical :: debug ! If true, write verbose checksums for debugging.
69  type(diag_ctrl), pointer :: diag ! A structure that is used to regulate the
70  ! timing of diagnostic output.
71  real :: tke_itide_max ! Maximum Internal tide conversion (W m-2)
72  ! available to mix above the BBL
73 
74  real, allocatable, dimension(:,:) :: &
75  tke_itidal_coef ! The time-invariant field that enters the TKE_itidal
76  ! input calculation, in J m-2.
77 
78  integer :: id_tke_itidal = -1, id_nb = -1, id_n2_bot = -1
79  character(len=200) :: inputdir
80 end type int_tide_input_cs
81 
82 type, public :: int_tide_input_type
83  real, allocatable, dimension(:,:) :: &
84  tke_itidal_input, & ! The internal tide TKE input at the bottom of
85  ! the ocean, in W m-2.
86  h2, & ! The squared topographic roughness height, in m2.
87  tideamp, & ! The amplitude of the tidal velocities, in m s-1.
88  nb ! The bottom stratification, in s-1.
89 end type int_tide_input_type
90 
91 contains
92 
93 subroutine set_int_tide_input(u, v, h, tv, fluxes, itide, dt, G, GV, CS)
94  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
95  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
96  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< The zonal velocity, in m s-1
97  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< The meridional velocity, in m s-1
98  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
99  type(thermo_var_ptrs), intent(in) :: tv
100  type(forcing), intent(in) :: fluxes
101  type(int_tide_input_type), intent(inout) :: itide
102  real, intent(in) :: dt
103  type(int_tide_input_cs), pointer :: CS
104 
105 ! Arguments: u - Zonal velocity, in m s-1.
106 ! (in) v - Meridional velocity, in m s-1.
107 ! (in) h - Layer thickness, in m or kg m-2.
108 ! (in) tv - A structure containing pointers to any available
109 ! thermodynamic fields. Absent fields have NULL ptrs.
110 ! (in) fluxes - A structure of surface fluxes that may be used.
111 ! (inout) itide - A structure containing fields related to the internal
112 ! tide sources.
113 ! (in) dt - The time increment in s.
114 ! (in) G - The ocean's grid structure.
115 ! (in) GV - The ocean's vertical grid structure.
116 ! (in) CS - This module's control structure.
117 
118  real, dimension(SZI_(G),SZJ_(G)) :: &
119  N2_bot ! The bottom squared buoyancy frequency, in s-2.
120 
121  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
122  T_f, S_f ! The temperature and salinity in C and PSU with the values in
123  ! the massless layers filled vertically by diffusion.
124  logical :: use_EOS ! If true, density is calculated from T & S using an
125  ! equation of state.
126  integer :: i, j, k, is, ie, js, je, nz
127  integer :: isd, ied, jsd, jed
128 
129  real :: kappa_fill ! diffusivity used to fill massless layers
130  real :: dt_fill ! timestep used to fill massless layers
131 
132  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
133  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
134 
135  if (.not.associated(cs)) call mom_error(fatal,"set_diffusivity: "//&
136  "Module must be initialized before it is used.")
137 
138  kappa_fill = 1.e-3 ! m2 s-1
139  dt_fill = 7200.
140 
141  use_eos = associated(tv%eqn_of_state)
142 
143  ! Smooth the properties through massless layers.
144  if (use_eos) then
145  call vert_fill_ts(h, tv%T, tv%S, kappa_fill, dt_fill, t_f, s_f, g, gv)
146  endif
147 
148  call find_n2_bottom(h, tv, t_f, s_f, itide%h2, fluxes, g, gv, n2_bot)
149 
150 !$OMP parallel do default(none) shared(is,ie,js,je,G,itide,N2_bot,CS)
151  do j=js,je ; do i=is,ie
152  itide%Nb(i,j) = g%mask2dT(i,j) * sqrt(n2_bot(i,j))
153  itide%TKE_itidal_input(i,j) = min(cs%TKE_itidal_coef(i,j)*itide%Nb(i,j),cs%TKE_itide_max)
154  enddo ; enddo
155 
156  if (cs%debug) then
157  call hchksum(n2_bot,"N2_bot",g%HI,haloshift=0)
158  call hchksum(itide%TKE_itidal_input,"TKE_itidal_input",g%HI,haloshift=0)
159  endif
160 
161  if (cs%id_TKE_itidal > 0) call post_data(cs%id_TKE_itidal, itide%TKE_itidal_input, cs%diag)
162  if (cs%id_Nb > 0) call post_data(cs%id_Nb, itide%Nb, cs%diag)
163  if (cs%id_N2_bot > 0 ) call post_data(cs%id_N2_bot,n2_bot,cs%diag)
164 
165 end subroutine set_int_tide_input
166 
167 subroutine find_n2_bottom(h, tv, T_f, S_f, h2, fluxes, G, GV, N2_bot)
168  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
169  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
170  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
171  type(thermo_var_ptrs), intent(in) :: tv
172  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: T_f, S_f
173  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: h2
174  type(forcing), intent(in) :: fluxes
175  type(int_tide_input_cs), pointer :: CS
176  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: N2_bot
177 
178  real, dimension(SZI_(G),SZK_(G)+1) :: &
179  dRho_int ! The unfiltered density differences across interfaces.
180  real, dimension(SZI_(G)) :: &
181  pres, & ! The pressure at each interface, in Pa.
182  Temp_int, & ! The temperature at each interface, in degC.
183  Salin_int, & ! The salinity at each interface, in PSU.
184  drho_bot, &
185  h_amp, &
186  hb, &
187  z_from_bot, &
188  dRho_dT, & ! The partial derivatives of density with temperature and
189  dRho_dS ! salinity, in kg m-3 degC-1 and kg m-3 PSU-1.
190 
191  real :: dz_int ! The thickness associated with an interface, in m.
192  real :: G_Rho0 ! The gravitation acceleration divided by the Boussinesq
193  ! density, in m4 s-2 kg-1.
194  logical :: do_i(szi_(g)), do_any
195  integer :: i, j, k, is, ie, js, je, nz
196  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
197  g_rho0 = gv%g_Earth / gv%Rho0
198 
199  ! Find the (limited) density jump across each interface.
200  do i=is,ie
201  drho_int(i,1) = 0.0 ; drho_int(i,nz+1) = 0.0
202  enddo
203 !$OMP parallel do default(none) shared(is,ie,js,je,nz,tv,fluxes,G,GV,h,T_f,S_f, &
204 !$OMP h2,N2_bot,G_Rho0) &
205 !$OMP private(pres,Temp_Int,Salin_Int,dRho_dT,dRho_dS, &
206 !$OMP hb,dRho_bot,z_from_bot,do_i,h_amp, &
207 !$OMP do_any,dz_int) &
208 !$OMP firstprivate(dRho_int)
209  do j=js,je
210  if (associated(tv%eqn_of_state)) then
211  if (associated(fluxes%p_surf)) then
212  do i=is,ie ; pres(i) = fluxes%p_surf(i,j) ; enddo
213  else
214  do i=is,ie ; pres(i) = 0.0 ; enddo
215  endif
216  do k=2,nz
217  do i=is,ie
218  pres(i) = pres(i) + gv%H_to_Pa*h(i,j,k-1)
219  temp_int(i) = 0.5 * (t_f(i,j,k) + t_f(i,j,k-1))
220  salin_int(i) = 0.5 * (s_f(i,j,k) + s_f(i,j,k-1))
221  enddo
222  call calculate_density_derivs(temp_int, salin_int, pres, &
223  drho_dt(:), drho_ds(:), is, ie-is+1, tv%eqn_of_state)
224  do i=is,ie
225  drho_int(i,k) = max(drho_dt(i)*(t_f(i,j,k) - t_f(i,j,k-1)) + &
226  drho_ds(i)*(s_f(i,j,k) - s_f(i,j,k-1)), 0.0)
227  enddo
228  enddo
229  else
230  do k=2,nz ; do i=is,ie
231  drho_int(i,k) = gv%Rlay(k) - gv%Rlay(k-1)
232  enddo ; enddo
233  endif
234 
235  ! Find the bottom boundary layer stratification.
236  do i=is,ie
237  hb(i) = 0.0 ; drho_bot(i) = 0.0
238  z_from_bot(i) = 0.5*gv%H_to_m*h(i,j,nz)
239  do_i(i) = (g%mask2dT(i,j) > 0.5)
240  h_amp(i) = sqrt(h2(i,j))
241  enddo
242 
243  do k=nz,2,-1
244  do_any = .false.
245  do i=is,ie ; if (do_i(i)) then
246  dz_int = 0.5*gv%H_to_m*(h(i,j,k) + h(i,j,k-1))
247  z_from_bot(i) = z_from_bot(i) + dz_int ! middle of the layer above
248 
249  hb(i) = hb(i) + dz_int
250  drho_bot(i) = drho_bot(i) + drho_int(i,k)
251 
252  if (z_from_bot(i) > h_amp(i)) then
253  if (k>2) then
254  ! Always include at least one full layer.
255  hb(i) = hb(i) + 0.5*gv%H_to_m*(h(i,j,k-1) + h(i,j,k-2))
256  drho_bot(i) = drho_bot(i) + drho_int(i,k-1)
257  endif
258  do_i(i) = .false.
259  else
260  do_any = .true.
261  endif
262  endif ; enddo
263  if (.not.do_any) exit
264  enddo
265 
266  do i=is,ie
267  if (hb(i) > 0.0) then
268  n2_bot(i,j) = (g_rho0 * drho_bot(i)) / hb(i)
269  else ; n2_bot(i,j) = 0.0 ; endif
270  enddo
271  enddo
272 
273 end subroutine find_n2_bottom
274 
275 subroutine int_tide_input_init(Time, G, GV, param_file, diag, CS, itide)
276  type(time_type), intent(in) :: Time
277  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
278  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure
279  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
280  type(diag_ctrl), target, intent(inout) :: diag
281  type(int_tide_input_cs), pointer :: CS
282  type(int_tide_input_type), pointer :: itide
283 ! Arguments: Time - The current model time.
284 ! (in) G - The ocean's grid structure.
285 ! (in) GV - The ocean's vertical grid structure.
286 ! (in) param_file - A structure indicating the open file to parse for
287 ! model parameter values.
288 ! (in) diag - A structure that is used to regulate diagnostic output.
289 ! (in/out) CS - A pointer that is set to point to the control structure
290 ! for this module
291 ! (in) diag_to_Z_CSp - A pointer to the Z-diagnostics control structure.
292  type(vardesc) :: vd
293  logical :: read_tideamp
294 ! This include declares and sets the variable "version".
295 #include "version_variable.h"
296  character(len=40) :: mdl = "MOM_int_tide_input" ! This module's name.
297  character(len=20) :: tmpstr
298  character(len=200) :: filename, tideamp_file, h2_file
299 
300  real :: mask_itidal
301  real :: utide ! constant tidal amplitude (m s-1) to be used if
302  ! tidal amplitude file is not present.
303  real :: kappa_h2_factor ! factor for the product of wavenumber * rms sgs height.
304  real :: kappa_itides ! topographic wavenumber and non-dimensional scaling
305  real :: min_zbot_itides ! Minimum ocean depth for internal tide conversion,
306  ! in m.
307  integer :: i, j, is, ie, js, je, isd, ied, jsd, jed
308 
309  if (associated(cs)) then
310  call mom_error(warning, "int_tide_input_init called with an associated "// &
311  "control structure.")
312  return
313  endif
314  if (associated(itide)) then
315  call mom_error(warning, "int_tide_input_init called with an associated "// &
316  "internal tide input type.")
317  return
318  endif
319  allocate(cs)
320  allocate(itide)
321 
322  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
323  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
324 
325  cs%diag => diag
326 
327  ! Read all relevant parameters and write them to the model log.
328  call log_version(param_file, mdl, version, "")
329 
330  call get_param(param_file, mdl, "INPUTDIR", cs%inputdir, default=".")
331  cs%inputdir = slasher(cs%inputdir)
332 
333  call get_param(param_file, mdl, "DEBUG", cs%debug, default=.false., do_not_log=.true.)
334 
335  call get_param(param_file, mdl, "MIN_ZBOT_ITIDES", min_zbot_itides, &
336  "Turn off internal tidal dissipation when the total \n"//&
337  "ocean depth is less than this value.", units="m", default=0.0)
338 
339  call get_param(param_file, mdl, "UTIDE", utide, &
340  "The constant tidal amplitude used with INT_TIDE_DISSIPATION.", &
341  units="m s-1", default=0.0)
342 
343  allocate(itide%Nb(isd:ied,jsd:jed)) ; itide%Nb(:,:) = 0.0
344  allocate(itide%h2(isd:ied,jsd:jed)) ; itide%h2(:,:) = 0.0
345  allocate(itide%TKE_itidal_input(isd:ied,jsd:jed)) ; itide%TKE_itidal_input(:,:) = 0.0
346  allocate(itide%tideamp(isd:ied,jsd:jed)) ; itide%tideamp(:,:) = utide
347  allocate(cs%TKE_itidal_coef(isd:ied,jsd:jed)) ; cs%TKE_itidal_coef(:,:) = 0.0
348 
349  call get_param(param_file, mdl, "KAPPA_ITIDES", kappa_itides, &
350  "A topographic wavenumber used with INT_TIDE_DISSIPATION. \n"//&
351  "The default is 2pi/10 km, as in St.Laurent et al. 2002.", &
352  units="m-1", default=8.e-4*atan(1.0))
353 
354  call get_param(param_file, mdl, "KAPPA_H2_FACTOR", kappa_h2_factor, &
355  "A scaling factor for the roughness amplitude with n"//&
356  "INT_TIDE_DISSIPATION.", units="nondim", default=1.0)
357  call get_param(param_file, mdl, "TKE_ITIDE_MAX", cs%TKE_itide_max, &
358  "The maximum internal tide energy source availble to mix \n"//&
359  "above the bottom boundary layer with INT_TIDE_DISSIPATION.", &
360  units="W m-2", default=1.0e3)
361 
362  call get_param(param_file, mdl, "READ_TIDEAMP", read_tideamp, &
363  "If true, read a file (given by TIDEAMP_FILE) containing \n"//&
364  "the tidal amplitude with INT_TIDE_DISSIPATION.", default=.false.)
365  if (read_tideamp) then
366  call get_param(param_file, mdl, "TIDEAMP_FILE", tideamp_file, &
367  "The path to the file containing the spatially varying \n"//&
368  "tidal amplitudes with INT_TIDE_DISSIPATION.", default="tideamp.nc")
369  filename = trim(cs%inputdir) // trim(tideamp_file)
370  call log_param(param_file, mdl, "INPUTDIR/TIDEAMP_FILE", filename)
371  call read_data(filename, 'tideamp', itide%tideamp, &
372  domain=g%domain%mpp_domain, timelevel=1)
373  endif
374 
375  call get_param(param_file, mdl, "H2_FILE", h2_file, &
376  "The path to the file containing the sub-grid-scale \n"//&
377  "topographic roughness amplitude with INT_TIDE_DISSIPATION.", &
378  fail_if_missing=.true.)
379  filename = trim(cs%inputdir) // trim(h2_file)
380  call log_param(param_file, mdl, "INPUTDIR/H2_FILE", filename)
381  call read_data(filename, 'h2', itide%h2, domain=g%domain%mpp_domain, &
382  timelevel=1)
383 
384  do j=js,je ; do i=is,ie
385  mask_itidal = 1.0
386  if (g%bathyT(i,j) < min_zbot_itides) mask_itidal = 0.0
387 
388  itide%tideamp(i,j) = itide%tideamp(i,j) * mask_itidal * g%mask2dT(i,j)
389 
390  ! Restrict rms topo to 10 percent of column depth.
391  itide%h2(i,j) = min(0.01*g%bathyT(i,j)**2, itide%h2(i,j))
392 
393  ! Compute the fixed part of internal tidal forcing; units are [J m-2] here.
394  cs%TKE_itidal_coef(i,j) = 0.5*kappa_h2_factor*gv%Rho0*&
395  kappa_itides * itide%h2(i,j) * itide%tideamp(i,j)**2
396  enddo; enddo
397 
398 
399  cs%id_TKE_itidal = register_diag_field('ocean_model','TKE_itidal_itide',diag%axesT1,time, &
400  'Internal Tide Driven Turbulent Kinetic Energy', 'Watt meter-2')
401 
402  cs%id_Nb = register_diag_field('ocean_model','Nb_itide',diag%axesT1,time, &
403  'Bottom Buoyancy Frequency', 'sec-1')
404 
405  cs%id_N2_bot = register_diag_field('ocean_model','N2_b_itide',diag%axesT1,time, &
406  'Bottom Buoyancy frequency squared', 's-2')
407 
408 end subroutine int_tide_input_init
409 
410 subroutine int_tide_input_end(CS)
411  type(int_tide_input_cs), pointer :: CS
412 
413  if (associated(cs)) deallocate(cs)
414 
415 end subroutine int_tide_input_end
416 
417 end module mom_int_tide_input
subroutine, public int_tide_input_init(Time, G, GV, param_file, diag, CS, itide)
This module implements boundary forcing for MOM6.
subroutine, public vert_fill_ts(h, T_in, S_in, kappa, dt, T_f, S_f, G, GV, halo_here)
Fills tracer values in massless layers with sensible values by diffusing vertically with a (small) co...
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
Provides the ocean grid type.
Definition: MOM_grid.F90:2
The vertvisc_type structure contains vertical viscosities, drag coefficients, and related fields...
This module contains I/O framework code.
Definition: MOM_io.F90:2
subroutine, public int_tide_input_end(CS)
subroutine, public calculate_density_derivs(T, S, pressure, drho_dT, drho_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate density derivatives for 1-D array inputs.
Definition: MOM_EOS.F90:214
Thickness diffusion (or Gent McWilliams)
logical function, public is_root_pe()
subroutine find_n2_bottom(h, tv, T_f, S_f, h2, fluxes, G, GV, N2_bot)
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:51
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine, public set_int_tide_input(u, v, h, tv, fluxes, itide, dt, G, GV, CS)
integer function, public register_zint_diag(var_desc, CS, day)
integer function, public register_diag_field(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name, cell_methods, x_cell_method, y_cell_method, v_cell_method, conversion, v_extensive)
Returns the "diag_mediator" handle for a group (native, CMOR, z-coord, ...) of diagnostics derived fr...
subroutine, public mom_error(level, message, all_print)
subroutine, public calc_zint_diags(h, in_ptrs, ids, num_diags, G, GV, CS)