MOM_kappa_shear.F90
1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Shear-dependent mixing following Jackson et al. 2008.
6module mom_kappa_shear
7
8use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
9use mom_cpu_clock, only : clock_module_driver, clock_module, clock_routine
10use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
11use mom_diag_mediator, only : diag_ctrl, time_type
12use mom_debugging, only : hchksum, bchksum
13use mom_error_handler, only : mom_error, is_root_pe, fatal, warning, note
14use mom_file_parser, only : get_param, log_version, param_file_type
15use mom_grid, only : ocean_grid_type
16use mom_interface_heights, only : thickness_to_dz
17use mom_unit_scaling, only : unit_scale_type
18use mom_variables, only : thermo_var_ptrs
19use mom_verticalgrid, only : verticalgrid_type
20use mom_eos, only : calculate_density_derivs
21use mom_eos, only : calculate_density, calculate_specific_vol_derivs
22
23implicit none ; private
24
25#include <MOM_memory.h>
26
28public kappa_shear_is_used, kappa_shear_at_vertex
29
30! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
31! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
32! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
33! vary with the Boussinesq approximation, the Boussinesq variant is given first.
34
35!> This control structure holds the parameters that regulate shear mixing
36type, public :: kappa_shear_cs ; private
37 real :: rino_crit !< The critical shear Richardson number for
38 !! shear-entrainment [nondim]. The theoretical value is 0.25.
39 !! The values found by Jackson et al. are 0.25-0.35.
40 real :: shearmix_rate !< A nondimensional rate scale for shear-driven
41 !! entrainment [nondim]. The value given by Jackson et al.
42 !! is 0.085-0.089.
43 real :: fri_curvature !< A constant giving the curvature of the function
44 !! of the Richardson number that relates shear to
45 !! sources in the kappa equation [nondim].
46 !! The values found by Jackson et al. are -0.97 - -0.89.
47 real :: c_n !< The coefficient for the decay of TKE due to
48 !! stratification (i.e. proportional to N*tke) [nondim].
49 !! The values found by Jackson et al. are 0.24-0.28.
50 real :: c_s !< The coefficient for the decay of TKE due to
51 !! shear (i.e. proportional to |S|*tke) [nondim].
52 !! The values found by Jackson et al. are 0.14-0.12.
53 real :: lambda !< The coefficient for the buoyancy length scale
54 !! in the kappa equation [nondim].
55 !! The values found by Jackson et al. are 0.82-0.81.
56 real :: lambda2_n_s !< The square of the ratio of the coefficients of
57 !! the buoyancy and shear scales in the diffusivity
58 !! equation, 0 to eliminate the shear scale [nondim].
59 real :: lz_rescale !< A coefficient to rescale the distance to the nearest
60 !! solid boundary. This adjustment is to account for
61 !! regions where 3 dimensional turbulence prevents the
62 !! growth of shear instabilities [nondim].
63 real :: tke_bg !< The background level of TKE [Z2 T-2 ~> m2 s-2].
64 real :: kappa_0 !< The background diapycnal diffusivity [H Z T-1 ~> m2 s-1 or Pa s]
65 real :: kappa_seed !< A moderately large seed value of diapycnal diffusivity that
66 !! is used as a starting turbulent diffusivity in the iterations
67 !! to finding an energetically constrained solution for the
68 !! shear-driven diffusivity [H Z T-1 ~> m2 s-1 or Pa s]
69 real :: kappa_trunc !< Diffusivities smaller than this are rounded to 0 [H Z T-1 ~> m2 s-1 or Pa s]
70 real :: kappa_tol_err !< The fractional error in kappa that is tolerated [nondim].
71 real :: prandtl_turb !< Prandtl number used to convert Kd_shear into viscosity [nondim].
72 integer :: nkml !< The number of layers in the mixed layer, as
73 !! treated in this routine. If the pieces of the
74 !! mixed layer are not to be treated collectively,
75 !! nkml is set to 1.
76 integer :: max_rino_it !< The maximum number of iterations that may be used
77 !! to estimate the instantaneous shear-driven mixing.
78 integer :: max_ks_it !< The maximum number of iterations that may be used
79 !! to estimate the time-averaged diffusivity.
80 logical :: dkdq_iteration_bug !< If true. use an older, dimensionally inconsistent estimate of
81 !! the derivative of diffusivity with energy in the Newton's method
82 !! iteration. The bug causes under-corrections when dz > 1m.
83 logical :: ks_at_vertex !< If true, do the calculations of the shear-driven mixing
84 !! at the cell vertices (i.e., the vorticity points).
85 logical :: eliminate_massless !< If true, massless layers are merged with neighboring
86 !! massive layers in this calculation.
87 ! I can think of no good reason why this should be false. - RWH
88 real :: vel_underflow !< Velocity components smaller than vel_underflow
89 !! are set to 0 [L T-1 ~> m s-1].
90 real :: kappa_src_max_chg !< The maximum permitted increase in the kappa source within an
91 !! iteration relative to the local source [nondim]. This must be
92 !! greater than 1. The lower limit for the permitted fractional
93 !! decrease is (1 - 0.5/kappa_src_max_chg). These limits could
94 !! perhaps be made dynamic with an improved iterative solver.
95 real :: vs_geomean_kdmin !< A minimum diffusivity for computing the horizontal averages
96 !! when using the geometric mean with VERTEX_SHEAR=True. The model
97 !! is sensitive to this value, which is a drawback of using the
98 !! geometric average as currently implemented.
99 logical :: psurf_bug !< If true, do a simple average of the cell surface pressures to get a
100 !! surface pressure at the corner if VERTEX_SHEAR=True. Otherwise mask
101 !! out any land points in the average.
102 logical :: all_layer_tke_bug !< If true, report back the latest estimate of TKE instead of the
103 !! time average TKE when there is mass in all layers. Otherwise always
104 !! report the time-averaged TKE, as is currently done when there
105 !! are some massless layers.
106 logical :: vs_viscosity_bug !< If true, use a bug in the calculation of the viscosity that sets
107 !! it to zero for all vertices that are on a coastline.
108 logical :: vertex_shear_obc_bug !< If false, use extra masking when interpolating thicknesses to velocity
109 !! points for setting up the shear velocities at vertices to avoid using
110 !! external thicknesses at open boundaries. When OBCs are not in use,
111 !! this parameter does not change answers, but true is more efficient.
112 logical :: vs_geometricmean !< If true use geometric averaging for Kd from vertices to tracer points
113 logical :: vs_thicknessmean !< If true use thickness weighting when averaging Kd from vertices to
114 !! tracer points
115 logical :: restrictive_tolerance_check !< If false, uses the less restrictive tolerance check to
116 !! determine if a timestep is acceptable for the KS_it outer iteration
117 !! loop, as the code was originally written. True uses the more
118 !! restrictive check.
119! logical :: layer_stagger = .false. ! If true, do the calculations centered at
120 ! layers, rather than the interfaces.
121 logical :: debug = .false. !< If true, write verbose debugging messages.
122 type(diag_ctrl), pointer :: diag => null() !< A structure that is used to
123 !! regulate the timing of diagnostic output.
124 !>@{ Diagnostic IDs
125 integer :: id_kd_shear = -1, id_tke = -1, id_kd_vertex = -1, &
126 id_s2_init = -1, id_n2_init = -1, id_s2_mean = -1, id_n2_mean = -1
127 !>@}
128end type kappa_shear_cs
129
130! integer :: id_clock_project, id_clock_KQ, id_clock_avg, id_clock_setup
131
132contains
133
134!> Subroutine for calculating shear-driven diffusivity and TKE in tracer columns
135subroutine calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, &
136 kv_io, dt, G, GV, US, CS)
137 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
138 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
139 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
140 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
141 intent(in) :: u_in !< Initial zonal velocity [L T-1 ~> m s-1].
142 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
143 intent(in) :: v_in !< Initial meridional velocity [L T-1 ~> m s-1].
144 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
145 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2].
146 type(thermo_var_ptrs), intent(in) :: tv !< A structure containing pointers to any
147 !! available thermodynamic fields. Absent fields
148 !! have NULL ptrs.
149 real, dimension(:,:), pointer :: p_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa] (or NULL).
150 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
151 intent(inout) :: kappa_io !< The diapycnal diffusivity at each interface
152 !! [H Z T-1 ~> m2 s-1 or kg m-1 s-1]. Initially this
153 !! is the value from the previous timestep, which may
154 !! accelerate the iteration toward convergence.
155 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
156 intent(out) :: tke_io !< The turbulent kinetic energy per unit mass at
157 !! each interface (not layer!) [Z2 T-2 ~> m2 s-2].
158 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
159 intent(inout) :: kv_io !< The vertical viscosity at each interface
160 !! (not layer!) [H Z T-1 ~> m2 s-1 or Pa s]. This discards any
161 !! previous value (i.e. it is intent out) and
162 !! simply sets Kv = Prandtl * Kd_shear
163 real, intent(in) :: dt !< Time increment [T ~> s].
164 type(kappa_shear_cs), pointer :: cs !< The control structure returned by a previous
165 !! call to kappa_shear_init.
166
167 ! Local variables
168 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: &
169 diag_n2_init, & ! Diagnostic of N2 as provided to this routine [T-2 ~> s-2]
170 diag_s2_init, & ! Diagnostic of S2 as provided to this routine [T-2 ~> s-2]
171 diag_n2_mean, & ! Diagnostic of N2 averaged over the timestep applied [T-2 ~> s-2]
172 diag_s2_mean ! Diagnostic of S2 averaged over the timestep applied [T-2 ~> s-2]
173 real, dimension(SZI_(G),SZK_(GV)) :: &
174 h_2d, & ! A 2-D version of h [H ~> m or kg m-2].
175 dz_2d, & ! Vertical distance between interface heights [Z ~> m].
176 u_2d, v_2d, & ! 2-D versions of u_in and v_in, converted to [L T-1 ~> m s-1].
177 t_2d, s_2d, rho_2d ! 2-D versions of T [C ~> degC], S [S ~> ppt], and rho [R ~> kg m-3].
178 real, dimension(SZI_(G),SZK_(GV)+1) :: &
179 kappa_2d, & ! 2-D version of kappa_io [H Z T-1 ~> m2 s-1 or Pa s]
180 tke_2d ! 2-D version tke_io [Z2 T-2 ~> m2 s-2].
181 real, dimension(SZK_(GV)) :: &
182 idz, & ! The inverse of the thickness of the merged layers [H-1 ~> m2 kg-1].
183 h_lay, & ! The layer thickness [H ~> m or kg m-2]
184 dz_lay, & ! The geometric layer thickness in height units [Z ~> m]
185 u0xdz, & ! The initial zonal velocity times dz [H L T-1 ~> m2 s-1 or kg m-1 s-1]
186 v0xdz, & ! The initial meridional velocity times dz [H L T-1 ~> m2 s-1 or kg m-1 s-1]
187 t0xdz, & ! The initial temperature times thickness [C H ~> degC m or degC kg m-2] or if
188 ! temperature is not a state variable, the density times thickness [R H ~> kg m-2 or kg2 m-5]
189 s0xdz ! The initial salinity times dz [S H ~> ppt m or ppt kg m-2].
190 real, dimension(SZK_(GV)+1) :: &
191 kappa, & ! The shear-driven diapycnal diffusivity at an interface [H Z T-1 ~> m2 s-1 or Pa s]
192 tke, & ! The Turbulent Kinetic Energy per unit mass at an interface [Z2 T-2 ~> m2 s-2].
193 kappa_avg, & ! The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
194 tke_avg, & ! The time-weighted average of TKE [Z2 T-2 ~> m2 s-2].
195 n2_init, & ! N2 as provided to this routine [T-2 ~> s-2].
196 s2_init, & ! S2 as provided to this routine [T-2 ~> s-2].
197 n2_mean, & ! The time-weighted average of N2 [T-2 ~> s-2].
198 s2_mean ! The time-weighted average of S2 [T-2 ~> s-2].
199
200 real :: f2 ! The squared Coriolis parameter of each column [T-2 ~> s-2].
201 real :: surface_pres ! The top surface pressure [R L2 T-2 ~> Pa].
202
203 real :: dz_in_lay ! The running sum of the thickness in a layer [H ~> m or kg m-2]
204 real :: k0dt ! The background diffusivity times the timestep [H Z ~> m2 or kg m-1]
205 real :: dz_massless ! A layer thickness that is considered massless [H ~> m or kg m-2]
206 logical :: use_temperature ! If true, temperature and salinity have been
207 ! allocated and are being used as state variables.
208
209 integer, dimension(SZK_(GV)+1) :: kc ! The index map between the original
210 ! interfaces and the interfaces with massless layers
211 ! merged into nearby massive layers.
212 real, dimension(SZK_(GV)+1) :: kf ! The fractional weight of interface kc+1 for
213 ! interpolating back to the original index space [nondim].
214 integer :: is, ie, js, je, i, j, k, nz, nzc
215
216 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
217
218 use_temperature = associated(tv%T)
219
220 k0dt = dt*cs%kappa_0
221 dz_massless = 0.1*sqrt((us%Z_to_m*gv%m_to_H)*k0dt)
222
223 if ((cs%id_N2_init>0) .or. cs%debug) diag_n2_init(:,:,:) = 0.0
224 if ((cs%id_S2_init>0) .or. cs%debug) diag_s2_init(:,:,:) = 0.0
225 if (cs%id_N2_mean>0) diag_n2_mean(:,:,:) = 0.0
226 if (cs%id_S2_mean>0) diag_s2_mean(:,:,:) = 0.0
227
228 !$OMP parallel do default(private) shared(js,je,is,ie,nz,h,u_in,v_in,use_temperature,tv,G,GV,US, &
229 !$OMP CS,kappa_io,dz_massless,k0dt,p_surf,dt,tke_io,kv_io, &
230 !$OMP diag_N2_init,diag_S2_init,diag_N2_mean,diag_S2_mean)
231 do j=js,je
232
233 ! Convert layer thicknesses into geometric thickness in height units.
234 call thickness_to_dz(h, tv, dz_2d, j, g, gv)
235
236 do k=1,nz ; do i=is,ie
237 h_2d(i,k) = h(i,j,k)
238 u_2d(i,k) = u_in(i,j,k) ; v_2d(i,k) = v_in(i,j,k)
239 enddo ; enddo
240 if (use_temperature) then ; do k=1,nz ; do i=is,ie
241 t_2d(i,k) = tv%T(i,j,k) ; s_2d(i,k) = tv%S(i,j,k)
242 enddo ; enddo ; else ; do k=1,nz ; do i=is,ie
243 rho_2d(i,k) = gv%Rlay(k) ! Could be tv%Rho(i,j,k) ?
244 enddo ; enddo ; endif
245
246!---------------------------------------
247! Work on each column.
248!---------------------------------------
249 do i=is,ie ; if (g%mask2dT(i,j) > 0.0) then
250 ! call cpu_clock_begin(id_clock_setup)
251
252 ! Store a transposed version of the initial arrays.
253 ! Any elimination of massless layers would occur here.
254 if (cs%eliminate_massless) then
255 nzc = 1
256 do k=1,nz
257 ! Zero out the thicknesses of all layers, even if they are unused.
258 h_lay(k) = 0.0 ; dz_lay(k) = 0.0 ; u0xdz(k) = 0.0 ; v0xdz(k) = 0.0
259 t0xdz(k) = 0.0 ; s0xdz(k) = 0.0
260
261 ! Add a new layer if this one has mass.
262! if ((h_lay(nzc) > 0.0) .and. (h_2d(i,k) > dz_massless)) nzc = nzc+1
263 if ((k>cs%nkml) .and. (h_lay(nzc) > 0.0) .and. &
264 (h_2d(i,k) > dz_massless)) nzc = nzc+1
265
266 ! Only merge clusters of massless layers.
267! if ((h_lay(nzc) > dz_massless) .or. &
268! ((h_lay(nzc) > 0.0) .and. (h_2d(i,k) > dz_massless))) nzc = nzc+1
269
270 kc(k) = nzc
271 h_lay(nzc) = h_lay(nzc) + h_2d(i,k)
272 dz_lay(nzc) = dz_lay(nzc) + dz_2d(i,k)
273 u0xdz(nzc) = u0xdz(nzc) + u_2d(i,k)*h_2d(i,k)
274 v0xdz(nzc) = v0xdz(nzc) + v_2d(i,k)*h_2d(i,k)
275 if (use_temperature) then
276 t0xdz(nzc) = t0xdz(nzc) + t_2d(i,k)*h_2d(i,k)
277 s0xdz(nzc) = s0xdz(nzc) + s_2d(i,k)*h_2d(i,k)
278 else
279 t0xdz(nzc) = t0xdz(nzc) + rho_2d(i,k)*h_2d(i,k)
280 s0xdz(nzc) = s0xdz(nzc) + rho_2d(i,k)*h_2d(i,k)
281 endif
282 enddo
283 kc(nz+1) = nzc+1
284
285 ! Set up Idz as the inverse of layer thicknesses.
286 do k=1,nzc ; idz(k) = 1.0 / h_lay(k) ; enddo
287
288 ! Now determine kf, the fractional weight of interface kc when
289 ! interpolating between interfaces kc and kc+1.
290 kf(1) = 0.0 ; dz_in_lay = h_2d(i,1)
291 do k=2,nz
292 if (kc(k) > kc(k-1)) then
293 kf(k) = 0.0 ; dz_in_lay = h_2d(i,k)
294 else
295 kf(k) = dz_in_lay*idz(kc(k)) ; dz_in_lay = dz_in_lay + h_2d(i,k)
296 endif
297 enddo
298 kf(nz+1) = 0.0
299 else
300 do k=1,nz
301 h_lay(k) = h_2d(i,k)
302 dz_lay(k) = dz_2d(i,k)
303 u0xdz(k) = u_2d(i,k)*h_lay(k) ; v0xdz(k) = v_2d(i,k)*h_lay(k)
304 enddo
305 if (use_temperature) then
306 do k=1,nz
307 t0xdz(k) = t_2d(i,k)*h_lay(k) ; s0xdz(k) = s_2d(i,k)*h_lay(k)
308 enddo
309 else
310 do k=1,nz
311 t0xdz(k) = rho_2d(i,k)*h_lay(k) ; s0xdz(k) = rho_2d(i,k)*h_lay(k)
312 enddo
313 endif
314 nzc = nz
315 do k=1,nzc+1 ; kc(k) = k ; kf(k) = 0.0 ; enddo
316 endif
317 f2 = 0.25 * ((g%Coriolis2Bu(i,j) + g%Coriolis2Bu(i-1,j-1)) + &
318 (g%Coriolis2Bu(i,j-1) + g%Coriolis2Bu(i-1,j)))
319 surface_pres = 0.0 ; if (associated(p_surf)) surface_pres = p_surf(i,j)
320
321 ! ---------------------------------------------------- I_Ld2_1d, dz_Int_1d
322
323 ! Set the initial guess for kappa, here defined at interfaces.
324 ! ----------------------------------------------------
325 do k=1,nzc+1 ; kappa(k) = cs%kappa_seed ; enddo
326
327 call kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, &
328 h_lay, dz_lay, u0xdz, v0xdz, t0xdz, s0xdz, kappa_avg, &
329 tke_avg, n2_init, s2_init, n2_mean, s2_mean, &
330 tv, cs, gv, us)
331
332 ! call cpu_clock_begin(id_clock_setup)
333 ! Extrapolate from the vertically reduced grid back to the original layers.
334 if (nz == nzc) then
335 do k=1,nz+1
336 kappa_2d(i,k) = kappa_avg(k)
337 if (cs%all_layer_TKE_bug) then
338 tke_2d(i,k) = tke(k)
339 else
340 tke_2d(i,k) = tke_avg(k)
341 endif
342 enddo
343 if (cs%id_N2_mean>0) then ; do k=1,nz+1
344 diag_n2_mean(i,j,k) = n2_mean(k)
345 enddo ; endif
346 if (cs%id_S2_mean>0) then ; do k=1,nz+1
347 diag_s2_mean(i,j,k) = s2_mean(k)
348 enddo ; endif
349 if ((cs%id_N2_init>0) .or. cs%debug) then ; do k=1,nz+1
350 diag_n2_init(i,j,k) = n2_init(k)
351 enddo ; endif
352 if ((cs%id_S2_init>0) .or. cs%debug) then ; do k=1,nz+1
353 diag_s2_init(i,j,k) = s2_init(k)
354 enddo ; endif
355 else
356 do k=1,nz+1
357 if (kf(k) == 0.0) then
358 kappa_2d(i,k) = kappa_avg(kc(k))
359 tke_2d(i,k) = tke_avg(kc(k))
360 else
361 kappa_2d(i,k) = (1.0-kf(k)) * kappa_avg(kc(k)) + kf(k) * kappa_avg(kc(k)+1)
362 tke_2d(i,k) = (1.0-kf(k)) * tke_avg(kc(k)) + kf(k) * tke_avg(kc(k)+1)
363 endif
364 enddo
365 do k=1,nz+1
366 if (kf(k) == 0.0) then
367 if (cs%id_N2_mean>0) diag_n2_mean(i,j,k) = n2_mean(kc(k))
368 if (cs%id_S2_mean>0) diag_s2_mean(i,j,k) = s2_mean(kc(k))
369 if ((cs%id_N2_init>0) .or. cs%debug) diag_n2_init(i,j,k) = n2_init(kc(k))
370 if ((cs%id_S2_init>0) .or. cs%debug) diag_s2_init(i,j,k) = s2_init(kc(k))
371 else
372 if (cs%id_N2_mean>0) &
373 diag_n2_mean(i,j,k) = (1.0-kf(k)) * n2_mean(kc(k)) + kf(k) * n2_mean(kc(k)+1)
374 if (cs%id_S2_mean>0) &
375 diag_s2_mean(i,j,k) = (1.0-kf(k)) * s2_mean(kc(k)) + kf(k) * s2_mean(kc(k)+1)
376 if ((cs%id_N2_init>0) .or. cs%debug) &
377 diag_n2_init(i,j,k) = (1.0-kf(k)) * n2_init(kc(k)) + kf(k) * n2_init(kc(k)+1)
378 if ((cs%id_S2_init>0) .or. cs%debug) &
379 diag_s2_init(i,j,k) = (1.0-kf(k)) * s2_init(kc(k)) + kf(k) * s2_init(kc(k)+1)
380 endif
381 enddo
382 endif
383 ! call cpu_clock_end(id_clock_setup)
384 else ! Land points, still inside the i-loop.
385 do k=1,nz+1
386 kappa_2d(i,k) = 0.0 ; tke_2d(i,k) = 0.0
387 enddo
388 endif ; enddo ! i-loop
389
390 do k=1,nz+1 ; do i=is,ie
391 kappa_io(i,j,k) = g%mask2dT(i,j) * kappa_2d(i,k)
392 tke_io(i,j,k) = g%mask2dT(i,j) * tke_2d(i,k)
393 kv_io(i,j,k) = ( g%mask2dT(i,j) * kappa_2d(i,k) ) * cs%Prandtl_turb
394
395 enddo ; enddo
396
397 enddo ! end of j-loop
398
399 if (cs%debug) then
400 call hchksum(diag_n2_init, "kappa_shear N2_init", g%HI, unscale=us%s_to_T**2)
401 call hchksum(diag_s2_init, "kappa_shear S2_init", g%HI, unscale=us%s_to_T**2)
402 call hchksum(kappa_io, "kappa", g%HI, unscale=gv%HZ_T_to_m2_s)
403 call hchksum(tke_io, "tke", g%HI, unscale=us%Z_to_m**2*us%s_to_T**2)
404 endif
405
406 if (cs%id_Kd_shear > 0) call post_data(cs%id_Kd_shear, kappa_io, cs%diag)
407 if (cs%id_TKE > 0) call post_data(cs%id_TKE, tke_io, cs%diag)
408 if (cs%id_N2_init > 0) call post_data(cs%id_N2_init, diag_n2_init, cs%diag)
409 if (cs%id_S2_init > 0) call post_data(cs%id_S2_init, diag_s2_init, cs%diag)
410 if (cs%id_N2_mean > 0) call post_data(cs%id_N2_mean, diag_n2_mean, cs%diag)
411 if (cs%id_S2_mean > 0) call post_data(cs%id_S2_mean, diag_s2_mean, cs%diag)
412
413end subroutine calculate_kappa_shear
414
415
416!> Subroutine for calculating shear-driven diffusivity and TKE in corner columns
417subroutine calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_io, tke_io, &
418 kv_io, dt, G, GV, US, CS)
419 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
420 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
421 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
422 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
423 intent(in) :: u_in !< Initial zonal velocity [L T-1 ~> m s-1].
424 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
425 intent(in) :: v_in !< Initial meridional velocity [L T-1 ~> m s-1].
426 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
427 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2].
428 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
429 intent(in) :: t_in !< Layer potential temperatures [C ~> degC]
430 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
431 intent(in) :: s_in !< Layer salinities [S ~> ppt]
432 type(thermo_var_ptrs), intent(in) :: tv !< A structure containing pointers to any
433 !! available thermodynamic fields. Absent fields
434 !! have NULL ptrs.
435 real, dimension(:,:), pointer :: p_surf !< The pressure at the ocean surface [R L2 T-2 ~> Pa]
436 !! (or NULL).
437 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
438 intent(out) :: kappa_io !< The diapycnal diffusivity at each interface
439 !! (not layer!) [H Z T-1 ~> m2 s-1 or kg m-1 s-1].
440 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)+1), &
441 intent(out) :: tke_io !< The turbulent kinetic energy per unit mass at
442 !! each interface (not layer!) [Z2 T-2 ~> m2 s-2].
443 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)+1), &
444 intent(inout) :: kv_io !< The vertical viscosity at each interface
445 !! [H Z T-1 ~> m2 s-1 or Pa s].
446 !! The previous value is used to initialize kappa
447 !! in the vertex columns as Kappa = Kv/Prandtl
448 !! to accelerate the iteration toward convergence.
449 real, intent(in) :: dt !< Time increment [T ~> s].
450 type(kappa_shear_cs), pointer :: cs !< The control structure returned by a previous
451 !! call to kappa_shear_init.
452
453 ! Local variables
454 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)+1) :: &
455 diag_n2_init, & ! Diagnostic of N2 as provided to this routine [T-2 ~> s-2]
456 diag_s2_init, & ! Diagnostic of S2 as provided to this routine [T-2 ~> s-2]
457 diag_n2_mean, & ! Diagnostic of N2 averaged over the timestep applied [T-2 ~> s-2]
458 diag_s2_mean ! Diagnostic of S2 averaged over the timestep applied [T-2 ~> s-2]
459
460 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: &
461 dz_3d ! Vertical distance between interface heights [Z ~> m].
462 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)+1) :: &
463 kappa_vertex ! Diffusivity at interfaces and vertices [H Z T-1 ~> m2 s-1 or Pa s]
464 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)) :: &
465 h_vert ! Thicknesses interpolated to vertices [H ~> m or kg m-2]
466 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: &
467 h_at_u ! A mask-weighted thickness interpolated to u-points [H ~> m or kg m-2]
468 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)) :: &
469 h_at_v ! A mask-weighted thickness interpolated to v-points [H ~> m or kg m-2]
470 real, dimension(SZIB_(G),SZK_(GV)) :: &
471 h_2d, & ! A 2-D version of h interpolated to vertices [H ~> m or kg m-2].
472 dz_2d, & ! Vertical distance between interface heights [Z ~> m].
473 u_2d, v_2d, & ! 2-D versions of u_in and v_in, converted to [L T-1 ~> m s-1].
474 t_2d, s_2d, rho_2d ! 2-D versions of T [C ~> degC], S [S ~> ppt], and rho [R ~> kg m-3].
475 real, dimension(SZIB_(G),SZK_(GV)+1) :: &
476 kappa_2d ! 2-D slice of kappa_vert [H Z T-1 ~> m2 s-1 or Pa s]
477 real, dimension(SZIB_(G),SZK_(GV)+1) :: &
478 tke_2d ! 2-D version tke_io [Z2 T-2 ~> m2 s-2].
479 real, dimension(SZK_(GV)) :: &
480 idz, & ! The inverse of the thickness of the merged layers [H-1 ~> m2 kg-1].
481 h_lay, & ! The layer thickness [H ~> m or kg m-2]
482 dz_lay, & ! The geometric layer thickness in height units [Z ~> m]
483 u0xdz, & ! The initial zonal velocity times dz [L H T-1 ~> m2 s-1 or kg m-1 s-1].
484 v0xdz, & ! The initial meridional velocity times dz [H L T-1 ~> m2 s-1 or kg m-1 s-1]
485 t0xdz, & ! The initial temperature times dz [C H ~> degC m or degC kg m-2]
486 s0xdz ! The initial salinity times dz [S H ~> ppt m or ppt kg m-2]
487 real, dimension(SZK_(GV)+1) :: &
488 kappa, & ! The shear-driven diapycnal diffusivity at an interface [H Z T-1 ~> m2 s-1 or Pa s]
489 tke, & ! The Turbulent Kinetic Energy per unit mass at an interface [Z2 T-2 ~> m2 s-2].
490 kappa_avg, & ! The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
491 tke_avg, & ! The time-weighted average of TKE [Z2 T-2 ~> m2 s-2].
492 n2_init, & ! N2 as provided to this routine [T-2 ~> s-2].
493 s2_init, & ! S2 as provided to this routine [T-2 ~> s-2].
494 n2_mean, & ! The time-weighted average of N2 [T-2 ~> s-2].
495 s2_mean ! The time-weighted average of S2 [T-2 ~> s-2].
496
497 real :: f2 ! The squared Coriolis parameter of each column [T-2 ~> s-2].
498 real :: surface_pres ! The top surface pressure [R L2 T-2 ~> Pa].
499
500 real :: dz_in_lay ! The running sum of the thickness in a layer [H ~> m or kg m-2]
501 real :: k0dt ! The background diffusivity times the timestep [H Z ~> m2 or kg m-1]
502 real :: dz_massless ! A layer thickness that is considered massless [H ~> m or kg m-2]
503 real :: i_hwt ! The inverse of the sum of the adjacent masked thickness weights [H-1 ~> m-1 or m2 kg-1]
504 real :: i_htot ! The inverse of the sum of the thicknesses at adjacent vertices [H-1 ~> m-1 or m2 kg-1]
505 real :: i_prandtl ! The inverse of the turbulent Prandtl number [nondim].
506 logical :: use_temperature ! If true, temperature and salinity have been
507 ! allocated and are being used as state variables.
508
509 integer, dimension(SZK_(GV)+1) :: kc ! The index map between the original
510 ! interfaces and the interfaces with massless layers
511 ! merged into nearby massive layers.
512 real, dimension(SZK_(GV)+1) :: kf ! The fractional weight of interface kc+1 for
513 ! interpolating back to the original index space [nondim].
514 real :: h_sw, h_se, h_nw, h_ne ! Thicknesses at adjacent vertices [H ~> m or kg m-2]
515 real :: mks_to_hz_t ! A factor used to restore dimensional scaling after the geometric mean
516 ! diffusivity is taken using thickness weighted powers [H Z s m-2 T-1 ~> 1]
517 ! or [H Z m s kg-1 T-1 ~> 1]
518 real :: h_tiny ! A sub-roundoff thickness to use in the denominator when calculating
519 ! thickness-weighted averages [H ~> m or kg m-2]
520 integer :: isb, ieb, jsb, jeb, i, j, k, nz, nzc
521
522 ! Diagnostics that should be deleted?
523 isb = g%isc-1 ; ieb = g%iecB ; jsb = g%jsc-1 ; jeb = g%jecB ; nz = gv%ke
524
525 if ((cs%id_N2_init>0) .or. cs%debug) diag_n2_init(:,:,:) = 0.0
526 if ((cs%id_S2_init>0) .or. cs%debug) diag_s2_init(:,:,:) = 0.0
527 if (cs%id_N2_mean>0) diag_n2_mean(:,:,:) = 0.0
528 if (cs%id_S2_mean>0) diag_s2_mean(:,:,:) = 0.0
529 kappa_vertex(:,:,:) = 0.0
530
531 use_temperature = associated(tv%T)
532
533 k0dt = dt*cs%kappa_0
534 dz_massless = 0.1*sqrt((us%Z_to_m*gv%m_to_H)*k0dt)
535 i_prandtl = 0.0 ; if (cs%Prandtl_turb > 0.0) i_prandtl = 1.0 / cs%Prandtl_turb
536 h_tiny = 0.5 * gv%H_subroundoff
537
538 ! Convert layer thicknesses into geometric thickness in height units.
539 call thickness_to_dz(h, tv, dz_3d, g, gv, us, halo_size=1)
540
541 if (cs%vertex_shear_OBC_bug) then
542 !$OMP parallel do default(shared)
543 do k=1,nz
544 do j=jsb,jeb+1 ; do i=isb,ieb
545 h_at_u(i,j,k) = g%mask2dCu(i,j) * (h(i,j,k) + h(i+1,j,k)) * 0.5
546 enddo ; enddo
547 do j=jsb,jeb ; do i=isb,ieb+1
548 h_at_v(i,j,k) = g%mask2dCv(i,j) * (h(i,j,k) + h(i,j+1,k)) * 0.5
549 enddo ; enddo
550 enddo
551 else
552 ! Because G%mask2dCu(I,j) is zero if either G%mask2dT(i,j) or G%mask2dT(i+1,j) except at OBC
553 ! faces, the following form give equivalent answers to those above unless OBCs are in use,
554 ! although the former is clearly less complicated and costly.
555 !$OMP parallel do default(shared)
556 do k=1,nz
557 do j=jsb,jeb+1 ; do i=isb,ieb
558 h_at_u(i,j,k) = g%mask2dCu(i,j) * (g%mask2dT(i,j) * h(i,j,k) + g%mask2dT(i+1,j) * h(i+1,j,k)) / &
559 (g%mask2dT(i,j) + g%mask2dT(i+1,j) + 1.0e-36)
560 enddo ; enddo
561 do j=jsb,jeb ; do i=isb,ieb+1
562 h_at_v(i,j,k) = g%mask2dCv(i,j) * (g%mask2dT(i,j) * h(i,j,k) + g%mask2dT(i,j+1) * h(i,j+1,k)) / &
563 (g%mask2dT(i,j) + g%mask2dT(i,j+1) + 1.0e-36)
564 enddo ; enddo
565 enddo
566 endif
567
568
569 !$OMP parallel do default(private) shared(jsB,jeB,isB,ieB,nz,h,u_in,v_in,use_temperature,tv,G,GV,US,CS,kappa_io, &
570 !$OMP dz_massless,k0dt,p_surf,dt,tke_io,kv_io,kappa_vertex,h_vert,I_Prandtl, &
571 !$OMP diag_N2_init,diag_S2_init,diag_N2_mean,diag_S2_mean)
572 do j=jsb,jeb
573
574 ! Interpolate the various quantities to the corners, using masks.
575 do k=1,nz ; do i=isb,ieb
576 u_2d(i,k) = ( (u_in(i,j,k) * h_at_u(i,j,k)) + (u_in(i,j+1,k) * h_at_u(i,j+1,k)) ) / &
577 ( (h_at_u(i,j,k) + h_at_u(i,j+1,k)) + h_tiny )
578 v_2d(i,k) = ( (v_in(i,j,k) * h_at_v(i,j,k)) + (v_in(i+1,j,k) * h_at_v(i+1,j,k)) ) / &
579 ( (h_at_v(i,j,k) + h_at_v(i+1,j,k)) + h_tiny )
580
581 i_hwt = 1.0 / (((g%mask2dT(i,j) * h(i,j,k) + g%mask2dT(i+1,j+1) * h(i+1,j+1,k)) + &
582 (g%mask2dT(i+1,j) * h(i+1,j,k) + g%mask2dT(i,j+1) * h(i,j+1,k))) + &
583 gv%H_subroundoff)
584 if (use_temperature) then
585 t_2d(i,k) = ( (g%mask2dT(i,j) * (h(i,j,k) * t_in(i,j,k)) + &
586 g%mask2dT(i+1,j+1) * (h(i+1,j+1,k) * t_in(i+1,j+1,k))) + &
587 (g%mask2dT(i+1,j) * (h(i+1,j,k) * t_in(i+1,j,k)) + &
588 g%mask2dT(i,j+1) * (h(i,j+1,k) * t_in(i,j+1,k))) ) * i_hwt
589 s_2d(i,k) = ( (g%mask2dT(i,j) * (h(i,j,k) * s_in(i,j,k)) + &
590 g%mask2dT(i+1,j+1) * (h(i+1,j+1,k) * s_in(i+1,j+1,k))) + &
591 (g%mask2dT(i+1,j) * (h(i+1,j,k) * s_in(i+1,j,k)) + &
592 g%mask2dT(i,j+1) * (h(i,j+1,k) * s_in(i,j+1,k))) ) * i_hwt
593 endif
594 h_2d(i,k) = ((g%mask2dT(i,j) * h(i,j,k) + g%mask2dT(i+1,j+1) * h(i+1,j+1,k)) + &
595 (g%mask2dT(i+1,j) * h(i+1,j,k) + g%mask2dT(i,j+1) * h(i,j+1,k)) ) / &
596 ((g%mask2dT(i,j) + g%mask2dT(i+1,j+1)) + &
597 (g%mask2dT(i+1,j) + g%mask2dT(i,j+1)) + 1.0e-36 )
598 dz_2d(i,k) = ((g%mask2dT(i,j) * dz_3d(i,j,k) + g%mask2dT(i+1,j+1) * dz_3d(i+1,j+1,k)) + &
599 (g%mask2dT(i+1,j) * dz_3d(i+1,j,k) + g%mask2dT(i,j+1) * dz_3d(i,j+1,k)) ) / &
600 ((g%mask2dT(i,j) + g%mask2dT(i+1,j+1)) + &
601 (g%mask2dT(i+1,j) + g%mask2dT(i,j+1)) + 1.0e-36 )
602! h_2d(I,k) = 0.25*((h(i,j,k) + h(i+1,j+1,k)) + (h(i+1,j,k) + h(i,j+1,k)))
603! h_2d(I,k) = (((h(i,j,k)**2) + (h(i+1,j+1,k)**2)) + &
604! ((h(i+1,j,k)**2) + (h(i,j+1,k)**2))) * I_hwt
605 enddo ; enddo
606 if (.not.use_temperature) then ; do k=1,nz ; do i=isb,ieb
607 rho_2d(i,k) = gv%Rlay(k)
608 enddo ; enddo ; endif
609
610!---------------------------------------
611! Work on each column.
612!---------------------------------------
613 do i=isb,ieb ; if ((g%mask2dCu(i,j) + g%mask2dCu(i,j+1)) + &
614 (g%mask2dCv(i,j) + g%mask2dCv(i+1,j)) > 0.0) then
615 ! call cpu_clock_begin(Id_clock_setup)
616 ! Store a transposed version of the initial arrays.
617 ! Any elimination of massless layers would occur here.
618 if (cs%eliminate_massless) then
619 nzc = 1
620 do k=1,nz
621 ! Zero out the thicknesses of all layers, even if they are unused.
622 h_lay(k) = 0.0 ; dz_lay(k) = 0.0 ; u0xdz(k) = 0.0 ; v0xdz(k) = 0.0
623 t0xdz(k) = 0.0 ; s0xdz(k) = 0.0
624
625 ! Add a new layer if this one has mass.
626! if ((h_lay(nzc) > 0.0) .and. (h_2d(I,k) > dz_massless)) nzc = nzc+1
627 if ((k>cs%nkml) .and. (h_lay(nzc) > 0.0) .and. &
628 (h_2d(i,k) > dz_massless)) nzc = nzc+1
629
630 ! Only merge clusters of massless layers.
631! if ((h_lay(nzc) > dz_massless) .or. &
632! ((h_lay(nzc) > 0.0) .and. (h_2d(I,k) > dz_massless))) nzc = nzc+1
633
634 kc(k) = nzc
635 h_lay(nzc) = h_lay(nzc) + h_2d(i,k)
636 dz_lay(nzc) = dz_lay(nzc) + dz_2d(i,k)
637 u0xdz(nzc) = u0xdz(nzc) + u_2d(i,k)*h_2d(i,k)
638 v0xdz(nzc) = v0xdz(nzc) + v_2d(i,k)*h_2d(i,k)
639 if (use_temperature) then
640 t0xdz(nzc) = t0xdz(nzc) + t_2d(i,k)*h_2d(i,k)
641 s0xdz(nzc) = s0xdz(nzc) + s_2d(i,k)*h_2d(i,k)
642 else
643 t0xdz(nzc) = t0xdz(nzc) + rho_2d(i,k)*h_2d(i,k)
644 s0xdz(nzc) = s0xdz(nzc) + rho_2d(i,k)*h_2d(i,k)
645 endif
646 enddo
647 kc(nz+1) = nzc+1
648
649 ! Set up Idz as the inverse of layer thicknesses.
650 do k=1,nzc ; idz(k) = 1.0 / h_lay(k) ; enddo
651
652 ! Now determine kf, the fractional weight of interface kc when
653 ! interpolating between interfaces kc and kc+1.
654 kf(1) = 0.0 ; dz_in_lay = h_2d(i,1)
655 do k=2,nz
656 if (kc(k) > kc(k-1)) then
657 kf(k) = 0.0 ; dz_in_lay = h_2d(i,k)
658 else
659 kf(k) = dz_in_lay*idz(kc(k)) ; dz_in_lay = dz_in_lay + h_2d(i,k)
660 endif
661 enddo
662 kf(nz+1) = 0.0
663 else
664 do k=1,nz
665 h_lay(k) = h_2d(i,k)
666 dz_lay(k) = dz_2d(i,k)
667 u0xdz(k) = u_2d(i,k)*h_lay(k) ; v0xdz(k) = v_2d(i,k)*h_lay(k)
668 enddo
669 if (use_temperature) then
670 do k=1,nz
671 t0xdz(k) = t_2d(i,k)*h_lay(k) ; s0xdz(k) = s_2d(i,k)*h_lay(k)
672 enddo
673 else
674 do k=1,nz
675 t0xdz(k) = rho_2d(i,k)*h_lay(k) ; s0xdz(k) = rho_2d(i,k)*h_lay(k)
676 enddo
677 endif
678 nzc = nz
679 do k=1,nzc+1 ; kc(k) = k ; kf(k) = 0.0 ; enddo
680 endif
681
682 f2 = g%Coriolis2Bu(i,j)
683 surface_pres = 0.0
684 if (associated(p_surf)) then
685 if (cs%psurf_bug) then
686 ! This is wrong because it is averaging values from land in some places.
687 surface_pres = 0.25 * ((p_surf(i,j) + p_surf(i+1,j+1)) + &
688 (p_surf(i+1,j) + p_surf(i,j+1)))
689 else
690 surface_pres = ((g%mask2dT(i,j) * p_surf(i,j) + g%mask2dT(i+1,j+1) * p_surf(i+1,j+1)) + &
691 (g%mask2dT(i+1,j) * p_surf(i+1,j) + g%mask2dT(i,j+1) * p_surf(i,j+1)) ) / &
692 ((g%mask2dT(i,j) + g%mask2dT(i+1,j+1)) + &
693 (g%mask2dT(i+1,j) + g%mask2dT(i,j+1)) + 1.0e-36 )
694 endif
695 endif
696
697 ! ----------------------------------------------------
698 ! Set the initial guess for kappa, here defined at interfaces.
699 ! ----------------------------------------------------
700 do k=1,nzc+1 ; kappa(k) = cs%kappa_seed ; enddo
701
702 call kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, &
703 h_lay, dz_lay, u0xdz, v0xdz, t0xdz, s0xdz, kappa_avg, &
704 tke_avg, n2_init, s2_init, n2_mean, s2_mean, tv, cs, gv, us)
705 ! call cpu_clock_begin(Id_clock_setup)
706 ! Extrapolate from the vertically reduced grid back to the original layers.
707 if (nz == nzc) then
708 do k=1,nz+1
709 kappa_2d(i,k) = kappa_avg(k)
710 if (cs%all_layer_TKE_bug) then
711 tke_2d(i,k) = tke(k)
712 else
713 tke_2d(i,k) = tke_avg(k)
714 endif
715 enddo
716 if (cs%id_N2_mean>0) then ; do k=1,nz+1
717 diag_n2_mean(i,j,k) = n2_mean(k)
718 enddo ; endif
719 if (cs%id_S2_mean>0) then ; do k=1,nz+1
720 diag_s2_mean(i,j,k) = s2_mean(k)
721 enddo ; endif
722 if ((cs%id_N2_init>0) .or. cs%debug) then ; do k=1,nz+1
723 diag_n2_init(i,j,k) = n2_init(k)
724 enddo ; endif
725 if ((cs%id_S2_init>0) .or. cs%debug) then ; do k=1,nz+1
726 diag_s2_init(i,j,k) = s2_init(k)
727 enddo ; endif
728 else
729 do k=1,nz+1
730 if (kf(k) == 0.0) then
731 kappa_2d(i,k) = kappa_avg(kc(k))
732 tke_2d(i,k) = tke_avg(kc(k))
733 else
734 kappa_2d(i,k) = (1.0-kf(k)) * kappa_avg(kc(k)) + kf(k) * kappa_avg(kc(k)+1)
735 tke_2d(i,k) = (1.0-kf(k)) * tke_avg(kc(k)) + kf(k) * tke_avg(kc(k)+1)
736 endif
737 enddo
738 do k=1,nz+1
739 if (kf(k) == 0.0) then
740 if (cs%id_N2_mean>0) diag_n2_mean(i,j,k) = n2_mean(kc(k))
741 if (cs%id_S2_mean>0) diag_s2_mean(i,j,k) = s2_mean(kc(k))
742 if ((cs%id_N2_init>0) .or. cs%debug) diag_n2_init(i,j,k) = n2_init(kc(k))
743 if ((cs%id_S2_init>0) .or. cs%debug) diag_s2_init(i,j,k) = s2_init(kc(k))
744 else
745 if (cs%id_N2_mean>0) &
746 diag_n2_mean(i,j,k) = (1.0-kf(k)) * n2_mean(kc(k)) + kf(k) * n2_mean(kc(k)+1)
747 if (cs%id_S2_mean>0) &
748 diag_s2_mean(i,j,k) = (1.0-kf(k)) * s2_mean(kc(k)) + kf(k) * s2_mean(kc(k)+1)
749 if ((cs%id_N2_init>0) .or. cs%debug) &
750 diag_n2_init(i,j,k) = (1.0-kf(k)) * n2_init(kc(k)) + kf(k) * n2_init(kc(k)+1)
751 if ((cs%id_S2_init>0) .or. cs%debug) &
752 diag_s2_init(i,j,k) = (1.0-kf(k)) * s2_init(kc(k)) + kf(k) * s2_init(kc(k)+1)
753 endif
754 enddo
755 endif
756 ! call cpu_clock_end(Id_clock_setup)
757 else ! Land points, still inside the i-loop.
758 do k=1,nz+1
759 kappa_2d(i,k) = 0.0 ; tke_2d(i,k) = 0.0
760 enddo
761 endif ; enddo ! i-loop
762
763 ! Store the 2-d slices back in the 3-d arrays for restarts or interpolation back to tracer points.
764 if (cs%VS_ThicknessMean) then
765 do k=1,nz+1 ; do i=isb,ieb
766 h_vert(i,j,k) = h_2d(i,k)
767 enddo ; enddo
768 endif
769 if (cs%VS_viscosity_bug) then
770 do k=1,nz+1 ; do i=isb,ieb
771 kappa_vertex(i,j,k) = kappa_2d(i,k)
772 tke_io(i,j,k) = g%mask2dBu(i,j) * tke_2d(i,k)
773 kv_io(i,j,k) = ( g%mask2dBu(i,j) * kappa_vertex(i,j,k) ) * cs%Prandtl_turb
774 enddo ; enddo
775 else
776 do k=1,nz+1 ; do i=isb,ieb
777 kappa_vertex(i,j,k) = kappa_2d(i,k)
778 tke_io(i,j,k) = tke_2d(i,k)
779 kv_io(i,j,k) = kappa_vertex(i,j,k) * cs%Prandtl_turb
780 enddo ; enddo
781 endif
782 enddo ! end of J-loop
783
784 ! Set the diffusivities in tracer columns from the values at vertices.
785
786 !$OMP parallel do default(private) shared(G,kappa_io)
787 do j=g%jsc,g%jec ; do i=g%isc,g%iec
788 ! The turbulent length scales (and hence turbulent diffusivity) should always go to 0 at the top and bottom.
789 kappa_io(i,j,1) = 0.0
790 kappa_io(i,j,nz+1) = 0.0
791 enddo ; enddo
792 if (cs%VS_ThicknessMean .and. cs%VS_GeometricMean) then
793 ! This conversion factor is required to allow for arbitrary fractional powers of the diffusivities.
794 mks_to_hz_t = 1.0 / gv%HZ_T_to_MKS
795 !$OMP parallel do default(private) shared(nz,G,GV,CS,kappa_io,kappa_vertex,h_vert)
796 do k=2,nz ; do j=g%jsc,g%jec ; do i=g%isc,g%iec
797 h_sw = 0.5 * (h_vert(i-1,j-1,k) + h_vert(i-1,j-1,k-1))
798 h_ne = 0.5 * (h_vert(i,j,k) + h_vert(i,j,k-1))
799 h_nw = 0.5 * (h_vert(i-1,j,k) + h_vert(i-1,j,k-1))
800 h_se = 0.5 * (h_vert(i,j-1,k) + h_vert(i,j-1,k-1))
801 if ((h_sw + h_ne) + (h_nw + h_se) > 0.0) then
802 ! The geometric mean is zero if any component is zero, hence the need to use a floor
803 ! on the value of kappa_trunc in regions on boundaries of shear zones.
804 i_htot = 1.0 / ((h_sw + h_ne) + (h_nw + h_se))
805 kappa_io(i,j,k) = g%mask2dT(i,j) * mks_to_hz_t * &
806 ( ((gv%HZ_T_to_MKS * max(kappa_vertex(i-1,j-1,k), cs%VS_GeoMean_Kdmin))**(h_sw*i_htot) * &
807 (gv%HZ_T_to_MKS * max(kappa_vertex(i,j,k), cs%VS_GeoMean_Kdmin))**(h_ne*i_htot)) * &
808 ((gv%HZ_T_to_MKS * max(kappa_vertex(i-1,j,k), cs%VS_GeoMean_Kdmin))**(h_nw*i_htot) * &
809 (gv%HZ_T_to_MKS * max(kappa_vertex(i,j-1,k), cs%VS_GeoMean_Kdmin))**(h_se*i_htot)) )
810 else
811 ! If all points have zero thickness, the thickness-weighted geometric mean is undefined, so use
812 ! the non-thickness weighted geometric mean instead.
813 kappa_io(i,j,k) = g%mask2dT(i,j) * sqrt(sqrt( &
814 (max(kappa_vertex(i-1,j-1,k),cs%VS_GeoMean_Kdmin) * max(kappa_vertex(i,j,k),cs%VS_GeoMean_Kdmin)) * &
815 (max(kappa_vertex(i-1,j,k),cs%VS_GeoMean_Kdmin) * max(kappa_vertex(i,j-1,k),cs%VS_GeoMean_Kdmin)) ))
816 endif
817 enddo ; enddo ; enddo
818 elseif (cs%VS_ThicknessMean) then ! Use thickness-weighted arithmetic mean diffusivities.
819 !$OMP parallel do default(private) shared(nz,G,GV,CS,kappa_io,kappa_vertex,h_vert)
820 do k=2,nz ; do j=g%jsc,g%jec ; do i=g%isc,g%iec
821 h_sw = 0.5 * (h_vert(i-1,j-1,k) + h_vert(i-1,j-1,k-1))
822 h_ne = 0.5 * (h_vert(i,j,k) + h_vert(i,j,k-1))
823 h_nw = 0.5 * (h_vert(i-1,j,k) + h_vert(i-1,j,k-1))
824 h_se = 0.5 * (h_vert(i,j-1,k) + h_vert(i,j-1,k-1))
825 ! The following expression is a thickness weighted arithmetic mean at tracer points:
826 i_htot = 1.0 / (((h_sw + h_ne) + (h_nw + h_se)) + gv%H_subroundoff)
827 kappa_io(i,j,k) = g%mask2dT(i,j) * &
828 (((kappa_vertex(i-1,j-1,k)*h_sw) + (kappa_vertex(i,j,k)*h_ne)) + &
829 ((kappa_vertex(i-1,j,k)*h_nw) + (kappa_vertex(i,j-1,k)*h_se))) * i_htot
830 enddo ; enddo ; enddo
831 elseif (cs%VS_GeometricMean) then ! The geometic mean diffusivities are not thickness weighted.
832 !$OMP parallel do default(private) shared(nz,G,CS,kappa_io,kappa_vertex)
833 do k=2,nz ; do j=g%jsc,g%jec ; do i=g%isc,g%iec
834 kappa_io(i,j,k) = g%mask2dT(i,j) * sqrt(sqrt( &
835 (max(kappa_vertex(i-1,j-1,k),cs%VS_GeoMean_Kdmin) * max(kappa_vertex(i,j,k),cs%VS_GeoMean_Kdmin)) * &
836 (max(kappa_vertex(i-1,j,k),cs%VS_GeoMean_Kdmin) * max(kappa_vertex(i,j-1,k),cs%VS_GeoMean_Kdmin)) ))
837 enddo ; enddo ; enddo
838 else ! Use a non-thickness weighted arithmetic mean.
839 !$OMP parallel do default(private) shared(nz,G,CS,kappa_io,kappa_vertex)
840 do k=2,nz ; do j=g%jsc,g%jec ; do i=g%isc,g%iec
841 kappa_io(i,j,k) = g%mask2dT(i,j) * 0.25 * &
842 ((kappa_vertex(i-1,j-1,k) + kappa_vertex(i,j,k)) +&
843 (kappa_vertex(i-1,j,k) + kappa_vertex(i,j-1,k)))
844 enddo ; enddo ; enddo
845 endif
846
847 if (cs%debug) then
848 call bchksum(diag_n2_init, "shear_vertex N2_init", g%HI, unscale=us%s_to_T**2)
849 call bchksum(diag_s2_init, "shear_vertex S2_init", g%HI, unscale=us%s_to_T**2)
850 call hchksum(kappa_io, "kappa", g%HI, unscale=gv%HZ_T_to_m2_s)
851 call bchksum(tke_io, "tke", g%HI, unscale=us%Z_to_m**2*us%s_to_T**2)
852 endif
853
854 if (cs%id_Kd_shear > 0) call post_data(cs%id_Kd_shear, kappa_io, cs%diag)
855 if (cs%id_TKE > 0) call post_data(cs%id_TKE, tke_io, cs%diag)
856 if (cs%id_Kd_vertex > 0) call post_data(cs%id_Kd_vertex, kappa_vertex, cs%diag)
857 if (cs%id_N2_init > 0) call post_data(cs%id_N2_init, diag_n2_init, cs%diag)
858 if (cs%id_S2_init > 0) call post_data(cs%id_S2_init, diag_s2_init, cs%diag)
859 if (cs%id_N2_mean > 0) call post_data(cs%id_N2_mean, diag_n2_mean, cs%diag)
860 if (cs%id_S2_mean > 0) call post_data(cs%id_S2_mean, diag_s2_mean, cs%diag)
861
862end subroutine calc_kappa_shear_vertex
863
864
865!> This subroutine calculates shear-driven diffusivity and TKE in a single column
866subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, hlay, dz_lay, &
867 u0xdz, v0xdz, T0xdz, S0xdz, kappa_avg, tke_avg, N2_init, S2_init, &
868 N2_mean, S2_mean, tv, CS, GV, US )
869 type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
870 real, dimension(SZK_(GV)+1), &
871 intent(inout) :: kappa !< The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
872 real, dimension(SZK_(GV)+1), &
873 intent(out) :: tke !< The Turbulent Kinetic Energy per unit mass at
874 !! an interface [Z2 T-2 ~> m2 s-2].
875 integer, intent(in) :: nzc !< The number of active layers in the column.
876 real, intent(in) :: f2 !< The square of the Coriolis parameter [T-2 ~> s-2].
877 real, intent(in) :: surface_pres !< The surface pressure [R L2 T-2 ~> Pa].
878 real, dimension(SZK_(GV)), &
879 intent(in) :: hlay !< The layer thickness [H ~> m or kg m-2]
880 real, dimension(SZK_(GV)), &
881 intent(in) :: dz_lay !< The geometric layer thickness in height units [Z ~> m]
882 real, dimension(SZK_(GV)), &
883 intent(in) :: u0xdz !< The initial zonal velocity times hlay [H L T-1 ~> m2 s-1 or kg m-1 s-1]
884 real, dimension(SZK_(GV)), &
885 intent(in) :: v0xdz !< The initial meridional velocity times the
886 !! layer thickness [H L T-1 ~> m2 s-1 or kg m-1 s-1]
887 real, dimension(SZK_(GV)), &
888 intent(in) :: T0xdz !< The initial temperature times hlay [C H ~> degC m or degC kg m-2]
889 real, dimension(SZK_(GV)), &
890 intent(in) :: S0xdz !< The initial salinity times hlay [S H ~> ppt m or ppt kg m-2]
891 real, dimension(SZK_(GV)+1), &
892 intent(out) :: kappa_avg !< The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
893 real, dimension(SZK_(GV)+1), &
894 intent(out) :: tke_avg !< The time-weighted average of TKE [Z2 T-2 ~> m2 s-2].
895 real, dimension(SZK_(GV)+1), &
896 intent(out) :: N2_mean !< The time-weighted average of N2 [Z2 T-2 ~> m2 s-2].
897 real, dimension(SZK_(GV)+1), &
898 intent(out) :: S2_mean !< The time-weighted average of S2 [Z2 T-2 ~> m2 s-2].
899 real, dimension(SZK_(GV)+1), &
900 intent(out) :: N2_init !< The initial value of N2 [Z2 T-2 ~> m2 s-2].
901 real, dimension(SZK_(GV)+1), &
902 intent(out) :: S2_init !< The initial value of S2 [Z2 T-2 ~> m2 s-2].
903 real, intent(in) :: dt !< Time increment [T ~> s].
904 type(thermo_var_ptrs), intent(in) :: tv !< A structure containing pointers to any
905 !! available thermodynamic fields. Absent fields
906 !! have NULL ptrs.
907 type(kappa_shear_cs), pointer :: CS !< The control structure returned by a previous
908 !! call to kappa_shear_init.
909 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
910
911 ! Local variables
912 real, dimension(nzc) :: &
913 u, & ! The zonal velocity after a timestep of mixing [L T-1 ~> m s-1].
914 v, & ! The meridional velocity after a timestep of mixing [L T-1 ~> m s-1].
915 Idz, & ! The inverse of the distance between TKE points [Z-1 ~> m-1].
916 T, & ! The potential temperature after a timestep of mixing [C ~> degC].
917 Sal, & ! The salinity after a timestep of mixing [S ~> ppt].
918 u_test, v_test, & ! Temporary velocities [L T-1 ~> m s-1].
919 T_test, S_test ! Temporary temperatures [C ~> degC] and salinities [S ~> ppt].
920
921 real, dimension(nzc+1) :: &
922 N2, & ! The squared buoyancy frequency at an interface [T-2 ~> s-2].
923 h_Int, & ! The extent of a finite-volume space surrounding an interface,
924 ! as used in calculating kappa and TKE [H ~> m or kg m-2]
925 dz_int, & ! The vertical distance with the space surrounding an interface,
926 ! as used in calculating kappa and TKE [Z ~> m]
927 dz_h_int, & ! The ratio of the vertical distances to the thickness around an
928 ! interface [Z H-1 ~> nondim or m3 kg-1]. In non-Boussinesq mode
929 ! this is the specific volume, otherwise it is a scaling factor.
930 i_dz_int, & ! The inverse of the distance between velocity & density points
931 ! above and below an interface [Z-1 ~> m-1]. This is used to
932 ! calculate N2, shear and fluxes.
933 s2, & ! The squared shear at an interface [T-2 ~> s-2].
934 a1, & ! a1 is the coupling between adjacent interfaces in the TKE,
935 ! velocity, and density equations [H ~> m or kg m-2]
936 c1, & ! c1 is used in the tridiagonal (and similar) solvers [nondim].
937 k_src, & ! The shear-dependent source term in the kappa equation [T-1 ~> s-1]
938 kappa_src, & ! The shear-dependent source term in the kappa equation [T-1 ~> s-1]
939 kappa_out, & ! The kappa that results from the kappa equation [H Z T-1 ~> m2 s-1 or Pa s]
940 kappa_mid, & ! The average of the initial and predictor estimates of kappa [H Z T-1 ~> m2 s-1 or Pa s]
941 tke_pred, & ! The value of TKE from a predictor step [Z2 T-2 ~> m2 s-2].
942 kappa_pred, & ! The value of kappa from a predictor step [H Z T-1 ~> m2 s-1 or Pa s]
943 pressure, & ! The pressure at an interface [R L2 T-2 ~> Pa].
944 t_int, & ! The temperature interpolated to an interface [C ~> degC].
945 sal_int, & ! The salinity interpolated to an interface [S ~> ppt].
946 dbuoy_dt, & ! The partial derivative of buoyancy with changes in temperature [Z T-2 C-1 ~> m s-2 degC-1]
947 dbuoy_ds, & ! The partial derivative of buoyancy with changes in salinity [Z T-2 S-1 ~> m s-2 ppt-1]
948 dspv_dt, & ! The partial derivative of specific volume with changes in temperature [R-1 C-1 ~> m3 kg-1 degC-1]
949 dspv_ds, & ! The partial derivative of specific volume with changes in salinity [R-1 S-1 ~> m3 kg-1 ppt-1]
950 rho_int, & ! The in situ density interpolated to an interface [R ~> kg m-3]
951 i_l2_bdry, & ! The inverse of the square of twice the harmonic mean
952 ! distance to the top and bottom boundaries [H-1 Z-1 ~> m-2 or m kg-1].
953 k_q, & ! Diffusivity divided by TKE [H T Z-1 ~> s or kg s m-3]
954 k_q_tmp, & ! A temporary copy of diffusivity divided by TKE [H T Z-1 ~> s or kg s m-3]
955 local_src_avg, & ! The time-integral of the local source [nondim]
956 tol_min, & ! Minimum tolerated ksrc for the corrector step [T-1 ~> s-1].
957 tol_max, & ! Maximum tolerated ksrc for the corrector step [T-1 ~> s-1].
958 tol_chg, & ! The tolerated kappa change integrated over a timestep [nondim].
959 dist_from_top, & ! The distance from the top surface [Z ~> m].
960 h_from_top, & ! The total thickness above an interface [H ~> m or kg m-2]
961 local_src ! The sum of all sources of kappa, including kappa_src and
962 ! sources from the elliptic term [T-1 ~> s-1]
963
964 real :: dist_from_bot ! The distance from the bottom surface [Z ~> m].
965 real :: h_from_bot ! The total thickness below and interface [H ~> m or kg m-2]
966 real :: b1 ! The inverse of the pivot in the tridiagonal equations [H-1 ~> m-1 or m2 kg-1].
967 real :: bd1 ! A term in the denominator of b1 [H ~> m or kg m-2].
968 real :: d1 ! 1 - c1 in the tridiagonal equations [nondim]
969 real :: gR0 ! A conversion factor from H to pressure, Rho_0 times g in Boussinesq
970 ! mode, or just g when non-Boussinesq [R L2 T-2 H-1 ~> kg m-2 s-2 or m s-2].
971 real :: g_R0 ! g_R0 is a rescaled version of g/Rho [Z R-1 T-2 ~> m4 kg-1 s-2].
972 real :: Norm ! A factor that normalizes two weights to 1 [H-2 ~> m-2 or m4 kg-2].
973 real :: tol_dksrc ! Tolerance for the change in the kappa source within an iteration
974 ! relative to the local source [nondim]. This must be greater than 1.
975 real :: tol2 ! The tolerance for the change in the kappa source within an iteration
976 ! relative to the average local source over previous iterations [nondim].
977 real :: tol_dksrc_low ! The tolerance for the fractional decrease in ksrc
978 ! within an iteration [nondim]. 0 < tol_dksrc_low < 1.
979 real :: Ri_crit ! The critical shear Richardson number for shear-
980 ! driven mixing [nondim]. The theoretical value is 0.25.
981 real :: dt_rem ! The remaining time to advance the solution [T ~> s].
982 real :: dt_now ! The time step used in the current iteration [T ~> s].
983 real :: dt_wt ! The fractional weight of the current iteration [nondim].
984 real :: dt_test ! A time-step that is being tested for whether it
985 ! gives acceptably small changes in k_src [T ~> s].
986 real :: Idtt ! Idtt = 1 / dt_test [T-1 ~> s-1].
987 real :: dt_inc ! An increment to dt_test that is being tested [T ~> s].
988 real :: wt_a ! The fraction of a layer thickness identified with the interface
989 ! above a layer [nondim]
990 real :: wt_b ! The fraction of a layer thickness identified with the interface
991 ! below a layer [nondim]
992 real :: k0dt ! The background diffusivity times the timestep [H Z ~> m2 or kg m-1].
993 real :: I_lz_rescale_sqr ! The inverse of a rescaling factor for L2_bdry (Lz) squared [nondim].
994 logical :: valid_dt ! If true, all levels so far exhibit acceptably small changes in k_src.
995 logical :: use_temperature ! If true, temperature and salinity have been
996 ! allocated and are being used as state variables.
997 integer :: ks_kappa, ke_kappa ! The k-range with nonzero kappas.
998 integer :: dt_refinements ! The number of 2-fold refinements that will be used
999 ! to estimate the maximum permitted time step. I.e.,
1000 ! the resolution is 1/2^dt_refinements.
1001 integer :: k, itt, itt_dt
1002
1003 ! This calculation of N2 is for debugging only.
1004 ! real, dimension(SZK_(GV)+1) :: &
1005 ! N2_debug, & ! A version of N2 for debugging [T-2 ~> s-2]
1006
1007 ri_crit = cs%Rino_crit
1008 gr0 = gv%H_to_RZ * gv%g_Earth
1009 g_r0 = gv%g_Earth_Z_T2 / gv%Rho0
1010 k0dt = dt*cs%kappa_0
1011
1012 i_lz_rescale_sqr = 1.0 ; if (cs%lz_rescale > 0) i_lz_rescale_sqr = 1/(cs%lz_rescale*cs%lz_rescale)
1013
1014 tol_dksrc = cs%kappa_src_max_chg
1015 if (tol_dksrc == 10.0) then
1016 ! This is equivalent to the expression below, but avoids changes at roundoff for the default value.
1017 tol_dksrc_low = 0.95
1018 else
1019 tol_dksrc_low = (tol_dksrc - 0.5)/tol_dksrc
1020 endif
1021 tol2 = 2.0*cs%kappa_tol_err
1022 dt_refinements = 5 ! Selected so that 1/2^dt_refinements < 1-tol_dksrc_low
1023 use_temperature = .false. ; if (associated(tv%T)) use_temperature = .true.
1024
1025
1026 ! Set up Idz as the inverse of layer thicknesses.
1027 do k=1,nzc ; idz(k) = 1.0 / dz_lay(k) ; enddo
1028 ! Set up I_dz_int as the inverse of the distance between
1029 ! adjacent layer centers.
1030 i_dz_int(1) = 2.0 / dz_lay(1)
1031 dist_from_top(1) = 0.0 ; h_from_top(1) = 0.0
1032 do k=2,nzc
1033 i_dz_int(k) = 2.0 / (dz_lay(k-1) + dz_lay(k))
1034 dist_from_top(k) = dist_from_top(k-1) + dz_lay(k-1)
1035 h_from_top(k) = h_from_top(k-1) + hlay(k-1)
1036 enddo
1037 i_dz_int(nzc+1) = 2.0 / dz_lay(nzc)
1038
1039 ! Find the inverse of the squared distances from the boundaries.
1040 dist_from_bot = 0.0 ; h_from_bot = 0.0
1041 do k=nzc,2,-1
1042 dist_from_bot = dist_from_bot + dz_lay(k)
1043 h_from_bot = h_from_bot + hlay(k)
1044 ! Find the inverse of the squared distances from the boundaries,
1045 i_l2_bdry(k) = ((dist_from_top(k) + dist_from_bot) * (h_from_top(k) + h_from_bot)) / &
1046 ((dist_from_top(k) * dist_from_bot) * (h_from_top(k) * h_from_bot))
1047 ! reduce the distance by a factor of "lz_rescale"
1048 i_l2_bdry(k) = i_lz_rescale_sqr*i_l2_bdry(k)
1049 enddo
1050
1051 ! Determine the velocities and thicknesses after eliminating massless
1052 ! layers and applying a time-step of background diffusion.
1053 if (nzc > 1) then
1054 a1(2) = k0dt*i_dz_int(2)
1055 b1 = 1.0 / (hlay(1) + a1(2))
1056 u(1) = b1 * u0xdz(1) ; v(1) = b1 * v0xdz(1)
1057 t(1) = b1 * t0xdz(1) ; sal(1) = b1 * s0xdz(1)
1058 c1(2) = a1(2) * b1 ; d1 = hlay(1) * b1 ! = 1 - c1
1059 do k=2,nzc-1
1060 bd1 = hlay(k) + d1*a1(k)
1061 a1(k+1) = k0dt*i_dz_int(k+1)
1062 b1 = 1.0 / (bd1 + a1(k+1))
1063 u(k) = b1 * (u0xdz(k) + a1(k)*u(k-1))
1064 v(k) = b1 * (v0xdz(k) + a1(k)*v(k-1))
1065 t(k) = b1 * (t0xdz(k) + a1(k)*t(k-1))
1066 sal(k) = b1 * (s0xdz(k) + a1(k)*sal(k-1))
1067 c1(k+1) = a1(k+1) * b1 ; d1 = bd1 * b1 ! d1 = 1 - c1
1068 enddo
1069 ! rho or T and S have insulating boundary conditions, u & v use no-slip
1070 ! bottom boundary conditions (if kappa0 > 0).
1071 ! For no-slip bottom boundary conditions
1072 b1 = 1.0 / ((hlay(nzc) + d1*a1(nzc)) + k0dt*i_dz_int(nzc+1))
1073 u(nzc) = b1 * (u0xdz(nzc) + a1(nzc)*u(nzc-1))
1074 v(nzc) = b1 * (v0xdz(nzc) + a1(nzc)*v(nzc-1))
1075 ! For insulating boundary conditions
1076 b1 = 1.0 / (hlay(nzc) + d1*a1(nzc))
1077 t(nzc) = b1 * (t0xdz(nzc) + a1(nzc)*t(nzc-1))
1078 sal(nzc) = b1 * (s0xdz(nzc) + a1(nzc)*sal(nzc-1))
1079 do k=nzc-1,1,-1
1080 u(k) = u(k) + c1(k+1)*u(k+1) ; v(k) = v(k) + c1(k+1)*v(k+1)
1081 t(k) = t(k) + c1(k+1)*t(k+1) ; sal(k) = sal(k) + c1(k+1)*sal(k+1)
1082 enddo
1083 else
1084 ! This is correct, but probably unnecessary.
1085 b1 = 1.0 / (hlay(1) + k0dt*i_dz_int(2))
1086 u(1) = b1 * u0xdz(1) ; v(1) = b1 * v0xdz(1)
1087 b1 = 1.0 / hlay(1)
1088 t(1) = b1 * t0xdz(1) ; sal(1) = b1 * s0xdz(1)
1089 endif
1090
1091 ! This uses half the harmonic mean of thicknesses to provide two estimates
1092 ! of the boundary between cells, and the inverse of the harmonic mean to
1093 ! weight the two estimates. The net effect is that interfaces around thin
1094 ! layers have thin cells, and the total thickness adds up properly.
1095 ! The top- and bottom- interfaces have zero thickness, consistent with
1096 ! adding additional zero thickness layers.
1097 h_int(1) = 0.0 ; h_int(2) = hlay(1)
1098 dz_int(1) = 0.0 ; dz_int(2) = dz_lay(1)
1099 do k=2,nzc-1
1100 norm = 1.0 / (hlay(k)*(hlay(k-1)+hlay(k+1)) + 2.0*hlay(k-1)*hlay(k+1))
1101 wt_a = ((hlay(k)+hlay(k+1)) * hlay(k-1)) * norm
1102 wt_b = ((hlay(k-1)+hlay(k)) * hlay(k+1)) * norm
1103 h_int(k) = h_int(k) + hlay(k) * wt_a
1104 h_int(k+1) = hlay(k) * wt_b
1105 dz_int(k) = dz_int(k) + dz_lay(k) * wt_a
1106 dz_int(k+1) = dz_lay(k) * wt_b
1107 enddo
1108 h_int(nzc) = h_int(nzc) + hlay(nzc) ; h_int(nzc+1) = 0.0
1109 dz_int(nzc) = dz_int(nzc) + dz_lay(nzc) ; dz_int(nzc+1) = 0.0
1110
1111 if (gv%Boussinesq) then
1112 do k=1,nzc+1 ; dz_h_int(k) = gv%H_to_Z ; enddo
1113 else
1114 ! Find an effective average specific volume around an interface.
1115 dz_h_int(1:nzc+1) = 0.0
1116 if (hlay(1) > 0.0) dz_h_int(1) = dz_lay(1) / hlay(1)
1117 do k=2,nzc+1
1118 if (h_int(k) > 0.0) then
1119 dz_h_int(k) = dz_int(k) / h_int(k)
1120 else
1121 dz_h_int(k) = dz_h_int(k-1)
1122 endif
1123 enddo
1124 endif
1125
1126 ! Calculate thermodynamic coefficients and an initial estimate of N2.
1127 if (use_temperature) then
1128 pressure(1) = surface_pres
1129 do k=2,nzc
1130 pressure(k) = pressure(k-1) + gr0*hlay(k-1)
1131 t_int(k) = 0.5*(t(k-1) + t(k))
1132 sal_int(k) = 0.5*(sal(k-1) + sal(k))
1133 enddo
1134 if (gv%Boussinesq .or. gv%semi_Boussinesq) then
1135 call calculate_density_derivs(t_int, sal_int, pressure, dbuoy_dt, dbuoy_ds, &
1136 tv%eqn_of_state, (/2,nzc/), scale=-g_r0 )
1137 else
1138 ! These should perhaps be combined into a single call to calculate the thermal expansion
1139 ! and haline contraction coefficients?
1140 call calculate_specific_vol_derivs(t_int, sal_int, pressure, dspv_dt, dspv_ds, &
1141 tv%eqn_of_state, (/2,nzc/) )
1142 call calculate_density(t_int, sal_int, pressure, rho_int, tv%eqn_of_state, (/2,nzc/) )
1143 do k=2,nzc
1144 dbuoy_dt(k) = gv%g_Earth_Z_T2 * (rho_int(k) * dspv_dt(k))
1145 dbuoy_ds(k) = gv%g_Earth_Z_T2 * (rho_int(k) * dspv_ds(k))
1146 enddo
1147 endif
1148 elseif (gv%Boussinesq .or. gv%semi_Boussinesq) then
1149 do k=1,nzc+1 ; dbuoy_dt(k) = -g_r0 ; dbuoy_ds(k) = 0.0 ; enddo
1150 else
1151 do k=1,nzc+1 ; dbuoy_ds(k) = 0.0 ; enddo
1152 dbuoy_dt(1) = -gv%g_Earth_Z_T2 / gv%Rlay(1)
1153 do k=2,nzc
1154 dbuoy_dt(k) = -gv%g_Earth_Z_T2 / (0.5*(gv%Rlay(k-1) + gv%Rlay(k)))
1155 enddo
1156 dbuoy_dt(nzc+1) = -gv%g_Earth_Z_T2 / gv%Rlay(nzc)
1157 endif
1158
1159 ! N2_debug(1) = 0.0 ; N2_debug(nzc+1) = 0.0
1160 ! do K=2,nzc
1161 ! N2_debug(K) = max((dbuoy_dT(K) * (T0xdz(k-1)*Idz(k-1) - T0xdz(k)*Idz(k)) + &
1162 ! dbuoy_dS(K) * (S0xdz(k-1)*Idz(k-1) - S0xdz(k)*Idz(k))) * &
1163 ! I_dz_int(K), 0.0)
1164 ! enddo
1165
1166 ! This call just calculates N2 and S2.
1167 call calculate_projected_state(kappa, u, v, t, sal, 0.0, nzc, hlay, i_dz_int, dbuoy_dt, dbuoy_ds, &
1168 cs%vel_underflow, u, v, t, sal, n2, s2, gv, us)
1169 do k=1,nzc+1
1170 n2_init(k) = n2(k)
1171 s2_init(k) = s2(k)
1172 enddo
1173
1174
1175! ----------------------------------------------------
1176! Iterate
1177! ----------------------------------------------------
1178 dt_rem = dt
1179 do k=1,nzc+1
1180 k_q(k) = 0.0
1181 kappa_avg(k) = 0.0 ; tke_avg(k) = 0.0 ; n2_mean(k) = 0.0 ; s2_mean(k) = 0.0
1182 local_src_avg(k) = 0.0
1183 ! Use the grid spacings to scale errors in the source.
1184 if ( h_int(k) > 0.0 ) &
1185 local_src_avg(k) = 0.1 * k0dt * i_dz_int(k) / h_int(k)
1186 enddo
1187
1188! call cpu_clock_end(id_clock_setup)
1189
1190! do itt=1,CS%max_RiNo_it
1191 do itt=1,cs%max_KS_it
1192
1193! ----------------------------------------------------
1194! Calculate new values of u, v, rho, N^2 and S.
1195! ----------------------------------------------------
1196
1197 ! call cpu_clock_begin(id_clock_KQ)
1198 call find_kappa_tke(n2, s2, kappa, idz, h_int, dz_int, dz_h_int, i_l2_bdry, f2, &
1199 nzc, cs, gv, us, k_q, tke, kappa_out, kappa_src, local_src)
1200 ! call cpu_clock_end(id_clock_KQ)
1201
1202 ! call cpu_clock_begin(id_clock_avg)
1203 ! Determine the range of non-zero values of kappa_out.
1204 ks_kappa = gv%ke+1 ; ke_kappa = 0
1205 do k=2,nzc ; if (kappa_out(k) > 0.0) then
1206 ks_kappa = k ; exit
1207 endif ; enddo
1208 do k=nzc,ks_kappa,-1 ; if (kappa_out(k) > 0.0) then
1209 ke_kappa = k ; exit
1210 endif ; enddo
1211 if (ke_kappa == nzc) kappa_out(nzc+1) = 0.0
1212 ! call cpu_clock_end(id_clock_avg)
1213
1214 ! Determine how long to use this value of kappa (dt_now).
1215
1216 ! call cpu_clock_begin(id_clock_project)
1217 if ((ke_kappa < ks_kappa) .or. (itt==cs%max_KS_it)) then
1218 dt_now = dt_rem
1219 else
1220 ! Limit dt_now so that |k_src(k)-kappa_src(k)| < tol * local_src(k)
1221 dt_test = dt_rem
1222 do k=2,nzc
1223 tol_max(k) = kappa_src(k) + tol_dksrc * local_src(k)
1224 tol_min(k) = kappa_src(k) - tol_dksrc_low * local_src(k)
1225 tol_chg(k) = tol2 * local_src_avg(k)
1226 enddo
1227
1228 do itt_dt=1,(cs%max_KS_it+1-itt)/2
1229 ! The maximum number of times that the time-step is halved in
1230 ! seeking an acceptable timestep is reduced with each iteration,
1231 ! so that as the maximum number of iterations is approached, the
1232 ! whole remaining timestep is used. Typically, an acceptable
1233 ! timestep is found long before the minimum is reached, so the
1234 ! value of max_KS_it may be unimportant, especially if it is large
1235 ! enough.
1236 call calculate_projected_state(kappa_out, u, v, t, sal, 0.5*dt_test, nzc, hlay, i_dz_int, &
1237 dbuoy_dt, dbuoy_ds, cs%vel_underflow, u_test, v_test, &
1238 t_test, s_test, n2, s2, gv, us, ks_int=ks_kappa, ke_int=ke_kappa)
1239 valid_dt = .true.
1240 idtt = 1.0 / dt_test
1241 do k=max(ks_kappa-1,2),min(ke_kappa+1,nzc)
1242 if (n2(k) < ri_crit * s2(k)) then ! Equivalent to Ri < Ri_crit.
1243 k_src(k) = (2.0 * cs%Shearmix_rate * sqrt(s2(k))) * &
1244 ((ri_crit*s2(k) - n2(k)) / (ri_crit*s2(k) + cs%FRi_curvature*n2(k)))
1245 if (cs%restrictive_tolerance_check) then
1246 if ((k_src(k) > min(tol_max(k), kappa_src(k) + idtt*tol_chg(k))) .or. &
1247 (k_src(k) < max(tol_min(k), kappa_src(k) - idtt*tol_chg(k)))) then
1248 valid_dt = .false. ; exit
1249 endif
1250 else
1251 if ((k_src(k) > max(tol_max(k), kappa_src(k) + idtt*tol_chg(k))) .or. &
1252 (k_src(k) < min(tol_min(k), kappa_src(k) - idtt*tol_chg(k)))) then
1253 valid_dt = .false. ; exit
1254 endif
1255 endif
1256 else
1257 if (0.0 < min(tol_min(k), kappa_src(k) - idtt*tol_chg(k))) then
1258 valid_dt = .false. ; k_src(k) = 0.0 ; exit
1259 endif
1260 endif
1261 enddo
1262
1263 if (valid_dt) exit
1264 dt_test = 0.5*dt_test
1265 enddo
1266 if ((dt_test < dt_rem) .and. valid_dt) then
1267 dt_inc = 0.5*dt_test
1268 do itt_dt=1,dt_refinements
1269 call calculate_projected_state(kappa_out, u, v, t, sal, 0.5*(dt_test+dt_inc), nzc, hlay, &
1270 i_dz_int, dbuoy_dt, dbuoy_ds, cs%vel_underflow, u_test, v_test, t_test, s_test, &
1271 n2, s2, gv, us, ks_int=ks_kappa, ke_int=ke_kappa)
1272 valid_dt = .true.
1273 idtt = 1.0 / (dt_test+dt_inc)
1274 do k=max(ks_kappa-1,2),min(ke_kappa+1,nzc)
1275 if (n2(k) < ri_crit * s2(k)) then ! Equivalent to Ri < Ri_crit.
1276 k_src(k) = (2.0 * cs%Shearmix_rate * sqrt(s2(k))) * &
1277 ((ri_crit*s2(k) - n2(k)) / (ri_crit*s2(k) + cs%FRi_curvature*n2(k)))
1278 if ((k_src(k) > max(tol_max(k), kappa_src(k) + idtt*tol_chg(k))) .or. &
1279 (k_src(k) < min(tol_min(k), kappa_src(k) - idtt*tol_chg(k)))) then
1280 valid_dt = .false. ; exit
1281 endif
1282 else
1283 if (0.0 < min(tol_min(k), kappa_src(k) - idtt*tol_chg(k))) then
1284 valid_dt = .false. ; k_src(k) = 0.0 ; exit
1285 endif
1286 endif
1287 enddo
1288
1289 if (valid_dt) dt_test = dt_test + dt_inc
1290 dt_inc = 0.5*dt_inc
1291 enddo
1292 else
1293 dt_inc = 0.0
1294 endif
1295
1296 dt_now = min(dt_test*(1.0+cs%kappa_tol_err)+dt_inc, dt_rem)
1297 do k=2,nzc
1298 local_src_avg(k) = local_src_avg(k) + dt_now * local_src(k)
1299 enddo
1300 endif ! Are all the values of kappa_out 0?
1301 ! call cpu_clock_end(id_clock_project)
1302
1303 ! The state has already been projected forward. Now find new values of kappa.
1304
1305 if (ke_kappa < ks_kappa) then
1306 ! There is no mixing now, and will not be again.
1307 ! call cpu_clock_begin(id_clock_avg)
1308 dt_wt = dt_rem / dt ; dt_rem = 0.0
1309 do k=1,nzc+1
1310 kappa_mid(k) = 0.0
1311 ! This would be here but does nothing.
1312 ! kappa_avg(K) = kappa_avg(K) + kappa_mid(K)*dt_wt
1313 tke_avg(k) = tke_avg(k) + dt_wt*tke(k)
1314 enddo
1315 ! call cpu_clock_end(id_clock_avg)
1316 else
1317 ! call cpu_clock_begin(id_clock_project)
1318 call calculate_projected_state(kappa_out, u, v, t, sal, dt_now, nzc, hlay, i_dz_int, &
1319 dbuoy_dt, dbuoy_ds, cs%vel_underflow, u_test, v_test, &
1320 t_test, s_test, n2, s2, gv, us, ks_int=ks_kappa, ke_int=ke_kappa)
1321 ! call cpu_clock_end(id_clock_project)
1322
1323 ! call cpu_clock_begin(id_clock_KQ)
1324 do k=1,nzc+1 ; k_q_tmp(k) = k_q(k) ; enddo
1325 call find_kappa_tke(n2, s2, kappa_out, idz, h_int, dz_int, dz_h_int, i_l2_bdry, f2, &
1326 nzc, cs, gv, us, k_q_tmp, tke_pred, kappa_pred)
1327 ! call cpu_clock_end(id_clock_KQ)
1328
1329 ks_kappa = gv%ke+1 ; ke_kappa = 0
1330 do k=1,nzc+1
1331 kappa_mid(k) = 0.5*(kappa_out(k) + kappa_pred(k))
1332 if ((kappa_mid(k) > 0.0) .and. (k<ks_kappa)) ks_kappa = k
1333 if (kappa_mid(k) > 0.0) ke_kappa = k
1334 enddo
1335
1336 ! call cpu_clock_begin(id_clock_project)
1337 call calculate_projected_state(kappa_mid, u, v, t, sal, dt_now, nzc, hlay, i_dz_int, &
1338 dbuoy_dt, dbuoy_ds, cs%vel_underflow, u_test, v_test, &
1339 t_test, s_test, n2, s2, gv, us, ks_int=ks_kappa, ke_int=ke_kappa)
1340 ! call cpu_clock_end(id_clock_project)
1341
1342 ! call cpu_clock_begin(id_clock_KQ)
1343 call find_kappa_tke(n2, s2, kappa_out, idz, h_int, dz_int, dz_h_int, i_l2_bdry, f2, &
1344 nzc, cs, gv, us, k_q, tke_pred, kappa_pred)
1345 ! call cpu_clock_end(id_clock_KQ)
1346
1347 ! call cpu_clock_begin(id_clock_avg)
1348 dt_wt = dt_now / dt ; dt_rem = dt_rem - dt_now
1349 do k=1,nzc+1
1350 kappa_mid(k) = 0.5*(kappa_out(k) + kappa_pred(k))
1351 kappa_avg(k) = kappa_avg(k) + kappa_mid(k)*dt_wt
1352 tke_avg(k) = tke_avg(k) + dt_wt*0.5*(tke_pred(k) + tke(k))
1353 n2_mean(k) = n2_mean(k) + dt_wt*n2(k)
1354 s2_mean(k) = s2_mean(k) + dt_wt*s2(k)
1355 kappa(k) = kappa_pred(k) ! First guess for the next iteration.
1356 enddo
1357
1358 ! call cpu_clock_end(id_clock_avg)
1359 endif
1360
1361 if (dt_rem > 0.0) then
1362 ! Update the values of u, v, T, Sal, N2, and S2 for the next iteration.
1363 ! call cpu_clock_begin(id_clock_project)
1364 call calculate_projected_state(kappa_mid, u, v, t, sal, dt_now, nzc, hlay, i_dz_int, &
1365 dbuoy_dt, dbuoy_ds, cs%vel_underflow, u, v, t, sal, n2, s2, &
1366 gv, us)
1367 ! call cpu_clock_end(id_clock_project)
1368 endif
1369
1370 if (dt_rem <= 0.0) exit
1371
1372 enddo ! end itt loop
1373
1374end subroutine kappa_shear_column
1375
1376!> This subroutine calculates the velocities, temperature and salinity that
1377!! the water column will have after mixing for dt with diffusivities kappa. It
1378!! may also calculate the projected buoyancy frequency and shear.
1379subroutine calculate_projected_state(kappa, u0, v0, T0, S0, dt, nz, dz, I_dz_int, dbuoy_dT, dbuoy_dS, &
1380 vel_under, u, v, T, Sal, N2, S2, GV, US, ks_int, ke_int)
1381 integer, intent(in) :: nz !< The number of layers (after eliminating massless
1382 !! layers?).
1383 real, dimension(nz+1), intent(in) :: kappa !< The diapycnal diffusivity at interfaces,
1384 !! [H Z T-1 ~> m2 s-1 or Pa s].
1385 real, dimension(nz), intent(in) :: u0 !< The initial zonal velocity [L T-1 ~> m s-1].
1386 real, dimension(nz), intent(in) :: v0 !< The initial meridional velocity [L T-1 ~> m s-1].
1387 real, dimension(nz), intent(in) :: T0 !< The initial temperature [C ~> degC].
1388 real, dimension(nz), intent(in) :: S0 !< The initial salinity [S ~> ppt].
1389 real, intent(in) :: dt !< The time step [T ~> s].
1390 real, dimension(nz), intent(in) :: dz !< The layer thicknesses [H ~> m or kg m-2]
1391 real, dimension(nz+1), intent(in) :: I_dz_int !< The inverse of the distance between successive
1392 !! layer centers [Z-1 ~> m-1].
1393 real, dimension(nz+1), intent(in) :: dbuoy_dT !< The partial derivative of buoyancy with
1394 !! temperature [Z T-2 C-1 ~> m s-2 degC-1].
1395 real, dimension(nz+1), intent(in) :: dbuoy_dS !< The partial derivative of buoyancy with
1396 !! salinity [Z T-2 S-1 ~> m s-2 ppt-1].
1397 real, intent(in) :: vel_under !< Any velocities that are smaller in magnitude
1398 !! than this value are set to 0 [L T-1 ~> m s-1].
1399 real, dimension(nz), intent(inout) :: u !< The zonal velocity after dt [L T-1 ~> m s-1].
1400 real, dimension(nz), intent(inout) :: v !< The meridional velocity after dt [L T-1 ~> m s-1].
1401 real, dimension(nz), intent(inout) :: T !< The temperature after dt [C ~> degC].
1402 real, dimension(nz), intent(inout) :: Sal !< The salinity after dt [S ~> ppt].
1403 real, dimension(nz+1), intent(inout) :: N2 !< The buoyancy frequency squared at interfaces [T-2 ~> s-2].
1404 real, dimension(nz+1), intent(inout) :: S2 !< The squared shear at interfaces [T-2 ~> s-2].
1405 type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1406 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1407 integer, optional, intent(in) :: ks_int !< The topmost k-index with a non-zero diffusivity.
1408 integer, optional, intent(in) :: ke_int !< The bottommost k-index with a non-zero
1409 !! diffusivity.
1410
1411 ! Local variables
1412 real, dimension(nz+1) :: c1 ! A tridiagonal variable [nondim]
1413 real :: a_a, a_b ! Tridiagonal coupling coefficients [H ~> m or kg m-2]
1414 real :: b1, b1nz_0 ! Tridiagonal variables [H-1 ~> m-1 or m2 kg-1]
1415 real :: bd1 ! A term in the denominator of b1 [H ~> m or kg m-2]
1416 real :: d1 ! A tridiagonal variable [nondim]
1417 integer :: k, ks, ke
1418
1419 ks = 1 ; ke = nz
1420 if (present(ks_int)) ks = max(ks_int-1,1)
1421 if (present(ke_int)) ke = min(ke_int,nz)
1422
1423 if (ks > ke) return
1424
1425 if (dt > 0.0) then
1426 a_b = dt*(kappa(ks+1)*i_dz_int(ks+1))
1427 b1 = 1.0 / (dz(ks) + a_b)
1428 c1(ks+1) = a_b * b1 ; d1 = dz(ks) * b1 ! = 1 - c1
1429
1430 u(ks) = (b1 * dz(ks))*u0(ks) ; v(ks) = (b1 * dz(ks))*v0(ks)
1431 t(ks) = (b1 * dz(ks))*t0(ks) ; sal(ks) = (b1 * dz(ks))*s0(ks)
1432 do k=ks+1,ke-1
1433 a_a = a_b
1434 a_b = dt*(kappa(k+1)*i_dz_int(k+1))
1435 bd1 = dz(k) + d1*a_a
1436 b1 = 1.0 / (bd1 + a_b)
1437 c1(k+1) = a_b * b1 ; d1 = bd1 * b1 ! d1 = 1 - c1
1438
1439 u(k) = b1 * (dz(k)*u0(k) + a_a*u(k-1))
1440 v(k) = b1 * (dz(k)*v0(k) + a_a*v(k-1))
1441 t(k) = b1 * (dz(k)*t0(k) + a_a*t(k-1))
1442 sal(k) = b1 * (dz(k)*s0(k) + a_a*sal(k-1))
1443 enddo
1444 ! T and S have insulating boundary conditions, u & v use no-slip
1445 ! bottom boundary conditions at the solid bottom.
1446
1447 ! For insulating boundary conditions or mixing simply stopping, use...
1448 a_a = a_b
1449 b1 = 1.0 / (dz(ke) + d1*a_a)
1450 t(ke) = b1 * (dz(ke)*t0(ke) + a_a*t(ke-1))
1451 sal(ke) = b1 * (dz(ke)*s0(ke) + a_a*sal(ke-1))
1452
1453 ! There is no distinction between the effective boundary conditions for
1454 ! tracers and velocities if the mixing is separated from the bottom, but if
1455 ! the mixing goes all the way to the bottom, use no-slip BCs for velocities.
1456 if (ke == nz) then
1457 a_b = dt*(kappa(nz+1)*i_dz_int(nz+1))
1458 b1nz_0 = 1.0 / ((dz(nz) + d1*a_a) + a_b)
1459 else
1460 b1nz_0 = b1
1461 endif
1462 u(ke) = b1nz_0 * (dz(ke)*u0(ke) + a_a*u(ke-1))
1463 v(ke) = b1nz_0 * (dz(ke)*v0(ke) + a_a*v(ke-1))
1464 if (abs(u(ke)) < vel_under) u(ke) = 0.0
1465 if (abs(v(ke)) < vel_under) v(ke) = 0.0
1466
1467 do k=ke-1,ks,-1
1468 u(k) = u(k) + c1(k+1)*u(k+1)
1469 v(k) = v(k) + c1(k+1)*v(k+1)
1470 if (abs(u(k)) < vel_under) u(k) = 0.0
1471 if (abs(v(k)) < vel_under) v(k) = 0.0
1472 t(k) = t(k) + c1(k+1)*t(k+1)
1473 sal(k) = sal(k) + c1(k+1)*sal(k+1)
1474 enddo
1475 else ! dt <= 0.0
1476 do k=1,nz
1477 u(k) = u0(k) ; v(k) = v0(k) ; t(k) = t0(k) ; sal(k) = s0(k)
1478 if (abs(u(k)) < vel_under) u(k) = 0.0
1479 if (abs(v(k)) < vel_under) v(k) = 0.0
1480 enddo
1481 endif
1482
1483 ! Store the squared shear at interfaces
1484 s2(1) = 0.0 ; s2(nz+1) = 0.0
1485 if (ks > 1) &
1486 s2(ks) = (((u(ks)-u0(ks-1))**2) + ((v(ks)-v0(ks-1))**2)) * (us%L_to_Z*i_dz_int(ks))**2
1487 do k=ks+1,ke
1488 s2(k) = (((u(k)-u(k-1))**2) + ((v(k)-v(k-1))**2)) * (us%L_to_Z*i_dz_int(k))**2
1489 enddo
1490 if (ke<nz) &
1491 s2(ke+1) = (((u0(ke+1)-u(ke))**2) + ((v0(ke+1)-v(ke))**2)) * (us%L_to_Z*i_dz_int(ke+1))**2
1492
1493 ! Store the buoyancy frequency at interfaces
1494 n2(1) = 0.0 ; n2(nz+1) = 0.0
1495 if (ks > 1) &
1496 n2(ks) = max(0.0, i_dz_int(ks) * &
1497 (dbuoy_dt(ks) * (t0(ks-1)-t(ks)) + dbuoy_ds(ks) * (s0(ks-1)-sal(ks))))
1498 do k=ks+1,ke
1499 n2(k) = max(0.0, i_dz_int(k) * &
1500 (dbuoy_dt(k) * (t(k-1)-t(k)) + dbuoy_ds(k) * (sal(k-1)-sal(k))))
1501 enddo
1502 if (ke<nz) &
1503 n2(ke+1) = max(0.0, i_dz_int(ke+1) * &
1504 (dbuoy_dt(ke+1) * (t(ke)-t0(ke+1)) + dbuoy_ds(ke+1) * (sal(ke)-s0(ke+1))))
1505
1506end subroutine calculate_projected_state
1507
1508!> This subroutine calculates new, consistent estimates of TKE and kappa.
1509subroutine find_kappa_tke(N2, S2, kappa_in, Idz, h_Int, dz_Int, dz_h_Int, I_L2_bdry, f2, &
1510 nz, CS, GV, US, K_Q, tke, kappa, kappa_src, local_src)
1511 integer, intent(in) :: nz !< The number of layers to work on.
1512 real, dimension(nz+1), intent(in) :: N2 !< The buoyancy frequency squared at interfaces [T-2 ~> s-2].
1513 real, dimension(nz+1), intent(in) :: S2 !< The squared shear at interfaces [T-2 ~> s-2].
1514 real, dimension(nz+1), intent(in) :: kappa_in !< The initial guess at the diffusivity
1515 !! [H Z T-1 ~> m2 s-1 or Pa s]
1516 real, dimension(nz+1), intent(in) :: h_Int !< The thicknesses associated with interfaces
1517 !! [H ~> m or kg m-2]
1518 real, dimension(nz+1), intent(in) :: dz_Int !< The vertical distances around interfaces [Z ~> m]
1519 real, dimension(nz+1), intent(in) :: dz_h_Int !< The ratio of the vertical distances to the
1520 !! thickness around an interface [Z H-1 ~> nondim or m3 kg-1].
1521 !! In non-Boussinesq mode this is the specific volume.
1522 real, dimension(nz+1), intent(in) :: I_L2_bdry !< The inverse of the squared distance to
1523 !! boundaries [H-1 Z-1 ~> m-2 or m kg-1].
1524 real, dimension(nz), intent(in) :: Idz !< The inverse grid spacing of layers [Z-1 ~> m-1].
1525 real, intent(in) :: f2 !< The squared Coriolis parameter [T-2 ~> s-2].
1526 type(kappa_shear_cs), pointer :: CS !< A pointer to this module's control structure.
1527 type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1528 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1529 real, dimension(nz+1), intent(inout) :: K_Q !< The shear-driven diapycnal diffusivity divided by
1530 !! the turbulent kinetic energy per unit mass at
1531 !! interfaces [H T Z-1 ~> s or kg s m-3].
1532 real, dimension(nz+1), intent(out) :: tke !< The turbulent kinetic energy per unit mass at
1533 !! interfaces [Z2 T-2 ~> m2 s-2].
1534 real, dimension(nz+1), intent(out) :: kappa !< The diapycnal diffusivity at interfaces
1535 !! [H Z T-1 ~> m2 s-1 or Pa s]
1536 real, dimension(nz+1), optional, &
1537 intent(out) :: kappa_src !< The source term for kappa [T-1 ~> s-1]
1538 real, dimension(nz+1), optional, &
1539 intent(out) :: local_src !< The sum of all local sources for kappa
1540 !! [T-1 ~> s-1]
1541 ! This subroutine calculates new, consistent estimates of TKE and kappa.
1542
1543 ! Local variables
1544 real, dimension(nz) :: &
1545 aQ, & ! aQ is the coupling between adjacent interfaces in the TKE equations [H T-1 ~> m s-1 or kg m-2 s-1]
1546 dQdz ! Half the partial derivative of TKE with depth [Z T-2 ~> m s-2].
1547 real, dimension(nz+1) :: &
1548 dK, & ! The change in kappa [H Z T-1 ~> m2 s-1 or Pa s].
1549 dQ, & ! The change in TKE [Z2 T-2 ~> m2 s-2].
1550 cQ, cK, & ! cQ and cK are the upward influences in the tridiagonal and
1551 ! hexadiagonal solvers for the TKE and kappa equations [nondim].
1552 i_ld2, & ! 1/Ld^2, where Ld is the effective decay length scale for kappa [H-1 Z-1 ~> m-2 or m kg-1]
1553 tke_decay, & ! The local TKE decay rate [T-1 ~> s-1].
1554 k_src, & ! The source term in the kappa equation [T-1 ~> s-1].
1555 dqmdk, & ! With Newton's method the change in dQ(k-1) due to dK(k) [Z T H-1 ~> s or m3 s kg-1]
1556 dkdq, & ! With Newton's method the change in dK(k) due to dQ(k) [H Z-1 T-1 ~> s-1 or kg m-3 s-1]
1557 e1 ! The fractional change in a layer TKE due to a change in the
1558 ! TKE of the layer above when all the kappas below are 0 [nondim].
1559 ! e1 is nondimensional, and 0 < e1 < 1.
1560 real :: tke_src ! The net source of TKE due to mixing against the shear and stratification
1561 ! [Z2 T-3 ~> m2 s-3] or [H Z T-3 ~> m2 s-3 or kg m-1 s-3].
1562 ! (For convenience, a term involving the non-dissipation of q0 is also included here.)
1563 real :: bQ ! The inverse of the pivot in the tridiagonal equations [T H-1 ~> s m-1 or m2 s kg-1]
1564 real :: bK ! The inverse of the pivot in the tridiagonal equations [Z-1 ~> m-1].
1565 real :: bQd1 ! A term in the denominator of bQ [H T-1 ~> m s-1 or kg m-2 s-1]
1566 real :: bKd1 ! A term in the denominator of bK [Z ~> m].
1567 real :: cQcomp, cKcomp ! 1 - cQ or 1 - cK in the tridiagonal equations [nondim].
1568 real :: c_s2 ! The coefficient for the decay of TKE due to
1569 ! shear (i.e. proportional to |S|*tke) [nondim].
1570 real :: c_n2 ! The coefficient for the decay of TKE due to
1571 ! stratification (i.e. proportional to N*tke) [nondim].
1572 real :: Ri_crit ! The critical shear Richardson number for shear-
1573 ! driven mixing [nondim]. The theoretical value is 0.25.
1574 real :: q0 ! The background level of TKE [Z2 T-2 ~> m2 s-2].
1575 real :: Ilambda2 ! 1.0 / CS%lambda**2 [nondim]
1576 real :: TKE_min ! The minimum value of shear-driven TKE that can be
1577 ! solved for [Z2 T-2 ~> m2 s-2].
1578 real :: kappa0 ! The background diapycnal diffusivity [H Z T-1 ~> m2 s-1 or Pa s]
1579 real :: kappa_trunc ! Diffusivities smaller than this are rounded to 0 [H Z T-1 ~> m2 s-1 or Pa s]
1580
1581 real :: eden1, eden2 ! Variables used in calculating e1 [H Z-2 ~> m-1 or kg m-4]
1582 real :: I_eden ! The inverse of the denominator in e1 [Z2 H-1 ~> m or m4 kg-1]
1583 real :: ome ! Variables used in calculating e1 [nondim]
1584 real :: diffusive_src ! The diffusive source in the kappa equation [H T-1 ~> m s-1 or kg m-2 s-1]
1585 real :: chg_by_k0 ! The value of k_src that leads to an increase of
1586 ! kappa_0 if only the diffusive term is a sink [T-1 ~> s-1]
1587 real :: h_dz_here ! The ratio of the thicknesses to the vertical distances around an interface
1588 ! [H Z-1 ~> nondim or kg m-3]. In non-Boussinesq mode this is the density.
1589
1590 real :: kappa_mean ! A mean value of kappa [H Z T-1 ~> m2 s-1 or Pa s]
1591 real :: Newton_test ! The value of relative error that will cause the next
1592 ! iteration to use Newton's method [nondim].
1593 ! Temporary variables used in the Newton's method iterations.
1594 real :: decay_term_k ! The decay term in the diffusivity equation [Z-1 ~> m-1]
1595 real :: decay_term_Q ! The decay term in the TKE equation - proportional to [H Z-1 T-1 ~> s-1 or kg m-3 s-1]
1596 real :: I_Q ! The inverse of TKE [T2 Z-2 ~> s2 m-2]
1597 real :: kap_src ! A source term in the kappa equation [H T-1 ~> m s-1 or kg m-2 s-1]
1598 real :: v1 ! A temporary variable proportional to [H Z-1 T-1 ~> s-1 or kg m-3 s-1]
1599 real :: v2 ! A temporary variable in [Z T-2 ~> m s-2]
1600 real :: tol_err ! The tolerance for max_err that determines when to
1601 ! stop iterating [nondim].
1602 real :: Newton_err ! The tolerance for max_err that determines when to
1603 ! start using Newton's method [nondim]. Empirically, an initial
1604 ! value of about 0.2 seems to be most efficient.
1605 real, parameter :: roundoff = 1.0e-16 ! A negligible fractional change in TKE [nondim].
1606 ! This could be larger but performance gains are small.
1607
1608 logical :: tke_noflux_bottom_BC = .false. ! Specify the boundary conditions
1609 logical :: tke_noflux_top_BC = .false. ! that are applied to the TKE equations.
1610 logical :: do_Newton ! If .true., use Newton's method for the next iteration.
1611 logical :: abort_Newton ! If .true., an Newton's method has encountered a 0
1612 ! pivot, and should not have been used.
1613 logical :: was_Newton ! The value of do_Newton before checking convergence.
1614 logical :: within_tolerance ! If .true., all points are within tolerance to
1615 ! enable this subroutine to return.
1616 integer :: ks_src, ke_src ! The range indices that have nonzero k_src.
1617 integer :: ks_kappa, ke_kappa, ke_tke ! The ranges of k-indices that are or
1618 integer :: ks_kappa_prev, ke_kappa_prev ! were being worked on.
1619 integer :: itt, k, k2
1620
1621 ! These variables are used only for debugging.
1622 logical, parameter :: debug_soln = .false.
1623 real :: K_err_lin ! The imbalance in the K equation [H T-1 ~> m s-1 or kg m-2 s-1]
1624 real :: Q_err_lin ! The imbalance in the Q equation [H Z T-3 ~> m2 s-3 or kg m-1 s-3]
1625 real, dimension(nz+1) :: &
1626 I_Ld2_debug, & ! A separate version of I_Ld2 for debugging [H-1 Z-1 ~> m-2 or m kg-1].
1627 kappa_prev, & ! The value of kappa at the start of the current iteration [H Z T-1 ~> m2 s-1 or Pa s]
1628 TKE_prev ! The value of TKE at the start of the current iteration [Z2 T-2 ~> m2 s-2].
1629
1630 c_n2 = cs%C_N**2 ; c_s2 = cs%C_S**2
1631 q0 = cs%TKE_bg ; kappa0 = cs%kappa_0
1632 tke_min = max(cs%TKE_bg, 1.0e-20*us%m_to_Z**2*us%T_to_s**2)
1633 ri_crit = cs%Rino_crit
1634 ilambda2 = 1.0 / cs%lambda**2
1635 kappa_trunc = cs%kappa_trunc
1636 do_newton = .false. ; abort_newton = .false.
1637 tol_err = cs%kappa_tol_err
1638 newton_err = 0.2 ! This initial value may be automatically reduced later.
1639
1640 ks_kappa = 2 ; ke_kappa = nz ; ks_kappa_prev = 2 ; ke_kappa_prev = nz
1641
1642 ke_src = 0 ; ks_src = nz+1
1643 do k=2,nz
1644 if (n2(k) < ri_crit * s2(k)) then ! Equivalent to Ri < Ri_crit.
1645! Ri = N2(K) / S2(K)
1646! k_src(K) = (2.0 * CS%Shearmix_rate * sqrt(S2(K))) * &
1647! ((Ri_crit - Ri) / (Ri_crit + CS%FRi_curvature*Ri))
1648 k_src(k) = (2.0 * cs%Shearmix_rate * sqrt(s2(k))) * &
1649 ((ri_crit*s2(k) - n2(k)) / (ri_crit*s2(k) + cs%FRi_curvature*n2(k)))
1650 ke_src = k
1651 if (ks_src > k) ks_src = k
1652 else
1653 k_src(k) = 0.0
1654 endif
1655 enddo
1656
1657 ! If there is no source anywhere, return kappa(K) = 0.
1658 if (ks_src > ke_src) then
1659 do k=1,nz+1
1660 kappa(k) = 0.0 ; k_q(k) = 0.0 ; tke(k) = tke_min
1661 enddo
1662 if (present(kappa_src)) then ; do k=1,nz+1 ; kappa_src(k) = 0.0 ; enddo ; endif
1663 if (present(local_src)) then ; do k=1,nz+1 ; local_src(k) = 0.0 ; enddo ; endif
1664 return
1665 endif
1666
1667 do k=1,nz+1
1668 kappa(k) = kappa_in(k)
1669! TKE_decay(K) = c_n*sqrt(N2(K)) + c_s*sqrt(S2(K)) ! The expression in JHL.
1670 tke_decay(k) = sqrt(c_n2*n2(k) + c_s2*s2(k))
1671 if ((kappa(k) > 0.0) .and. (k_q(k) > 0.0)) then
1672 tke(k) = kappa(k) / k_q(k) ! Perhaps take the max with TKE_min
1673 else
1674 tke(k) = tke_min
1675 endif
1676 enddo
1677 ! Apply boundary conditions to kappa.
1678 kappa(1) = 0.0 ; kappa(nz+1) = 0.0
1679
1680 ! Calculate the term (e1) that allows changes in TKE to be calculated quickly
1681 ! below the deepest nonzero value of kappa. If kappa = 0, below interface
1682 ! k-1, the final changes in TKE are related by dQ(K+1) = e1(K+1)*dQ(K).
1683 eden2 = kappa0 * idz(nz)
1684 if (tke_noflux_bottom_bc) then
1685 eden1 = h_int(nz+1)*tke_decay(nz+1)
1686 i_eden = 1.0 / (eden2 + eden1)
1687 e1(nz+1) = eden2 * i_eden ; ome = eden1 * i_eden
1688 else
1689 e1(nz+1) = 0.0 ; ome = 1.0
1690 endif
1691 do k=nz,2,-1
1692 eden1 = h_int(k)*tke_decay(k) + ome * eden2
1693 eden2 = kappa0 * idz(k-1)
1694 i_eden = 1.0 / (eden2 + eden1)
1695 e1(k) = eden2 * i_eden ; ome = eden1 * i_eden ! = 1-e1
1696 enddo
1697 e1(1) = 0.0
1698
1699
1700 ! Iterate here to convergence to within some tolerance of order tol_err.
1701 do itt=1,cs%max_RiNo_it
1702
1703 ! ----------------------------------------------------
1704 ! Calculate TKE
1705 ! ----------------------------------------------------
1706
1707 if (debug_soln) then ; do k=1,nz+1 ; kappa_prev(k) = kappa(k) ; tke_prev(k) = tke(k) ; enddo ; endif
1708
1709 if (.not.do_newton) then
1710 ! Use separate steps of the TKE and kappa equations, that are
1711 ! explicit in the nonlinear source terms, implicit in a linearized
1712 ! version of the nonlinear sink terms, and implicit in the linear
1713 ! terms.
1714
1715 ke_tke = max(ke_kappa,ke_kappa_prev)+1
1716 ! aQ is the coupling between adjacent interfaces [Z T-1 ~> m s-1].
1717 do k=1,min(ke_tke,nz)
1718 aq(k) = (0.5*(kappa(k)+kappa(k+1)) + kappa0) * idz(k)
1719 enddo
1720 dq(1) = -tke(1)
1721 if (tke_noflux_top_bc) then
1722 tke_src = dz_h_int(1)*kappa0*s2(1) + q0 * tke_decay(1) ! Uses that kappa(1) = 0
1723 bqd1 = h_int(1) * tke_decay(1)
1724 bq = 1.0 / (bqd1 + aq(1))
1725 tke(1) = bq * (h_int(1)*tke_src)
1726 cq(2) = aq(1) * bq ; cqcomp = bqd1 * bq ! = 1 - cQ
1727 else
1728 tke(1) = q0 ; cq(2) = 0.0 ; cqcomp = 1.0
1729 endif
1730 do k=2,ke_tke-1
1731 dq(k) = -tke(k)
1732 tke_src = dz_h_int(k)*(kappa(k) + kappa0)*s2(k) + q0*tke_decay(k)
1733 bqd1 = h_int(k)*(tke_decay(k) + dz_h_int(k)*n2(k)*k_q(k)) + cqcomp*aq(k-1)
1734 bq = 1.0 / (bqd1 + aq(k))
1735 tke(k) = bq * (h_int(k)*tke_src + aq(k-1)*tke(k-1))
1736 cq(k+1) = aq(k) * bq ; cqcomp = bqd1 * bq ! = 1 - cQ
1737 enddo
1738 if ((ke_tke == nz+1) .and. .not.(tke_noflux_bottom_bc)) then
1739 tke(nz+1) = tke_min
1740 dq(nz+1) = 0.0
1741 else
1742 k = ke_tke
1743 tke_src = dz_h_int(k)*kappa0*s2(k) + q0*tke_decay(k) ! Uses that kappa(ke_tke) = 0
1744 if (k == nz+1) then
1745 dq(k) = -tke(k)
1746 bq = 1.0 / (h_int(k)*tke_decay(k) + cqcomp*aq(k-1))
1747 tke(k) = max(tke_min, bq * (h_int(k)*tke_src + aq(k-1)*tke(k-1)))
1748 dq(k) = tke(k) + dq(k)
1749 else
1750 bq = 1.0 / ((h_int(k)*tke_decay(k) + cqcomp*aq(k-1)) + aq(k))
1751 cq(k+1) = aq(k) * bq
1752 ! Account for all changes deeper in the water column.
1753 dq(k) = -tke(k)
1754 tke(k) = max((bq * (h_int(k)*tke_src + aq(k-1)*tke(k-1)) + &
1755 cq(k+1)*(tke(k+1) - e1(k+1)*tke(k))) / (1.0 - cq(k+1)*e1(k+1)), tke_min)
1756 dq(k) = tke(k) + dq(k)
1757
1758 ! Adjust TKE deeper in the water column in case ke_tke increases.
1759 ! This might not be strictly necessary?
1760 do k=ke_tke+1,nz+1
1761 dq(k) = e1(k)*dq(k-1)
1762 tke(k) = max(tke(k) + dq(k), tke_min)
1763 if (abs(dq(k)) < roundoff*tke(k)) exit
1764 enddo
1765 do k2=k+1,nz
1766 if (dq(k2) == 0.0) exit
1767 dq(k2) = 0.0
1768 enddo
1769 endif
1770 endif
1771 do k=ke_tke-1,1,-1
1772 tke(k) = max(tke(k) + cq(k+1)*tke(k+1), tke_min)
1773 dq(k) = tke(k) + dq(k)
1774 enddo
1775
1776 ! ----------------------------------------------------
1777 ! Calculate kappa, here defined at interfaces.
1778 ! ----------------------------------------------------
1779
1780 ke_kappa_prev = ke_kappa ; ks_kappa_prev = ks_kappa
1781
1782 dk(1) = 0.0 ! kappa takes boundary values of 0.
1783 ck(2) = 0.0 ; ckcomp = 1.0
1784 if (itt == 1) then ; do k=2,nz
1785 i_ld2(k) = dz_h_int(k)*(n2(k)*ilambda2 + f2) / tke(k) + i_l2_bdry(k)
1786 enddo ; endif
1787 do k=2,nz
1788 dk(k) = -kappa(k)
1789 if (itt>1) &
1790 i_ld2(k) = dz_h_int(k)*(n2(k)*ilambda2 + f2) / tke(k) + i_l2_bdry(k)
1791 bkd1 = h_int(k)*i_ld2(k) + ckcomp*idz(k-1)
1792 bk = 1.0 / (bkd1 + idz(k))
1793
1794 kappa(k) = bk * (idz(k-1)*kappa(k-1) + h_int(k) * k_src(k))
1795 ck(k+1) = idz(k) * bk ; ckcomp = bkd1 * bk ! = 1 - cK(K+1)
1796
1797 ! Neglect values that are smaller than kappa_trunc.
1798 if (kappa(k) < ckcomp*kappa_trunc) then
1799 kappa(k) = 0.0
1800 if (k > ke_src) then ; ke_kappa = k-1 ; k_q(k) = 0.0 ; exit ; endif
1801 elseif (kappa(k) < 2.0*ckcomp*kappa_trunc) then
1802 kappa(k) = 2.0 * (kappa(k) - ckcomp*kappa_trunc)
1803 endif
1804 enddo
1805 k_q(ke_kappa) = kappa(ke_kappa) / tke(ke_kappa)
1806 dk(ke_kappa) = dk(ke_kappa) + kappa(ke_kappa)
1807 do k=ke_kappa+2,ke_kappa_prev
1808 dk(k) = -kappa(k) ; kappa(k) = 0.0 ; k_q(k) = 0.0
1809 enddo
1810 do k=ke_kappa-1,2,-1
1811 kappa(k) = kappa(k) + ck(k+1)*kappa(k+1)
1812 ! Neglect values that are smaller than kappa_trunc.
1813 if (kappa(k) <= kappa_trunc) then
1814 kappa(k) = 0.0
1815 if (k < ks_src) then ; ks_kappa = k+1 ; k_q(k) = 0.0 ; exit ; endif
1816 elseif (kappa(k) < 2.0*kappa_trunc) then
1817 kappa(k) = 2.0 * (kappa(k) - kappa_trunc)
1818 endif
1819
1820 dk(k) = dk(k) + kappa(k)
1821 k_q(k) = kappa(k) / tke(k)
1822 enddo
1823 do k=ks_kappa_prev,ks_kappa-2 ; kappa(k) = 0.0 ; k_q(k) = 0.0 ; enddo
1824
1825 else ! do_Newton is .true.
1826! Once the solutions are close enough, use a Newton's method solver of the
1827! whole system to accelerate convergence.
1828 ks_kappa_prev = ks_kappa ; ke_kappa_prev = ke_kappa ; ke_kappa = nz
1829 ks_kappa = 2
1830 dk(1) = 0.0 ; ck(2) = 0.0 ; ckcomp = 1.0 ; dkdq(1) = 0.0
1831 aq(1) = (0.5*(kappa(1)+kappa(2))+kappa0) * idz(1)
1832 dqdz(1) = 0.5*(tke(1) - tke(2))*idz(1)
1833 if (tke_noflux_top_bc) then
1834 tke_src = h_int(1) * (kappa0*dz_h_int(1)*s2(1) - (tke(1) - q0)*tke_decay(1)) - &
1835 aq(1) * (tke(1) - tke(2))
1836
1837 bq = 1.0 / (aq(1) + h_int(1)*tke_decay(1))
1838 cq(2) = aq(1) * bq
1839 cqcomp = (h_int(1)*tke_decay(1)) * bq ! = 1 - cQ(2)
1840 dqmdk(2) = -dqdz(1) * bq
1841 dq(1) = bq * tke_src
1842 else
1843 dq(1) = 0.0 ; cq(2) = 0.0 ; cqcomp = 1.0 ; dqmdk(2) = 0.0
1844 endif
1845 do k=2,nz
1846 i_q = 1.0 / tke(k)
1847 i_ld2(k) = (n2(k)*ilambda2 + f2) * dz_h_int(k)*i_q + i_l2_bdry(k)
1848
1849 kap_src = h_int(k) * (k_src(k) - i_ld2(k)*kappa(k)) + &
1850 idz(k-1)*(kappa(k-1)-kappa(k)) - idz(k)*(kappa(k)-kappa(k+1))
1851
1852 ! Ensure that the pivot is always positive, and that 0 <= cK <= 1.
1853 ! Otherwise do not use Newton's method.
1854 decay_term_k = -idz(k-1)*dqmdk(k)*dkdq(k-1) + h_int(k)*i_ld2(k)
1855 if (decay_term_k < 0.0) then ; abort_newton = .true. ; exit ; endif
1856 bk = 1.0 / (idz(k) + idz(k-1)*ckcomp + decay_term_k)
1857
1858 ck(k+1) = bk * idz(k)
1859 ckcomp = bk * (idz(k-1)*ckcomp + decay_term_k) ! = 1-cK(K+1)
1860 if (cs%dKdQ_iteration_bug) then
1861 dkdq(k) = bk * (idz(k-1)*dkdq(k-1)*cq(k) + &
1862 us%m_to_Z*(n2(k)*ilambda2 + f2) * i_q**2 * kappa(k) )
1863 else
1864 dkdq(k) = bk * (idz(k-1)*dkdq(k-1)*cq(k) + &
1865 dz_int(k)*(n2(k)*ilambda2 + f2) * i_q**2 * kappa(k) )
1866 endif
1867 dk(k) = bk * (kap_src + idz(k-1)*dk(k-1) + idz(k-1)*dkdq(k-1)*dq(k-1))
1868
1869 ! Truncate away negligibly small values of kappa.
1870 if (dk(k) <= ckcomp*(kappa_trunc - kappa(k))) then
1871 dk(k) = -ckcomp*kappa(k)
1872! if (K > ke_src) then ; ke_kappa = k-1 ; K_Q(K) = 0.0 ; exit ; endif
1873 elseif (dk(k) < ckcomp*(2.0*kappa_trunc - kappa(k))) then
1874 dk(k) = 2.0 * dk(k) - ckcomp*(2.0*kappa_trunc - kappa(k))
1875 endif
1876
1877 ! Solve for dQ(K)...
1878 aq(k) = (0.5*(kappa(k)+kappa(k+1))+kappa0) * idz(k)
1879 dqdz(k) = 0.5*(tke(k) - tke(k+1))*idz(k)
1880 tke_src = h_int(k) * ((dz_h_int(k) * ((kappa(k) + kappa0)*s2(k) - kappa(k)*n2(k))) - &
1881 (tke(k) - q0)*tke_decay(k)) - &
1882 (aq(k) * (tke(k) - tke(k+1)) - aq(k-1) * (tke(k-1) - tke(k)))
1883 v1 = aq(k-1) + dqdz(k-1)*dkdq(k-1)
1884 v2 = (v1*dqmdk(k) + dqdz(k-1)*ck(k)) + &
1885 ((dqdz(k-1) - dqdz(k)) + dz_int(k)*(s2(k) - n2(k)))
1886
1887 ! Ensure that the pivot is always positive, and that 0 <= cQ <= 1.
1888 ! Otherwise do not use Newton's method.
1889 decay_term_q = h_int(k)*tke_decay(k) - dqdz(k-1)*dkdq(k-1)*cq(k) - v2*dkdq(k)
1890 if (decay_term_q < 0.0) then ; abort_newton = .true. ; exit ; endif
1891 bq = 1.0 / (aq(k) + (cqcomp*aq(k-1) + decay_term_q))
1892
1893 cq(k+1) = aq(k) * bq
1894 cqcomp = (cqcomp*aq(k-1) + decay_term_q) * bq
1895 dqmdk(k+1) = (v2 * ck(k+1) - dqdz(k)) * bq
1896
1897 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
1898 dq(k) = max(bq * ((v1 * dq(k-1) + dqdz(k-1)*dk(k-1)) + &
1899 (v2 * dk(k) + tke_src)), cqcomp*(-0.5*tke(k)))
1900
1901 ! Check whether the next layer will be affected by any nonzero kappas.
1902 if ((itt > 1) .and. (k > ke_src) .and. (dk(k) == 0.0) .and. &
1903 ((kappa(k) + kappa(k+1)) == 0.0)) then
1904 ! Could also do .and. (bQ*abs(tke_src) < roundoff*TKE(K)) then
1905 ke_kappa = k-1 ; exit
1906 endif
1907 enddo
1908 if ((ke_kappa == nz) .and. (.not. abort_newton)) then
1909 dk(nz+1) = 0.0 ; dkdq(nz+1) = 0.0
1910 if (tke_noflux_bottom_bc) then
1911 k = nz+1
1912 tke_src = h_int(k) * (kappa0*dz_h_int(k)*s2(k) - (tke(k) - q0)*tke_decay(k)) + &
1913 aq(k-1) * (tke(k-1) - tke(k))
1914
1915 v1 = aq(k-1) + dqdz(k-1)*dkdq(k-1)
1916 decay_term_q = max(0.0, h_int(k)*tke_decay(k) - dqdz(k-1)*dkdq(k-1)*cq(k))
1917 if (decay_term_q < 0.0) then
1918 abort_newton = .true.
1919 else
1920 bq = 1.0 / (aq(k) + (cqcomp*aq(k-1) + decay_term_q))
1921 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
1922 dq(k) = max(bq * ((v1 * dq(k-1) + dqdz(k-1)*dk(k-1)) + tke_src), -0.5*tke(k))
1923 tke(k) = max(tke(k) + dq(k), tke_min)
1924 endif
1925 else
1926 dq(nz+1) = 0.0
1927 endif
1928 elseif (.not. abort_newton) then
1929 ! Alter the first-guess determination of dQ(K).
1930 dq(ke_kappa+1) = dq(ke_kappa+1) / (1.0 - cq(ke_kappa+2)*e1(ke_kappa+2))
1931 tke(ke_kappa+1) = max(tke(ke_kappa+1) + dq(ke_kappa+1), tke_min)
1932 do k=ke_kappa+2,nz+1
1933 if (debug_soln .and. (k < nz+1)) then
1934 ! Ignore this source?
1935 aq(k) = (0.5*(kappa(k)+kappa(k+1))+kappa0) * idz(k)
1936 ! tke_src_norm = ((kappa0*dz_Int(K)*S2(K) - h_Int(K)*(TKE(K)-q0)*TKE_decay(K)) - &
1937 ! (aQ(k) * (TKE(K) - TKE(K+1)) - aQ(k-1) * (TKE(K-1) - TKE(K))) ) / &
1938 ! (aQ(k) + (aQ(k-1) + h_Int(K)*TKE_decay(K)))
1939 endif
1940 dk(k) = 0.0
1941 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
1942 dq(k) = max(e1(k)*dq(k-1),-0.5*tke(k))
1943 tke(k) = max(tke(k) + dq(k), tke_min)
1944 if (abs(dq(k)) < roundoff*tke(k)) exit
1945 enddo
1946 if (debug_soln) then ; do k2=k+1,nz+1 ; dq(k2) = 0.0 ; dk(k2) = 0.0 ; enddo ; endif
1947 endif
1948 if (.not. abort_newton) then
1949 do k=ke_kappa,2,-1
1950 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
1951 dq(k) = max(dq(k) + (cq(k+1)*dq(k+1) + dqmdk(k+1) * dk(k+1)), -0.5*tke(k))
1952 tke(k) = max(tke(k) + dq(k), tke_min)
1953 dk(k) = dk(k) + (ck(k+1)*dk(k+1) + dkdq(k) * dq(k))
1954 ! Truncate away negligibly small values of kappa.
1955 if (dk(k) <= kappa_trunc - kappa(k)) then
1956 dk(k) = -kappa(k)
1957 kappa(k) = 0.0
1958 if ((k < ks_src) .and. (k+1 > ks_kappa)) ks_kappa = k+1
1959 elseif (dk(k) < 2.0*kappa_trunc - kappa(k)) then
1960 dk(k) = 2.0*dk(k) - (2.0*kappa_trunc - kappa(k))
1961 kappa(k) = max(kappa(k) + dk(k), 0.0) ! The max is for paranoia.
1962 if (k<=ks_kappa) ks_kappa = 2
1963 else
1964 kappa(k) = kappa(k) + dk(k)
1965 if (k<=ks_kappa) ks_kappa = 2
1966 endif
1967 enddo
1968 dq(1) = max(dq(1) + cq(2)*dq(2) + dqmdk(2) * dk(2), tke_min - tke(1))
1969 tke(1) = max(tke(1) + dq(1), tke_min)
1970 dk(1) = 0.0
1971 endif
1972
1973 ! Check these solutions for consistency.
1974 ! The unit conversions here have not been carefully tested.
1975 if (debug_soln) then ; do k=2,nz
1976 ! In these equations, K_err_lin and Q_err_lin should be at round-off levels
1977 ! compared with the dominant terms, perhaps, h_Int*I_Ld2*kappa and
1978 ! h_Int*TKE_decay*TKE. The exception is where, either 1) the decay term has been
1979 ! been increased to ensure a positive pivot, or 2) negative TKEs have been
1980 ! truncated, or 3) small or negative kappas have been rounded toward 0.
1981 i_q = 1.0 / tke(k)
1982 i_ld2_debug(k) = (n2(k)*ilambda2 + f2) * dz_h_int(k)*i_q + i_l2_bdry(k)
1983
1984 kap_src = h_int(k) * (k_src(k) - i_ld2(k)*kappa_prev(k)) + &
1985 (idz(k-1)*(kappa_prev(k-1)-kappa_prev(k)) - &
1986 idz(k)*(kappa_prev(k)-kappa_prev(k+1)))
1987 k_err_lin = -idz(k-1)*(dk(k-1)-dk(k)) + idz(k)*(dk(k)-dk(k+1)) + &
1988 h_int(k)*i_ld2_debug(k)*dk(k) - kap_src - &
1989 dz_int(k)*(n2(k)*ilambda2 + f2)*i_q**2*kappa_prev(k) * dq(k)
1990
1991 h_dz_here = 0.0 ; if (abs(dz_h_int(k)) > 0.0) h_dz_here = 1.0 / dz_h_int(k)
1992 tke_src = h_int(k) * ((kappa_prev(k) + kappa0)*s2(k) - &
1993 kappa_prev(k)*n2(k) - (tke_prev(k) - q0)*h_dz_here*tke_decay(k)) - &
1994 (aq(k) * (tke_prev(k) - tke_prev(k+1)) - aq(k-1) * (tke_prev(k-1) - tke_prev(k)))
1995 q_err_lin = tke_src + (aq(k-1) * (dq(k-1)-dq(k)) - aq(k) * (dq(k)-dq(k+1))) - &
1996 0.5*(tke_prev(k)-tke_prev(k+1))*idz(k) * (dk(k) + dk(k+1)) - &
1997 0.5*(tke_prev(k)-tke_prev(k-1))*idz(k-1)* (dk(k-1) + dk(k)) + &
1998 dz_int(k) * (dk(k) * (s2(k) - n2(k)) - dq(k)*tke_decay(k))
1999 enddo ; endif
2000
2001 endif ! End of the Newton's method solver.
2002
2003 ! Test kappa for convergence...
2004 if ((tol_err < newton_err) .and. (.not.abort_newton)) then
2005 ! A lower tolerance is used to switch to Newton's method than to switch back.
2006 newton_test = newton_err ; if (do_newton) newton_test = 2.0*newton_err
2007 was_newton = do_newton
2008 within_tolerance = .true. ; do_newton = .true.
2009 do k=min(ks_kappa,ks_kappa_prev),max(ke_kappa,ke_kappa_prev)
2010 kappa_mean = kappa0 + (kappa(k) - 0.5*dk(k))
2011 if (abs(dk(k)) > newton_test * kappa_mean) then
2012 if (do_newton) abort_newton = .true.
2013 within_tolerance = .false. ; do_newton = .false. ; exit
2014 elseif (abs(dk(k)) > tol_err * kappa_mean) then
2015 within_tolerance = .false. ; if (.not.do_newton) exit
2016 endif
2017 if (abs(dq(k)) > newton_test*(tke(k) - 0.5*dq(k))) then
2018 if (do_newton) abort_newton = .true.
2019 do_newton = .false. ; if (.not.within_tolerance) exit
2020 endif
2021 enddo
2022
2023 else ! Newton's method will not be used again, so no need to check.
2024 within_tolerance = .true.
2025 do k=min(ks_kappa,ks_kappa_prev),max(ke_kappa,ke_kappa_prev)
2026 if (abs(dk(k)) > tol_err * (kappa0 + (kappa(k) - 0.5*dk(k)))) then
2027 within_tolerance = .false. ; exit
2028 endif
2029 enddo
2030 endif
2031
2032 if (abort_newton) then
2033 do_newton = .false. ; abort_newton = .false.
2034 ! We went to Newton too quickly last time, so restrict the tolerance.
2035 newton_err = 0.5*newton_err
2036 ke_kappa_prev = nz
2037 do k=2,nz ; k_q(k) = kappa(k) / max(tke(k), tke_min) ; enddo
2038 endif
2039
2040 if (within_tolerance) exit
2041
2042 enddo
2043
2044 if (do_newton) then ! K_Q needs to be calculated.
2045 do k=1,ks_kappa-1 ; k_q(k) = 0.0 ; enddo
2046 do k=ks_kappa,ke_kappa ; k_q(k) = kappa(k) / tke(k) ; enddo
2047 do k=ke_kappa+1,nz+1 ; k_q(k) = 0.0 ; enddo
2048 endif
2049
2050 if (present(local_src)) then
2051 local_src(1) = 0.0 ; local_src(nz+1) = 0.0
2052 do k=2,nz
2053 diffusive_src = idz(k-1)*(kappa(k-1)-kappa(k)) + idz(k)*(kappa(k+1)-kappa(k))
2054 chg_by_k0 = kappa0 * ((idz(k-1)+idz(k)) / h_int(k) + i_ld2(k))
2055 if (diffusive_src <= 0.0) then
2056 local_src(k) = k_src(k) + chg_by_k0
2057 else
2058 local_src(k) = (k_src(k) + chg_by_k0) + diffusive_src / h_int(k)
2059 endif
2060 enddo
2061 endif
2062 if (present(kappa_src)) then
2063 kappa_src(1) = 0.0 ; kappa_src(nz+1) = 0.0
2064 do k=2,nz
2065 kappa_src(k) = k_src(k)
2066 enddo
2067 endif
2068
2069end subroutine find_kappa_tke
2070
2071!> This subroutine initializes the parameters that regulate shear-driven mixing
2072function kappa_shear_init(Time, G, GV, US, param_file, diag, CS)
2073 type(time_type), intent(in) :: time !< The current model time.
2074 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
2075 type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
2076 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
2077 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
2078 !! parameters.
2079 type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to regulate diagnostic
2080 !! output.
2081 type(kappa_shear_cs), pointer :: cs !< A pointer that is set to point to the control
2082 !! structure for this module
2083 logical :: kappa_shear_init !< True if module is to be used, False otherwise
2084
2085 ! Local variables
2086 real :: kd_normal ! The KD of the main model, read here only as a parameter
2087 ! for setting the default of KD_SMOOTH [Z2 T-1 ~> m2 s-1]
2088 real :: kappa_0_default ! The default value for KD_KAPPA_SHEAR_0 [Z2 T-1 ~> m2 s-1]
2089 logical :: merge_mixedlayer
2090 integer :: number_of_obc_segments
2091 logical :: debug_shear
2092 logical :: enable_bugs ! If true, the defaults for recently added bug-fix flags are set to
2093 ! recreate the bugs, or if false bugs are only used if actively selected.
2094 logical :: just_read ! If true, this module is not used, so only read the parameters.
2095 ! This include declares and sets the variable "version".
2096# include "version_variable.h"
2097 character(len=40) :: mdl = "MOM_kappa_shear" ! This module's name.
2098
2099 if (associated(cs)) then
2100 call mom_error(warning, "kappa_shear_init called with an associated "// &
2101 "control structure.")
2102 return
2103 endif
2104 allocate(cs)
2105
2106 ! The Jackson-Hallberg-Legg shear mixing parameterization uses the following
2107 ! 6 nondimensional coefficients. That paper gives 3 best fit parameter sets.
2108 ! Ri_Crit Rate FRi_Curv K_buoy TKE_N TKE_Shear
2109 ! p1: 0.25 0.089 -0.97 0.82 0.24 0.14
2110 ! p2: 0.30 0.085 -0.94 0.86 0.26 0.13
2111 ! p3: 0.35 0.088 -0.89 0.81 0.28 0.12
2112 ! Future research will reveal how these should be modified to take
2113 ! subgridscale inhomogeneity into account.
2114
2115! Set default, read and log parameters
2116 call get_param(param_file, mdl, "USE_JACKSON_PARAM", kappa_shear_init, default=.false., do_not_log=.true.)
2117 call log_version(param_file, mdl, version, &
2118 "Parameterization of shear-driven turbulence following Jackson, Hallberg and Legg, JPO 2008", &
2119 log_to_all=.true., debugging=kappa_shear_init, all_default=.not.kappa_shear_init)
2120 call get_param(param_file, mdl, "USE_JACKSON_PARAM", kappa_shear_init, &
2121 "If true, use the Jackson-Hallberg-Legg (JPO 2008) "//&
2122 "shear mixing parameterization.", default=.false.)
2123 just_read = .not.kappa_shear_init
2124 call get_param(param_file, mdl, "VERTEX_SHEAR", cs%KS_at_vertex, &
2125 "If true, do the calculations of the shear-driven mixing "//&
2126 "at the cell vertices (i.e., the vorticity points).", &
2127 default=.false., do_not_log=just_read)
2128 call get_param(param_file, mdl, "ENABLE_BUGS_BY_DEFAULT", enable_bugs, &
2129 default=.true., do_not_log=.true.) ! This is logged from MOM.F90.
2130 call get_param(param_file, mdl, "VERTEX_SHEAR_VISCOSITY_BUG", cs%VS_viscosity_bug, &
2131 "If true, use a bug in vertex shear that zeros out viscosities at "//&
2132 "vertices on coastlines.", &
2133 default=enable_bugs, do_not_log=just_read.or.(.not.cs%KS_at_vertex))
2134 call get_param(param_file, mdl, "OBC_NUMBER_OF_SEGMENTS", number_of_obc_segments, &
2135 default=0, do_not_log=.true.)
2136 call get_param(param_file, mdl, "VERTEX_SHEAR_OBC_BUG", cs%vertex_shear_OBC_bug, &
2137 "If false, use extra masking when interpolating thicknesses to velocity "//&
2138 "points for setting up the shear velocities at vertices to avoid using "//&
2139 "external thicknesses at open boundaries. When OBCs are not in use, "//&
2140 "this parameter does not change answers, but true is more efficient.", &
2141 default=enable_bugs, &
2142 do_not_log=just_read.or.(.not.cs%KS_at_vertex).or.(number_of_obc_segments<=0))
2143 ! Use OBC settings to set the default for VERTEX_SHEAR_OBC_BUG?
2144 call get_param(param_file, mdl, "VERTEX_SHEAR_GEOMETRIC_MEAN", cs%VS_GeometricMean, &
2145 "If true, use a geometric mean for moving diffusivity from "//&
2146 "vertices to tracer points. False uses algebraic mean.", &
2147 default=.false., do_not_log=just_read.or.(.not.cs%KS_at_vertex))
2148 call get_param(param_file, mdl, "VERTEX_SHEAR_THICKNESS_MEAN", cs%VS_ThicknessMean, &
2149 "If true, apply thickness weighting to horizontal averagings of diffusivity "//&
2150 "to tracer points in the kappa shear solver.", &
2151 default=.false.)
2152 if (cs%VS_GeometricMean) then
2153 call get_param(param_file, mdl, "VERTEX_SHEAR_GEOMETRIC_MEAN_KDMIN", &
2154 cs%VS_GeoMean_Kdmin, "If using the geometric mean in vertex shear, "//&
2155 "use this minimum value for Kd. This is an ad-hoc parameter, the "//&
2156 "diffusivities on the edge of shear regions are sensitive to the choice.",&
2157 units="m2 s-1", default=0.0, scale=gv%m2_s_to_HZ_T, do_not_log=just_read)
2158 endif
2159 call get_param(param_file, mdl, "RINO_CRIT", cs%RiNo_crit, &
2160 "The critical Richardson number for shear mixing.", &
2161 units="nondim", default=0.25, do_not_log=just_read)
2162 call get_param(param_file, mdl, "SHEARMIX_RATE", cs%Shearmix_rate, &
2163 "A nondimensional rate scale for shear-driven entrainment. "//&
2164 "Jackson et al find values in the range of 0.085-0.089.", &
2165 units="nondim", default=0.089, do_not_log=just_read)
2166 call get_param(param_file, mdl, "MAX_RINO_IT", cs%max_RiNo_it, &
2167 "The maximum number of iterations that may be used to "//&
2168 "estimate the Richardson number driven mixing.", &
2169 units="nondim", default=50, do_not_log=just_read)
2170 call get_param(param_file, mdl, "KD", kd_normal, &
2171 units="m2 s-1", scale=us%m2_s_to_Z2_T, default=0.0, do_not_log=.true.)
2172 kappa_0_default = max(kd_normal, 1.0e-7*us%m2_s_to_Z2_T)
2173 call get_param(param_file, mdl, "KD_KAPPA_SHEAR_0", cs%kappa_0, &
2174 "The background diffusivity that is used to smooth the "//&
2175 "density and shear profiles before solving for the "//&
2176 "diffusivities. The default is the greater of KD and 1e-7 m2 s-1.", &
2177 units="m2 s-1", default=kappa_0_default*us%Z2_T_to_m2_s, scale=gv%m2_s_to_HZ_T, &
2178 do_not_log=just_read)
2179 call get_param(param_file, mdl, "KD_SEED_KAPPA_SHEAR", cs%kappa_seed, &
2180 "A moderately large seed value of diapycnal diffusivity that is used as a "//&
2181 "starting turbulent diffusivity in the iterations to find an energetically "//&
2182 "constrained solution for the shear-driven diffusivity.", &
2183 units="m2 s-1", default=1.0, scale=gv%m2_s_to_HZ_T)
2184 call get_param(param_file, mdl, "KD_TRUNC_KAPPA_SHEAR", cs%kappa_trunc, &
2185 "The value of shear-driven diffusivity that is considered negligible "//&
2186 "and is rounded down to 0. The default is 1% of KD_KAPPA_SHEAR_0.", &
2187 units="m2 s-1", default=0.01*cs%kappa_0*gv%HZ_T_to_m2_s, scale=gv%m2_s_to_HZ_T, &
2188 do_not_log=just_read)
2189 call get_param(param_file, mdl, "FRI_CURVATURE", cs%FRi_curvature, &
2190 "The nondimensional curvature of the function of the "//&
2191 "Richardson number in the kappa source term in the "//&
2192 "Jackson et al. scheme.", units="nondim", default=-0.97, do_not_log=just_read)
2193 call get_param(param_file, mdl, "TKE_N_DECAY_CONST", cs%C_N, &
2194 "The coefficient for the decay of TKE due to "//&
2195 "stratification (i.e. proportional to N*tke). "//&
2196 "The values found by Jackson et al. are 0.24-0.28.", &
2197 units="nondim", default=0.24, do_not_log=just_read)
2198! call get_param(param_file, mdl, "LAYER_KAPPA_STAGGER", CS%layer_stagger, &
2199! default=.false., do_not_log=just_read)
2200 call get_param(param_file, mdl, "TKE_SHEAR_DECAY_CONST", cs%C_S, &
2201 "The coefficient for the decay of TKE due to shear (i.e. "//&
2202 "proportional to |S|*tke). The values found by Jackson "//&
2203 "et al. are 0.14-0.12.", units="nondim", default=0.14, do_not_log=just_read)
2204 call get_param(param_file, mdl, "KAPPA_BUOY_SCALE_COEF", cs%lambda, &
2205 "The coefficient for the buoyancy length scale in the "//&
2206 "kappa equation. The values found by Jackson et al. are "//&
2207 "in the range of 0.81-0.86.", units="nondim", default=0.82, do_not_log=just_read)
2208 call get_param(param_file, mdl, "KAPPA_N_OVER_S_SCALE_COEF2", cs%lambda2_N_S, &
2209 "The square of the ratio of the coefficients of the "//&
2210 "buoyancy and shear scales in the diffusivity equation, "//&
2211 "Set this to 0 (the default) to eliminate the shear scale. "//&
2212 "This is only used if USE_JACKSON_PARAM is true.", &
2213 units="nondim", default=0.0, do_not_log=just_read)
2214 call get_param(param_file, mdl, "LZ_RESCALE", cs%lz_rescale, &
2215 "A coefficient to rescale the distance to the nearest solid boundary. "//&
2216 "This adjustment is to account for regions where 3 dimensional turbulence "//&
2217 "prevents the growth of shear instabilities [nondim].", &
2218 units="nondim", default=1.0)
2219 call get_param(param_file, mdl, "KAPPA_SHEAR_TOL_ERR", cs%kappa_tol_err, &
2220 "The fractional error in kappa that is tolerated. "//&
2221 "Iteration stops when changes between subsequent "//&
2222 "iterations are smaller than this everywhere in a "//&
2223 "column. The peak diffusivities usually converge most "//&
2224 "rapidly, and have much smaller errors than this.", &
2225 units="nondim", default=0.1, do_not_log=just_read)
2226 call get_param(param_file, mdl, "TKE_BACKGROUND", cs%TKE_bg, &
2227 "A background level of TKE used in the first iteration "//&
2228 "of the kappa equation. TKE_BACKGROUND could be 0.", &
2229 units="m2 s-2", default=0.0, scale=us%m_to_Z**2*us%T_to_s**2)
2230 call get_param(param_file, mdl, "KAPPA_SHEAR_ELIM_MASSLESS", cs%eliminate_massless, &
2231 "If true, massless layers are merged with neighboring "//&
2232 "massive layers in this calculation. The default is "//&
2233 "true and I can think of no good reason why it should "//&
2234 "be false. This is only used if USE_JACKSON_PARAM is true.", &
2235 default=.true., do_not_log=just_read)
2236 call get_param(param_file, mdl, "MAX_KAPPA_SHEAR_IT", cs%max_KS_it, &
2237 "The maximum number of iterations that may be used to "//&
2238 "estimate the time-averaged diffusivity.", &
2239 default=13, do_not_log=just_read)
2240 call get_param(param_file, mdl, "PRANDTL_TURB", cs%Prandtl_turb, &
2241 "The turbulent Prandtl number applied to shear instability.", &
2242 units="nondim", default=1.0, do_not_log=just_read)
2243 call get_param(param_file, mdl, "VEL_UNDERFLOW", cs%vel_underflow, &
2244 "A negligibly small velocity magnitude below which velocity components are set "//&
2245 "to 0. A reasonable value might be 1e-30 m/s, which is less than an "//&
2246 "Angstrom divided by the age of the universe.", &
2247 units="m s-1", default=0.0, scale=us%m_s_to_L_T, do_not_log=just_read)
2248 call get_param(param_file, mdl, "KAPPA_SHEAR_MAX_KAP_SRC_CHG", cs%kappa_src_max_chg, &
2249 "The maximum permitted increase in the kappa source within an iteration relative "//&
2250 "to the local source; this must be greater than 1. The lower limit for the "//&
2251 "permitted fractional decrease is (1 - 0.5/kappa_src_max_chg). These limits "//&
2252 "could perhaps be made dynamic with an improved iterative solver.", &
2253 default=10.0, units="nondim", do_not_log=just_read)
2254
2255 call get_param(param_file, mdl, "DEBUG", cs%debug, &
2256 "If true, write out verbose debugging data.", &
2257 default=.false., debuggingparam=.true., do_not_log=just_read)
2258 call get_param(param_file, mdl, "DEBUG_KAPPA_SHEAR", debug_shear, &
2259 "If true, write debugging data for the kappa-shear code.", &
2260 default=.false., debuggingparam=.true., do_not_log=.true.)
2261 if (debug_shear) cs%debug = .true.
2262 call get_param(param_file, mdl, "KAPPA_SHEAR_VERTEX_PSURF_BUG", cs%psurf_bug, &
2263 "If true, do a simple average of the cell surface pressures to get a pressure "//&
2264 "at the corner if VERTEX_SHEAR=True. Otherwise mask out any land points in "//&
2265 "the average.", default=.false., do_not_log=(just_read .or. (.not.cs%KS_at_vertex)))
2266
2267 call get_param(param_file, mdl, "KAPPA_SHEAR_ITER_BUG", cs%dKdQ_iteration_bug, &
2268 "If true, use an older, dimensionally inconsistent estimate of the "//&
2269 "derivative of diffusivity with energy in the Newton's method iteration. "//&
2270 "The bug causes undercorrections when dz > 1 m.", default=.false., do_not_log=just_read)
2271 call get_param(param_file, mdl, "KAPPA_SHEAR_ALL_LAYER_TKE_BUG", cs%all_layer_TKE_bug, &
2272 "If true, report back the latest estimate of TKE instead of the time average "//&
2273 "TKE when there is mass in all layers. Otherwise always report the time "//&
2274 "averaged TKE, as is currently done when there are some massless layers.", &
2275 default=.false., do_not_log=just_read)
2276 call get_param(param_file, mdl, "USE_RESTRICTIVE_TOLERANCE_CHECK", cs%restrictive_tolerance_check, &
2277 "If true, uses the more restrictive tolerance check to determine if a timestep "//&
2278 "is acceptable for the KS_it outer iteration loop. False uses the original less "//&
2279 "restrictive check.", default=.false., do_not_log=just_read)
2280! id_clock_KQ = cpu_clock_id('Ocean KS kappa_shear', grain=CLOCK_ROUTINE)
2281! id_clock_avg = cpu_clock_id('Ocean KS avg', grain=CLOCK_ROUTINE)
2282! id_clock_project = cpu_clock_id('Ocean KS project', grain=CLOCK_ROUTINE)
2283! id_clock_setup = cpu_clock_id('Ocean KS setup', grain=CLOCK_ROUTINE)
2284
2285 cs%nkml = 1
2286 if (gv%nkml>0) then
2287 call get_param(param_file, mdl, "KAPPA_SHEAR_MERGE_ML",merge_mixedlayer, &
2288 "If true, combine the mixed layers together before solving the "//&
2289 "kappa-shear equations.", default=.true., do_not_log=just_read)
2290 if (merge_mixedlayer) cs%nkml = gv%nkml
2291 endif
2292
2293! Forego remainder of initialization if not using this scheme
2294 if (.not. kappa_shear_init) return
2295
2296 cs%diag => diag
2297
2298 cs%id_Kd_shear = register_diag_field('ocean_model','Kd_shear', diag%axesTi, time, &
2299 'Shear-driven Diapycnal Diffusivity at horizontal tracer points', 'm2 s-1', conversion=gv%HZ_T_to_m2_s)
2300 if (cs%KS_at_vertex) then
2301 cs%id_TKE = register_diag_field('ocean_model','TKE_shear', diag%axesBi, time, &
2302 'Shear-driven Turbulent Kinetic Energy at horizontal vertices', 'm2 s-2', conversion=us%Z_to_m**2*us%s_to_T**2)
2303 cs%id_Kd_vertex = register_diag_field('ocean_model','Kd_shear_vertex', diag%axesBi, time, &
2304 'Shear-driven Diapycnal Diffusivity at horizontal vertices', 'm2 s-1', conversion=gv%HZ_T_to_m2_s)
2305 cs%id_S2_init = register_diag_field('ocean_model','S2_shear_in', diag%axesBi, time, &
2306 'Interface shear squared at horizontal vertices, as input to kappa-shear', 's-2', conversion=us%s_to_T**2)
2307 cs%id_N2_init = register_diag_field('ocean_model','N2_shear_in', diag%axesBi, time, &
2308 'Interface stratification at horizontal vertices, as input to kappa-shear', 's-2', conversion=us%s_to_T**2)
2309 cs%id_S2_mean = register_diag_field('ocean_model','S2_shear_mean', diag%axesBi, time, &
2310 'Interface shear squared at horizontal vertices, averaged over timestep in kappa-shear', &
2311 's-2', conversion=us%s_to_T**2)
2312 cs%id_N2_mean = register_diag_field('ocean_model','N2_shear_mean', diag%axesBi, time, &
2313 'Interface stratification at horizontal vertices, averaged over timestep in kappa-shear', &
2314 's-2', conversion=us%s_to_T**2)
2315 else
2316 cs%id_TKE = register_diag_field('ocean_model','TKE_shear', diag%axesTi, time, &
2317 'Shear-driven Turbulent Kinetic Energy at horizontal tracer points', &
2318 'm2 s-2', conversion=us%Z_to_m**2*us%s_to_T**2)
2319 cs%id_S2_init = register_diag_field('ocean_model','S2_shear_in', diag%axesTi, time, &
2320 'Interface shear squared at horizontal tracer points, as input to kappa-shear', 's-2', conversion=us%s_to_T**2)
2321 cs%id_N2_init = register_diag_field('ocean_model','N2_shear_in', diag%axesTi, time, &
2322 'Interface stratification at horizontal tracer points, as input to kappa-shear', &
2323 's-2', conversion=us%s_to_T**2)
2324 cs%id_S2_mean = register_diag_field('ocean_model','S2_shear_mean', diag%axesTi, time, &
2325 'Interface shear squared at horizontal tracer points, averaged over timestep in kappa-shear', &
2326 's-2', conversion=us%s_to_T**2)
2327 cs%id_N2_mean = register_diag_field('ocean_model','N2_shear_mean', diag%axesTi, time, &
2328 'Interface stratification at horizontal tracer points, averaged ove timestep in kappa-shear', &
2329 's-2', conversion=us%s_to_T**2)
2330 endif
2331
2332end function kappa_shear_init
2333
2334!> This function indicates to other modules whether the Jackson et al shear mixing
2335!! parameterization will be used without needing to duplicate the log entry.
2336logical function kappa_shear_is_used(param_file)
2337 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
2338
2339 ! Local variables
2340 character(len=40) :: mdl = "MOM_kappa_shear" ! This module's name.
2341 ! This function reads the parameter "USE_JACKSON_PARAM" and returns its value.
2342
2343 call get_param(param_file, mdl, "USE_JACKSON_PARAM", kappa_shear_is_used, &
2344 default=.false., do_not_log=.true.)
2345end function kappa_shear_is_used
2346
2347!> This function indicates to other modules whether the Jackson et al shear mixing parameterization
2348!! will be used at the vertices without needing to duplicate the log entry. It returns false if
2349!! the Jackson et al scheme is not used or if it is used via calculations at the tracer points.
2350logical function kappa_shear_at_vertex(param_file)
2351 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
2352
2353 ! Local variables
2354 character(len=40) :: mdl = "MOM_kappa_shear" ! This module's name.
2355 logical :: do_kappa_shear
2356 ! This function returns true only if the parameters "USE_JACKSON_PARAM" and "VERTEX_SHEAR" are both true.
2357
2358 kappa_shear_at_vertex = .false.
2359
2360 call get_param(param_file, mdl, "USE_JACKSON_PARAM", do_kappa_shear, &
2361 default=.false., do_not_log=.true.)
2362 if (do_kappa_shear) &
2363 call get_param(param_file, mdl, "VERTEX_SHEAR", kappa_shear_at_vertex, &
2364 "If true, do the calculations of the shear-driven mixing "//&
2365 "at the cell vertices (i.e., the vorticity points).", &
2366 default=.false., do_not_log=.true.)
2367
2368end function kappa_shear_at_vertex
2369
2370!> \namespace mom_kappa_shear
2371!!
2372!! By Laura Jackson and Robert Hallberg, 2006-2008
2373!!
2374!! This file contains the subroutines that determine the diapycnal
2375!! diffusivity driven by resolved shears, as specified by the
2376!! parameterizations described in Jackson and Hallberg (JPO, 2008).
2377!!
2378!! The technique by which the 6 equations (for kappa, TKE, u, v, T,
2379!! and S) are solved simultaneously has been dramatically revised
2380!! from the previous version. The previous version was not converging
2381!! in some cases, especially near the surface mixed layer, while the
2382!! revised version does. The revised version solves for kappa and
2383!! TKE with shear and stratification fixed, then marches the density
2384!! and velocities forward with an adaptive (and aggressive) time step
2385!! in a predictor-corrector-corrector emulation of a trapezoidal
2386!! scheme. Run-time-settable parameters determine the tolerance to
2387!! which the kappa and TKE equations are solved and the minimum time
2388!! step that can be taken.
2389
2390end module mom_kappa_shear