← back to index

src/parameterizations/vertical/MOM_kappa_shear.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

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
27public Calculate_kappa_shear, Calc_kappa_shear_vertex, kappa_shear_init
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
1351subroutine Calculate_kappa_shear(u_in, v_in, h, tv, p_surf, kappa_io, tke_io, &
1361 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) :: &
1692 diag_N2_init, & ! Diagnostic of N2 as provided to this routine [T-2 ~> s-2]
1702 diag_S2_init, & ! Diagnostic of S2 as provided to this routine [T-2 ~> s-2]
1712 diag_N2_mean, & ! Diagnostic of N2 averaged over the timestep applied [T-2 ~> s-2]
1722 diag_S2_mean ! Diagnostic of S2 averaged over the timestep applied [T-2 ~> s-2]
173 real, dimension(SZI_(G),SZK_(GV)) :: &
1742 h_2d, & ! A 2-D version of h [H ~> m or kg m-2].
1752 dz_2d, & ! Vertical distance between interface heights [Z ~> m].
1762 u_2d, v_2d, & ! 2-D versions of u_in and v_in, converted to [L T-1 ~> m s-1].
1772 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) :: &
1792 kappa_2d, & ! 2-D version of kappa_io [H Z T-1 ~> m2 s-1 or Pa s]
1802 tke_2d ! 2-D version tke_io [Z2 T-2 ~> m2 s-2].
181 real, dimension(SZK_(GV)) :: &
1822 Idz, & ! The inverse of the thickness of the merged layers [H-1 ~> m2 kg-1].
1832 h_lay, & ! The layer thickness [H ~> m or kg m-2]
1842 dz_lay, & ! The geometric layer thickness in height units [Z ~> m]
1852 u0xdz, & ! The initial zonal velocity times dz [H L T-1 ~> m2 s-1 or kg m-1 s-1]
1862 v0xdz, & ! The initial meridional velocity times dz [H L T-1 ~> m2 s-1 or kg m-1 s-1]
1872 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]
1892 S0xdz ! The initial salinity times dz [S H ~> ppt m or ppt kg m-2].
190 real, dimension(SZK_(GV)+1) :: &
1912 kappa, & ! The shear-driven diapycnal diffusivity at an interface [H Z T-1 ~> m2 s-1 or Pa s]
1922 tke, & ! The Turbulent Kinetic Energy per unit mass at an interface [Z2 T-2 ~> m2 s-2].
1932 kappa_avg, & ! The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
1942 tke_avg, & ! The time-weighted average of TKE [Z2 T-2 ~> m2 s-2].
1952 N2_init, & ! N2 as provided to this routine [T-2 ~> s-2].
1962 S2_init, & ! S2 as provided to this routine [T-2 ~> s-2].
1972 N2_mean, & ! The time-weighted average of N2 [T-2 ~> s-2].
1982 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
2092 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.
2122 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
2161 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
217
2181 use_temperature = associated(tv%T)
219
2201 k0dt = dt*CS%kappa_0
2211 dz_massless = 0.1*sqrt((US%Z_to_m*GV%m_to_H)*k0dt)
222
2231 if ((CS%id_N2_init>0) .or. CS%debug) diag_N2_init(:,:,:) = 0.0
2241 if ((CS%id_S2_init>0) .or. CS%debug) diag_S2_init(:,:,:) = 0.0
2251 if (CS%id_N2_mean>0) diag_N2_mean(:,:,:) = 0.0
2261 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)
231181 do j=js,je
232
233 ! Convert layer thicknesses into geometric thickness in height units.
234180 call thickness_to_dz(h, tv, dz_2d, j, G, GV)
235
2361429740 do k=1,nz ; do i=is,ie
2371425600 h_2d(i,k) = h(i,j,k)
2381429560 u_2d(i,k) = u_in(i,j,k) ; v_2d(i,k) = v_in(i,j,k)
239 enddo ; enddo
2401429740 if (use_temperature) then ; do k=1,nz ; do i=is,ie
2411429560 T_2d(i,k) = tv%T(i,j,k) ; S_2d(i,k) = tv%S(i,j,k)
2420 enddo ; enddo ; else ; do k=1,nz ; do i=is,ie
2430 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!---------------------------------------
24964980 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.
25446250 if (CS%eliminate_massless) then
25546250 nzc = 1
2561063750 do k=1,nz
257 ! Zero out the thicknesses of all layers, even if they are unused.
2581017500 h_lay(k) = 0.0 ; dz_lay(k) = 0.0 ; u0xdz(k) = 0.0 ; v0xdz(k) = 0.0
2591017500 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
2631017500 if ((k>CS%nkml) .and. (h_lay(nzc) > 0.0) .and. &
264345393 (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
2701017500 kc(k) = nzc
2711017500 h_lay(nzc) = h_lay(nzc) + h_2d(i,k)
2721017500 dz_lay(nzc) = dz_lay(nzc) + dz_2d(i,k)
2731017500 u0xdz(nzc) = u0xdz(nzc) + u_2d(i,k)*h_2d(i,k)
2741017500 v0xdz(nzc) = v0xdz(nzc) + v_2d(i,k)*h_2d(i,k)
2751063750 if (use_temperature) then
2761017500 T0xdz(nzc) = T0xdz(nzc) + T_2d(i,k)*h_2d(i,k)
2771017500 S0xdz(nzc) = S0xdz(nzc) + S_2d(i,k)*h_2d(i,k)
278 else
2790 T0xdz(nzc) = T0xdz(nzc) + rho_2d(i,k)*h_2d(i,k)
2800 S0xdz(nzc) = S0xdz(nzc) + rho_2d(i,k)*h_2d(i,k)
281 endif
282 enddo
28346250 kc(nz+1) = nzc+1
284
285 ! Set up Idz as the inverse of layer thicknesses.
286437893 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.
29046250 kf(1) = 0.0 ; dz_in_lay = h_2d(i,1)
2911017500 do k=2,nz
2921017500 if (kc(k) > kc(k-1)) then
293345393 kf(k) = 0.0 ; dz_in_lay = h_2d(i,k)
294 else
295625857 kf(k) = dz_in_lay*Idz(kc(k)) ; dz_in_lay = dz_in_lay + h_2d(i,k)
296 endif
297 enddo
29846250 kf(nz+1) = 0.0
299 else
3000 do k=1,nz
3010 h_lay(k) = h_2d(i,k)
3020 dz_lay(k) = dz_2d(i,k)
3030 u0xdz(k) = u_2d(i,k)*h_lay(k) ; v0xdz(k) = v_2d(i,k)*h_lay(k)
304 enddo
3050 if (use_temperature) then
3060 do k=1,nz
3070 T0xdz(k) = T_2d(i,k)*h_lay(k) ; S0xdz(k) = S_2d(i,k)*h_lay(k)
308 enddo
309 else
3100 do k=1,nz
3110 T0xdz(k) = rho_2d(i,k)*h_lay(k) ; S0xdz(k) = rho_2d(i,k)*h_lay(k)
312 enddo
313 endif
3140 nzc = nz
3150 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)) + &
31846250 (G%Coriolis2Bu(I,J-1) + G%Coriolis2Bu(I-1,J)))
31946250 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 ! ----------------------------------------------------
325484143 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, &
33046250 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.
33446250 if (nz == nzc) then
3350 do K=1,nz+1
3360 kappa_2d(i,K) = kappa_avg(K)
3370 if (CS%all_layer_TKE_bug) then
3380 tke_2d(i,K) = tke(K)
339 else
3400 tke_2d(i,K) = tke_avg(K)
341 endif
342 enddo
3430 if (CS%id_N2_mean>0) then ; do K=1,nz+1
3440 diag_N2_mean(i,j,K) = N2_mean(K)
345 enddo ; endif
3460 if (CS%id_S2_mean>0) then ; do K=1,nz+1
3470 diag_S2_mean(i,j,K) = S2_mean(K)
348 enddo ; endif
3490 if ((CS%id_N2_init>0) .or. CS%debug) then ; do K=1,nz+1
3500 diag_N2_init(i,j,K) = N2_init(K)
351 enddo ; endif
3520 if ((CS%id_S2_init>0) .or. CS%debug) then ; do K=1,nz+1
3530 diag_S2_init(i,j,K) = S2_init(K)
354 enddo ; endif
355 else
3561110000 do K=1,nz+1
3571110000 if (kf(K) == 0.0) then
358437893 kappa_2d(i,K) = kappa_avg(kc(K))
359437893 tke_2d(i,K) = tke_avg(kc(K))
360 else
361625857 kappa_2d(i,K) = (1.0-kf(K)) * kappa_avg(kc(K)) + kf(K) * kappa_avg(kc(K)+1)
362625857 tke_2d(i,K) = (1.0-kf(K)) * tke_avg(kc(K)) + kf(K) * tke_avg(kc(K)+1)
363 endif
364 enddo
3651110000 do K=1,nz+1
3661110000 if (kf(K) == 0.0) then
367437893 if (CS%id_N2_mean>0) diag_N2_mean(i,j,K) = N2_mean(kc(K))
368437893 if (CS%id_S2_mean>0) diag_S2_mean(i,j,K) = S2_mean(kc(K))
369437893 if ((CS%id_N2_init>0) .or. CS%debug) diag_N2_init(i,j,K) = N2_init(kc(K))
370437893 if ((CS%id_S2_init>0) .or. CS%debug) diag_S2_init(i,j,K) = S2_init(kc(K))
371 else
372625857 if (CS%id_N2_mean>0) &
3730 diag_N2_mean(i,j,K) = (1.0-kf(K)) * N2_mean(kc(K)) + kf(K) * N2_mean(kc(K)+1)
374625857 if (CS%id_S2_mean>0) &
3750 diag_S2_mean(i,j,K) = (1.0-kf(K)) * S2_mean(kc(K)) + kf(K) * S2_mean(kc(K)+1)
376625857 if ((CS%id_N2_init>0) .or. CS%debug) &
3770 diag_N2_init(i,j,K) = (1.0-kf(K)) * N2_init(kc(K)) + kf(K) * N2_init(kc(K)+1)
378625857 if ((CS%id_S2_init>0) .or. CS%debug) &
3790 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.
385445200 do K=1,nz+1
386445200 kappa_2d(i,K) = 0.0 ; tke_2d(i,K) = 0.0
387 enddo
388 endif ; enddo ! i-loop
389
3901494721 do K=1,nz+1 ; do i=is,ie
3911490400 kappa_io(i,j,K) = G%mask2dT(i,j) * kappa_2d(i,K)
3921490400 tke_io(i,j,K) = G%mask2dT(i,j) * tke_2d(i,K)
3931494540 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
3991 if (CS%debug) then
4000 call hchksum(diag_N2_init, "kappa_shear N2_init", G%HI, unscale=US%s_to_T**2)
4010 call hchksum(diag_S2_init, "kappa_shear S2_init", G%HI, unscale=US%s_to_T**2)
4020 call hchksum(kappa_io, "kappa", G%HI, unscale=GV%HZ_T_to_m2_s)
4030 call hchksum(tke_io, "tke", G%HI, unscale=US%Z_to_m**2*US%s_to_T**2)
404 endif
405
4061 if (CS%id_Kd_shear > 0) call post_data(CS%id_Kd_shear, kappa_io, CS%diag)
4071 if (CS%id_TKE > 0) call post_data(CS%id_TKE, tke_io, CS%diag)
4081 if (CS%id_N2_init > 0) call post_data(CS%id_N2_init, diag_N2_init, CS%diag)
4091 if (CS%id_S2_init > 0) call post_data(CS%id_S2_init, diag_S2_init, CS%diag)
4101 if (CS%id_N2_mean > 0) call post_data(CS%id_N2_mean, diag_N2_mean, CS%diag)
4111 if (CS%id_S2_mean > 0) call post_data(CS%id_S2_mean, diag_S2_mean, CS%diag)
412
4131end subroutine Calculate_kappa_shear
414
415
416!> Subroutine for calculating shear-driven diffusivity and TKE in corner columns
4170subroutine Calc_kappa_shear_vertex(u_in, v_in, h, T_in, S_in, tv, p_surf, kappa_io, tke_io, &
4180 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) :: &
4550 diag_N2_init, & ! Diagnostic of N2 as provided to this routine [T-2 ~> s-2]
4560 diag_S2_init, & ! Diagnostic of S2 as provided to this routine [T-2 ~> s-2]
4570 diag_N2_mean, & ! Diagnostic of N2 averaged over the timestep applied [T-2 ~> s-2]
4580 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)) :: &
4610 dz_3d ! Vertical distance between interface heights [Z ~> m].
462 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)+1) :: &
4630 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)) :: &
4650 h_vert ! Thicknesses interpolated to vertices [H ~> m or kg m-2]
466 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: &
4670 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)) :: &
4690 h_at_v ! A mask-weighted thickness interpolated to v-points [H ~> m or kg m-2]
470 real, dimension(SZIB_(G),SZK_(GV)) :: &
4710 h_2d, & ! A 2-D version of h interpolated to vertices [H ~> m or kg m-2].
4720 dz_2d, & ! Vertical distance between interface heights [Z ~> m].
4730 u_2d, v_2d, & ! 2-D versions of u_in and v_in, converted to [L T-1 ~> m s-1].
4740 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) :: &
4760 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) :: &
4780 tke_2d ! 2-D version tke_io [Z2 T-2 ~> m2 s-2].
479 real, dimension(SZK_(GV)) :: &
4800 Idz, & ! The inverse of the thickness of the merged layers [H-1 ~> m2 kg-1].
4810 h_lay, & ! The layer thickness [H ~> m or kg m-2]
4820 dz_lay, & ! The geometric layer thickness in height units [Z ~> m]
4830 u0xdz, & ! The initial zonal velocity times dz [L H T-1 ~> m2 s-1 or kg m-1 s-1].
4840 v0xdz, & ! The initial meridional velocity times dz [H L T-1 ~> m2 s-1 or kg m-1 s-1]
4850 T0xdz, & ! The initial temperature times dz [C H ~> degC m or degC kg m-2]
4860 S0xdz ! The initial salinity times dz [S H ~> ppt m or ppt kg m-2]
487 real, dimension(SZK_(GV)+1) :: &
4880 kappa, & ! The shear-driven diapycnal diffusivity at an interface [H Z T-1 ~> m2 s-1 or Pa s]
4890 tke, & ! The Turbulent Kinetic Energy per unit mass at an interface [Z2 T-2 ~> m2 s-2].
4900 kappa_avg, & ! The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
4910 tke_avg, & ! The time-weighted average of TKE [Z2 T-2 ~> m2 s-2].
4920 N2_init, & ! N2 as provided to this routine [T-2 ~> s-2].
4930 S2_init, & ! S2 as provided to this routine [T-2 ~> s-2].
4940 N2_mean, & ! The time-weighted average of N2 [T-2 ~> s-2].
4950 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
5090 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.
5120 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?
5230 isB = G%isc-1 ; ieB = G%iecB ; jsB = G%jsc-1 ; jeB = G%jecB ; nz = GV%ke
524
5250 if ((CS%id_N2_init>0) .or. CS%debug) diag_N2_init(:,:,:) = 0.0
5260 if ((CS%id_S2_init>0) .or. CS%debug) diag_S2_init(:,:,:) = 0.0
5270 if (CS%id_N2_mean>0) diag_N2_mean(:,:,:) = 0.0
5280 if (CS%id_S2_mean>0) diag_S2_mean(:,:,:) = 0.0
5290 kappa_vertex(:,:,:) = 0.0
530
5310 use_temperature = associated(tv%T)
532
5330 k0dt = dt*CS%kappa_0
5340 dz_massless = 0.1*sqrt((US%Z_to_m*GV%m_to_H)*k0dt)
5350 I_Prandtl = 0.0 ; if (CS%Prandtl_turb > 0.0) I_Prandtl = 1.0 / CS%Prandtl_turb
5360 H_tiny = 0.5 * GV%H_subroundoff
537
538 ! Convert layer thicknesses into geometric thickness in height units.
5390 call thickness_to_dz(h, tv, dz_3d, G, GV, US, halo_size=1)
540
5410 if (CS%vertex_shear_OBC_bug) then
542 !$OMP parallel do default(shared)
5430 do k=1,nz
5440 do j=JsB,JeB+1 ; do I=IsB,IeB
5450 h_at_u(I,j,k) = G%mask2dCu(I,j) * (h(i,j,k) + h(i+1,j,k)) * 0.5
546 enddo ; enddo
5470 do J=JsB,JeB ; do i=IsB,IeB+1
5480 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)
5560 do k=1,nz
5570 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)) / &
5590 (G%mask2dT(i,j) + G%mask2dT(i+1,j) + 1.0e-36)
560 enddo ; enddo
5610 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)) / &
5630 (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,T_in,S_in,h_at_u,h_at_v,dz_3d,H_tiny, &
570 !$OMP use_temperature,tv,G,GV,US,CS,kappa_io, &
571 !$OMP dz_massless,k0dt,p_surf,dt,tke_io,kv_io,kappa_vertex,h_vert,I_Prandtl, &
572 !$OMP diag_N2_init,diag_S2_init,diag_N2_mean,diag_S2_mean)
5730 do J=JsB,JeB
574
575 ! Interpolate the various quantities to the corners, using masks.
5760 do k=1,nz ; do I=IsB,IeB
577 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)) ) / &
5780 ( (h_at_u(I,j,k) + h_at_u(I,j+1,k)) + H_tiny )
579 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)) ) / &
5800 ( (h_at_v(i,J,k) + h_at_v(i+1,J,k)) + H_tiny )
581
582 I_hwt = 1.0 / (((G%mask2dT(i,j) * h(i,j,k) + G%mask2dT(i+1,j+1) * h(i+1,j+1,k)) + &
583 (G%mask2dT(i+1,j) * h(i+1,j,k) + G%mask2dT(i,j+1) * h(i,j+1,k))) + &
5840 GV%H_subroundoff)
5850 if (use_temperature) then
586 T_2d(I,k) = ( (G%mask2dT(i,j) * (h(i,j,k) * T_in(i,j,k)) + &
587 G%mask2dT(i+1,j+1) * (h(i+1,j+1,k) * T_in(i+1,j+1,k))) + &
588 (G%mask2dT(i+1,j) * (h(i+1,j,k) * T_in(i+1,j,k)) + &
5890 G%mask2dT(i,j+1) * (h(i,j+1,k) * T_in(i,j+1,k))) ) * I_hwt
590 S_2d(I,k) = ( (G%mask2dT(i,j) * (h(i,j,k) * S_in(i,j,k)) + &
591 G%mask2dT(i+1,j+1) * (h(i+1,j+1,k) * S_in(i+1,j+1,k))) + &
592 (G%mask2dT(i+1,j) * (h(i+1,j,k) * S_in(i+1,j,k)) + &
5930 G%mask2dT(i,j+1) * (h(i,j+1,k) * S_in(i,j+1,k))) ) * I_hwt
594 endif
595 h_2d(I,k) = ((G%mask2dT(i,j) * h(i,j,k) + G%mask2dT(i+1,j+1) * h(i+1,j+1,k)) + &
596 (G%mask2dT(i+1,j) * h(i+1,j,k) + G%mask2dT(i,j+1) * h(i,j+1,k)) ) / &
597 ((G%mask2dT(i,j) + G%mask2dT(i+1,j+1)) + &
5980 (G%mask2dT(i+1,j) + G%mask2dT(i,j+1)) + 1.0e-36 )
599 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)) + &
600 (G%mask2dT(i+1,j) * dz_3d(i+1,j,k) + G%mask2dT(i,j+1) * dz_3d(i,j+1,k)) ) / &
601 ((G%mask2dT(i,j) + G%mask2dT(i+1,j+1)) + &
6020 (G%mask2dT(i+1,j) + G%mask2dT(i,j+1)) + 1.0e-36 )
603! 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)))
604! h_2d(I,k) = (((h(i,j,k)**2) + (h(i+1,j+1,k)**2)) + &
605! ((h(i+1,j,k)**2) + (h(i,j+1,k)**2))) * I_hwt
606 enddo ; enddo
6070 if (.not.use_temperature) then ; do k=1,nz ; do I=IsB,IeB
6080 rho_2d(I,k) = GV%Rlay(k)
609 enddo ; enddo ; endif
610
611!---------------------------------------
612! Work on each column.
613!---------------------------------------
6140 do I=IsB,IeB ; if ((G%mask2dCu(I,j) + G%mask2dCu(I,j+1)) + &
6150 (G%mask2dCv(i,J) + G%mask2dCv(i+1,J)) > 0.0) then
616 ! call cpu_clock_begin(Id_clock_setup)
617 ! Store a transposed version of the initial arrays.
618 ! Any elimination of massless layers would occur here.
6190 if (CS%eliminate_massless) then
6200 nzc = 1
6210 do k=1,nz
622 ! Zero out the thicknesses of all layers, even if they are unused.
6230 h_lay(k) = 0.0 ; dz_lay(k) = 0.0 ; u0xdz(k) = 0.0 ; v0xdz(k) = 0.0
6240 T0xdz(k) = 0.0 ; S0xdz(k) = 0.0
625
626 ! Add a new layer if this one has mass.
627! if ((h_lay(nzc) > 0.0) .and. (h_2d(I,k) > dz_massless)) nzc = nzc+1
6280 if ((k>CS%nkml) .and. (h_lay(nzc) > 0.0) .and. &
6290 (h_2d(I,k) > dz_massless)) nzc = nzc+1
630
631 ! Only merge clusters of massless layers.
632! if ((h_lay(nzc) > dz_massless) .or. &
633! ((h_lay(nzc) > 0.0) .and. (h_2d(I,k) > dz_massless))) nzc = nzc+1
634
6350 kc(k) = nzc
6360 h_lay(nzc) = h_lay(nzc) + h_2d(I,k)
6370 dz_lay(nzc) = dz_lay(nzc) + dz_2d(I,k)
6380 u0xdz(nzc) = u0xdz(nzc) + u_2d(I,k)*h_2d(I,k)
6390 v0xdz(nzc) = v0xdz(nzc) + v_2d(I,k)*h_2d(I,k)
6400 if (use_temperature) then
6410 T0xdz(nzc) = T0xdz(nzc) + T_2d(I,k)*h_2d(I,k)
6420 S0xdz(nzc) = S0xdz(nzc) + S_2d(I,k)*h_2d(I,k)
643 else
6440 T0xdz(nzc) = T0xdz(nzc) + rho_2d(I,k)*h_2d(I,k)
6450 S0xdz(nzc) = S0xdz(nzc) + rho_2d(I,k)*h_2d(I,k)
646 endif
647 enddo
6480 kc(nz+1) = nzc+1
649
650 ! Set up Idz as the inverse of layer thicknesses.
6510 do k=1,nzc ; Idz(k) = 1.0 / h_lay(k) ; enddo
652
653 ! Now determine kf, the fractional weight of interface kc when
654 ! interpolating between interfaces kc and kc+1.
6550 kf(1) = 0.0 ; dz_in_lay = h_2d(I,1)
6560 do k=2,nz
6570 if (kc(k) > kc(k-1)) then
6580 kf(k) = 0.0 ; dz_in_lay = h_2d(I,k)
659 else
6600 kf(k) = dz_in_lay*Idz(kc(k)) ; dz_in_lay = dz_in_lay + h_2d(I,k)
661 endif
662 enddo
6630 kf(nz+1) = 0.0
664 else
6650 do k=1,nz
6660 h_lay(k) = h_2d(I,k)
6670 dz_lay(k) = dz_2d(I,k)
6680 u0xdz(k) = u_2d(I,k)*h_lay(k) ; v0xdz(k) = v_2d(I,k)*h_lay(k)
669 enddo
6700 if (use_temperature) then
6710 do k=1,nz
6720 T0xdz(k) = T_2d(I,k)*h_lay(k) ; S0xdz(k) = S_2d(I,k)*h_lay(k)
673 enddo
674 else
6750 do k=1,nz
6760 T0xdz(k) = rho_2d(I,k)*h_lay(k) ; S0xdz(k) = rho_2d(I,k)*h_lay(k)
677 enddo
678 endif
6790 nzc = nz
6800 do k=1,nzc+1 ; kc(k) = k ; kf(k) = 0.0 ; enddo
681 endif
682
6830 f2 = G%Coriolis2Bu(I,J)
6840 surface_pres = 0.0
6850 if (associated(p_surf)) then
6860 if (CS%psurf_bug) then
687 ! This is wrong because it is averaging values from land in some places.
688 surface_pres = 0.25 * ((p_surf(i,j) + p_surf(i+1,j+1)) + &
6890 (p_surf(i+1,j) + p_surf(i,j+1)))
690 else
691 surface_pres = ((G%mask2dT(i,j) * p_surf(i,j) + G%mask2dT(i+1,j+1) * p_surf(i+1,j+1)) + &
692 (G%mask2dT(i+1,j) * p_surf(i+1,j) + G%mask2dT(i,j+1) * p_surf(i,j+1)) ) / &
693 ((G%mask2dT(i,j) + G%mask2dT(i+1,j+1)) + &
6940 (G%mask2dT(i+1,j) + G%mask2dT(i,j+1)) + 1.0e-36 )
695 endif
696 endif
697
698 ! ----------------------------------------------------
699 ! Set the initial guess for kappa, here defined at interfaces.
700 ! ----------------------------------------------------
7010 do K=1,nzc+1 ; kappa(K) = CS%kappa_seed ; enddo
702
703 call kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, &
704 h_lay, dz_lay, u0xdz, v0xdz, T0xdz, S0xdz, kappa_avg, &
7050 tke_avg, N2_init, S2_init, N2_mean, S2_mean, tv, CS, GV, US)
706 ! call cpu_clock_begin(Id_clock_setup)
707 ! Extrapolate from the vertically reduced grid back to the original layers.
7080 if (nz == nzc) then
7090 do K=1,nz+1
7100 kappa_2d(I,K) = kappa_avg(K)
7110 if (CS%all_layer_TKE_bug) then
7120 tke_2d(I,K) = tke(K)
713 else
7140 tke_2d(I,K) = tke_avg(K)
715 endif
716 enddo
7170 if (CS%id_N2_mean>0) then ; do K=1,nz+1
7180 diag_N2_mean(I,J,K) = N2_mean(K)
719 enddo ; endif
7200 if (CS%id_S2_mean>0) then ; do K=1,nz+1
7210 diag_S2_mean(I,J,K) = S2_mean(K)
722 enddo ; endif
7230 if ((CS%id_N2_init>0) .or. CS%debug) then ; do K=1,nz+1
7240 diag_N2_init(I,J,K) = N2_init(K)
725 enddo ; endif
7260 if ((CS%id_S2_init>0) .or. CS%debug) then ; do K=1,nz+1
7270 diag_S2_init(I,J,K) = S2_init(K)
728 enddo ; endif
729 else
7300 do K=1,nz+1
7310 if (kf(K) == 0.0) then
7320 kappa_2d(I,K) = kappa_avg(kc(K))
7330 tke_2d(I,K) = tke_avg(kc(K))
734 else
7350 kappa_2d(I,K) = (1.0-kf(K)) * kappa_avg(kc(K)) + kf(K) * kappa_avg(kc(K)+1)
7360 tke_2d(I,K) = (1.0-kf(K)) * tke_avg(kc(K)) + kf(K) * tke_avg(kc(K)+1)
737 endif
738 enddo
7390 do K=1,nz+1
7400 if (kf(K) == 0.0) then
7410 if (CS%id_N2_mean>0) diag_N2_mean(I,J,K) = N2_mean(kc(K))
7420 if (CS%id_S2_mean>0) diag_S2_mean(I,J,K) = S2_mean(kc(K))
7430 if ((CS%id_N2_init>0) .or. CS%debug) diag_N2_init(I,J,K) = N2_init(kc(K))
7440 if ((CS%id_S2_init>0) .or. CS%debug) diag_S2_init(I,J,K) = S2_init(kc(K))
745 else
7460 if (CS%id_N2_mean>0) &
7470 diag_N2_mean(I,J,K) = (1.0-kf(K)) * N2_mean(kc(K)) + kf(K) * N2_mean(kc(K)+1)
7480 if (CS%id_S2_mean>0) &
7490 diag_S2_mean(I,J,K) = (1.0-kf(K)) * S2_mean(kc(K)) + kf(K) * S2_mean(kc(K)+1)
7500 if ((CS%id_N2_init>0) .or. CS%debug) &
7510 diag_N2_init(I,J,K) = (1.0-kf(K)) * N2_init(kc(K)) + kf(K) * N2_init(kc(K)+1)
7520 if ((CS%id_S2_init>0) .or. CS%debug) &
7530 diag_S2_init(I,J,K) = (1.0-kf(K)) * S2_init(kc(K)) + kf(K) * S2_init(kc(K)+1)
754 endif
755 enddo
756 endif
757 ! call cpu_clock_end(Id_clock_setup)
758 else ! Land points, still inside the i-loop.
7590 do K=1,nz+1
7600 kappa_2d(I,K) = 0.0 ; tke_2d(I,K) = 0.0
761 enddo
762 endif ; enddo ! i-loop
763
764 ! Store the 2-d slices back in the 3-d arrays for restarts or interpolation back to tracer points.
7650 if (CS%VS_ThicknessMean) then
7660 do K=1,nz+1 ; do I=IsB,IeB
7670 h_vert(I,J,k) = h_2d(I,k)
768 enddo ; enddo
769 endif
7700 if (CS%VS_viscosity_bug) then
7710 do K=1,nz+1 ; do I=IsB,IeB
7720 kappa_vertex(I,J,K) = kappa_2d(I,K)
7730 tke_io(I,J,K) = G%mask2dBu(I,J) * tke_2d(I,K)
7740 kv_io(I,J,K) = ( G%mask2dBu(I,J) * kappa_vertex(I,J,K) ) * CS%Prandtl_turb
775 enddo ; enddo
776 else
7770 do K=1,nz+1 ; do I=IsB,IeB
7780 kappa_vertex(I,J,K) = kappa_2d(I,K)
7790 tke_io(I,J,K) = tke_2d(I,K)
7800 kv_io(I,J,K) = kappa_vertex(I,J,K) * CS%Prandtl_turb
781 enddo ; enddo
782 endif
783 enddo ! end of J-loop
784
785 ! Set the diffusivities in tracer columns from the values at vertices.
786
787 !$OMP parallel do default(private) shared(G,kappa_io)
7880 do j=G%jsc,G%jec ; do i=G%isc,G%iec
789 ! The turbulent length scales (and hence turbulent diffusivity) should always go to 0 at the top and bottom.
7900 kappa_io(i,j,1) = 0.0
7910 kappa_io(i,j,nz+1) = 0.0
792 enddo ; enddo
7930 if (CS%VS_ThicknessMean .and. CS%VS_GeometricMean) then
794 ! This conversion factor is required to allow for arbitrary fractional powers of the diffusivities.
7950 mks_to_HZ_T = 1.0 / GV%HZ_T_to_MKS
796 !$OMP parallel do default(private) shared(nz,G,GV,CS,kappa_io,kappa_vertex,h_vert)
7970 do K=2,nz ; do j=G%jsc,G%jec ; do i=G%isc,G%iec
7980 h_SW = 0.5 * (h_vert(I-1,J-1,k) + h_vert(I-1,J-1,k-1))
7990 h_NE = 0.5 * (h_vert(I,J,k) + h_vert(I,J,k-1))
8000 h_NW = 0.5 * (h_vert(I-1,J,k) + h_vert(I-1,J,k-1))
8010 h_SE = 0.5 * (h_vert(I,J-1,k) + h_vert(I,J-1,k-1))
8020 if ((h_SW + h_NE) + (h_NW + h_SE) > 0.0) then
803 ! The geometric mean is zero if any component is zero, hence the need to use a floor
804 ! on the value of kappa_trunc in regions on boundaries of shear zones.
8050 I_htot = 1.0 / ((h_SW + h_NE) + (h_NW + h_SE))
806 kappa_io(i,j,K) = G%mask2dT(i,j) * mks_to_HZ_T * &
807 ( ((GV%HZ_T_to_MKS * max(kappa_vertex(I-1,J-1,K), CS%VS_GeoMean_Kdmin))**(h_SW*I_htot) * &
808 (GV%HZ_T_to_MKS * max(kappa_vertex(I,J,K), CS%VS_GeoMean_Kdmin))**(h_NE*I_htot)) * &
809 ((GV%HZ_T_to_MKS * max(kappa_vertex(I-1,J,K), CS%VS_GeoMean_Kdmin))**(h_NW*I_htot) * &
8100 (GV%HZ_T_to_MKS * max(kappa_vertex(I,J-1,K), CS%VS_GeoMean_Kdmin))**(h_SE*I_htot)) )
811 else
812 ! If all points have zero thickness, the thickness-weighted geometric mean is undefined, so use
813 ! the non-thickness weighted geometric mean instead.
814 kappa_io(i,j,K) = G%mask2dT(i,j) * sqrt(sqrt( &
815 (max(kappa_vertex(I-1,J-1,K),CS%VS_GeoMean_Kdmin) * max(kappa_vertex(I,J,K),CS%VS_GeoMean_Kdmin)) * &
8160 (max(kappa_vertex(I-1,J,K),CS%VS_GeoMean_Kdmin) * max(kappa_vertex(I,J-1,K),CS%VS_GeoMean_Kdmin)) ))
817 endif
818 enddo ; enddo ; enddo
8190 elseif (CS%VS_ThicknessMean) then ! Use thickness-weighted arithmetic mean diffusivities.
820 !$OMP parallel do default(private) shared(nz,G,GV,CS,kappa_io,kappa_vertex,h_vert)
8210 do K=2,nz ; do j=G%jsc,G%jec ; do i=G%isc,G%iec
8220 h_SW = 0.5 * (h_vert(I-1,J-1,k) + h_vert(I-1,J-1,k-1))
8230 h_NE = 0.5 * (h_vert(I,J,k) + h_vert(I,J,k-1))
8240 h_NW = 0.5 * (h_vert(I-1,J,k) + h_vert(I-1,J,k-1))
8250 h_SE = 0.5 * (h_vert(I,J-1,k) + h_vert(I,J-1,k-1))
826 ! The following expression is a thickness weighted arithmetic mean at tracer points:
8270 I_htot = 1.0 / (((h_SW + h_NE) + (h_NW + h_SE)) + GV%H_subroundoff)
828 kappa_io(i,j,K) = G%mask2dT(i,j) * &
829 (((kappa_vertex(I-1,J-1,K)*h_SW) + (kappa_vertex(I,J,K)*h_NE)) + &
8300 ((kappa_vertex(I-1,J,K)*h_NW) + (kappa_vertex(I,J-1,K)*h_SE))) * I_htot
831 enddo ; enddo ; enddo
8320 elseif (CS%VS_GeometricMean) then ! The geometic mean diffusivities are not thickness weighted.
833 !$OMP parallel do default(private) shared(nz,G,CS,kappa_io,kappa_vertex)
8340 do K=2,nz ; do j=G%jsc,G%jec ; do i=G%isc,G%iec
835 kappa_io(i,j,K) = G%mask2dT(i,j) * sqrt(sqrt( &
836 (max(kappa_vertex(I-1,J-1,K),CS%VS_GeoMean_Kdmin) * max(kappa_vertex(I,J,K),CS%VS_GeoMean_Kdmin)) * &
8370 (max(kappa_vertex(I-1,J,K),CS%VS_GeoMean_Kdmin) * max(kappa_vertex(I,J-1,K),CS%VS_GeoMean_Kdmin)) ))
838 enddo ; enddo ; enddo
839 else ! Use a non-thickness weighted arithmetic mean.
840 !$OMP parallel do default(private) shared(nz,G,CS,kappa_io,kappa_vertex)
8410 do K=2,nz ; do j=G%jsc,G%jec ; do i=G%isc,G%iec
842 kappa_io(i,j,K) = G%mask2dT(i,j) * 0.25 * &
843 ((kappa_vertex(I-1,J-1,K) + kappa_vertex(I,J,K)) +&
8440 (kappa_vertex(I-1,J,K) + kappa_vertex(I,J-1,K)))
845 enddo ; enddo ; enddo
846 endif
847
8480 if (CS%debug) then
8490 call Bchksum(diag_N2_init, "shear_vertex N2_init", G%HI, unscale=US%s_to_T**2)
8500 call Bchksum(diag_S2_init, "shear_vertex S2_init", G%HI, unscale=US%s_to_T**2)
8510 call hchksum(kappa_io, "kappa", G%HI, unscale=GV%HZ_T_to_m2_s)
8520 call Bchksum(tke_io, "tke", G%HI, unscale=US%Z_to_m**2*US%s_to_T**2)
853 endif
854
8550 if (CS%id_Kd_shear > 0) call post_data(CS%id_Kd_shear, kappa_io, CS%diag)
8560 if (CS%id_TKE > 0) call post_data(CS%id_TKE, tke_io, CS%diag)
8570 if (CS%id_Kd_vertex > 0) call post_data(CS%id_Kd_vertex, kappa_vertex, CS%diag)
8580 if (CS%id_N2_init > 0) call post_data(CS%id_N2_init, diag_N2_init, CS%diag)
8590 if (CS%id_S2_init > 0) call post_data(CS%id_S2_init, diag_S2_init, CS%diag)
8600 if (CS%id_N2_mean > 0) call post_data(CS%id_N2_mean, diag_N2_mean, CS%diag)
8610 if (CS%id_S2_mean > 0) call post_data(CS%id_S2_mean, diag_S2_mean, CS%diag)
862
8630end subroutine Calc_kappa_shear_vertex
864
865
866!> This subroutine calculates shear-driven diffusivity and TKE in a single column
86746250subroutine kappa_shear_column(kappa, tke, dt, nzc, f2, surface_pres, hlay, dz_lay, &
86846250 u0xdz, v0xdz, T0xdz, S0xdz, kappa_avg, tke_avg, N2_init, S2_init, &
86946250 N2_mean, S2_mean, tv, CS, GV, US )
870 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
871 real, dimension(SZK_(GV)+1), &
872 intent(inout) :: kappa !< The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
873 real, dimension(SZK_(GV)+1), &
874 intent(out) :: tke !< The Turbulent Kinetic Energy per unit mass at
875 !! an interface [Z2 T-2 ~> m2 s-2].
876 integer, intent(in) :: nzc !< The number of active layers in the column.
877 real, intent(in) :: f2 !< The square of the Coriolis parameter [T-2 ~> s-2].
878 real, intent(in) :: surface_pres !< The surface pressure [R L2 T-2 ~> Pa].
879 real, dimension(SZK_(GV)), &
880 intent(in) :: hlay !< The layer thickness [H ~> m or kg m-2]
881 real, dimension(SZK_(GV)), &
882 intent(in) :: dz_lay !< The geometric layer thickness in height units [Z ~> m]
883 real, dimension(SZK_(GV)), &
884 intent(in) :: u0xdz !< The initial zonal velocity times hlay [H L T-1 ~> m2 s-1 or kg m-1 s-1]
885 real, dimension(SZK_(GV)), &
886 intent(in) :: v0xdz !< The initial meridional velocity times the
887 !! layer thickness [H L T-1 ~> m2 s-1 or kg m-1 s-1]
888 real, dimension(SZK_(GV)), &
889 intent(in) :: T0xdz !< The initial temperature times hlay [C H ~> degC m or degC kg m-2]
890 real, dimension(SZK_(GV)), &
891 intent(in) :: S0xdz !< The initial salinity times hlay [S H ~> ppt m or ppt kg m-2]
892 real, dimension(SZK_(GV)+1), &
893 intent(out) :: kappa_avg !< The time-weighted average of kappa [H Z T-1 ~> m2 s-1 or Pa s]
894 real, dimension(SZK_(GV)+1), &
895 intent(out) :: tke_avg !< The time-weighted average of TKE [Z2 T-2 ~> m2 s-2].
896 real, dimension(SZK_(GV)+1), &
897 intent(out) :: N2_mean !< The time-weighted average of N2 [Z2 T-2 ~> m2 s-2].
898 real, dimension(SZK_(GV)+1), &
899 intent(out) :: S2_mean !< The time-weighted average of S2 [Z2 T-2 ~> m2 s-2].
900 real, dimension(SZK_(GV)+1), &
901 intent(out) :: N2_init !< The initial value of N2 [Z2 T-2 ~> m2 s-2].
902 real, dimension(SZK_(GV)+1), &
903 intent(out) :: S2_init !< The initial value of S2 [Z2 T-2 ~> m2 s-2].
904 real, intent(in) :: dt !< Time increment [T ~> s].
905 type(thermo_var_ptrs), intent(in) :: tv !< A structure containing pointers to any
906 !! available thermodynamic fields. Absent fields
907 !! have NULL ptrs.
908 type(Kappa_shear_CS), pointer :: CS !< The control structure returned by a previous
909 !! call to kappa_shear_init.
910 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
911
912 ! Local variables
913 real, dimension(nzc) :: &
91492500 u, & ! The zonal velocity after a timestep of mixing [L T-1 ~> m s-1].
91592500 v, & ! The meridional velocity after a timestep of mixing [L T-1 ~> m s-1].
91692500 Idz, & ! The inverse of the distance between TKE points [Z-1 ~> m-1].
91792500 T, & ! The potential temperature after a timestep of mixing [C ~> degC].
91892500 Sal, & ! The salinity after a timestep of mixing [S ~> ppt].
91992500 u_test, v_test, & ! Temporary velocities [L T-1 ~> m s-1].
92092500 T_test, S_test ! Temporary temperatures [C ~> degC] and salinities [S ~> ppt].
921
922 real, dimension(nzc+1) :: &
92392500 N2, & ! The squared buoyancy frequency at an interface [T-2 ~> s-2].
92492500 h_Int, & ! The extent of a finite-volume space surrounding an interface,
925 ! as used in calculating kappa and TKE [H ~> m or kg m-2]
92692500 dz_Int, & ! The vertical distance with the space surrounding an interface,
927 ! as used in calculating kappa and TKE [Z ~> m]
92892500 dz_h_Int, & ! The ratio of the vertical distances to the thickness around an
929 ! interface [Z H-1 ~> nondim or m3 kg-1]. In non-Boussinesq mode
930 ! this is the specific volume, otherwise it is a scaling factor.
93192500 I_dz_int, & ! The inverse of the distance between velocity & density points
932 ! above and below an interface [Z-1 ~> m-1]. This is used to
933 ! calculate N2, shear and fluxes.
93492500 S2, & ! The squared shear at an interface [T-2 ~> s-2].
93592500 a1, & ! a1 is the coupling between adjacent interfaces in the TKE,
936 ! velocity, and density equations [H ~> m or kg m-2]
93792500 c1, & ! c1 is used in the tridiagonal (and similar) solvers [nondim].
93892500 k_src, & ! The shear-dependent source term in the kappa equation [T-1 ~> s-1]
93992500 kappa_src, & ! The shear-dependent source term in the kappa equation [T-1 ~> s-1]
94092500 kappa_out, & ! The kappa that results from the kappa equation [H Z T-1 ~> m2 s-1 or Pa s]
94192500 kappa_mid, & ! The average of the initial and predictor estimates of kappa [H Z T-1 ~> m2 s-1 or Pa s]
94292500 tke_pred, & ! The value of TKE from a predictor step [Z2 T-2 ~> m2 s-2].
94392500 kappa_pred, & ! The value of kappa from a predictor step [H Z T-1 ~> m2 s-1 or Pa s]
94492500 pressure, & ! The pressure at an interface [R L2 T-2 ~> Pa].
94592500 T_int, & ! The temperature interpolated to an interface [C ~> degC].
94692500 Sal_int, & ! The salinity interpolated to an interface [S ~> ppt].
94792500 dbuoy_dT, & ! The partial derivative of buoyancy with changes in temperature [Z T-2 C-1 ~> m s-2 degC-1]
94892500 dbuoy_dS, & ! The partial derivative of buoyancy with changes in salinity [Z T-2 S-1 ~> m s-2 ppt-1]
94992500 dSpV_dT, & ! The partial derivative of specific volume with changes in temperature [R-1 C-1 ~> m3 kg-1 degC-1]
95092500 dSpV_dS, & ! The partial derivative of specific volume with changes in salinity [R-1 S-1 ~> m3 kg-1 ppt-1]
95192500 rho_int, & ! The in situ density interpolated to an interface [R ~> kg m-3]
95292500 I_L2_bdry, & ! The inverse of the square of twice the harmonic mean
953 ! distance to the top and bottom boundaries [H-1 Z-1 ~> m-2 or m kg-1].
95492500 K_Q, & ! Diffusivity divided by TKE [H T Z-1 ~> s or kg s m-3]
95592500 K_Q_tmp, & ! A temporary copy of diffusivity divided by TKE [H T Z-1 ~> s or kg s m-3]
95692500 local_src_avg, & ! The time-integral of the local source [nondim]
95792500 tol_min, & ! Minimum tolerated ksrc for the corrector step [T-1 ~> s-1].
95892500 tol_max, & ! Maximum tolerated ksrc for the corrector step [T-1 ~> s-1].
95992500 tol_chg, & ! The tolerated kappa change integrated over a timestep [nondim].
96092500 dist_from_top, & ! The distance from the top surface [Z ~> m].
96192500 h_from_top, & ! The total thickness above an interface [H ~> m or kg m-2]
96292500 local_src ! The sum of all sources of kappa, including kappa_src and
963 ! sources from the elliptic term [T-1 ~> s-1]
964
965 real :: dist_from_bot ! The distance from the bottom surface [Z ~> m].
966 real :: h_from_bot ! The total thickness below and interface [H ~> m or kg m-2]
967 real :: b1 ! The inverse of the pivot in the tridiagonal equations [H-1 ~> m-1 or m2 kg-1].
968 real :: bd1 ! A term in the denominator of b1 [H ~> m or kg m-2].
969 real :: d1 ! 1 - c1 in the tridiagonal equations [nondim]
970 real :: gR0 ! A conversion factor from H to pressure, Rho_0 times g in Boussinesq
971 ! mode, or just g when non-Boussinesq [R L2 T-2 H-1 ~> kg m-2 s-2 or m s-2].
972 real :: g_R0 ! g_R0 is a rescaled version of g/Rho [Z R-1 T-2 ~> m4 kg-1 s-2].
973 real :: Norm ! A factor that normalizes two weights to 1 [H-2 ~> m-2 or m4 kg-2].
974 real :: tol_dksrc ! Tolerance for the change in the kappa source within an iteration
975 ! relative to the local source [nondim]. This must be greater than 1.
976 real :: tol2 ! The tolerance for the change in the kappa source within an iteration
977 ! relative to the average local source over previous iterations [nondim].
978 real :: tol_dksrc_low ! The tolerance for the fractional decrease in ksrc
979 ! within an iteration [nondim]. 0 < tol_dksrc_low < 1.
980 real :: Ri_crit ! The critical shear Richardson number for shear-
981 ! driven mixing [nondim]. The theoretical value is 0.25.
982 real :: dt_rem ! The remaining time to advance the solution [T ~> s].
983 real :: dt_now ! The time step used in the current iteration [T ~> s].
984 real :: dt_wt ! The fractional weight of the current iteration [nondim].
985 real :: dt_test ! A time-step that is being tested for whether it
986 ! gives acceptably small changes in k_src [T ~> s].
987 real :: Idtt ! Idtt = 1 / dt_test [T-1 ~> s-1].
988 real :: dt_inc ! An increment to dt_test that is being tested [T ~> s].
989 real :: wt_a ! The fraction of a layer thickness identified with the interface
990 ! above a layer [nondim]
991 real :: wt_b ! The fraction of a layer thickness identified with the interface
992 ! below a layer [nondim]
993 real :: k0dt ! The background diffusivity times the timestep [H Z ~> m2 or kg m-1].
994 real :: I_lz_rescale_sqr ! The inverse of a rescaling factor for L2_bdry (Lz) squared [nondim].
995 logical :: valid_dt ! If true, all levels so far exhibit acceptably small changes in k_src.
996 logical :: use_temperature ! If true, temperature and salinity have been
997 ! allocated and are being used as state variables.
998 integer :: ks_kappa, ke_kappa ! The k-range with nonzero kappas.
999 integer :: dt_refinements ! The number of 2-fold refinements that will be used
1000 ! to estimate the maximum permitted time step. I.e.,
1001 ! the resolution is 1/2^dt_refinements.
1002 integer :: k, itt, itt_dt
1003
1004 ! This calculation of N2 is for debugging only.
1005 ! real, dimension(SZK_(GV)+1) :: &
1006 ! N2_debug, & ! A version of N2 for debugging [T-2 ~> s-2]
1007
100846250 Ri_crit = CS%Rino_crit
100946250 gR0 = GV%H_to_RZ * GV%g_Earth
101046250 g_R0 = GV%g_Earth_Z_T2 / GV%Rho0
101146250 k0dt = dt*CS%kappa_0
1012
101346250 I_lz_rescale_sqr = 1.0 ; if (CS%lz_rescale > 0) I_lz_rescale_sqr = 1/(CS%lz_rescale*CS%lz_rescale)
1014
101546250 tol_dksrc = CS%kappa_src_max_chg
101646250 if (tol_dksrc == 10.0) then
1017 ! This is equivalent to the expression below, but avoids changes at roundoff for the default value.
101846250 tol_dksrc_low = 0.95
1019 else
10200 tol_dksrc_low = (tol_dksrc - 0.5)/tol_dksrc
1021 endif
102246250 tol2 = 2.0*CS%kappa_tol_err
102346250 dt_refinements = 5 ! Selected so that 1/2^dt_refinements < 1-tol_dksrc_low
102446250 use_temperature = .false. ; if (associated(tv%T)) use_temperature = .true.
1025
1026
1027 ! Set up Idz as the inverse of layer thicknesses.
1028437893 do k=1,nzc ; Idz(k) = 1.0 / dz_lay(k) ; enddo
1029 ! Set up I_dz_int as the inverse of the distance between
1030 ! adjacent layer centers.
103146250 I_dz_int(1) = 2.0 / dz_lay(1)
103246250 dist_from_top(1) = 0.0 ; h_from_top(1) = 0.0
1033391643 do K=2,nzc
1034345393 I_dz_int(K) = 2.0 / (dz_lay(k-1) + dz_lay(k))
1035345393 dist_from_top(K) = dist_from_top(K-1) + dz_lay(k-1)
1036391643 h_from_top(K) = h_from_top(K-1) + hlay(k-1)
1037 enddo
103846250 I_dz_int(nzc+1) = 2.0 / dz_lay(nzc)
1039
1040 ! Find the inverse of the squared distances from the boundaries.
104146250 dist_from_bot = 0.0 ; h_from_bot = 0.0
1042391643 do K=nzc,2,-1
1043345393 dist_from_bot = dist_from_bot + dz_lay(k)
1044345393 h_from_bot = h_from_bot + hlay(k)
1045 ! Find the inverse of the squared distances from the boundaries,
1046 I_L2_bdry(K) = ((dist_from_top(K) + dist_from_bot) * (h_from_top(K) + h_from_bot)) / &
1047345393 ((dist_from_top(K) * dist_from_bot) * (h_from_top(K) * h_from_bot))
1048 ! reduce the distance by a factor of "lz_rescale"
1049391643 I_L2_bdry(K) = I_lz_rescale_sqr*I_L2_bdry(K)
1050 enddo
1051
1052 ! Determine the velocities and thicknesses after eliminating massless
1053 ! layers and applying a time-step of background diffusion.
105446250 if (nzc > 1) then
105545972 a1(2) = k0dt*I_dz_int(2)
105645972 b1 = 1.0 / (hlay(1) + a1(2))
105745972 u(1) = b1 * u0xdz(1) ; v(1) = b1 * v0xdz(1)
105845972 T(1) = b1 * T0xdz(1) ; Sal(1) = b1 * S0xdz(1)
105945972 c1(2) = a1(2) * b1 ; d1 = hlay(1) * b1 ! = 1 - c1
1060345393 do k=2,nzc-1
1061299421 bd1 = hlay(k) + d1*a1(k)
1062299421 a1(k+1) = k0dt*I_dz_int(k+1)
1063299421 b1 = 1.0 / (bd1 + a1(k+1))
1064299421 u(k) = b1 * (u0xdz(k) + a1(k)*u(k-1))
1065299421 v(k) = b1 * (v0xdz(k) + a1(k)*v(k-1))
1066299421 T(k) = b1 * (T0xdz(k) + a1(k)*T(k-1))
1067299421 Sal(k) = b1 * (S0xdz(k) + a1(k)*Sal(k-1))
1068345393 c1(k+1) = a1(k+1) * b1 ; d1 = bd1 * b1 ! d1 = 1 - c1
1069 enddo
1070 ! rho or T and S have insulating boundary conditions, u & v use no-slip
1071 ! bottom boundary conditions (if kappa0 > 0).
1072 ! For no-slip bottom boundary conditions
107345972 b1 = 1.0 / ((hlay(nzc) + d1*a1(nzc)) + k0dt*I_dz_int(nzc+1))
107445972 u(nzc) = b1 * (u0xdz(nzc) + a1(nzc)*u(nzc-1))
107545972 v(nzc) = b1 * (v0xdz(nzc) + a1(nzc)*v(nzc-1))
1076 ! For insulating boundary conditions
107745972 b1 = 1.0 / (hlay(nzc) + d1*a1(nzc))
107845972 T(nzc) = b1 * (T0xdz(nzc) + a1(nzc)*T(nzc-1))
107945972 Sal(nzc) = b1 * (S0xdz(nzc) + a1(nzc)*Sal(nzc-1))
1080391365 do k=nzc-1,1,-1
1081345393 u(k) = u(k) + c1(k+1)*u(k+1) ; v(k) = v(k) + c1(k+1)*v(k+1)
1082391365 T(k) = T(k) + c1(k+1)*T(k+1) ; Sal(k) = Sal(k) + c1(k+1)*Sal(k+1)
1083 enddo
1084 else
1085 ! This is correct, but probably unnecessary.
1086278 b1 = 1.0 / (hlay(1) + k0dt*I_dz_int(2))
1087278 u(1) = b1 * u0xdz(1) ; v(1) = b1 * v0xdz(1)
1088278 b1 = 1.0 / hlay(1)
1089278 T(1) = b1 * T0xdz(1) ; Sal(1) = b1 * S0xdz(1)
1090 endif
1091
1092 ! This uses half the harmonic mean of thicknesses to provide two estimates
1093 ! of the boundary between cells, and the inverse of the harmonic mean to
1094 ! weight the two estimates. The net effect is that interfaces around thin
1095 ! layers have thin cells, and the total thickness adds up properly.
1096 ! The top- and bottom- interfaces have zero thickness, consistent with
1097 ! adding additional zero thickness layers.
109846250 h_Int(1) = 0.0 ; h_Int(2) = hlay(1)
109946250 dz_Int(1) = 0.0 ; dz_Int(2) = dz_lay(1)
1100345671 do K=2,nzc-1
1101299421 Norm = 1.0 / (hlay(k)*(hlay(k-1)+hlay(k+1)) + 2.0*hlay(k-1)*hlay(k+1))
1102299421 wt_a = ((hlay(k)+hlay(k+1)) * hlay(k-1)) * Norm
1103299421 wt_b = ((hlay(k-1)+hlay(k)) * hlay(k+1)) * Norm
1104299421 h_Int(K) = h_Int(K) + hlay(k) * wt_a
1105299421 h_Int(K+1) = hlay(k) * wt_b
1106299421 dz_Int(K) = dz_Int(K) + dz_lay(k) * wt_a
1107345671 dz_Int(K+1) = dz_lay(k) * wt_b
1108 enddo
110946250 h_Int(nzc) = h_Int(nzc) + hlay(nzc) ; h_Int(nzc+1) = 0.0
111046250 dz_Int(nzc) = dz_Int(nzc) + dz_lay(nzc) ; dz_Int(nzc+1) = 0.0
1111
111246250 if (GV%Boussinesq) then
1113484143 do K=1,nzc+1 ; dz_h_Int(K) = GV%H_to_Z ; enddo
1114 else
1115 ! Find an effective average specific volume around an interface.
11160 dz_h_Int(1:nzc+1) = 0.0
11170 if (hlay(1) > 0.0) dz_h_Int(1) = dz_lay(1) / hlay(1)
11180 do K=2,nzc+1
11190 if (h_Int(K) > 0.0) then
11200 dz_h_Int(K) = dz_Int(K) / h_Int(K)
1121 else
11220 dz_h_Int(K) = dz_h_Int(K-1)
1123 endif
1124 enddo
1125 endif
1126
1127 ! Calculate thermodynamic coefficients and an initial estimate of N2.
112846250 if (use_temperature) then
112946250 pressure(1) = surface_pres
1130391643 do K=2,nzc
1131345393 pressure(K) = pressure(K-1) + gR0*hlay(k-1)
1132345393 T_int(K) = 0.5*(T(k-1) + T(k))
1133391643 Sal_int(K) = 0.5*(Sal(k-1) + Sal(k))
1134 enddo
113546250 if (GV%Boussinesq .or. GV%semi_Boussinesq) then
1136 call calculate_density_derivs(T_int, Sal_int, pressure, dbuoy_dT, dbuoy_dS, &
1137138750 tv%eqn_of_state, (/2,nzc/), scale=-g_R0 )
1138 else
1139 ! These should perhaps be combined into a single call to calculate the thermal expansion
1140 ! and haline contraction coefficients?
1141 call calculate_specific_vol_derivs(T_int, Sal_int, pressure, dSpV_dT, dSpV_dS, &
11420 tv%eqn_of_state, (/2,nzc/) )
11430 call calculate_density(T_int, Sal_int, pressure, rho_int, tv%eqn_of_state, (/2,nzc/) )
11440 do K=2,nzc
11450 dbuoy_dT(K) = GV%g_Earth_Z_T2 * (rho_int(K) * dSpV_dT(K))
11460 dbuoy_dS(K) = GV%g_Earth_Z_T2 * (rho_int(K) * dSpV_dS(K))
1147 enddo
1148 endif
11490 elseif (GV%Boussinesq .or. GV%semi_Boussinesq) then
11500 do K=1,nzc+1 ; dbuoy_dT(K) = -g_R0 ; dbuoy_dS(K) = 0.0 ; enddo
1151 else
11520 do K=1,nzc+1 ; dbuoy_dS(K) = 0.0 ; enddo
11530 dbuoy_dT(1) = -GV%g_Earth_Z_T2 / GV%Rlay(1)
11540 do K=2,nzc
11550 dbuoy_dT(K) = -GV%g_Earth_Z_T2 / (0.5*(GV%Rlay(k-1) + GV%Rlay(k)))
1156 enddo
11570 dbuoy_dT(nzc+1) = -GV%g_Earth_Z_T2 / GV%Rlay(nzc)
1158 endif
1159
1160 ! N2_debug(1) = 0.0 ; N2_debug(nzc+1) = 0.0
1161 ! do K=2,nzc
1162 ! N2_debug(K) = max((dbuoy_dT(K) * (T0xdz(k-1)*Idz(k-1) - T0xdz(k)*Idz(k)) + &
1163 ! dbuoy_dS(K) * (S0xdz(k-1)*Idz(k-1) - S0xdz(k)*Idz(k))) * &
1164 ! I_dz_int(K), 0.0)
1165 ! enddo
1166
1167 ! This call just calculates N2 and S2.
1168 call calculate_projected_state(kappa, u, v, T, Sal, 0.0, nzc, hlay, I_dz_int, dbuoy_dT, dbuoy_dS, &
116946250 CS%vel_underflow, u, v, T, Sal, N2, S2, GV, US)
1170484143 do K=1,nzc+1
1171437893 N2_init(K) = N2(K)
1172484143 S2_init(K) = S2(K)
1173 enddo
1174
1175
1176! ----------------------------------------------------
1177! Iterate
1178! ----------------------------------------------------
117946250 dt_rem = dt
1180484143 do K=1,nzc+1
1181437893 K_Q(K) = 0.0
1182437893 kappa_avg(K) = 0.0 ; tke_avg(K) = 0.0 ; N2_mean(K) = 0.0 ; S2_mean(K) = 0.0
1183437893 local_src_avg(K) = 0.0
1184 ! Use the grid spacings to scale errors in the source.
1185437893 if ( h_Int(K) > 0.0 ) &
1186391921 local_src_avg(K) = 0.1 * k0dt * I_dz_int(K) / h_Int(K)
1187 enddo
1188
1189! call cpu_clock_end(id_clock_setup)
1190
1191! do itt=1,CS%max_RiNo_it
119246250 do itt=1,CS%max_KS_it
1193
1194! ----------------------------------------------------
1195! Calculate new values of u, v, rho, N^2 and S.
1196! ----------------------------------------------------
1197
1198 ! call cpu_clock_begin(id_clock_KQ)
1199 call find_kappa_tke(N2, S2, kappa, Idz, h_Int, dz_Int, dz_h_Int, I_L2_bdry, f2, &
120046250 nzc, CS, GV, US, K_Q, tke, kappa_out, kappa_src, local_src)
1201 ! call cpu_clock_end(id_clock_KQ)
1202
1203 ! call cpu_clock_begin(id_clock_avg)
1204 ! Determine the range of non-zero values of kappa_out.
120546250 ks_kappa = GV%ke+1 ; ke_kappa = 0
1206373558 do K=2,nzc ; if (kappa_out(K) > 0.0) then
12073584 ks_kappa = K ; exit
1208 endif ; enddo
120960409 do k=nzc,ks_kappa,-1 ; if (kappa_out(K) > 0.0) then
12103584 ke_kappa = K ; exit
1211 endif ; enddo
121246250 if (ke_kappa == nzc) kappa_out(nzc+1) = 0.0
1213 ! call cpu_clock_end(id_clock_avg)
1214
1215 ! Determine how long to use this value of kappa (dt_now).
1216
1217 ! call cpu_clock_begin(id_clock_project)
121846250 if ((ke_kappa < ks_kappa) .or. (itt==CS%max_KS_it)) then
121942666 dt_now = dt_rem
1220 else
1221 ! Limit dt_now so that |k_src(k)-kappa_src(k)| < tol * local_src(k)
12223584 dt_test = dt_rem
122321669 do K=2,nzc
122418085 tol_max(K) = kappa_src(K) + tol_dksrc * local_src(K)
122518085 tol_min(K) = kappa_src(K) - tol_dksrc_low * local_src(K)
122621669 tol_chg(K) = tol2 * local_src_avg(K)
1227 enddo
1228
12293584 do itt_dt=1,(CS%max_KS_it+1-itt)/2
1230 ! The maximum number of times that the time-step is halved in
1231 ! seeking an acceptable timestep is reduced with each iteration,
1232 ! so that as the maximum number of iterations is approached, the
1233 ! whole remaining timestep is used. Typically, an acceptable
1234 ! timestep is found long before the minimum is reached, so the
1235 ! value of max_KS_it may be unimportant, especially if it is large
1236 ! enough.
1237 call calculate_projected_state(kappa_out, u, v, T, Sal, 0.5*dt_test, nzc, hlay, I_dz_int, &
1238 dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, &
12393584 T_test, S_test, N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa)
12403584 valid_dt = .true.
12413584 Idtt = 1.0 / dt_test
124211094 do K=max(ks_kappa-1,2),min(ke_kappa+1,nzc)
124311094 if (N2(K) < Ri_crit * S2(K)) then ! Equivalent to Ri < Ri_crit.
1244 K_src(K) = (2.0 * CS%Shearmix_rate * sqrt(S2(K))) * &
12453584 ((Ri_crit*S2(K) - N2(K)) / (Ri_crit*S2(K) + CS%FRi_curvature*N2(K)))
12463584 if (CS%restrictive_tolerance_check) then
12470 if ((K_src(K) > min(tol_max(K), kappa_src(K) + Idtt*tol_chg(K))) .or. &
1248 (K_src(K) < max(tol_min(K), kappa_src(K) - Idtt*tol_chg(K)))) then
12490 valid_dt = .false. ; exit
1250 endif
1251 else
12523584 if ((K_src(K) > max(tol_max(K), kappa_src(K) + Idtt*tol_chg(K))) .or. &
1253 (K_src(K) < min(tol_min(K), kappa_src(K) - Idtt*tol_chg(K)))) then
12540 valid_dt = .false. ; exit
1255 endif
1256 endif
1257 else
12583926 if (0.0 < min(tol_min(K), kappa_src(K) - Idtt*tol_chg(K))) then
12590 valid_dt = .false. ; k_src(K) = 0.0 ; exit
1260 endif
1261 endif
1262 enddo
1263
12643584 if (valid_dt) exit
12650 dt_test = 0.5*dt_test
1266 enddo
12673584 if ((dt_test < dt_rem) .and. valid_dt) then
12680 dt_inc = 0.5*dt_test
12690 do itt_dt=1,dt_refinements
1270 call calculate_projected_state(kappa_out, u, v, T, Sal, 0.5*(dt_test+dt_inc), nzc, hlay, &
1271 I_dz_int, dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, T_test, S_test, &
12720 N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa)
12730 valid_dt = .true.
12740 Idtt = 1.0 / (dt_test+dt_inc)
12750 do K=max(ks_kappa-1,2),min(ke_kappa+1,nzc)
12760 if (N2(K) < Ri_crit * S2(K)) then ! Equivalent to Ri < Ri_crit.
1277 K_src(K) = (2.0 * CS%Shearmix_rate * sqrt(S2(K))) * &
12780 ((Ri_crit*S2(K) - N2(K)) / (Ri_crit*S2(K) + CS%FRi_curvature*N2(K)))
12790 if ((K_src(K) > max(tol_max(K), kappa_src(K) + Idtt*tol_chg(K))) .or. &
1280 (K_src(K) < min(tol_min(K), kappa_src(K) - Idtt*tol_chg(K)))) then
12810 valid_dt = .false. ; exit
1282 endif
1283 else
12840 if (0.0 < min(tol_min(K), kappa_src(K) - Idtt*tol_chg(K))) then
12850 valid_dt = .false. ; k_src(K) = 0.0 ; exit
1286 endif
1287 endif
1288 enddo
1289
12900 if (valid_dt) dt_test = dt_test + dt_inc
12910 dt_inc = 0.5*dt_inc
1292 enddo
1293 else
12943584 dt_inc = 0.0
1295 endif
1296
12973584 dt_now = min(dt_test*(1.0+CS%kappa_tol_err)+dt_inc, dt_rem)
129821669 do K=2,nzc
129921669 local_src_avg(K) = local_src_avg(K) + dt_now * local_src(K)
1300 enddo
1301 endif ! Are all the values of kappa_out 0?
1302 ! call cpu_clock_end(id_clock_project)
1303
1304 ! The state has already been projected forward. Now find new values of kappa.
1305
130646250 if (ke_kappa < ks_kappa) then
1307 ! There is no mixing now, and will not be again.
1308 ! call cpu_clock_begin(id_clock_avg)
130942666 dt_wt = dt_rem / dt ; dt_rem = 0.0
1310455306 do K=1,nzc+1
1311412640 kappa_mid(K) = 0.0
1312 ! This would be here but does nothing.
1313 ! kappa_avg(K) = kappa_avg(K) + kappa_mid(K)*dt_wt
1314455306 tke_avg(K) = tke_avg(K) + dt_wt*tke(K)
1315 enddo
1316 ! call cpu_clock_end(id_clock_avg)
1317 else
1318 ! call cpu_clock_begin(id_clock_project)
1319 call calculate_projected_state(kappa_out, u, v, T, Sal, dt_now, nzc, hlay, I_dz_int, &
1320 dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, &
13213584 T_test, S_test, N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa)
1322 ! call cpu_clock_end(id_clock_project)
1323
1324 ! call cpu_clock_begin(id_clock_KQ)
132528837 do K=1,nzc+1 ; K_Q_tmp(K) = K_Q(K) ; enddo
1326 call find_kappa_tke(N2, S2, kappa_out, Idz, h_Int, dz_Int, dz_h_Int, I_L2_bdry, f2, &
13273584 nzc, CS, GV, US, K_Q_tmp, tke_pred, kappa_pred)
1328 ! call cpu_clock_end(id_clock_KQ)
1329
13303584 ks_kappa = GV%ke+1 ; ke_kappa = 0
133128837 do K=1,nzc+1
133225253 kappa_mid(K) = 0.5*(kappa_out(K) + kappa_pred(K))
133325253 if ((kappa_mid(K) > 0.0) .and. (K<ks_kappa)) ks_kappa = K
133428837 if (kappa_mid(K) > 0.0) ke_kappa = K
1335 enddo
1336
1337 ! call cpu_clock_begin(id_clock_project)
1338 call calculate_projected_state(kappa_mid, u, v, T, Sal, dt_now, nzc, hlay, I_dz_int, &
1339 dbuoy_dT, dbuoy_dS, CS%vel_underflow, u_test, v_test, &
13403584 T_test, S_test, N2, S2, GV, US, ks_int=ks_kappa, ke_int=ke_kappa)
1341 ! call cpu_clock_end(id_clock_project)
1342
1343 ! call cpu_clock_begin(id_clock_KQ)
1344 call find_kappa_tke(N2, S2, kappa_out, Idz, h_Int, dz_Int, dz_h_Int, I_L2_bdry, f2, &
13453584 nzc, CS, GV, US, K_Q, tke_pred, kappa_pred)
1346 ! call cpu_clock_end(id_clock_KQ)
1347
1348 ! call cpu_clock_begin(id_clock_avg)
13493584 dt_wt = dt_now / dt ; dt_rem = dt_rem - dt_now
135028837 do K=1,nzc+1
135125253 kappa_mid(K) = 0.5*(kappa_out(K) + kappa_pred(K))
135225253 kappa_avg(K) = kappa_avg(K) + kappa_mid(K)*dt_wt
135325253 tke_avg(K) = tke_avg(K) + dt_wt*0.5*(tke_pred(K) + tke(K))
135425253 N2_mean(K) = N2_mean(K) + dt_wt*N2(K)
135525253 S2_mean(K) = S2_mean(K) + dt_wt*S2(K)
135628837 kappa(K) = kappa_pred(K) ! First guess for the next iteration.
1357 enddo
1358
1359 ! call cpu_clock_end(id_clock_avg)
1360 endif
1361
136246250 if (dt_rem > 0.0) then
1363 ! Update the values of u, v, T, Sal, N2, and S2 for the next iteration.
1364 ! call cpu_clock_begin(id_clock_project)
1365 call calculate_projected_state(kappa_mid, u, v, T, Sal, dt_now, nzc, hlay, I_dz_int, &
1366 dbuoy_dT, dbuoy_dS, CS%vel_underflow, u, v, T, Sal, N2, S2, &
13670 GV, US)
1368 ! call cpu_clock_end(id_clock_project)
1369 endif
1370
137146250 if (dt_rem <= 0.0) exit
1372
1373 enddo ! end itt loop
1374
137546250end subroutine kappa_shear_column
1376
1377!> This subroutine calculates the velocities, temperature and salinity that
1378!! the water column will have after mixing for dt with diffusivities kappa. It
1379!! may also calculate the projected buoyancy frequency and shear.
138057002subroutine calculate_projected_state(kappa, u0, v0, T0, S0, dt, nz, dz, I_dz_int, dbuoy_dT, dbuoy_dS, &
138157002 vel_under, u, v, T, Sal, N2, S2, GV, US, ks_int, ke_int)
1382 integer, intent(in) :: nz !< The number of layers (after eliminating massless
1383 !! layers?).
1384 real, dimension(nz+1), intent(in) :: kappa !< The diapycnal diffusivity at interfaces,
1385 !! [H Z T-1 ~> m2 s-1 or Pa s].
1386 real, dimension(nz), intent(in) :: u0 !< The initial zonal velocity [L T-1 ~> m s-1].
1387 real, dimension(nz), intent(in) :: v0 !< The initial meridional velocity [L T-1 ~> m s-1].
1388 real, dimension(nz), intent(in) :: T0 !< The initial temperature [C ~> degC].
1389 real, dimension(nz), intent(in) :: S0 !< The initial salinity [S ~> ppt].
1390 real, intent(in) :: dt !< The time step [T ~> s].
1391 real, dimension(nz), intent(in) :: dz !< The layer thicknesses [H ~> m or kg m-2]
1392 real, dimension(nz+1), intent(in) :: I_dz_int !< The inverse of the distance between successive
1393 !! layer centers [Z-1 ~> m-1].
1394 real, dimension(nz+1), intent(in) :: dbuoy_dT !< The partial derivative of buoyancy with
1395 !! temperature [Z T-2 C-1 ~> m s-2 degC-1].
1396 real, dimension(nz+1), intent(in) :: dbuoy_dS !< The partial derivative of buoyancy with
1397 !! salinity [Z T-2 S-1 ~> m s-2 ppt-1].
1398 real, intent(in) :: vel_under !< Any velocities that are smaller in magnitude
1399 !! than this value are set to 0 [L T-1 ~> m s-1].
1400 real, dimension(nz), intent(inout) :: u !< The zonal velocity after dt [L T-1 ~> m s-1].
1401 real, dimension(nz), intent(inout) :: v !< The meridional velocity after dt [L T-1 ~> m s-1].
1402 real, dimension(nz), intent(inout) :: T !< The temperature after dt [C ~> degC].
1403 real, dimension(nz), intent(inout) :: Sal !< The salinity after dt [S ~> ppt].
1404 real, dimension(nz+1), intent(inout) :: N2 !< The buoyancy frequency squared at interfaces [T-2 ~> s-2].
1405 real, dimension(nz+1), intent(inout) :: S2 !< The squared shear at interfaces [T-2 ~> s-2].
1406 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1407 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1408 integer, optional, intent(in) :: ks_int !< The topmost k-index with a non-zero diffusivity.
1409 integer, optional, intent(in) :: ke_int !< The bottommost k-index with a non-zero
1410 !! diffusivity.
1411
1412 ! Local variables
141357002 real, dimension(nz+1) :: c1 ! A tridiagonal variable [nondim]
1414 real :: a_a, a_b ! Tridiagonal coupling coefficients [H ~> m or kg m-2]
1415 real :: b1, b1nz_0 ! Tridiagonal variables [H-1 ~> m-1 or m2 kg-1]
1416 real :: bd1 ! A term in the denominator of b1 [H ~> m or kg m-2]
1417 real :: d1 ! A tridiagonal variable [nondim]
1418 integer :: k, ks, ke
1419
142057002 ks = 1 ; ke = nz
142157002 if (present(ks_int)) ks = max(ks_int-1,1)
142257002 if (present(ke_int)) ke = min(ke_int,nz)
1423
142457002 if (ks > ke) return
1425
142657002 if (dt > 0.0) then
142710752 a_b = dt*(kappa(ks+1)*I_dz_int(ks+1))
142810752 b1 = 1.0 / (dz(ks) + a_b)
142910752 c1(ks+1) = a_b * b1 ; d1 = dz(ks) * b1 ! = 1 - c1
1430
143110752 u(ks) = (b1 * dz(ks))*u0(ks) ; v(ks) = (b1 * dz(ks))*v0(ks)
143210752 T(ks) = (b1 * dz(ks))*T0(ks) ; Sal(ks) = (b1 * dz(ks))*S0(ks)
143311778 do K=ks+1,ke-1
14341026 a_a = a_b
14351026 a_b = dt*(kappa(K+1)*I_dz_int(K+1))
14361026 bd1 = dz(k) + d1*a_a
14371026 b1 = 1.0 / (bd1 + a_b)
14381026 c1(K+1) = a_b * b1 ; d1 = bd1 * b1 ! d1 = 1 - c1
1439
14401026 u(k) = b1 * (dz(k)*u0(k) + a_a*u(k-1))
14411026 v(k) = b1 * (dz(k)*v0(k) + a_a*v(k-1))
14421026 T(k) = b1 * (dz(k)*T0(k) + a_a*T(k-1))
144311778 Sal(k) = b1 * (dz(k)*S0(k) + a_a*Sal(k-1))
1444 enddo
1445 ! T and S have insulating boundary conditions, u & v use no-slip
1446 ! bottom boundary conditions at the solid bottom.
1447
1448 ! For insulating boundary conditions or mixing simply stopping, use...
144910752 a_a = a_b
145010752 b1 = 1.0 / (dz(ke) + d1*a_a)
145110752 T(ke) = b1 * (dz(ke)*T0(ke) + a_a*T(ke-1))
145210752 Sal(ke) = b1 * (dz(ke)*S0(ke) + a_a*Sal(ke-1))
1453
1454 ! There is no distinction between the effective boundary conditions for
1455 ! tracers and velocities if the mixing is separated from the bottom, but if
1456 ! the mixing goes all the way to the bottom, use no-slip BCs for velocities.
145710752 if (ke == nz) then
14580 a_b = dt*(kappa(nz+1)*I_dz_int(nz+1))
14590 b1nz_0 = 1.0 / ((dz(nz) + d1*a_a) + a_b)
1460 else
146110752 b1nz_0 = b1
1462 endif
146310752 u(ke) = b1nz_0 * (dz(ke)*u0(ke) + a_a*u(ke-1))
146410752 v(ke) = b1nz_0 * (dz(ke)*v0(ke) + a_a*v(ke-1))
146510752 if (abs(u(ke)) < vel_under) u(ke) = 0.0
146610752 if (abs(v(ke)) < vel_under) v(ke) = 0.0
1467
146822530 do k=ke-1,ks,-1
146911778 u(k) = u(k) + c1(k+1)*u(k+1)
147011778 v(k) = v(k) + c1(k+1)*v(k+1)
147111778 if (abs(u(k)) < vel_under) u(k) = 0.0
147211778 if (abs(v(k)) < vel_under) v(k) = 0.0
147311778 T(k) = T(k) + c1(k+1)*T(k+1)
147422530 Sal(k) = Sal(k) + c1(k+1)*Sal(k+1)
1475 enddo
1476 else ! dt <= 0.0
1477437893 do k=1,nz
1478391643 u(k) = u0(k) ; v(k) = v0(k) ; T(k) = T0(k) ; Sal(k) = S0(k)
1479391643 if (abs(u(k)) < vel_under) u(k) = 0.0
1480437893 if (abs(v(k)) < vel_under) v(k) = 0.0
1481 enddo
1482 endif
1483
1484 ! Store the squared shear at interfaces
148557002 S2(1) = 0.0 ; S2(nz+1) = 0.0
148657002 if (ks > 1) &
14870 S2(ks) = (((u(ks)-u0(ks-1))**2) + ((v(ks)-v0(ks-1))**2)) * (US%L_to_Z*I_dz_int(ks))**2
1488414173 do K=ks+1,ke
1489414173 S2(K) = (((u(k)-u(k-1))**2) + ((v(k)-v(k-1))**2)) * (US%L_to_Z*I_dz_int(K))**2
1490 enddo
149157002 if (ke<nz) &
149210752 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
1493
1494 ! Store the buoyancy frequency at interfaces
149557002 N2(1) = 0.0 ; N2(nz+1) = 0.0
149657002 if (ks > 1) &
1497 N2(ks) = max(0.0, I_dz_int(ks) * &
14980 (dbuoy_dT(ks) * (T0(ks-1)-T(ks)) + dbuoy_dS(ks) * (S0(ks-1)-Sal(ks))))
1499414173 do K=ks+1,ke
1500 N2(K) = max(0.0, I_dz_int(K) * &
1501414173 (dbuoy_dT(K) * (T(k-1)-T(k)) + dbuoy_dS(K) * (Sal(k-1)-Sal(k))))
1502 enddo
150357002 if (ke<nz) &
1504 N2(ke+1) = max(0.0, I_dz_int(ke+1) * &
150510752 (dbuoy_dT(ke+1) * (T(ke)-T0(ke+1)) + dbuoy_dS(ke+1) * (Sal(ke)-S0(ke+1))))
1506
1507end subroutine calculate_projected_state
1508
1509!> This subroutine calculates new, consistent estimates of TKE and kappa.
1510106836subroutine find_kappa_tke(N2, S2, kappa_in, Idz, h_Int, dz_Int, dz_h_Int, I_L2_bdry, f2, &
151192500 nz, CS, GV, US, K_Q, tke, kappa, kappa_src, local_src)
1512 integer, intent(in) :: nz !< The number of layers to work on.
1513 real, dimension(nz+1), intent(in) :: N2 !< The buoyancy frequency squared at interfaces [T-2 ~> s-2].
1514 real, dimension(nz+1), intent(in) :: S2 !< The squared shear at interfaces [T-2 ~> s-2].
1515 real, dimension(nz+1), intent(in) :: kappa_in !< The initial guess at the diffusivity
1516 !! [H Z T-1 ~> m2 s-1 or Pa s]
1517 real, dimension(nz+1), intent(in) :: h_Int !< The thicknesses associated with interfaces
1518 !! [H ~> m or kg m-2]
1519 real, dimension(nz+1), intent(in) :: dz_Int !< The vertical distances around interfaces [Z ~> m]
1520 real, dimension(nz+1), intent(in) :: dz_h_Int !< The ratio of the vertical distances to the
1521 !! thickness around an interface [Z H-1 ~> nondim or m3 kg-1].
1522 !! In non-Boussinesq mode this is the specific volume.
1523 real, dimension(nz+1), intent(in) :: I_L2_bdry !< The inverse of the squared distance to
1524 !! boundaries [H-1 Z-1 ~> m-2 or m kg-1].
1525 real, dimension(nz), intent(in) :: Idz !< The inverse grid spacing of layers [Z-1 ~> m-1].
1526 real, intent(in) :: f2 !< The squared Coriolis parameter [T-2 ~> s-2].
1527 type(Kappa_shear_CS), pointer :: CS !< A pointer to this module's control structure.
1528 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1529 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1530 real, dimension(nz+1), intent(inout) :: K_Q !< The shear-driven diapycnal diffusivity divided by
1531 !! the turbulent kinetic energy per unit mass at
1532 !! interfaces [H T Z-1 ~> s or kg s m-3].
1533 real, dimension(nz+1), intent(out) :: tke !< The turbulent kinetic energy per unit mass at
1534 !! interfaces [Z2 T-2 ~> m2 s-2].
1535 real, dimension(nz+1), intent(out) :: kappa !< The diapycnal diffusivity at interfaces
1536 !! [H Z T-1 ~> m2 s-1 or Pa s]
1537 real, dimension(nz+1), optional, &
1538 intent(out) :: kappa_src !< The source term for kappa [T-1 ~> s-1]
1539 real, dimension(nz+1), optional, &
1540 intent(out) :: local_src !< The sum of all local sources for kappa
1541 !! [T-1 ~> s-1]
1542 ! This subroutine calculates new, consistent estimates of TKE and kappa.
1543
1544 ! Local variables
1545 real, dimension(nz) :: &
154610752 aQ, & ! aQ is the coupling between adjacent interfaces in the TKE equations [H T-1 ~> m s-1 or kg m-2 s-1]
1547106836 dQdz ! Half the partial derivative of TKE with depth [Z T-2 ~> m s-2].
1548 real, dimension(nz+1) :: &
1549106836 dK, & ! The change in kappa [H Z T-1 ~> m2 s-1 or Pa s].
1550106836 dQ, & ! The change in TKE [Z2 T-2 ~> m2 s-2].
1551106836 cQ, cK, & ! cQ and cK are the upward influences in the tridiagonal and
1552 ! hexadiagonal solvers for the TKE and kappa equations [nondim].
1553106836 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]
1554106836 TKE_decay, & ! The local TKE decay rate [T-1 ~> s-1].
1555106836 k_src, & ! The source term in the kappa equation [T-1 ~> s-1].
1556106836 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]
1557106836 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]
1558106836 e1 ! The fractional change in a layer TKE due to a change in the
1559 ! TKE of the layer above when all the kappas below are 0 [nondim].
1560 ! e1 is nondimensional, and 0 < e1 < 1.
1561 real :: tke_src ! The net source of TKE due to mixing against the shear and stratification
1562 ! [Z2 T-3 ~> m2 s-3] or [H Z T-3 ~> m2 s-3 or kg m-1 s-3].
1563 ! (For convenience, a term involving the non-dissipation of q0 is also included here.)
1564 real :: bQ ! The inverse of the pivot in the tridiagonal equations [T H-1 ~> s m-1 or m2 s kg-1]
1565 real :: bK ! The inverse of the pivot in the tridiagonal equations [Z-1 ~> m-1].
1566 real :: bQd1 ! A term in the denominator of bQ [H T-1 ~> m s-1 or kg m-2 s-1]
1567 real :: bKd1 ! A term in the denominator of bK [Z ~> m].
1568 real :: cQcomp, cKcomp ! 1 - cQ or 1 - cK in the tridiagonal equations [nondim].
1569 real :: c_s2 ! The coefficient for the decay of TKE due to
1570 ! shear (i.e. proportional to |S|*tke) [nondim].
1571 real :: c_n2 ! The coefficient for the decay of TKE due to
1572 ! stratification (i.e. proportional to N*tke) [nondim].
1573 real :: Ri_crit ! The critical shear Richardson number for shear-
1574 ! driven mixing [nondim]. The theoretical value is 0.25.
1575 real :: q0 ! The background level of TKE [Z2 T-2 ~> m2 s-2].
1576 real :: Ilambda2 ! 1.0 / CS%lambda**2 [nondim]
1577 real :: TKE_min ! The minimum value of shear-driven TKE that can be
1578 ! solved for [Z2 T-2 ~> m2 s-2].
1579 real :: kappa0 ! The background diapycnal diffusivity [H Z T-1 ~> m2 s-1 or Pa s]
1580 real :: kappa_trunc ! Diffusivities smaller than this are rounded to 0 [H Z T-1 ~> m2 s-1 or Pa s]
1581
1582 real :: eden1, eden2 ! Variables used in calculating e1 [H Z-2 ~> m-1 or kg m-4]
1583 real :: I_eden ! The inverse of the denominator in e1 [Z2 H-1 ~> m or m4 kg-1]
1584 real :: ome ! Variables used in calculating e1 [nondim]
1585 real :: diffusive_src ! The diffusive source in the kappa equation [H T-1 ~> m s-1 or kg m-2 s-1]
1586 real :: chg_by_k0 ! The value of k_src that leads to an increase of
1587 ! kappa_0 if only the diffusive term is a sink [T-1 ~> s-1]
1588 real :: h_dz_here ! The ratio of the thicknesses to the vertical distances around an interface
1589 ! [H Z-1 ~> nondim or kg m-3]. In non-Boussinesq mode this is the density.
1590
1591 real :: kappa_mean ! A mean value of kappa [H Z T-1 ~> m2 s-1 or Pa s]
1592 real :: Newton_test ! The value of relative error that will cause the next
1593 ! iteration to use Newton's method [nondim].
1594 ! Temporary variables used in the Newton's method iterations.
1595 real :: decay_term_k ! The decay term in the diffusivity equation [Z-1 ~> m-1]
1596 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]
1597 real :: I_Q ! The inverse of TKE [T2 Z-2 ~> s2 m-2]
1598 real :: kap_src ! A source term in the kappa equation [H T-1 ~> m s-1 or kg m-2 s-1]
1599 real :: v1 ! A temporary variable proportional to [H Z-1 T-1 ~> s-1 or kg m-3 s-1]
1600 real :: v2 ! A temporary variable in [Z T-2 ~> m s-2]
1601 real :: tol_err ! The tolerance for max_err that determines when to
1602 ! stop iterating [nondim].
1603 real :: Newton_err ! The tolerance for max_err that determines when to
1604 ! start using Newton's method [nondim]. Empirically, an initial
1605 ! value of about 0.2 seems to be most efficient.
1606 real, parameter :: roundoff = 1.0e-16 ! A negligible fractional change in TKE [nondim].
1607 ! This could be larger but performance gains are small.
1608
1609 logical :: tke_noflux_bottom_BC = .false. ! Specify the boundary conditions
1610 logical :: tke_noflux_top_BC = .false. ! that are applied to the TKE equations.
1611 logical :: do_Newton ! If .true., use Newton's method for the next iteration.
1612 logical :: abort_Newton ! If .true., an Newton's method has encountered a 0
1613 ! pivot, and should not have been used.
1614 logical :: was_Newton ! The value of do_Newton before checking convergence.
1615 logical :: within_tolerance ! If .true., all points are within tolerance to
1616 ! enable this subroutine to return.
1617 integer :: ks_src, ke_src ! The range indices that have nonzero k_src.
1618 integer :: ks_kappa, ke_kappa, ke_tke ! The ranges of k-indices that are or
1619 integer :: ks_kappa_prev, ke_kappa_prev ! were being worked on.
1620 integer :: itt, k, k2
1621
1622 ! These variables are used only for debugging.
1623 logical, parameter :: debug_soln = .false.
1624 real :: K_err_lin ! The imbalance in the K equation [H T-1 ~> m s-1 or kg m-2 s-1]
1625 real :: Q_err_lin ! The imbalance in the Q equation [H Z T-3 ~> m2 s-3 or kg m-1 s-3]
1626 real, dimension(nz+1) :: &
1627106836 I_Ld2_debug, & ! A separate version of I_Ld2 for debugging [H-1 Z-1 ~> m-2 or m kg-1].
1628106836 kappa_prev, & ! The value of kappa at the start of the current iteration [H Z T-1 ~> m2 s-1 or Pa s]
162953418 TKE_prev ! The value of TKE at the start of the current iteration [Z2 T-2 ~> m2 s-2].
1630
163153418 c_N2 = CS%C_N**2 ; c_S2 = CS%C_S**2
163253418 q0 = CS%TKE_bg ; kappa0 = CS%kappa_0
163353418 TKE_min = max(CS%TKE_bg, 1.0E-20*US%m_to_Z**2*US%T_to_s**2)
163453418 Ri_crit = CS%Rino_crit
163553418 Ilambda2 = 1.0 / CS%lambda**2
163653418 kappa_trunc = CS%kappa_trunc
163753418 do_Newton = .false. ; abort_Newton = .false.
163853418 tol_err = CS%kappa_tol_err
163953418 Newton_err = 0.2 ! This initial value may be automatically reduced later.
1640
164153418 ks_kappa = 2 ; ke_kappa = nz ; ks_kappa_prev = 2 ; ke_kappa_prev = nz
1642
164353418 ke_src = 0 ; ks_src = nz+1
1644434981 do K=2,nz
1645434981 if (N2(K) < Ri_crit * S2(K)) then ! Equivalent to Ri < Ri_crit.
1646! Ri = N2(K) / S2(K)
1647! k_src(K) = (2.0 * CS%Shearmix_rate * sqrt(S2(K))) * &
1648! ((Ri_crit - Ri) / (Ri_crit + CS%FRi_curvature*Ri))
1649 K_src(K) = (2.0 * CS%Shearmix_rate * sqrt(S2(K))) * &
165010752 ((Ri_crit*S2(K) - N2(K)) / (Ri_crit*S2(K) + CS%FRi_curvature*N2(K)))
165110752 ke_src = K
165210752 if (ks_src > k) ks_src = K
1653 else
1654370811 k_src(K) = 0.0
1655 endif
1656 enddo
1657
1658 ! If there is no source anywhere, return kappa(K) = 0.
165953418 if (ks_src > ke_src) then
1660455306 do K=1,nz+1
1661455306 kappa(K) = 0.0 ; K_Q(K) = 0.0 ; tke(K) = TKE_min
1662 enddo
1663455306 if (present(kappa_src)) then ; do K=1,nz+1 ; kappa_src(K) = 0.0 ; enddo ; endif
1664455306 if (present(local_src)) then ; do K=1,nz+1 ; local_src(K) = 0.0 ; enddo ; endif
166542666 return
1666 endif
1667
166886511 do K=1,nz+1
166975759 kappa(K) = kappa_in(K)
1670! TKE_decay(K) = c_n*sqrt(N2(K)) + c_s*sqrt(S2(K)) ! The expression in JHL.
167175759 TKE_decay(K) = sqrt(c_n2*N2(K) + c_s2*S2(K))
167286511 if ((kappa(K) > 0.0) .and. (K_Q(K) > 0.0)) then
16737852 TKE(K) = kappa(K) / K_Q(K) ! Perhaps take the max with TKE_min
1674 else
167567907 TKE(K) = TKE_min
1676 endif
1677 enddo
1678 ! Apply boundary conditions to kappa.
167910752 kappa(1) = 0.0 ; kappa(nz+1) = 0.0
1680
1681 ! Calculate the term (e1) that allows changes in TKE to be calculated quickly
1682 ! below the deepest nonzero value of kappa. If kappa = 0, below interface
1683 ! k-1, the final changes in TKE are related by dQ(K+1) = e1(K+1)*dQ(K).
168410752 eden2 = kappa0 * Idz(nz)
168510752 if (tke_noflux_bottom_BC) then
16860 eden1 = h_Int(nz+1)*TKE_decay(nz+1)
16870 I_eden = 1.0 / (eden2 + eden1)
16880 e1(nz+1) = eden2 * I_eden ; ome = eden1 * I_eden
1689 else
169010752 e1(nz+1) = 0.0 ; ome = 1.0
1691 endif
169265007 do k=nz,2,-1
169354255 eden1 = h_Int(K)*TKE_decay(K) + ome * eden2
169454255 eden2 = kappa0 * Idz(k-1)
169554255 I_eden = 1.0 / (eden2 + eden1)
169665007 e1(K) = eden2 * I_eden ; ome = eden1 * I_eden ! = 1-e1
1697 enddo
169810752 e1(1) = 0.0
1699
1700
1701 ! Iterate here to convergence to within some tolerance of order tol_err.
170235562 do itt=1,CS%max_RiNo_it
1703
1704 ! ----------------------------------------------------
1705 ! Calculate TKE
1706 ! ----------------------------------------------------
1707
1708 if (debug_soln) then ; do K=1,nz+1 ; kappa_prev(K) = kappa(K) ; TKE_prev(K) = TKE(K) ; enddo ; endif
1709
171035562 if (.not.do_Newton) then
1711 ! Use separate steps of the TKE and kappa equations, that are
1712 ! explicit in the nonlinear source terms, implicit in a linearized
1713 ! version of the nonlinear sink terms, and implicit in the linear
1714 ! terms.
1715
171635562 ke_tke = max(ke_kappa,ke_kappa_prev)+1
1717 ! aQ is the coupling between adjacent interfaces [Z T-1 ~> m s-1].
1718199129 do k=1,min(ke_tke,nz)
1719199129 aQ(k) = (0.5*(kappa(K)+kappa(K+1)) + kappa0) * Idz(k)
1720 enddo
172135562 dQ(1) = -TKE(1)
172235562 if (tke_noflux_top_BC) then
17230 tke_src = dz_h_Int(1)*kappa0*S2(1) + q0 * TKE_decay(1) ! Uses that kappa(1) = 0
17240 bQd1 = h_Int(1) * TKE_decay(1)
17250 bQ = 1.0 / (bQd1 + aQ(1))
17260 tke(1) = bQ * (h_Int(1)*tke_src)
17270 cQ(2) = aQ(1) * bQ ; cQcomp = bQd1 * bQ ! = 1 - cQ
1728 else
172935562 tke(1) = q0 ; cQ(2) = 0.0 ; cQcomp = 1.0
1730 endif
1731144193 do K=2,ke_tke-1
1732108631 dQ(K) = -TKE(K)
1733108631 tke_src = dz_h_Int(K)*(kappa(K) + kappa0)*S2(K) + q0*TKE_decay(K)
1734108631 bQd1 = h_Int(K)*(TKE_decay(K) + dz_h_Int(K)*N2(K)*K_Q(K)) + cQcomp*aQ(k-1)
1735108631 bQ = 1.0 / (bQd1 + aQ(k))
1736108631 tke(K) = bQ * (h_Int(K)*tke_src + aQ(k-1)*tke(K-1))
1737144193 cQ(K+1) = aQ(k) * bQ ; cQcomp = bQd1 * bQ ! = 1 - cQ
1738 enddo
173935562 if ((ke_tke == nz+1) .and. .not.(tke_noflux_bottom_BC)) then
174016188 tke(nz+1) = TKE_min
174116188 dQ(nz+1) = 0.0
1742 else
174319374 k = ke_tke
174419374 tke_src = dz_h_Int(K)*kappa0*S2(K) + q0*TKE_decay(K) ! Uses that kappa(ke_tke) = 0
174519374 if (K == nz+1) then
17460 dQ(K) = -TKE(K)
17470 bQ = 1.0 / (h_Int(K)*TKE_decay(K) + cQcomp*aQ(k-1))
17480 tke(K) = max(TKE_min, bQ * (h_Int(K)*tke_src + aQ(k-1)*tke(K-1)))
17490 dQ(K) = tke(K) + dQ(K)
1750 else
175119374 bQ = 1.0 / ((h_Int(K)*TKE_decay(K) + cQcomp*aQ(k-1)) + aQ(k))
175219374 cQ(K+1) = aQ(k) * bQ
1753 ! Account for all changes deeper in the water column.
175419374 dQ(K) = -TKE(K)
1755 tke(K) = max((bQ * (h_Int(K)*tke_src + aQ(k-1)*tke(K-1)) + &
175619374 cQ(K+1)*(tke(K+1) - e1(K+1)*tke(K))) / (1.0 - cQ(K+1)*e1(K+1)), TKE_min)
175719374 dQ(K) = tke(K) + dQ(K)
1758
1759 ! Adjust TKE deeper in the water column in case ke_tke increases.
1760 ! This might not be strictly necessary?
176156300 do K=ke_tke+1,nz+1
176256300 dQ(K) = e1(K)*dQ(K-1)
176356300 tke(K) = max(tke(K) + dQ(K), TKE_min)
176456300 if (abs(dQ(K)) < roundoff*tke(K)) exit
1765 enddo
176620260 do K2=K+1,nz
17671676 if (dQ(K2) == 0.0) exit
176819470 dQ(K2) = 0.0
1769 enddo
1770 endif
1771 endif
1772179755 do K=ke_tke-1,1,-1
1773144193 tke(K) = max(tke(K) + cQ(K+1)*tke(K+1), TKE_min)
1774179755 dQ(K) = tke(K) + dQ(K)
1775 enddo
1776
1777 ! ----------------------------------------------------
1778 ! Calculate kappa, here defined at interfaces.
1779 ! ----------------------------------------------------
1780
178135562 ke_kappa_prev = ke_kappa ; ks_kappa_prev = ks_kappa
1782
178335562 dK(1) = 0.0 ! kappa takes boundary values of 0.
178435562 cK(2) = 0.0 ; cKcomp = 1.0
178589817 if (itt == 1) then ; do K=2,nz
178665007 I_Ld2(K) = dz_h_Int(K)*(N2(K)*Ilambda2 + f2) / tke(K) + I_L2_bdry(K)
1787 enddo ; endif
178877432 do K=2,nz
178977430 dK(K) = -kappa(K)
179077430 if (itt>1) &
179152020 I_Ld2(K) = dz_h_Int(K)*(N2(K)*Ilambda2 + f2) / tke(K) + I_L2_bdry(K)
179277430 bKd1 = h_Int(K)*I_Ld2(K) + cKcomp*Idz(k-1)
179377430 bK = 1.0 / (bKd1 + Idz(k))
1794
179577430 kappa(K) = bK * (Idz(k-1)*kappa(K-1) + h_Int(K) * K_src(K))
179677430 cK(K+1) = Idz(k) * bK ; cKcomp = bKd1 * bK ! = 1 - cK(K+1)
1797
1798 ! Neglect values that are smaller than kappa_trunc.
179977432 if (kappa(K) < cKcomp*kappa_trunc) then
180035560 kappa(K) = 0.0
180135560 if (K > ke_src) then ; ke_kappa = k-1 ; K_Q(K) = 0.0 ; exit ; endif
180241870 elseif (kappa(K) < 2.0*cKcomp*kappa_trunc) then
1803360 kappa(K) = 2.0 * (kappa(K) - cKcomp*kappa_trunc)
1804 endif
1805 enddo
180635562 K_Q(ke_kappa) = kappa(ke_kappa) / tke(ke_kappa)
180735562 dK(ke_kappa) = dK(ke_kappa) + kappa(ke_kappa)
180864407 do K=ke_kappa+2,ke_kappa_prev
180964407 dK(K) = -kappa(K) ; kappa(K) = 0.0 ; K_Q(K) = 0.0
1810 enddo
181141870 do K=ke_kappa-1,2,-1
18126308 kappa(K) = kappa(K) + cK(K+1)*kappa(K+1)
1813 ! Neglect values that are smaller than kappa_trunc.
18146308 if (kappa(K) <= kappa_trunc) then
18150 kappa(K) = 0.0
18160 if (K < ks_src) then ; ks_kappa = k+1 ; K_Q(K) = 0.0 ; exit ; endif
18176308 elseif (kappa(K) < 2.0*kappa_trunc) then
18180 kappa(K) = 2.0 * (kappa(K) - kappa_trunc)
1819 endif
1820
18216308 dK(K) = dK(K) + kappa(K)
182241870 K_Q(K) = kappa(K) / tke(K)
1823 enddo
182435562 do K=ks_kappa_prev,ks_kappa-2 ; kappa(K) = 0.0 ; K_Q(K) = 0.0 ; enddo
1825
1826 else ! do_Newton is .true.
1827! Once the solutions are close enough, use a Newton's method solver of the
1828! whole system to accelerate convergence.
18290 ks_kappa_prev = ks_kappa ; ke_kappa_prev = ke_kappa ; ke_kappa = nz
18300 ks_kappa = 2
18310 dK(1) = 0.0 ; cK(2) = 0.0 ; cKcomp = 1.0 ; dKdQ(1) = 0.0
18320 aQ(1) = (0.5*(kappa(1)+kappa(2))+kappa0) * Idz(1)
18330 dQdz(1) = 0.5*(TKE(1) - TKE(2))*Idz(1)
18340 if (tke_noflux_top_BC) then
1835 tke_src = h_Int(1) * (kappa0*dz_h_Int(1)*S2(1) - (TKE(1) - q0)*TKE_decay(1)) - &
18360 aQ(1) * (TKE(1) - TKE(2))
1837
18380 bQ = 1.0 / (aQ(1) + h_Int(1)*TKE_decay(1))
18390 cQ(2) = aQ(1) * bQ
18400 cQcomp = (h_Int(1)*TKE_decay(1)) * bQ ! = 1 - cQ(2)
18410 dQmdK(2) = -dQdz(1) * bQ
18420 dQ(1) = bQ * tke_src
1843 else
18440 dQ(1) = 0.0 ; cQ(2) = 0.0 ; cQcomp = 1.0 ; dQmdK(2) = 0.0
1845 endif
18460 do K=2,nz
18470 I_Q = 1.0 / TKE(K)
18480 I_Ld2(K) = (N2(K)*Ilambda2 + f2) * dz_h_Int(K)*I_Q + I_L2_bdry(K)
1849
1850 kap_src = h_Int(K) * (K_src(K) - I_Ld2(K)*kappa(K)) + &
18510 Idz(k-1)*(kappa(K-1)-kappa(K)) - Idz(k)*(kappa(K)-kappa(K+1))
1852
1853 ! Ensure that the pivot is always positive, and that 0 <= cK <= 1.
1854 ! Otherwise do not use Newton's method.
18550 decay_term_k = -Idz(k-1)*dQmdK(K)*dKdQ(K-1) + h_Int(K)*I_Ld2(K)
18560 if (decay_term_k < 0.0) then ; abort_Newton = .true. ; exit ; endif
18570 bK = 1.0 / (Idz(k) + Idz(k-1)*cKcomp + decay_term_k)
1858
18590 cK(K+1) = bK * Idz(k)
18600 cKcomp = bK * (Idz(k-1)*cKcomp + decay_term_k) ! = 1-cK(K+1)
18610 if (CS%dKdQ_iteration_bug) then
1862 dKdQ(K) = bK * (Idz(k-1)*dKdQ(K-1)*cQ(K) + &
18630 US%m_to_Z*(N2(K)*Ilambda2 + f2) * I_Q**2 * kappa(K) )
1864 else
1865 dKdQ(K) = bK * (Idz(k-1)*dKdQ(K-1)*cQ(K) + &
18660 dz_Int(K)*(N2(K)*Ilambda2 + f2) * I_Q**2 * kappa(K) )
1867 endif
18680 dK(K) = bK * (kap_src + Idz(k-1)*dK(K-1) + Idz(k-1)*dKdQ(K-1)*dQ(K-1))
1869
1870 ! Truncate away negligibly small values of kappa.
18710 if (dK(K) <= cKcomp*(kappa_trunc - kappa(K))) then
18720 dK(K) = -cKcomp*kappa(K)
1873! if (K > ke_src) then ; ke_kappa = k-1 ; K_Q(K) = 0.0 ; exit ; endif
18740 elseif (dK(K) < cKcomp*(2.0*kappa_trunc - kappa(K))) then
18750 dK(K) = 2.0 * dK(K) - cKcomp*(2.0*kappa_trunc - kappa(K))
1876 endif
1877
1878 ! Solve for dQ(K)...
18790 aQ(k) = (0.5*(kappa(K)+kappa(K+1))+kappa0) * Idz(k)
18800 dQdz(k) = 0.5*(TKE(K) - TKE(K+1))*Idz(k)
1881 tke_src = h_Int(K) * ((dz_h_Int(K) * ((kappa(K) + kappa0)*S2(K) - kappa(k)*N2(K))) - &
1882 (TKE(k) - q0)*TKE_decay(k)) - &
18830 (aQ(k) * (TKE(K) - TKE(K+1)) - aQ(k-1) * (TKE(K-1) - TKE(K)))
18840 v1 = aQ(k-1) + dQdz(k-1)*dKdQ(K-1)
1885 v2 = (v1*dQmdK(K) + dQdz(k-1)*cK(K)) + &
18860 ((dQdz(k-1) - dQdz(k)) + dz_Int(K)*(S2(K) - N2(K)))
1887
1888 ! Ensure that the pivot is always positive, and that 0 <= cQ <= 1.
1889 ! Otherwise do not use Newton's method.
18900 decay_term_Q = h_Int(K)*TKE_decay(K) - dQdz(k-1)*dKdQ(K-1)*cQ(K) - v2*dKdQ(K)
18910 if (decay_term_Q < 0.0) then ; abort_Newton = .true. ; exit ; endif
18920 bQ = 1.0 / (aQ(k) + (cQcomp*aQ(k-1) + decay_term_Q))
1893
18940 cQ(K+1) = aQ(k) * bQ
18950 cQcomp = (cQcomp*aQ(k-1) + decay_term_Q) * bQ
18960 dQmdK(K+1) = (v2 * cK(K+1) - dQdz(k)) * bQ
1897
1898 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
1899 dQ(K) = max(bQ * ((v1 * dQ(K-1) + dQdz(k-1)*dK(k-1)) + &
19000 (v2 * dK(K) + tke_src)), cQcomp*(-0.5*TKE(K)))
1901
1902 ! Check whether the next layer will be affected by any nonzero kappas.
19030 if ((itt > 1) .and. (K > ke_src) .and. (dK(K) == 0.0) .and. &
19040 ((kappa(K) + kappa(K+1)) == 0.0)) then
1905 ! Could also do .and. (bQ*abs(tke_src) < roundoff*TKE(K)) then
19060 ke_kappa = k-1 ; exit
1907 endif
1908 enddo
19090 if ((ke_kappa == nz) .and. (.not. abort_Newton)) then
19100 dK(nz+1) = 0.0 ; dKdQ(nz+1) = 0.0
19110 if (tke_noflux_bottom_BC) then
19120 K = nz+1
1913 tke_src = h_Int(K) * (kappa0*dz_h_Int(K)*S2(K) - (TKE(K) - q0)*TKE_decay(K)) + &
19140 aQ(k-1) * (TKE(K-1) - TKE(K))
1915
19160 v1 = aQ(k-1) + dQdz(k-1)*dKdQ(K-1)
19170 decay_term_Q = max(0.0, h_Int(K)*TKE_decay(K) - dQdz(k-1)*dKdQ(K-1)*cQ(K))
19180 if (decay_term_Q < 0.0) then
19190 abort_Newton = .true.
1920 else
19210 bQ = 1.0 / (aQ(k) + (cQcomp*aQ(k-1) + decay_term_Q))
1922 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
19230 dQ(K) = max(bQ * ((v1 * dQ(K-1) + dQdz(k-1)*dK(K-1)) + tke_src), -0.5*TKE(K))
19240 TKE(K) = max(TKE(K) + dQ(K), TKE_min)
1925 endif
1926 else
19270 dQ(nz+1) = 0.0
1928 endif
19290 elseif (.not. abort_Newton) then
1930 ! Alter the first-guess determination of dQ(K).
19310 dQ(ke_kappa+1) = dQ(ke_kappa+1) / (1.0 - cQ(ke_kappa+2)*e1(ke_kappa+2))
19320 TKE(ke_kappa+1) = max(TKE(ke_kappa+1) + dQ(ke_kappa+1), TKE_min)
19330 do k=ke_kappa+2,nz+1
1934 if (debug_soln .and. (K < nz+1)) then
1935 ! Ignore this source?
1936 aQ(k) = (0.5*(kappa(K)+kappa(K+1))+kappa0) * Idz(k)
1937 ! tke_src_norm = ((kappa0*dz_Int(K)*S2(K) - h_Int(K)*(TKE(K)-q0)*TKE_decay(K)) - &
1938 ! (aQ(k) * (TKE(K) - TKE(K+1)) - aQ(k-1) * (TKE(K-1) - TKE(K))) ) / &
1939 ! (aQ(k) + (aQ(k-1) + h_Int(K)*TKE_decay(K)))
1940 endif
19410 dK(K) = 0.0
1942 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
19430 dQ(K) = max(e1(K)*dQ(K-1),-0.5*TKE(K))
19440 TKE(K) = max(TKE(K) + dQ(K), TKE_min)
19450 if (abs(dQ(K)) < roundoff*TKE(K)) exit
1946 enddo
1947 if (debug_soln) then ; do K2=K+1,nz+1 ; dQ(K2) = 0.0 ; dK(K2) = 0.0 ; enddo ; endif
1948 endif
19490 if (.not. abort_Newton) then
19500 do K=ke_kappa,2,-1
1951 ! Ensure that TKE+dQ will not drop below 0.5*TKE.
19520 dQ(K) = max(dQ(K) + (cQ(K+1)*dQ(K+1) + dQmdK(K+1) * dK(K+1)), -0.5*TKE(K))
19530 TKE(K) = max(TKE(K) + dQ(K), TKE_min)
19540 dK(K) = dK(K) + (cK(K+1)*dK(K+1) + dKdQ(K) * dQ(K))
1955 ! Truncate away negligibly small values of kappa.
19560 if (dK(K) <= kappa_trunc - kappa(K)) then
19570 dK(K) = -kappa(K)
19580 kappa(K) = 0.0
19590 if ((K < ks_src) .and. (K+1 > ks_kappa)) ks_kappa = K+1
19600 elseif (dK(K) < 2.0*kappa_trunc - kappa(K)) then
19610 dK(K) = 2.0*dK(K) - (2.0*kappa_trunc - kappa(K))
19620 kappa(K) = max(kappa(K) + dK(K), 0.0) ! The max is for paranoia.
19630 if (K<=ks_kappa) ks_kappa = 2
1964 else
19650 kappa(K) = kappa(K) + dK(K)
19660 if (K<=ks_kappa) ks_kappa = 2
1967 endif
1968 enddo
19690 dQ(1) = max(dQ(1) + cQ(2)*dQ(2) + dQmdK(2) * dK(2), TKE_min - TKE(1))
19700 TKE(1) = max(TKE(1) + dQ(1), TKE_min)
19710 dK(1) = 0.0
1972 endif
1973
1974 ! Check these solutions for consistency.
1975 ! The unit conversions here have not been carefully tested.
1976 if (debug_soln) then ; do K=2,nz
1977 ! In these equations, K_err_lin and Q_err_lin should be at round-off levels
1978 ! compared with the dominant terms, perhaps, h_Int*I_Ld2*kappa and
1979 ! h_Int*TKE_decay*TKE. The exception is where, either 1) the decay term has been
1980 ! been increased to ensure a positive pivot, or 2) negative TKEs have been
1981 ! truncated, or 3) small or negative kappas have been rounded toward 0.
1982 I_Q = 1.0 / TKE(K)
1983 I_Ld2_debug(K) = (N2(K)*Ilambda2 + f2) * dz_h_Int(K)*I_Q + I_L2_bdry(K)
1984
1985 kap_src = h_Int(K) * (k_src(K) - I_Ld2(K)*kappa_prev(K)) + &
1986 (Idz(k-1)*(kappa_prev(k-1)-kappa_prev(k)) - &
1987 Idz(k)*(kappa_prev(k)-kappa_prev(k+1)))
1988 K_err_lin = -Idz(k-1)*(dK(K-1)-dK(K)) + Idz(k)*(dK(K)-dK(K+1)) + &
1989 h_Int(K)*I_Ld2_debug(K)*dK(K) - kap_src - &
1990 dz_Int(K)*(N2(K)*Ilambda2 + f2)*I_Q**2*kappa_prev(K) * dQ(K)
1991
1992 h_dz_here = 0.0 ; if (abs(dz_h_Int(K)) > 0.0) h_dz_here = 1.0 / dz_h_Int(K)
1993 tke_src = h_Int(K) * ((kappa_prev(K) + kappa0)*S2(K) - &
1994 kappa_prev(K)*N2(K) - (TKE_prev(K) - q0)*h_dz_here*TKE_decay(K)) - &
1995 (aQ(k) * (TKE_prev(K) - TKE_prev(K+1)) - aQ(k-1) * (TKE_prev(K-1) - TKE_prev(K)))
1996 Q_err_lin = tke_src + (aQ(k-1) * (dQ(K-1)-dQ(K)) - aQ(k) * (dQ(k)-dQ(k+1))) - &
1997 0.5*(TKE_prev(K)-TKE_prev(K+1))*Idz(k) * (dK(K) + dK(K+1)) - &
1998 0.5*(TKE_prev(K)-TKE_prev(K-1))*Idz(k-1)* (dK(K-1) + dK(K)) + &
1999 dz_Int(K) * (dK(K) * (S2(K) - N2(K)) - dQ(K)*TKE_decay(K))
2000 enddo ; endif
2001
2002 endif ! End of the Newton's method solver.
2003
2004 ! Test kappa for convergence...
200535562 if ((tol_err < Newton_err) .and. (.not.abort_Newton)) then
2006 ! A lower tolerance is used to switch to Newton's method than to switch back.
200710752 Newton_test = Newton_err ; if (do_Newton) Newton_test = 2.0*Newton_err
200810752 was_Newton = do_Newton
200910752 within_tolerance = .true. ; do_Newton = .true.
201036765 do K=min(ks_kappa,ks_kappa_prev),max(ke_kappa,ke_kappa_prev)
201131447 kappa_mean = kappa0 + (kappa(K) - 0.5*dK(K))
201231447 if (abs(dK(K)) > Newton_test * kappa_mean) then
20133584 if (do_Newton) abort_Newton = .true.
20143584 within_tolerance = .false. ; do_Newton = .false. ; exit
201527863 elseif (abs(dK(K)) > tol_err * kappa_mean) then
20161850 within_tolerance = .false. ; if (.not.do_Newton) exit
2017 endif
201833181 if (abs(dQ(K)) > Newton_test*(tke(K) - 0.5*dQ(K))) then
201920043 if (do_Newton) abort_Newton = .true.
202020043 do_Newton = .false. ; if (.not.within_tolerance) exit
2021 endif
2022 enddo
2023
2024 else ! Newton's method will not be used again, so no need to check.
202524810 within_tolerance = .true.
202631600 do K=min(ks_kappa,ks_kappa_prev),max(ke_kappa,ke_kappa_prev)
202731600 if (abs(dK(K)) > tol_err * (kappa0 + (kappa(K) - 0.5*dK(K)))) then
202819376 within_tolerance = .false. ; exit
2029 endif
2030 enddo
2031 endif
2032
203335562 if (abort_Newton) then
203410752 do_Newton = .false. ; abort_Newton = .false.
2035 ! We went to Newton too quickly last time, so restrict the tolerance.
203610752 Newton_err = 0.5*Newton_err
203710752 ke_kappa_prev = nz
203865007 do K=2,nz ; K_Q(K) = kappa(K) / max(TKE(K), TKE_min) ; enddo
2039 endif
2040
204135562 if (within_tolerance) exit
2042
2043 enddo
2044
204510752 if (do_Newton) then ! K_Q needs to be calculated.
20460 do K=1,ks_kappa-1 ; K_Q(K) = 0.0 ; enddo
20470 do K=ks_kappa,ke_kappa ; K_Q(K) = kappa(K) / TKE(K) ; enddo
20480 do K=ke_kappa+1,nz+1 ; K_Q(K) = 0.0 ; enddo
2049 endif
2050
205110752 if (present(local_src)) then
20523584 local_src(1) = 0.0 ; local_src(nz+1) = 0.0
205321669 do K=2,nz
205418085 diffusive_src = Idz(k-1)*(kappa(K-1)-kappa(K)) + Idz(k)*(kappa(K+1)-kappa(K))
205518085 chg_by_k0 = kappa0 * ((Idz(k-1)+Idz(k)) / h_Int(K) + I_Ld2(K))
205621669 if (diffusive_src <= 0.0) then
205714159 local_src(K) = K_src(K) + chg_by_k0
2058 else
20593926 local_src(K) = (K_src(K) + chg_by_k0) + diffusive_src / h_Int(K)
2060 endif
2061 enddo
2062 endif
206310752 if (present(kappa_src)) then
20643584 kappa_src(1) = 0.0 ; kappa_src(nz+1) = 0.0
206521669 do K=2,nz
206621669 kappa_src(K) = K_src(K)
2067 enddo
2068 endif
2069
207099668end subroutine find_kappa_tke
2071
2072!> This subroutine initializes the parameters that regulate shear-driven mixing
20731function kappa_shear_init(Time, G, GV, US, param_file, diag, CS)
2074 type(time_type), intent(in) :: Time !< The current model time.
2075 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2076 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2077 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2078 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
2079 !! parameters.
2080 type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to regulate diagnostic
2081 !! output.
2082 type(Kappa_shear_CS), pointer :: CS !< A pointer that is set to point to the control
2083 !! structure for this module
2084 logical :: kappa_shear_init !< True if module is to be used, False otherwise
2085
2086 ! Local variables
2087 real :: KD_normal ! The KD of the main model, read here only as a parameter
2088 ! for setting the default of KD_SMOOTH [Z2 T-1 ~> m2 s-1]
2089 real :: kappa_0_default ! The default value for KD_KAPPA_SHEAR_0 [Z2 T-1 ~> m2 s-1]
2090 logical :: merge_mixedlayer
2091 integer :: number_of_OBC_segments
2092 logical :: debug_shear
2093 logical :: enable_bugs ! If true, the defaults for recently added bug-fix flags are set to
2094 ! recreate the bugs, or if false bugs are only used if actively selected.
2095 logical :: just_read ! If true, this module is not used, so only read the parameters.
2096 ! This include declares and sets the variable "version".
2097# include "version_variable.h"
2098 character(len=40) :: mdl = "MOM_kappa_shear" ! This module's name.
2099
21001 if (associated(CS)) then
2101 call MOM_error(WARNING, "kappa_shear_init called with an associated "// &
21020 "control structure.")
21030 return
2104 endif
21051 allocate(CS)
2106
2107 ! The Jackson-Hallberg-Legg shear mixing parameterization uses the following
2108 ! 6 nondimensional coefficients. That paper gives 3 best fit parameter sets.
2109 ! Ri_Crit Rate FRi_Curv K_buoy TKE_N TKE_Shear
2110 ! p1: 0.25 0.089 -0.97 0.82 0.24 0.14
2111 ! p2: 0.30 0.085 -0.94 0.86 0.26 0.13
2112 ! p3: 0.35 0.088 -0.89 0.81 0.28 0.12
2113 ! Future research will reveal how these should be modified to take
2114 ! subgridscale inhomogeneity into account.
2115
2116! Set default, read and log parameters
21171 call get_param(param_file, mdl, "USE_JACKSON_PARAM", kappa_shear_init, default=.false., do_not_log=.true.)
2118 call log_version(param_file, mdl, version, &
2119 "Parameterization of shear-driven turbulence following Jackson, Hallberg and Legg, JPO 2008", &
21201 log_to_all=.true., debugging=kappa_shear_init, all_default=.not.kappa_shear_init)
2121 call get_param(param_file, mdl, "USE_JACKSON_PARAM", kappa_shear_init, &
2122 "If true, use the Jackson-Hallberg-Legg (JPO 2008) "//&
21231 "shear mixing parameterization.", default=.false.)
21241 just_read = .not.kappa_shear_init
2125 call get_param(param_file, mdl, "VERTEX_SHEAR", CS%KS_at_vertex, &
2126 "If true, do the calculations of the shear-driven mixing "//&
2127 "at the cell vertices (i.e., the vorticity points).", &
21281 default=.false., do_not_log=just_read)
2129 call get_param(param_file, mdl, "ENABLE_BUGS_BY_DEFAULT", enable_bugs, &
21301 default=.true., do_not_log=.true.) ! This is logged from MOM.F90.
2131 call get_param(param_file, mdl, "VERTEX_SHEAR_VISCOSITY_BUG", CS%VS_viscosity_bug, &
2132 "If true, use a bug in vertex shear that zeros out viscosities at "//&
2133 "vertices on coastlines.", &
21341 default=enable_bugs, do_not_log=just_read.or.(.not.CS%KS_at_vertex))
2135 call get_param(param_file, mdl, "OBC_NUMBER_OF_SEGMENTS", number_of_OBC_segments, &
21361 default=0, do_not_log=.true.)
2137 call get_param(param_file, mdl, "VERTEX_SHEAR_OBC_BUG", CS%vertex_shear_OBC_bug, &
2138 "If false, use extra masking when interpolating thicknesses to velocity "//&
2139 "points for setting up the shear velocities at vertices to avoid using "//&
2140 "external thicknesses at open boundaries. When OBCs are not in use, "//&
2141 "this parameter does not change answers, but true is more efficient.", &
2142 default=enable_bugs, &
21431 do_not_log=just_read.or.(.not.CS%KS_at_vertex).or.(number_of_OBC_segments<=0))
2144 ! Use OBC settings to set the default for VERTEX_SHEAR_OBC_BUG?
2145 call get_param(param_file, mdl, "VERTEX_SHEAR_GEOMETRIC_MEAN", CS%VS_GeometricMean, &
2146 "If true, use a geometric mean for moving diffusivity from "//&
2147 "vertices to tracer points. False uses algebraic mean.", &
21481 default=.false., do_not_log=just_read.or.(.not.CS%KS_at_vertex))
2149 call get_param(param_file, mdl, "VERTEX_SHEAR_THICKNESS_MEAN", CS%VS_ThicknessMean, &
2150 "If true, apply thickness weighting to horizontal averagings of diffusivity "//&
2151 "to tracer points in the kappa shear solver.", &
21521 default=.false.)
21531 if (CS%VS_GeometricMean) then
2154 call get_param(param_file, mdl, "VERTEX_SHEAR_GEOMETRIC_MEAN_KDMIN", &
2155 CS%VS_GeoMean_Kdmin, "If using the geometric mean in vertex shear, "//&
2156 "use this minimum value for Kd. This is an ad-hoc parameter, the "//&
2157 "diffusivities on the edge of shear regions are sensitive to the choice.",&
21580 units="m2 s-1", default=0.0, scale=GV%m2_s_to_HZ_T, do_not_log=just_read)
2159 endif
2160 call get_param(param_file, mdl, "RINO_CRIT", CS%RiNo_crit, &
2161 "The critical Richardson number for shear mixing.", &
21621 units="nondim", default=0.25, do_not_log=just_read)
2163 call get_param(param_file, mdl, "SHEARMIX_RATE", CS%Shearmix_rate, &
2164 "A nondimensional rate scale for shear-driven entrainment. "//&
2165 "Jackson et al find values in the range of 0.085-0.089.", &
21661 units="nondim", default=0.089, do_not_log=just_read)
2167 call get_param(param_file, mdl, "MAX_RINO_IT", CS%max_RiNo_it, &
2168 "The maximum number of iterations that may be used to "//&
2169 "estimate the Richardson number driven mixing.", &
21701 units="nondim", default=50, do_not_log=just_read)
2171 call get_param(param_file, mdl, "KD", KD_normal, &
21721 units="m2 s-1", scale=US%m2_s_to_Z2_T, default=0.0, do_not_log=.true.)
21731 kappa_0_default = max(Kd_normal, 1.0e-7*US%m2_s_to_Z2_T)
2174 call get_param(param_file, mdl, "KD_KAPPA_SHEAR_0", CS%kappa_0, &
2175 "The background diffusivity that is used to smooth the "//&
2176 "density and shear profiles before solving for the "//&
2177 "diffusivities. The default is the greater of KD and 1e-7 m2 s-1.", &
2178 units="m2 s-1", default=kappa_0_default*US%Z2_T_to_m2_s, scale=GV%m2_s_to_HZ_T, &
21791 do_not_log=just_read)
2180 call get_param(param_file, mdl, "KD_SEED_KAPPA_SHEAR", CS%kappa_seed, &
2181 "A moderately large seed value of diapycnal diffusivity that is used as a "//&
2182 "starting turbulent diffusivity in the iterations to find an energetically "//&
2183 "constrained solution for the shear-driven diffusivity.", &
21841 units="m2 s-1", default=1.0, scale=GV%m2_s_to_HZ_T)
2185 call get_param(param_file, mdl, "KD_TRUNC_KAPPA_SHEAR", CS%kappa_trunc, &
2186 "The value of shear-driven diffusivity that is considered negligible "//&
2187 "and is rounded down to 0. The default is 1% of KD_KAPPA_SHEAR_0.", &
2188 units="m2 s-1", default=0.01*CS%kappa_0*GV%HZ_T_to_m2_s, scale=GV%m2_s_to_HZ_T, &
21891 do_not_log=just_read)
2190 call get_param(param_file, mdl, "FRI_CURVATURE", CS%FRi_curvature, &
2191 "The nondimensional curvature of the function of the "//&
2192 "Richardson number in the kappa source term in the "//&
21931 "Jackson et al. scheme.", units="nondim", default=-0.97, do_not_log=just_read)
2194 call get_param(param_file, mdl, "TKE_N_DECAY_CONST", CS%C_N, &
2195 "The coefficient for the decay of TKE due to "//&
2196 "stratification (i.e. proportional to N*tke). "//&
2197 "The values found by Jackson et al. are 0.24-0.28.", &
21981 units="nondim", default=0.24, do_not_log=just_read)
2199! call get_param(param_file, mdl, "LAYER_KAPPA_STAGGER", CS%layer_stagger, &
2200! default=.false., do_not_log=just_read)
2201 call get_param(param_file, mdl, "TKE_SHEAR_DECAY_CONST", CS%C_S, &
2202 "The coefficient for the decay of TKE due to shear (i.e. "//&
2203 "proportional to |S|*tke). The values found by Jackson "//&
22041 "et al. are 0.14-0.12.", units="nondim", default=0.14, do_not_log=just_read)
2205 call get_param(param_file, mdl, "KAPPA_BUOY_SCALE_COEF", CS%lambda, &
2206 "The coefficient for the buoyancy length scale in the "//&
2207 "kappa equation. The values found by Jackson et al. are "//&
22081 "in the range of 0.81-0.86.", units="nondim", default=0.82, do_not_log=just_read)
2209 call get_param(param_file, mdl, "KAPPA_N_OVER_S_SCALE_COEF2", CS%lambda2_N_S, &
2210 "The square of the ratio of the coefficients of the "//&
2211 "buoyancy and shear scales in the diffusivity equation, "//&
2212 "Set this to 0 (the default) to eliminate the shear scale. "//&
2213 "This is only used if USE_JACKSON_PARAM is true.", &
22141 units="nondim", default=0.0, do_not_log=just_read)
2215 call get_param(param_file, mdl, "LZ_RESCALE", CS%lz_rescale, &
2216 "A coefficient to rescale the distance to the nearest solid boundary. "//&
2217 "This adjustment is to account for regions where 3 dimensional turbulence "//&
2218 "prevents the growth of shear instabilities [nondim].", &
22191 units="nondim", default=1.0)
2220 call get_param(param_file, mdl, "KAPPA_SHEAR_TOL_ERR", CS%kappa_tol_err, &
2221 "The fractional error in kappa that is tolerated. "//&
2222 "Iteration stops when changes between subsequent "//&
2223 "iterations are smaller than this everywhere in a "//&
2224 "column. The peak diffusivities usually converge most "//&
2225 "rapidly, and have much smaller errors than this.", &
22261 units="nondim", default=0.1, do_not_log=just_read)
2227 call get_param(param_file, mdl, "TKE_BACKGROUND", CS%TKE_bg, &
2228 "A background level of TKE used in the first iteration "//&
2229 "of the kappa equation. TKE_BACKGROUND could be 0.", &
22301 units="m2 s-2", default=0.0, scale=US%m_to_Z**2*US%T_to_s**2)
2231 call get_param(param_file, mdl, "KAPPA_SHEAR_ELIM_MASSLESS", CS%eliminate_massless, &
2232 "If true, massless layers are merged with neighboring "//&
2233 "massive layers in this calculation. The default is "//&
2234 "true and I can think of no good reason why it should "//&
2235 "be false. This is only used if USE_JACKSON_PARAM is true.", &
22361 default=.true., do_not_log=just_read)
2237 call get_param(param_file, mdl, "MAX_KAPPA_SHEAR_IT", CS%max_KS_it, &
2238 "The maximum number of iterations that may be used to "//&
2239 "estimate the time-averaged diffusivity.", &
22401 default=13, do_not_log=just_read)
2241 call get_param(param_file, mdl, "PRANDTL_TURB", CS%Prandtl_turb, &
2242 "The turbulent Prandtl number applied to shear instability.", &
22431 units="nondim", default=1.0, do_not_log=just_read)
2244 call get_param(param_file, mdl, "VEL_UNDERFLOW", CS%vel_underflow, &
2245 "A negligibly small velocity magnitude below which velocity components are set "//&
2246 "to 0. A reasonable value might be 1e-30 m/s, which is less than an "//&
2247 "Angstrom divided by the age of the universe.", &
22481 units="m s-1", default=0.0, scale=US%m_s_to_L_T, do_not_log=just_read)
2249 call get_param(param_file, mdl, "KAPPA_SHEAR_MAX_KAP_SRC_CHG", CS%kappa_src_max_chg, &
2250 "The maximum permitted increase in the kappa source within an iteration relative "//&
2251 "to the local source; this must be greater than 1. The lower limit for the "//&
2252 "permitted fractional decrease is (1 - 0.5/kappa_src_max_chg). These limits "//&
2253 "could perhaps be made dynamic with an improved iterative solver.", &
22541 default=10.0, units="nondim", do_not_log=just_read)
2255
2256 call get_param(param_file, mdl, "DEBUG", CS%debug, &
2257 "If true, write out verbose debugging data.", &
22581 default=.false., debuggingParam=.true., do_not_log=just_read)
2259 call get_param(param_file, mdl, "DEBUG_KAPPA_SHEAR", debug_shear, &
2260 "If true, write debugging data for the kappa-shear code.", &
22611 default=.false., debuggingParam=.true., do_not_log=.true.)
22621 if (debug_shear) CS%debug = .true.
2263 call get_param(param_file, mdl, "KAPPA_SHEAR_VERTEX_PSURF_BUG", CS%psurf_bug, &
2264 "If true, do a simple average of the cell surface pressures to get a pressure "//&
2265 "at the corner if VERTEX_SHEAR=True. Otherwise mask out any land points in "//&
22661 "the average.", default=.false., do_not_log=(just_read .or. (.not.CS%KS_at_vertex)))
2267
2268 call get_param(param_file, mdl, "KAPPA_SHEAR_ITER_BUG", CS%dKdQ_iteration_bug, &
2269 "If true, use an older, dimensionally inconsistent estimate of the "//&
2270 "derivative of diffusivity with energy in the Newton's method iteration. "//&
22711 "The bug causes undercorrections when dz > 1 m.", default=.false., do_not_log=just_read)
2272 call get_param(param_file, mdl, "KAPPA_SHEAR_ALL_LAYER_TKE_BUG", CS%all_layer_TKE_bug, &
2273 "If true, report back the latest estimate of TKE instead of the time average "//&
2274 "TKE when there is mass in all layers. Otherwise always report the time "//&
2275 "averaged TKE, as is currently done when there are some massless layers.", &
22761 default=.false., do_not_log=just_read)
2277 call get_param(param_file, mdl, "USE_RESTRICTIVE_TOLERANCE_CHECK", CS%restrictive_tolerance_check, &
2278 "If true, uses the more restrictive tolerance check to determine if a timestep "//&
2279 "is acceptable for the KS_it outer iteration loop. False uses the original less "//&
22801 "restrictive check.", default=.false., do_not_log=just_read)
2281! id_clock_KQ = cpu_clock_id('Ocean KS kappa_shear', grain=CLOCK_ROUTINE)
2282! id_clock_avg = cpu_clock_id('Ocean KS avg', grain=CLOCK_ROUTINE)
2283! id_clock_project = cpu_clock_id('Ocean KS project', grain=CLOCK_ROUTINE)
2284! id_clock_setup = cpu_clock_id('Ocean KS setup', grain=CLOCK_ROUTINE)
2285
22861 CS%nkml = 1
22871 if (GV%nkml>0) then
2288 call get_param(param_file, mdl, "KAPPA_SHEAR_MERGE_ML",merge_mixedlayer, &
2289 "If true, combine the mixed layers together before solving the "//&
22901 "kappa-shear equations.", default=.true., do_not_log=just_read)
22911 if (merge_mixedlayer) CS%nkml = GV%nkml
2292 endif
2293
2294! Forego remainder of initialization if not using this scheme
22951 if (.not. kappa_shear_init) return
2296
22971 CS%diag => diag
2298
2299 CS%id_Kd_shear = register_diag_field('ocean_model','Kd_shear', diag%axesTi, Time, &
23001 'Shear-driven Diapycnal Diffusivity at horizontal tracer points', 'm2 s-1', conversion=GV%HZ_T_to_m2_s)
23011 if (CS%KS_at_vertex) then
2302 CS%id_TKE = register_diag_field('ocean_model','TKE_shear', diag%axesBi, Time, &
23030 'Shear-driven Turbulent Kinetic Energy at horizontal vertices', 'm2 s-2', conversion=US%Z_to_m**2*US%s_to_T**2)
2304 CS%id_Kd_vertex = register_diag_field('ocean_model','Kd_shear_vertex', diag%axesBi, Time, &
23050 'Shear-driven Diapycnal Diffusivity at horizontal vertices', 'm2 s-1', conversion=GV%HZ_T_to_m2_s)
2306 CS%id_S2_init = register_diag_field('ocean_model','S2_shear_in', diag%axesBi, Time, &
23070 'Interface shear squared at horizontal vertices, as input to kappa-shear', 's-2', conversion=US%s_to_T**2)
2308 CS%id_N2_init = register_diag_field('ocean_model','N2_shear_in', diag%axesBi, Time, &
23090 'Interface stratification at horizontal vertices, as input to kappa-shear', 's-2', conversion=US%s_to_T**2)
2310 CS%id_S2_mean = register_diag_field('ocean_model','S2_shear_mean', diag%axesBi, Time, &
2311 'Interface shear squared at horizontal vertices, averaged over timestep in kappa-shear', &
23120 's-2', conversion=US%s_to_T**2)
2313 CS%id_N2_mean = register_diag_field('ocean_model','N2_shear_mean', diag%axesBi, Time, &
2314 'Interface stratification at horizontal vertices, averaged over timestep in kappa-shear', &
23150 's-2', conversion=US%s_to_T**2)
2316 else
2317 CS%id_TKE = register_diag_field('ocean_model','TKE_shear', diag%axesTi, Time, &
2318 'Shear-driven Turbulent Kinetic Energy at horizontal tracer points', &
23191 'm2 s-2', conversion=US%Z_to_m**2*US%s_to_T**2)
2320 CS%id_S2_init = register_diag_field('ocean_model','S2_shear_in', diag%axesTi, Time, &
23211 'Interface shear squared at horizontal tracer points, as input to kappa-shear', 's-2', conversion=US%s_to_T**2)
2322 CS%id_N2_init = register_diag_field('ocean_model','N2_shear_in', diag%axesTi, Time, &
2323 'Interface stratification at horizontal tracer points, as input to kappa-shear', &
23241 's-2', conversion=US%s_to_T**2)
2325 CS%id_S2_mean = register_diag_field('ocean_model','S2_shear_mean', diag%axesTi, Time, &
2326 'Interface shear squared at horizontal tracer points, averaged over timestep in kappa-shear', &
23271 's-2', conversion=US%s_to_T**2)
2328 CS%id_N2_mean = register_diag_field('ocean_model','N2_shear_mean', diag%axesTi, Time, &
2329 'Interface stratification at horizontal tracer points, averaged ove timestep in kappa-shear', &
23301 's-2', conversion=US%s_to_T**2)
2331 endif
2332
23331end function kappa_shear_init
2334
2335!> This function indicates to other modules whether the Jackson et al shear mixing
2336!! parameterization will be used without needing to duplicate the log entry.
23374logical function kappa_shear_is_used(param_file)
2338 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
2339
2340 ! Local variables
2341 character(len=40) :: mdl = "MOM_kappa_shear" ! This module's name.
2342 ! This function reads the parameter "USE_JACKSON_PARAM" and returns its value.
2343
2344 call get_param(param_file, mdl, "USE_JACKSON_PARAM", kappa_shear_is_used, &
23454 default=.false., do_not_log=.true.)
23464end function kappa_shear_is_used
2347
2348!> This function indicates to other modules whether the Jackson et al shear mixing parameterization
2349!! will be used at the vertices without needing to duplicate the log entry. It returns false if
2350!! the Jackson et al scheme is not used or if it is used via calculations at the tracer points.
23514logical function kappa_shear_at_vertex(param_file)
2352 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
2353
2354 ! Local variables
2355 character(len=40) :: mdl = "MOM_kappa_shear" ! This module's name.
2356 logical :: do_kappa_shear
2357 ! This function returns true only if the parameters "USE_JACKSON_PARAM" and "VERTEX_SHEAR" are both true.
2358
23594 kappa_shear_at_vertex = .false.
2360
2361 call get_param(param_file, mdl, "USE_JACKSON_PARAM", do_kappa_shear, &
23624 default=.false., do_not_log=.true.)
23634 if (do_Kappa_Shear) &
2364 call get_param(param_file, mdl, "VERTEX_SHEAR", kappa_shear_at_vertex, &
2365 "If true, do the calculations of the shear-driven mixing "//&
2366 "at the cell vertices (i.e., the vorticity points).", &
23674 default=.false., do_not_log=.true.)
2368
23694end function kappa_shear_at_vertex
2370
2371!> \namespace mom_kappa_shear
2372!!
2373!! By Laura Jackson and Robert Hallberg, 2006-2008
2374!!
2375!! This file contains the subroutines that determine the diapycnal
2376!! diffusivity driven by resolved shears, as specified by the
2377!! parameterizations described in Jackson and Hallberg (JPO, 2008).
2378!!
2379!! The technique by which the 6 equations (for kappa, TKE, u, v, T,
2380!! and S) are solved simultaneously has been dramatically revised
2381!! from the previous version. The previous version was not converging
2382!! in some cases, especially near the surface mixed layer, while the
2383!! revised version does. The revised version solves for kappa and
2384!! TKE with shear and stratification fixed, then marches the density
2385!! and velocities forward with an adaptive (and aggressive) time step
2386!! in a predictor-corrector-corrector emulation of a trapezoidal
2387!! scheme. Run-time-settable parameters determine the tolerance to
2388!! which the kappa and TKE equations are solved and the minimum time
2389!! step that can be taken.
2390
23910end module MOM_kappa_shear