← back to index

src/parameterizations/lateral/MOM_hor_visc.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#include "do_concurrent_compat.h"
6
7!> Calculates horizontal viscosity and viscous stresses
8module MOM_hor_visc
9
10use MOM_checksums, only : hchksum, Bchksum, uvchksum
11use MOM_coms, only : min_across_PEs
12use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
13use MOM_diag_mediator, only : post_product_u, post_product_sum_u
14use MOM_diag_mediator, only : post_product_v, post_product_sum_v
15use MOM_diag_mediator, only : diag_ctrl, time_type
16use MOM_domains, only : pass_var, CORNER, pass_vector, AGRID, BGRID_NE
17use MOM_domains, only : To_All, Scalar_Pair
18use MOM_error_handler, only : MOM_error, FATAL, WARNING, is_root_pe
19use MOM_file_parser, only : get_param, log_version, param_file_type
20use MOM_grid, only : ocean_grid_type
21use MOM_interface_heights, only : thickness_to_dz
22use MOM_lateral_mixing_coeffs, only : VarMix_CS, calc_QG_slopes, calc_QG_Leith_viscosity
23use MOM_barotropic, only : barotropic_CS, barotropic_get_tav
24use MOM_thickness_diffuse, only : thickness_diffuse_CS, thickness_diffuse_get_KH
25use MOM_io, only : MOM_read_data, slasher
26use MOM_MEKE_types, only : MEKE_type
27use MOM_open_boundary, only : ocean_OBC_type, OBC_DIRECTION_E, OBC_DIRECTION_W
28use MOM_open_boundary, only : OBC_DIRECTION_N, OBC_DIRECTION_S
29use MOM_open_boundary, only : OBC_STRAIN_NONE, OBC_STRAIN_ZERO, OBC_STRAIN_FREESLIP
30use MOM_open_boundary, only : OBC_STRAIN_COMPUTED, OBC_STRAIN_SPECIFIED
31use MOM_stochastics, only : stochastic_CS
32use MOM_unit_scaling, only : unit_scale_type
33use MOM_verticalGrid, only : verticalGrid_type
34use MOM_variables, only : accel_diag_ptrs, thermo_var_ptrs
35use MOM_Zanna_Bolton, only : ZB2020_lateral_stress, ZB2020_init, ZB2020_end
36use MOM_Zanna_Bolton, only : ZB2020_CS, ZB2020_copy_gradient_and_thickness
37
38implicit none ; private
39
40#include <MOM_memory.h>
41
42public horizontal_viscosity, hor_visc_nkblock, hor_visc_init, hor_visc_end, hor_visc_vel_stencil
43
44!> Control structure for horizontal viscosity
45type, public :: hor_visc_CS ; private
46 logical :: initialized = .false. !< True if this control structure has been initialized.
47 logical :: Laplacian !< Use a Laplacian horizontal viscosity if true.
48 logical :: biharmonic !< Use a biharmonic horizontal viscosity if true.
49 logical :: debug !< If true, write verbose checksums for debugging purposes.
50 logical :: no_slip !< If true, no slip boundary conditions are used.
51 !! Otherwise free slip boundary conditions are assumed.
52 !! The implementation of the free slip boundary
53 !! conditions on a C-grid is much cleaner than the
54 !! no slip boundary conditions. The use of free slip
55 !! b.c.s is strongly encouraged. The no slip b.c.s
56 !! are not implemented with the biharmonic viscosity.
57 logical :: bound_Kh !< If true, the Laplacian coefficient is locally
58 !! limited to guarantee stability.
59 logical :: EY24_EBT_BS !! If true, use an equivalent barotropic backscatter
60 !! with a stabilizing kill switch in MEKE,
61 !< developed by Yankovsky et al. 2024
62 logical :: bound_Ah !< If true, the biharmonic coefficient is locally
63 !! limited to guarantee stability.
64 real :: Re_Ah !! If nonzero, the biharmonic coefficient is scaled
65 !< so that the biharmonic Reynolds number is equal to this [nondim].
66 real :: bound_coef !< The nondimensional coefficient of the ratio of
67 !! the viscosity bounds to the theoretical maximum
68 !! for stability without considering other terms [nondim].
69 !! The default is 0.8.
70 real :: KS_coef !< A nondimensional coefficient on the biharmonic viscosity that sets the
71 !! kill switch for backscatter. Default is 1.0 [nondim].
72 real :: KS_timescale !< A timescale for computing CFL limit for turning off backscatter [T ~> s].
73 logical :: backscatter_underbound !< If true, the bounds on the biharmonic viscosity are allowed
74 !! to increase where the Laplacian viscosity is negative (due to
75 !! backscatter parameterizations) beyond the largest timestep-dependent
76 !! stable values of biharmonic viscosity when no Laplacian viscosity is
77 !! applied. The default is true for historical reasons, but this option
78 !! probably should not be used as it can lead to numerical instabilities.
79 logical :: Smagorinsky_Kh !< If true, use Smagorinsky nonlinear eddy
80 !! viscosity. KH is the background value.
81 logical :: Smagorinsky_Ah !< If true, use a biharmonic form of Smagorinsky
82 !! nonlinear eddy viscosity. AH is the background.
83 logical :: Leith_Kh !< If true, use 2D Leith nonlinear eddy
84 !! viscosity. KH is the background value.
85 logical :: Modified_Leith !< If true, use extra component of Leith viscosity
86 !! to damp divergent flow. To use, still set Leith_Kh=.TRUE.
87 logical :: use_beta_in_Leith !< If true, includes the beta term in the Leith viscosity
88 logical :: Leith_Ah !< If true, use a biharmonic form of 2D Leith
89 !! nonlinear eddy viscosity. AH is the background.
90 logical :: use_Leithy !< If true, use a biharmonic form of 2D Leith
91 !! nonlinear eddy viscosity with harmonic backscatter.
92 !! Ah is the background. Leithy = Leith+E
93 real :: c_K !< Fraction of energy dissipated by the biharmonic term
94 !! that gets backscattered in the Leith+E scheme. [nondim]
95 logical :: smooth_Ah !< If true (default), then Ah and m_leithy are smoothed.
96 !! This smoothing requires a lot of blocking communication.
97 logical :: use_QG_Leith_visc !< If true, use QG Leith nonlinear eddy viscosity.
98 !! KH is the background value.
99 logical :: bound_Coriolis !< If true & SMAGORINSKY_AH is used, the biharmonic
100 !! viscosity is modified to include a term that
101 !! scales quadratically with the velocity shears.
102 logical :: use_Kh_bg_2d !< Read 2d background viscosity from a file.
103 logical :: Kh_bg_2d_bug !< If true, retain an answer-changing horizontal indexing bug
104 !! in setting the corner-point viscosities when USE_KH_BG_2D=True.
105 real :: Kh_bg_min !< The minimum value allowed for Laplacian horizontal
106 !! viscosity [L2 T-1 ~> m2 s-1]. The default is 0.0.
107 logical :: FrictWork_bug !< If true, retain an answer-changing bug in calculating FrictWork,
108 !! which cancels the h in thickness flux and the h at velocity point.
109 logical :: OBC_strain_bug !< If true, recover a bug that specified shear strain option at open
110 !! boundaries cannot be applied.
111 logical :: use_land_mask !< Use the land mask for the computation of thicknesses
112 !! at velocity locations. This eliminates the dependence on
113 !! arbitrary values over land or outside of the domain.
114 !! Default is False to maintain answers with legacy experiments
115 !! but should be changed to True for new experiments.
116 logical :: anisotropic !< If true, allow anisotropic component to the viscosity.
117 logical :: add_LES_viscosity!< If true, adds the viscosity from Smagorinsky and Leith to
118 !! the background viscosity instead of taking the maximum.
119 real :: Kh_aniso !< The anisotropic viscosity [L2 T-1 ~> m2 s-1].
120 logical :: dynamic_aniso !< If true, the anisotropic viscosity is recomputed as a function
121 !! of state. This is set depending on ANISOTROPIC_MODE.
122 logical :: res_scale_MEKE !< If true, the viscosity contribution from MEKE is scaled by
123 !! the resolution function.
124 logical :: use_GME !< If true, use GME backscatter scheme.
125 integer :: nkblock !< The k block size used in horizontal viscosity calculations [nondim].
126 integer :: answer_date !< The vintage of the order of arithmetic and expressions in the
127 !! horizontal viscosity calculations. Values below 20190101 recover
128 !! the answers from the end of 2018, while higher values use updated
129 !! and more robust forms of the same expressions.
130 real :: GME_h0 !< The strength of GME tapers quadratically to zero when the bathymetric
131 !! total water column thickness is less than GME_H0 [H ~> m or kg m-2]
132 real :: GME_efficiency !< The nondimensional prefactor multiplying the GME coefficient [nondim]
133 real :: GME_limiter !< The absolute maximum value the GME coefficient is allowed to take [L2 T-1 ~> m2 s-1].
134 real :: min_grid_Kh !< Minimum horizontal Laplacian viscosity used to
135 !! limit the grid Reynolds number [L2 T-1 ~> m2 s-1]
136 real :: min_grid_Ah !< Minimun horizontal biharmonic viscosity used to
137 !! limit grid Reynolds number [L4 T-1 ~> m4 s-1]
138 logical :: use_cont_thick !< If true, thickness at velocity points adopts h[uv] in BT_cont from continuity solver.
139 logical :: use_cont_thick_bug !< If true, retain an answer-changing bug for thickness at velocity points.
140 type(ZB2020_CS) :: ZB2020 !< Zanna-Bolton 2020 control structure.
141 logical :: use_ZB2020 !< If true, use Zanna-Bolton 2020 parameterization.
142 logical :: use_circulation !< If true, use circulation theorem to compute vorticity (for ZB20 or Leith)
143
144 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: Kh_bg_xx
145 !< The background Laplacian viscosity at h points [L2 T-1 ~> m2 s-1].
146 !! The actual viscosity may be the larger of this
147 !! viscosity and the Smagorinsky and Leith viscosities.
148 real, allocatable :: Kh_bg_2d(:,:)
149 !< The background Laplacian viscosity at h points [L2 T-1 ~> m2 s-1].
150 !! The actual viscosity may be the larger of this
151 !! viscosity and the Smagorinsky and Leith viscosities.
152 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: Ah_bg_xx
153 !< The background biharmonic viscosity at h points [L4 T-1 ~> m4 s-1].
154 !! The actual viscosity may be the larger of this
155 !! viscosity and the Smagorinsky and Leith viscosities.
156 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: reduction_xx
157 !< The amount by which stresses through h points are reduced
158 !! due to partial barriers [nondim].
159 real, allocatable :: Kh_Max_xx(:,:) !< The maximum permitted Laplacian viscosity [L2 T-1 ~> m2 s-1].
160 real, allocatable :: Ah_Max_xx(:,:) !< The maximum permitted biharmonic viscosity [L4 T-1 ~> m4 s-1].
161 real, allocatable :: Ah_Max_xx_KS(:,:) !< The maximum permitted biharmonic viscosity for
162 !! the kill switch [L4 T-1 ~> m4 s-1].
163 real, allocatable :: n1n2_h(:,:) !< Factor n1*n2 in the anisotropic direction tensor at h-points [nondim]
164 real, allocatable :: n1n1_m_n2n2_h(:,:) !< Factor n1**2-n2**2 in the anisotropic direction tensor at h-points [nondim]
165 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: &
166 grid_sp_h2, & !< Harmonic mean of the squares of the grid [L2 ~> m2]
167 grid_sp_h3 !< Harmonic mean of the squares of the grid^(3/2) [L3 ~> m3]
168 real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEMB_PTR_) :: Kh_bg_xy
169 !< The background Laplacian viscosity at q points [L2 T-1 ~> m2 s-1].
170 !! The actual viscosity may be the larger of this
171 !! viscosity and the Smagorinsky and Leith viscosities.
172 real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEMB_PTR_) :: Ah_bg_xy
173 !< The background biharmonic viscosity at q points [L4 T-1 ~> m4 s-1].
174 !! The actual viscosity may be the larger of this
175 !! viscosity and the Smagorinsky and Leith viscosities.
176 real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEMB_PTR_) :: reduction_xy
177 !< The amount by which stresses through q points are reduced
178 !! due to partial barriers [nondim].
179 real, allocatable :: Kh_Max_xy(:,:) !< The maximum permitted Laplacian viscosity [L2 T-1 ~> m2 s-1].
180 real, allocatable :: Ah_Max_xy(:,:) !< The maximum permitted biharmonic viscosity [L4 T-1 ~> m4 s-1].
181 real, allocatable :: Ah_Max_xy_KS(:,:) !< The maximum permitted biharmonic viscosity for
182 !! the kill switch [L4 T-1 ~> m4 s-1].
183 real, allocatable :: n1n2_q(:,:) !< Factor n1*n2 in the anisotropic direction tensor at q-points [nondim]
184 real, allocatable :: n1n1_m_n2n2_q(:,:) !< Factor n1**2-n2**2 in the anisotropic direction tensor at q-points [nondim]
185
186 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: &
187 dx2h, & !< Pre-calculated dx^2 at h points [L2 ~> m2]
188 dy2h, & !< Pre-calculated dy^2 at h points [L2 ~> m2]
189 dx_dyT, & !< Pre-calculated dx/dy at h points [nondim]
190 dy_dxT !< Pre-calculated dy/dx at h points [nondim]
191 real, allocatable :: m_const_leithy(:,:) !< Pre-calculated .5*sqrt(c_K)*max{dx,dy} [L ~> m]
192 real, allocatable :: m_leithy_max(:,:) !< Pre-calculated 4./max(dx,dy)^2 at h points [L-2 ~> m-2]
193 real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEMB_PTR_) :: &
194 dx2q, & !< Pre-calculated dx^2 at q points [L2 ~> m2]
195 dy2q, & !< Pre-calculated dy^2 at q points [L2 ~> m2]
196 dx_dyBu, & !< Pre-calculated dx/dy at q points [nondim]
197 dy_dxBu !< Pre-calculated dy/dx at q points [nondim]
198 real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEM_) :: &
199 Idx2dyCu, & !< 1/(dx^2 dy) at u points [L-3 ~> m-3]
200 Idxdy2u !< 1/(dx dy^2) at u points [L-3 ~> m-3]
201 real ALLOCABLE_, dimension(NIMEM_,NJMEMB_PTR_) :: &
202 Idx2dyCv, & !< 1/(dx^2 dy) at v points [L-3 ~> m-3]
203 Idxdy2v !< 1/(dx dy^2) at v points [L-3 ~> m-3]
204
205 ! The following variables are precalculated time-invariant combinations of
206 ! parameters and metric terms.
207 real, allocatable :: Laplac2_const_xx(:,:) !< Laplacian metric-dependent constants [L2 ~> m2]
208 real, allocatable :: Biharm6_const_xx(:,:) !< Biharmonic metric-dependent constants [L6 ~> m6]
209 real, allocatable :: Laplac3_const_xx(:,:) !< Laplacian metric-dependent constants [L3 ~> m3]
210 real, allocatable :: Biharm_const_xx(:,:) !< Biharmonic metric-dependent constants [L4 ~> m4]
211 real, allocatable :: Biharm_const2_xx(:,:) !< Biharmonic metric-dependent constants [T L4 ~> s m4]
212 real, allocatable :: Re_Ah_const_xx(:,:) !< Biharmonic metric-dependent constants [L3 ~> m3]
213
214 real, allocatable :: Laplac2_const_xy(:,:) !< Laplacian metric-dependent constants [L2 ~> m2]
215 real, allocatable :: Biharm6_const_xy(:,:) !< Biharmonic metric-dependent constants [L6 ~> m6]
216 real, allocatable :: Laplac3_const_xy(:,:) !< Laplacian metric-dependent constants [L3 ~> m3]
217 real, allocatable :: Biharm_const_xy(:,:) !< Biharmonic metric-dependent constants [L4 ~> m4]
218 real, allocatable :: Biharm_const2_xy(:,:) !< Biharmonic metric-dependent constants [T L4 ~> s m4]
219 real, allocatable :: Re_Ah_const_xy(:,:) !< Biharmonic metric-dependent constants [L3 ~> m3]
220
221 type(diag_ctrl), pointer :: diag => NULL() !< structure to regulate diagnostics
222
223 ! real, allocatable :: hf_diffu(:,:,:) ! Zonal horizontal viscous acceleleration times
224 ! ! fractional thickness [L T-2 ~> m s-2].
225 ! real, allocatable :: hf_diffv(:,:,:) ! Meridional horizontal viscous acceleleration times
226 ! ! fractional thickness [L T-2 ~> m s-2].
227 ! 3D diagnostics hf_diffu(diffv) are commented because there is no clarity on proper remapping grid option.
228 ! The code is retained for debugging purposes in the future.
229
230 integer :: num_smooth_gme !< number of smoothing passes for the GME fluxes.
231 !>@{
232 !! Diagnostic id
233 integer :: id_grid_Re_Ah = -1, id_grid_Re_Kh = -1
234 integer :: id_diffu = -1, id_diffv = -1
235 ! integer :: id_hf_diffu = -1, id_hf_diffv = -1
236 integer :: id_h_diffu = -1, id_h_diffv = -1
237 integer :: id_hf_diffu_2d = -1, id_hf_diffv_2d = -1
238 integer :: id_intz_diffu_2d = -1, id_intz_diffv_2d = -1
239 integer :: id_diffu_visc_rem = -1, id_diffv_visc_rem = -1
240 integer :: id_Ah_h = -1, id_Ah_q = -1
241 integer :: id_Kh_h = -1, id_Kh_q = -1
242 integer :: id_GME_coeff_h = -1, id_GME_coeff_q = -1
243 integer :: id_dudx_bt = -1, id_dvdy_bt = -1
244 integer :: id_dudy_bt = -1, id_dvdx_bt = -1
245 integer :: id_vort_xy_q = -1, id_div_xx_h = -1
246 integer :: id_sh_xy_q = -1, id_sh_xx_h = -1
247 integer :: id_FrictWork = -1, id_FrictWorkIntz = -1
248 integer :: id_FrictWork_bh = -1, id_FrictWorkIntz_bh = -1
249 integer :: id_FrictWork_GME = -1
250 integer :: id_normstress = -1, id_shearstress = -1
251 integer :: id_visc_limit_h = -1, id_visc_limit_q = -1
252 integer :: id_visc_limit_h_flag = -1, id_visc_limit_q_flag = -1
253 integer :: id_visc_limit_h_frac = -1, id_visc_limit_q_frac = -1
254 integer :: id_BS_coeff_h = -1, id_BS_coeff_q = -1
255 !>@}
256
257end type hor_visc_CS
258
259contains
260
261!> Calculates the acceleration due to the horizontal viscosity.
262!!
263!! A combination of biharmonic and Laplacian forms can be used. The coefficient
264!! may either be a constant or a shear-dependent form. The biharmonic is
265!! determined by twice taking the divergence of an appropriately defined stress
266!! tensor. The Laplacian is determined by doing so once.
267!!
268!! To work, the following fields must be set outside of the usual
269!! is:ie range before this subroutine is called:
270!! u(is-2:ie+2,js-2:je+2)
271!! v(is-2:ie+2,js-2:je+2)
272!! h(is-1:ie+1,js-1:je+1) or up to h(is-2:ie+2,js-2:je+2) with some Leith options.
27350subroutine horizontal_viscosity(u, v, h, uh, vh, diffu, diffv, MEKE, VarMix, G, GV, US, &
27450 CS, nkblock, tv, dt, OBC, BT, TD, ADp, hu_cont, hv_cont, STOCH)
275 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
276 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
277 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
278 intent(in) :: u !< The zonal velocity [L T-1 ~> m s-1].
279 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
280 intent(in) :: v !< The meridional velocity [L T-1 ~> m s-1].
281 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
282 intent(inout) :: h !< Layer thicknesses [H ~> m or kg m-2].
283 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
284 intent(in) :: uh !< The zonal volume transport [H L2 T-1 ~> m3 s-1].
285 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
286 intent(in) :: vh !< The meridional volume transport [H L2 T-1 ~> m3 s-1].
287 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
288 intent(out) :: diffu !< Zonal acceleration due to convergence of
289 !! along-coordinate stress tensor [L T-2 ~> m s-2]
290 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
291 intent(out) :: diffv !< Meridional acceleration due to convergence
292 !! of along-coordinate stress tensor [L T-2 ~> m s-2].
293 type(MEKE_type), intent(inout) :: MEKE !< MEKE fields
294 !! related to Mesoscale Eddy Kinetic Energy.
295 type(VarMix_CS), intent(inout) :: VarMix !< Variable mixing control structure
296 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
297 type(hor_visc_CS), intent(inout) :: CS !< Horizontal viscosity control structure
298 integer, intent(in) :: nkblock !< The effective k-block size [nondim]
299 type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various
300 !! thermodynamic variables
301 real, intent(in) :: dt !< Time increment [T ~> s]
302 type(ocean_OBC_type), optional, pointer :: OBC !< Pointer to an open boundary condition type
303 type(barotropic_CS), optional, intent(in) :: BT !< Barotropic control structure
304 type(thickness_diffuse_CS), optional, intent(in) :: TD !< Thickness diffusion control structure
305 type(accel_diag_ptrs), optional, intent(in) :: ADp !< Acceleration diagnostics
306 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
307 optional, intent(inout) :: hu_cont !< Layer thickness at u-points [H ~> m or kg m-2].
308 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
309 optional, intent(inout) :: hv_cont !< Layer thickness at v-points [H ~> m or kg m-2].
310 type(stochastic_CS), intent(inout), optional :: STOCH !< Stochastic control structure
311
312 ! Local variables
313 real, dimension(SZIB_(G),SZJ_(G),nkblock) :: &
31450 Del2u, & ! The u-component of the Laplacian of velocity [L-1 T-1 ~> m-1 s-1]
31550 h_u ! Thickness interpolated to u points [H ~> m or kg m-2].
316 real, dimension(SZI_(G),SZJB_(G),nkblock) :: &
31750 Del2v, & ! The v-component of the Laplacian of velocity [L-1 T-1 ~> m-1 s-1]
31850 h_v ! Thickness interpolated to v points [H ~> m or kg m-2].
319 real, dimension(SZI_(G),SZJB_(G)) :: &
32050 dudx_bt, dvdy_bt ! components in the barotropic horizontal tension [T-1 ~> s-1]
321 real, dimension(SZI_(G),SZJ_(G),nkblock) :: &
32250 sh_xx, & ! horizontal tension (du/dx - dv/dy) including metric terms [T-1 ~> s-1]
32350 sh_xx_smooth ! horizontal tension from smoothed velocity including metric terms [T-1 ~> s-1]
324 real, dimension(SZI_(G),SZJ_(G)) :: &
32550 sh_xx_bt ! barotropic horizontal tension (du/dx - dv/dy) including metric terms [T-1 ~> s-1]
326 real, dimension(SZI_(G),SZJ_(G),nkblock) :: &
32750 str_xx, & ! str_xx is the diagonal term in the stress tensor [H L2 T-2 ~> m3 s-2 or kg s-2], but
328 ! at some points in the code it is not yet layer integrated, so is in [L2 T-2 ~> m2 s-2].
32950 str_xx_GME, & ! smoothed diagonal term in the stress tensor from GME [L2 T-2 ~> m2 s-2]
33050 bhstr_xx, & ! A copy of str_xx that only contains the biharmonic contribution [H L2 T-2 ~> m3 s-2 or kg s-2]
33150 FrictWorkIntz, & ! depth integrated energy dissipated by lateral friction [R Z L2 T-3 ~> W m-2]
33250 FrictWorkIntz_bh, & ! depth integrated energy dissipated by biharmonic lateral friction [R Z L2 T-3 ~> W m-2]
33350 grad_vort_mag_h, & ! Magnitude of vorticity gradient at h-points [L-1 T-1 ~> m-1 s-1]
33450 grad_vort_mag_h_2d, & ! Magnitude of 2d vorticity gradient at h-points [L-1 T-1 ~> m-1 s-1]
33550 grad_div_mag_h, & ! Magnitude of divergence gradient at h-points [L-1 T-1 ~> m-1 s-1]
33650 dudx, dvdy ! components in the horizontal tension [T-1 ~> s-1]
337 real, dimension(SZI_(G),SZJ_(G)) :: &
33850 GME_effic_h ! The filtered efficiency of the GME terms at h points [nondim]
339 real, dimension(SZI_(G),SZJ_(G),nkblock) :: &
34050 m_leithy ! Kh=m_leithy*Ah in Leith+E parameterization [L-2 ~> m-2]
341 real :: Del2vort_h ! Laplacian of vorticity at h-points [L-2 T-1 ~> m-2 s-1]
342
343 real, dimension(SZIB_(G),SZJB_(G),nkblock) :: &
34450 dvdx, dudy, & ! components in the shearing strain [T-1 ~> s-1]
34550 dvdx_smooth, dudy_smooth, & ! components in the shearing strain from smoothed velocity [T-1 ~> s-1]
34650 dDel2vdx, dDel2udy ! Components in the biharmonic equivalent of the shearing strain [L-2 T-1 ~> m-2 s-1]
347 real, dimension(SZIB_(G),SZJB_(G)) :: &
34850 dvdx_bt, dudy_bt ! components in the barotropic shearing strain [T-1 ~> s-1]
349 real, dimension(SZIB_(G),SZJB_(G),nkblock) :: &
35050 sh_xy, & ! horizontal shearing strain (du/dy + dv/dx) including metric terms [T-1 ~> s-1]
35150 sh_xy_smooth ! horizontal shearing strain from smoothed velocity including metric terms [T-1 ~> s-1]
352 real, dimension(SZIB_(G),SZJB_(G)) :: &
35350 sh_xy_bt ! barotropic horizontal shearing strain (du/dy + dv/dx) inc. metric terms [T-1 ~> s-1]
354 real, dimension(SZIB_(G),SZJB_(G),nkblock) :: &
35550 str_xy, & ! str_xy is the cross term in the stress tensor [H L2 T-2 ~> m3 s-2 or kg s-2], but
356 ! at some points in the code it is not yet layer integrated, so is in [L2 T-2 ~> m2 s-2].
35750 str_xy_GME, & ! smoothed cross term in the stress tensor from GME [L2 T-2 ~> m2 s-2]
35850 bhstr_xy, & ! A copy of str_xy that only contains the biharmonic contribution [H L2 T-2 ~> m3 s-2 or kg s-2]
35950 vort_xy, & ! Vertical vorticity (dv/dx - du/dy) including metric terms [T-1 ~> s-1]
36050 vort_xy_smooth, & ! Vertical vorticity including metric terms, smoothed [T-1 ~> s-1]
36150 grad_vort_mag_q, & ! Magnitude of vorticity gradient at q-points [L-1 T-1 ~> m-1 s-1]
36250 grad_vort_mag_q_2d, & ! Magnitude of 2d vorticity gradient at q-points [L-1 T-1 ~> m-1 s-1]
36350 Del2vort_q, & ! Laplacian of vorticity at q-points [L-2 T-1 ~> m-2 s-1]
36450 grad_div_mag_q, & ! Magnitude of divergence gradient at q-points [L-1 T-1 ~> m-1 s-1]
36550 hq ! harmonic mean of the harmonic means of the u- & v point thicknesses [H ~> m or kg m-2]
366 ! This form guarantees that hq/hu < 4.
367 real, dimension(SZIB_(G),SZJB_(G)) :: &
36850 GME_effic_q ! The filtered efficiency of the GME terms at q points [nondim]
369
370 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)) :: &
37150 Ah_q, & ! biharmonic viscosity at corner points [L4 T-1 ~> m4 s-1]
37250 Kh_q, & ! Laplacian viscosity at corner points [L2 T-1 ~> m2 s-1]
37350 vort_xy_q, & ! vertical vorticity at corner points [T-1 ~> s-1]
37450 sh_xy_q, & ! horizontal shearing strain at corner points [T-1 ~> s-1]
37550 GME_coeff_q, & !< GME coeff. at q-points [L2 T-1 ~> m2 s-1]
37650 visc_limit_q, & ! used to stabilize the EY24_EBT_BS backscatter [nondim]
37750 visc_limit_q_flag, & ! determines whether backscatter is shut off [nondim]
37850 visc_limit_q_frac, & ! determines how close backscatter is to shutting off [nondim]
37950 BS_coeff_q, & ! A diagnostic array of the backscatter coefficient [L2 T-1 ~> m2 s-1]
38050 ShSt ! A diagnostic array of shear stress [T-1 ~> s-1].
381 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)+1) :: &
38250 KH_u_GME, & !< Isopycnal height diffusivities in u-columns [L2 T-1 ~> m2 s-1]
38350 slope_x !< Isopycnal slope in i-direction [Z L-1 ~> nondim]
384 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)+1) :: &
38550 KH_v_GME, & !< Isopycnal height diffusivities in v-columns [L2 T-1 ~> m2 s-1]
38650 slope_y !< Isopycnal slope in j-direction [Z L-1 ~> nondim]
387 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: &
38850 Ah_h, & ! biharmonic viscosity at thickness points [L4 T-1 ~> m4 s-1]
38950 Kh_h, & ! Laplacian viscosity at thickness points [L2 T-1 ~> m2 s-1]
39050 dz, & ! Height change across layers [Z ~> m]
39150 FrictWork, & ! work done by MKE dissipation mechanisms [R Z L2 T-3 ~> W m-2]
39250 FrictWork_bh, & ! work done by the biharmonic MKE dissipation mechanisms [R Z L2 T-3 ~> W m-2]
39350 FrictWork_GME, & ! work done by GME [R Z L2 T-3 ~> W m-2]
39450 div_xx_h, & ! horizontal divergence [T-1 ~> s-1]
39550 sh_xx_h, & ! horizontal tension (du/dx - dv/dy) including metric terms [T-1 ~> s-1]
39650 NoSt, & ! A diagnostic array of normal stress [T-1 ~> s-1].
39750 BS_coeff_h ! A diagnostic array of the backscatter coefficient [L2 T-1 ~> m2 s-1]
398 real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
39950 grid_Re_Kh, & ! Grid Reynolds number for Laplacian horizontal viscosity at h points [nondim]
40050 grid_Re_Ah, & ! Grid Reynolds number for Biharmonic horizontal viscosity at h points [nondim]
40150 GME_coeff_h, & ! GME coefficient at h-points [L2 T-1 ~> m2 s-1]
40250 visc_limit_h, & ! Used to stabilize the EY24_EBT_BS backscatter [nondim]
40350 visc_limit_h_flag, & ! determines whether backscatter is shut off [nondim]
40450 visc_limit_h_frac ! determines how close backscatter is to shutting off [nondim]
405 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)) :: &
40650 u_smooth ! Zonal velocity, smoothed with a spatial low-pass filter [L T-1 ~> m s-1]
407 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)) :: &
40850 v_smooth ! Meridional velocity, smoothed with a spatial low-pass filter [L T-1 ~> m s-1]
409 real :: AhSm ! Smagorinsky biharmonic viscosity [L4 T-1 ~> m4 s-1]
410 real :: AhLth ! 2D Leith biharmonic viscosity [L4 T-1 ~> m4 s-1]
411 real :: Shear_mag_bc ! Shear_mag value in backscatter [T-1 ~> s-1]
412 real :: sh_xx_sq ! Square of tension (sh_xx) [T-2 ~> s-2]
413 real :: sh_xy_sq ! Square of shearing strain (sh_xy) [T-2 ~> s-2]
414 real :: h2uq, h2vq ! temporary variables [H2 ~> m2 or kg2 m-4].
415 real :: hu, hv ! Thicknesses interpolated by arithmetic means to corner
416 ! points; these are first interpolated to u or v velocity
417 ! points where masks are applied [H ~> m or kg m-2].
418 real :: h_neglect ! thickness so small it can be lost in roundoff and so neglected [H ~> m or kg m-2]
419 real :: h_neglect3 ! h_neglect^3 [H3 ~> m3 or kg3 m-6]
420 real :: h_min ! Minimum h at the 4 neighboring velocity points [H ~> m]
421 real :: Kh_max_here ! The local maximum Laplacian viscosity for stability [L2 T-1 ~> m2 s-1]
422 real :: RoScl ! The scaling function for MEKE source term [nondim]
423 real :: FatH ! abs(f) at h-point for MEKE source term [T-1 ~> s-1]
424 real :: local_strain ! Local variable for interpolating computed strain rates [T-1 ~> s-1].
425 real :: meke_res_fn ! A copy of the resolution scaling factor if being applied to MEKE [nondim]. Otherwise = 1.
426 real :: GME_coeff ! The GME (negative) viscosity coefficient [L2 T-1 ~> m2 s-1]
427 real :: DY_dxBu ! Ratio of meridional over zonal grid spacing at vertices [nondim]
428 real :: DX_dyBu ! Ratio of zonal over meridional grid spacing at vertices [nondim]
429 real :: Sh_F_pow ! The ratio of shear over the absolute value of f raised to some power and rescaled [nondim]
430 real :: backscat_subround ! The ratio of f over Shear_mag that is so small that the backscatter
431 ! calculation gives the same value as if f were 0 [nondim].
432 real :: KE ! Local kinetic energy [L2 T-2 ~> m2 s-2]
433 real :: d_del2u ! dy-weighted Laplacian(u) diff in x [L-2 T-1 ~> m-2 s-1]
434 real :: d_del2v ! dx-weighted Laplacian(v) diff in y [L-2 T-1 ~> m-2 s-1]
435 real :: d_str ! Stress tensor update [L2 T-2 ~> m2 s-2]
436 real :: grad_vort ! Vorticity gradient magnitude [L-1 T-1 ~> m-1 s-1]
437 real :: grad_vort_qg ! QG-based vorticity gradient magnitude [L-1 T-1 ~> m-1 s-1]
438 real :: grid_Kh ! Laplacian viscosity bound by grid [L2 T-1 ~> m2 s-1]
439 real :: grid_Ah ! Biharmonic viscosity bound by grid [L4 T-1 ~> m4 s-1]
440 real :: dudx_smooth, dvdy_smooth ! components in the horizontal tension from smoothed velocity [T-1 ~> s-1]
441
442 logical :: rescale_Kh
443 logical :: find_FrictWork
444 logical :: apply_OBC = .false.
445 logical :: apply_OBC_strain
446 logical :: use_MEKE_Ku
447 logical :: use_MEKE_Au
448 logical :: skeb_use_frict
449 logical :: use_cont_huv
450 logical :: use_kh_struct
451 logical :: use_Leith ! True if any Leith parameterizations are enabled
452 logical :: use_vort_xy ! True if vort_xy must be computed
453 logical :: use_Smag ! True if a Smagorinsky viscosity is enabled
454 integer :: is_vort, ie_vort, js_vort, je_vort ! Loop ranges for vorticity terms
455 integer :: is_Kh, ie_Kh, js_Kh, je_Kh ! Loop ranges for thickness point viscosities
456 integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
457 integer :: i, j, k, kk, n, kstart, kend, kmax
458 real :: inv_PI3, inv_PI2, inv_PI6 ! Powers of the inverse of pi [nondim]
459 real :: tmp
460
461 ! Fields evaluated on active layers, used for constructing 3D stress fields
462 ! NOTE: The position of these declarations can impact performance, due to the
463 ! very large number of stack arrays in this function. Move with caution!
464 ! NOTE: Several of these are declared with the memory extent of q-points, but the
465 ! same arrays are also used at h-points to reduce the memory footprint of this
466 ! module, so they should never be used in halo point or checksum calls.
467 real, dimension(SZIB_(G),SZJB_(G),nkblock) :: &
46825 Ah, & ! biharmonic viscosity (h or q) [L4 T-1 ~> m4 s-1]
46950 Kh, & ! Laplacian viscosity (h or q) [L2 T-1 ~> m2 s-1]
47050 Shear_mag, & ! magnitude of the shear (h or q) [T-1 ~> s-1]
47150 vert_vort_mag, & ! magnitude of the vertical vorticity gradient (h or q) [L-1 T-1 ~> m-1 s-1]
47250 vert_vort_mag_smooth, & ! magnitude of gradient of smoothed vertical vorticity (h or q) [L-1 T-1 ~> m-1 s-1]
47350 hrat_min, & ! h_min divided by the thickness at the stress point (h or q) [nondim]
47425 visc_bound_rem ! fraction of overall viscous bounds that remain to be applied (h or q) [nondim]
475
47625 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
47725 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
478
47925 h_neglect = GV%H_subroundoff
480 !h_neglect3 = h_neglect**3
48125 h_neglect3 = h_neglect*h_neglect*h_neglect
48225 inv_PI3 = 1.0/((4.0*atan(1.0))**3)
48325 inv_PI2 = 1.0/((4.0*atan(1.0))**2)
48425 inv_PI6 = inv_PI3 * inv_PI3
485
48625 if (CS%EY24_EBT_BS) then
4870 visc_limit_h(:,:,:) = 0.
4880 visc_limit_q(:,:,:) = 0.
4890 visc_limit_h_flag(:,:,:) = 0.
4900 visc_limit_q_flag(:,:,:) = 0.
4910 visc_limit_h_frac(:,:,:) = 0.
4920 visc_limit_q_frac(:,:,:) = 0.
493 endif
494
49525 skeb_use_frict = .false.
49625 if (present(STOCH)) skeb_use_frict = STOCH%skeb_use_frict
497
49825 if (CS%use_Leithy) m_leithy(:,:,:) = 0.0 ! Initialize
499
50025 if (present(OBC)) then ; if (associated(OBC)) then ; if (OBC%OBC_pe) then
5010 apply_OBC = OBC%Flather_u_BCs_exist_globally .or. OBC%Flather_v_BCs_exist_globally
5020 apply_OBC = .true.
503 endif ; endif ; endif
504
50525 apply_OBC_strain = .false.
50625 if (present(OBC)) then ; if (associated(OBC)) then
507 apply_OBC_strain = (OBC%strain_config /= OBC_STRAIN_NONE) &
5080 .and. ((.not. CS%OBC_strain_bug) .or. (OBC%strain_config /= OBC_STRAIN_SPECIFIED))
509 endif ; endif
510
51125 if (.not.CS%initialized) call MOM_error(FATAL, &
5120 "MOM_hor_visc: Module must be initialized before it is used.")
513
51425 if (.not.(CS%Laplacian .or. CS%biharmonic)) return
515
51625 find_FrictWork = (CS%id_FrictWork > 0)
51725 if (CS%id_FrictWorkIntz > 0) find_FrictWork = .true.
518
51925 if (allocated(MEKE%mom_src)) find_FrictWork = .true.
52025 use_kh_struct = allocated(VarMix%BS_struct)
52125 backscat_subround = 0.0
52225 if (find_FrictWork .and. allocated(MEKE%mom_src) .and. (MEKE%backscatter_Ro_c > 0.0) .and. &
523 (MEKE%backscatter_Ro_Pow /= 0.0)) &
5240 backscat_subround = (1.0e-16/MEKE%backscatter_Ro_c)**(1.0/MEKE%backscatter_Ro_Pow)
525
526 ! Toggle whether to use a Laplacian viscosity derived from MEKE
52725 use_MEKE_Ku = allocated(MEKE%Ku)
52825 use_MEKE_Au = allocated(MEKE%Au)
529
53025 use_cont_huv = CS%use_cont_thick .and. present(hu_cont) .and. present(hv_cont)
53125 if (use_cont_huv .and. .not.CS%use_cont_thick_bug) then
5320 call pass_vector(hu_cont, hv_cont, G%domain, To_All+Scalar_Pair, halo=2)
533 endif
534
53525 rescale_Kh = .false.
53625 if (VarMix%use_variable_mixing) then
53725 rescale_Kh = VarMix%Resoln_scaled_Kh
538 if ((rescale_Kh .or. CS%res_scale_MEKE) &
53925 .and. (.not. allocated(VarMix%Res_fn_h) .or. .not. allocated(VarMix%Res_fn_q))) &
540 call MOM_error(FATAL, "MOM_hor_visc: VarMix%Res_fn_h and VarMix%Res_fn_q "//&
5410 "both need to be associated with Resoln_scaled_Kh or RES_SCALE_MEKE_VISC.")
5420 elseif (CS%res_scale_MEKE) then
543 call MOM_error(FATAL, "MOM_hor_visc: VarMix needs to be associated if "//&
5440 "RES_SCALE_MEKE_VISC is True.")
545 endif
546
547 ! Set the halo sizes used for the thickness-point viscosities.
54825 if (CS%use_Leithy .or. CS%debug) then
5490 js_Kh = js-1 ; je_Kh = je+1 ; is_Kh = is-1 ; ie_Kh = ie+1
550 else
55125 js_Kh = Jsq ; je_Kh = je+1 ; is_Kh = Isq ; ie_Kh = ie+1
552 endif
553
554 ! Set the halo sizes used for the vorticity calculations.
55525 if ((CS%Leith_Kh) .or. (CS%Leith_Ah) .or. (CS%use_Leithy)) then
5560 js_vort = js_Kh-2 ; je_vort = Jeq+2 ; is_vort = is_Kh-2 ; ie_vort = Ieq+2
5570 if ((G%isc-G%isd < 3) .or. (G%isc-G%isd < 3)) call MOM_error(FATAL, &
5580 "The minimum halo size is 3 when a Leith viscosity is being used.")
559 else
56025 js_vort = js-2 ; je_vort = Jeq+1 ; is_vort = is-2 ; ie_vort = Ieq+1
561 endif
562
56325 if (CS%use_GME) then
564 call hor_visc_GME_setup(G, GV, US, CS, h, BT, TD, nkblock, &
565 dudx_bt, dvdy_bt, dvdx_bt, dudy_bt, sh_xx_bt, sh_xy_bt, &
566 GME_effic_h, GME_effic_q, KH_u_GME, KH_v_GME, &
5670 GME_coeff_h, GME_coeff_q, str_xx_GME, str_xy_GME)
568 ! NOTE: sh_xx_bt, sh_xy_bt, GME_effic_h, GME_effic_q, KH_u_GME and KH_v_GME
569 ! are computed on the host above and are only read (never written) on the
570 ! device. dudx_bt, dvdy_bt, dvdx_bt and dudy_bt are only used on the
571 ! host (post_data diagnostics), so they are not mapped at all.
572 !$omp target enter data map(to: sh_xx_bt, sh_xy_bt, GME_effic_h, GME_effic_q, KH_u_GME, KH_v_GME)
573 ! NOTE: GME_coeff_h, GME_coeff_q, str_xx_GME and str_xy_GME are written and
574 ! read entirely on the device (aside from the smooth_GME host round-trip
575 ! below), so a bare alloc is enough on entry.
576 !$omp target enter data map(alloc: GME_coeff_h, GME_coeff_q, str_xx_GME, str_xy_GME)
577 endif
578
57925 if (CS%use_Leithy) then
580 ! Smooth the velocity. Right now it happens twice. In the future
581 ! one might make the number of smoothing cycles a user-specified parameter
5820 do k=1,nz
583 ! One call applies the filter twice
5840 u_smooth(:,:,k) = u(:,:,k)
5850 v_smooth(:,:,k) = v(:,:,k)
5860 call smooth_x9_uv(G, u_smooth(:,:,k), v_smooth(:,:,k), zero_land=.false.)
587 enddo
5880 call pass_vector(u_smooth, v_smooth, G%Domain)
589 endif
590
59125 if (CS%use_QG_Leith_visc .and. ((CS%Leith_Kh) .or. (CS%Leith_Ah))) then
5920 call thickness_to_dz(h, tv, dz, G, GV, US, halo_size=2)
593 ! Calculate isopycnal slopes that will be used for some forms of viscosity.
5940 call calc_QG_slopes(h, tv, dt, G, GV, US, slope_x, slope_y, VarMix, OBC)
595 ! If the following halo update is added, the calculations in calc_QG_slopes could work on just
596 ! the computational domains, and some halo updates outside of this routine could be smaller.
597 ! call pass_vector(slope_x, slope_y, G%Domain, halo=2)
598 endif
599
60025 if (find_FrictWork .and. allocated(MEKE%mom_src)) then
6010 do j=js,je ; do i=is,ie
6020 MEKE%mom_src(i,j) = 0.
603 enddo ; enddo
604
6050 if (allocated(MEKE%mom_src_bh)) then
6060 do j=js,je ; do i=is,ie
6070 MEKE%mom_src_bh(i,j) = 0.
608 enddo ; enddo
609 endif
610
6110 if (allocated(MEKE%GME_snk)) then
6120 do j=js,je ; do i=is,ie
6130 MEKE%GME_snk(i,j) = 0.
614 enddo ; enddo
615 endif
616 endif
617
61825 use_Leith = CS%Leith_Kh .or. CS%Leith_Ah .or. CS%use_Leithy
61925 use_vort_xy = use_Leith .or. CS%id_vort_xy_q > 0 .or. CS%use_ZB2020
62025 use_Smag = CS%Smagorinsky_Kh .or. CS%Smagorinsky_Ah
621
622 !$omp target enter data map(alloc: dudx, dudy, dvdx, dvdy, sh_xx, sh_xy)
623 !$omp target enter data map(alloc: h_u, h_v, hq)
624 !$omp target enter data map(alloc: str_xx, str_xy, ShSt)
625 !$omp target enter data map(alloc: Del2u, Del2v) if (CS%biharmonic)
626 !$omp target enter data map(alloc: dDel2vdx, dDel2udy) if (CS%biharmonic)
627 !$omp target enter data map(alloc: Shear_mag) if (use_Smag)
628 !$omp target enter data map(alloc: Kh) if (CS%Laplacian .or. CS%biharmonic)
629 !$omp target enter data map(alloc: Ah) if (CS%biharmonic)
630 ! TODO: Only needed if FrictWork_bh is true, and currently only used on CPU,
631 ! but I do not yet see any benefit to breaking up the calculation.
632 !$omp target enter data map(alloc: bhstr_xx, bhstr_xy) if (CS%biharmonic)
633
634 !$omp target enter data map(alloc: hrat_min) &
635 !$omp if (CS%bound_Kh .or. CS%bound_Ah)
636 !$omp target enter data map(alloc: visc_bound_rem) &
637 !$omp if (CS%bound_Kh .or. CS%bound_Ah)
638 !$omp target enter data map(alloc: sh_xy_q) &
639 !$omp if (CS%id_sh_xy_q > 0)
640
641 !$omp target enter data map(alloc: vert_vort_mag)
642 !$omp target enter data map(alloc: sh_xx_smooth) if (CS%use_Leithy .or. CS%biharmonic)
643 !!$omp target enter data map(alloc: CS%use_Leithy)
644
6451900 do kstart=1,nz,nkblock
6461875 kend = min(kstart+nkblock-1,nz)
6471875 kmax = kend-kstart+1
6481875 k=kstart
649
650 ! The following are the forms of the horizontal tension and horizontal
651 ! shearing strain advocated by Smagorinsky (1993) and discussed in
652 ! Griffies and Hallberg (2000).
653
654 ! NOTE: There is a ~1% speedup when the tension and shearing loops below
655 ! are fused (presumably due to shared access of Id[xy]C[uv]). However,
656 ! this breaks the center/vertex index case convention, and also evaluates
657 ! the dudx and dvdy terms beyond their valid bounds.
658 ! TODO: Explore methods for retaining both the syntax and speedup.
659
660 ! Calculate horizontal tension
661234375 do concurrent (kk=1:kmax, j=Jsq-1:Jeq+2, i=Isq-1:Ieq+2) DO_LOCALITY(local(k))
66214880000 k = kstart + kk - 1
663 dudx(i,j,kk) = CS%DY_dxT(i,j)*((G%IdyCu(I,j) * u(I,j,k)) - &
66414880000 (G%IdyCu(I-1,j) * u(I-1,j,k)))
665 dvdy(i,j,kk) = CS%DX_dyT(i,j)*((G%IdxCv(i,J) * v(i,J,k)) - &
66614880000 (G%IdxCv(i,J-1) * v(i,J-1,k)))
66729994375 sh_xx(i,j,kk) = dudx(i,j,kk) - dvdy(i,j,kk)
668 enddo
669
670 ! Components for the shearing strain
6711875 do concurrent (kk=1:kmax, J=js_vort:je_vort, I=is_vort:ie_vort) DO_LOCALITY(local(k))
67214529375 k = kstart + kk - 1
67314529375 dvdx(I,J,kk) = CS%DY_dxBu(I,J)*((v(i+1,J,k)*G%IdyCv(i+1,J)) - (v(i,J,k)*G%IdyCv(i,J)))
67429291250 dudy(I,J,kk) = CS%DX_dyBu(I,J)*((u(I,j+1,k)*G%IdxCu(I,j+1)) - (u(I,j,k)*G%IdxCu(I,j)))
675 enddo
676
6771875 if (CS%use_Leithy) then
678 ! Calculate horizontal tension from smoothed velocity
6790 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1) DO_LOCALITY(local(k, dudx_smooth, dvdy_smooth))
6800 k = kstart + kk - 1
681 dudx_smooth = CS%DY_dxT(i,j)*((G%IdyCu(I,j) * u_smooth(I,j,k)) - &
6820 (G%IdyCu(I-1,j) * u_smooth(I-1,j,k)))
683 dvdy_smooth = CS%DX_dyT(i,j)*((G%IdxCv(i,J) * v_smooth(i,J,k)) - &
6840 (G%IdxCv(i,J-1) * v_smooth(i,J-1,k)))
6850 sh_xx_smooth(i,j,kk) = dudx_smooth - dvdy_smooth
686 enddo
687
688 ! Components for the shearing strain from smoothed velocity
6890 do concurrent (kk=1:kmax, J=js_Kh-1:je_Kh, I=is_Kh-1:ie_Kh) DO_LOCALITY(local(k))
6900 k = kstart + kk - 1
691 dvdx_smooth(I,J,kk) = CS%DY_dxBu(I,J) * &
6920 ((v_smooth(i+1,J,k)*G%IdyCv(i+1,J)) - (v_smooth(i,J,k)*G%IdyCv(i,J)))
693 dudy_smooth(I,J,kk) = CS%DX_dyBu(I,J) * &
6940 ((u_smooth(I,j+1,k)*G%IdxCu(I,j+1)) - (u_smooth(I,j,k)*G%IdxCu(I,j)))
695 enddo
696 endif ! use Leith+E
697
6981875 if (CS%id_normstress > 0) then
6990 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
7000 k = kstart + kk - 1
7010 NoSt(i,j,k) = sh_xx(i,j,kk)
702 enddo
703 endif
704
705 ! Interpolate the thicknesses to velocity points.
706 ! The extra wide halos are to accommodate the cross-corner-point projections
707 ! in OBCs, which are not ordinarily be necessary, and might not be necessary
708 ! even with OBCs if the accelerations are zeroed at OBC points, in which
709 ! case the j-loop for h_u could collapse to j=js=1,je+1. -RWH
7101875 if (use_cont_huv) then
7110 do concurrent (kk=1:kmax, j=js-2:je+2, I=Isq-1:Ieq+1) DO_LOCALITY(local(k))
7120 k = kstart + kk - 1
7130 h_u(I,j,kk) = hu_cont(I,j,k)
714 enddo
7150 do concurrent (kk=1:kmax, J=Jsq-1:Jeq+1, i=is-2:ie+2) DO_LOCALITY(local(k))
7160 k = kstart + kk - 1
7170 h_v(i,J,kk) = hv_cont(i,J,k)
718 enddo
7191875 elseif (CS%use_land_mask) then
7200 do concurrent (kk=1:kmax, j=js-2:je+2, I=is-2:Ieq+1) DO_LOCALITY(local(k))
7210 k = kstart + kk - 1
7220 h_u(I,j,kk) = 0.5 * (G%mask2dT(i,j)*h(i,j,k) + G%mask2dT(i+1,j)*h(i+1,j,k))
723 enddo
7240 do concurrent (kk=1:kmax, J=js-2:Jeq+1, i=is-2:ie+2) DO_LOCALITY(local(k))
7250 k = kstart + kk - 1
7260 h_v(i,J,kk) = 0.5 * (G%mask2dT(i,j)*h(i,j,k) + G%mask2dT(i,j+1)*h(i,j+1,k))
727 enddo
728 else
729232500 do concurrent (kk=1:kmax, j=js-2:je+2, I=is-2:Ieq+1) DO_LOCALITY(local(k))
73014760000 k = kstart + kk - 1
73129752500 h_u(I,j,kk) = 0.5 * (h(i,j,k) + h(i+1,j,k))
732 enddo
733234375 do concurrent (kk=1:kmax, J=js-2:Jeq+1, i=is-2:ie+2) DO_LOCALITY(local(k))
73414647500 k = kstart + kk - 1
73529529375 h_v(i,J,kk) = 0.5 * (h(i,j,k) + h(i,j+1,k))
736 enddo
737 endif
738
739 ! Adjust contributions to shearing strain and interpolated values of
740 ! thicknesses on open boundaries.
7411875 if (apply_OBC) then ; do n=1,OBC%number_of_segments
7420 J = OBC%segment(n)%HI%JsdB ; I = OBC%segment(n)%HI%IsdB
7430 if (apply_OBC_strain) then
7440 if (OBC%segment(n)%is_N_or_S .and. (J >= Js_vort) .and. (J <= Je_vort)) then
745 do concurrent (kk=1:kmax, &
746 I=max(OBC%segment(n)%HI%IsdB,Is_vort):min(OBC%segment(n)%HI%IedB,Ie_vort)) &
7470 DO_LOCALITY(local(k))
7480 k = kstart + kk - 1
7490 select case (OBC%strain_config)
750 case (OBC_STRAIN_ZERO)
7510 dvdx(I,J,kk) = 0. ; dudy(I,J,kk) = 0.
752 case (OBC_STRAIN_FREESLIP)
7530 dudy(I,J,kk) = 0.
754 case (OBC_STRAIN_COMPUTED)
7550 if (OBC%segment(n)%direction == OBC_DIRECTION_N) then
756 dudy(I,J,kk) = 2.0*CS%DX_dyBu(I,J)* &
7570 (OBC%segment(n)%tangential_vel(I,J,k) - u(I,j,k))*G%IdxCu(I,j)
758 else
759 dudy(I,J,kk) = 2.0*CS%DX_dyBu(I,J)* &
7600 (u(I,j+1,k) - OBC%segment(n)%tangential_vel(I,J,k))*G%IdxCu(I,j+1)
761 endif
762 case (OBC_STRAIN_SPECIFIED)
7630 if (OBC%segment(n)%direction == OBC_DIRECTION_N) then
7640 dudy(I,J,kk) = CS%DX_dyBu(I,J)*OBC%segment(n)%tangential_grad(I,J,k)*G%IdxCu(I,j)*G%dxBu(I,J)
765 else
7660 dudy(I,J,kk) = CS%DX_dyBu(I,J)*OBC%segment(n)%tangential_grad(I,J,k)*G%IdxCu(I,j+1)*G%dxBu(I,J)
767 endif
768 end select
7690 if (CS%use_Leithy) then
7700 dvdx_smooth(I,J,kk) = dvdx(I,J,kk)
7710 dudy_smooth(I,J,kk) = dudy(I,J,kk)
772 endif
773 enddo
7740 elseif (OBC%segment(n)%is_E_or_W .and. (I >= is_vort) .and. (I <= ie_vort)) then
775 do concurrent (kk=1:kmax, &
776 J=max(OBC%segment(n)%HI%JsdB,js_vort):min(OBC%segment(n)%HI%JedB,je_vort)) &
7770 DO_LOCALITY(local(k))
7780 k = kstart + kk - 1
7790 select case (OBC%strain_config)
780 case (OBC_STRAIN_ZERO)
7810 dvdx(I,J,kk) = 0. ; dudy(I,J,kk) = 0.
782 case (OBC_STRAIN_FREESLIP)
7830 dvdx(I,J,kk) = 0.
784 case (OBC_STRAIN_COMPUTED)
7850 if (OBC%segment(n)%direction == OBC_DIRECTION_E) then
786 dvdx(I,J,kk) = 2.0*CS%DY_dxBu(I,J)* &
7870 (OBC%segment(n)%tangential_vel(I,J,k) - v(i,J,k))*G%IdyCv(i,J)
788 else
789 dvdx(I,J,kk) = 2.0*CS%DY_dxBu(I,J)* &
7900 (v(i+1,J,k) - OBC%segment(n)%tangential_vel(I,J,k))*G%IdyCv(i+1,J)
791 endif
792 case (OBC_STRAIN_SPECIFIED)
7930 if (OBC%segment(n)%direction == OBC_DIRECTION_E) then
7940 dvdx(I,J,kk) = CS%DY_dxBu(I,J)*OBC%segment(n)%tangential_grad(I,J,k)*G%IdyCv(i,J)*G%dxBu(I,J)
795 else
7960 dvdx(I,J,kk) = CS%DY_dxBu(I,J)*OBC%segment(n)%tangential_grad(I,J,k)*G%IdyCv(i+1,J)*G%dxBu(I,J)
797 endif
798 end select
7990 if (CS%use_Leithy) then
8000 dvdx_smooth(I,J,kk) = dvdx(I,J,kk)
8010 dudy_smooth(I,J,kk) = dudy(I,J,kk)
802 endif
803 enddo
804 endif
805 endif
806
8070 if (OBC%segment(n)%direction == OBC_DIRECTION_N) then
808 ! There are extra wide halos here to accommodate the cross-corner-point
809 ! OBC projections, but they might not be necessary if the accelerations
810 ! are always zeroed out at OBC points, in which case the i-loop below
811 ! becomes do i=is-1,ie+1. -RWH
8120 if ((J >= js-2) .and. (J <= Jeq+1)) then
813 do concurrent (kk=1:kmax, &
8140 i=max(is-2,OBC%segment(n)%HI%isd):min(ie+2,OBC%segment(n)%HI%ied)) DO_LOCALITY(local(k))
8150 k = kstart + kk - 1
8160 h_v(i,J,kk) = h(i,j,k)
817 enddo
818 endif
8190 elseif (OBC%segment(n)%direction == OBC_DIRECTION_S) then
8200 if ((J >= js-2) .and. (J <= Jeq+1)) then
821 do concurrent (kk=1:kmax, &
8220 i=max(is-2,OBC%segment(n)%HI%isd):min(ie+2,OBC%segment(n)%HI%ied)) DO_LOCALITY(local(k))
8230 k = kstart + kk - 1
8240 h_v(i,J,kk) = h(i,j+1,k)
825 enddo
826 endif
8270 elseif (OBC%segment(n)%direction == OBC_DIRECTION_E) then
8280 if ((I >= is-2) .and. (I <= Ieq+1)) then
829 do concurrent (kk=1:kmax, &
8300 j=max(js-2,OBC%segment(n)%HI%jsd):min(je+2,OBC%segment(n)%HI%jed)) DO_LOCALITY(local(k))
8310 k = kstart + kk - 1
8320 h_u(I,j,kk) = h(i,j,k)
833 enddo
834 endif
8350 elseif (OBC%segment(n)%direction == OBC_DIRECTION_W) then
8360 if ((I >= is-2) .and. (I <= Ieq+1)) then
837 do concurrent (kk=1:kmax, &
8380 j=max(js-2,OBC%segment(n)%HI%jsd):min(je+2,OBC%segment(n)%HI%jed)) DO_LOCALITY(local(k))
8390 k = kstart + kk - 1
8400 h_u(I,j,kk) = h(i+1,j,k)
841 enddo
842 endif
843 endif
844 enddo ; endif
845 ! Now project thicknesses across corner points on OBCs.
8461875 if (apply_OBC) then ; do n=1,OBC%number_of_segments
8470 J = OBC%segment(n)%HI%JsdB ; I = OBC%segment(n)%HI%IsdB
8480 if (OBC%segment(n)%direction == OBC_DIRECTION_N) then
8490 if ((J >= js-2) .and. (J <= je)) then
8500 do concurrent (kk=1:kmax, I=max(is-2,OBC%segment(n)%HI%IsdB):min(Ieq+1,OBC%segment(n)%HI%IedB))
8510 h_u(I,j+1,kk) = h_u(I,j,kk)
852 enddo
853 endif
8540 elseif (OBC%segment(n)%direction == OBC_DIRECTION_S) then
8550 if ((J >= js-1) .and. (J <= je+1)) then
8560 do concurrent (kk=1:kmax, I=max(is-2,OBC%segment(n)%HI%isd):min(Ieq+1,OBC%segment(n)%HI%ied))
8570 h_u(I,j,kk) = h_u(I,j+1,kk)
858 enddo
859 endif
8600 elseif (OBC%segment(n)%direction == OBC_DIRECTION_E) then
8610 if ((I >= is-2) .and. (I <= ie)) then
8620 do concurrent (kk=1:kmax, J=max(js-2,OBC%segment(n)%HI%jsd):min(Jeq+1,OBC%segment(n)%HI%jed))
8630 h_v(i+1,J,kk) = h_v(i,J,kk)
864 enddo
865 endif
8660 elseif (OBC%segment(n)%direction == OBC_DIRECTION_W) then
8670 if ((I >= is-1) .and. (I <= ie+1)) then
8680 do concurrent (kk=1:kmax, J=max(js-2,OBC%segment(n)%HI%jsd):min(Jeq+1,OBC%segment(n)%HI%jed))
8690 h_v(i,J,kk) = h_v(i+1,J,kk)
870 enddo
871 endif
872 endif
873 enddo ; endif
874
875 ! Shearing strain (including no-slip boundary conditions at the 2-D land-sea mask).
876 ! dudy and dvdx include modifications at OBCs from above.
8771875 if (CS%no_slip) then
8780 do concurrent (kk=1:kmax, J=js-2:Jeq+1, I=is-2:Ieq+1) DO_LOCALITY(local(k))
8790 k = kstart + kk - 1
8800 sh_xy(I,J,kk) = (2.0-G%mask2dBu(I,J)) * ( dvdx(I,J,kk) + dudy(I,J,kk) )
8810 if (CS%id_shearstress > 0) ShSt(I,J,k) = sh_xy(I,J,kk)
882 enddo
883 else
884232500 do concurrent (kk=1:kmax, J=js-2:Jeq+1, I=is-2:Ieq+1) DO_LOCALITY(local(k))
88514529375 k = kstart + kk - 1
88614529375 sh_xy(I,J,kk) = G%mask2dBu(I,J) * ( dvdx(I,J,kk) + dudy(I,J,kk) )
88729291250 if (CS%id_shearstress > 0) ShSt(I,J,k) = sh_xy(I,J,kk)
888 enddo
889 endif
890
8911875 if (CS%use_Leithy) then
892 ! Shearing strain (including no-slip boundary conditions at the 2-D land-sea mask).
893 ! dudy_smooth and dvdx_smooth do not (yet) include modifications at OBCs from above.
8940 if (CS%no_slip) then
8950 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
8960 sh_xy_smooth(I,J,kk) = (2.0-G%mask2dBu(I,J)) * ( dvdx_smooth(I,J,kk) + dudy_smooth(I,J,kk) )
897 enddo
898 else
8990 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
9000 sh_xy_smooth(I,J,kk) = G%mask2dBu(I,J) * ( dvdx_smooth(I,J,kk) + dudy_smooth(I,J,kk) )
901 enddo
902 endif
903 endif ! use Leith+E
904
905 ! Evaluate Del2u = x.Div(Grad u) and Del2v = y.Div( Grad u)
9061875 if (CS%biharmonic) then
907232500 do concurrent (kk=1:kmax, j=js-1:Jeq+1, I=Isq-1:Ieq+1)
908 Del2u(I,j,kk) = CS%Idx2dyCu(I,j) * ((CS%dx2q(I,J)*sh_xy(I,J,kk)) - (CS%dx2q(I,J-1)*sh_xy(I,J-1,kk))) + &
90928830000 CS%Idxdy2u(I,j) * ((CS%dy2h(i+1,j)*sh_xx(i+1,j,kk)) - (CS%dy2h(i,j)*sh_xx(i,j,kk)))
910 enddo
911230625 do concurrent (kk=1:kmax, J=Jsq-1:Jeq+1, i=is-1:Ieq+1)
912 Del2v(i,J,kk) = CS%Idxdy2v(i,J) * ((CS%dy2q(I,J)*sh_xy(I,J,kk)) - (CS%dy2q(I-1,J)*sh_xy(I-1,J,kk))) - &
91329053125 CS%Idx2dyCv(i,J) * ((CS%dx2h(i,j+1)*sh_xx(i,j+1,kk)) - (CS%dx2h(i,j)*sh_xx(i,j,kk)))
914 enddo
9151875 if (apply_OBC) then ; if (OBC%zero_biharmonic) then
9160 do n=1,OBC%number_of_segments
9170 I = OBC%segment(n)%HI%IsdB ; J = OBC%segment(n)%HI%JsdB
9180 if (OBC%segment(n)%is_N_or_S .and. (J >= Jsq-1) .and. (J <= Jeq+1)) then
9190 do concurrent (kk=1:kmax, I=OBC%segment(n)%HI%isd:OBC%segment(n)%HI%ied)
9200 Del2v(i,J,kk) = 0.
921 enddo
9220 elseif (OBC%segment(n)%is_E_or_W .and. (I >= Isq-1) .and. (I <= Ieq+1)) then
9230 do concurrent (kk=1:kmax, j=OBC%segment(n)%HI%jsd:OBC%segment(n)%HI%jed)
9240 Del2u(I,j,kk) = 0.
925 enddo
926 endif
927 enddo
928 endif ; endif
929 endif
930
931 ! Vorticity
9321875 if (use_vort_xy) then
9330 if (CS%no_slip) then
9340 do concurrent (kk=1:kmax, J=js_vort:je_vort, I=is_vort:ie_vort)
9350 vort_xy(I,J,kk) = (2.0-G%mask2dBu(I,J)) * ( dvdx(I,J,kk) - dudy(I,J,kk) )
936 enddo
937 else
9380 if (CS%use_circulation) then
9390 do concurrent (kk=1:kmax, J=js_vort:je_vort, I=is_vort:ie_vort) DO_LOCALITY(local(k))
9400 k = kstart + kk - 1
941 vort_xy(I,J,kk) = G%mask2dBu(I,J) * G%IareaBu(I,J) * ( &
942 ((v(i+1,J,k)*G%dyCv(i+1,J)) - (v(i,J,k)*G%dyCv(i,J))) &
943 - ((u(I,j+1,k)*G%dxCu(I,j+1)) - (u(I,j,k)*G%dxCu(I,j))) &
9440 )
945 enddo
946 else
9470 do concurrent (kk=1:kmax, J=js_vort:je_vort, I=is_vort:ie_vort)
9480 vort_xy(I,J,kk) = G%mask2dBu(I,J) * ( dvdx(I,J,kk) - dudy(I,J,kk) )
949 enddo
950 endif
951 endif
952 endif
953
9541875 if (CS%use_Leithy) then
9550 if (CS%no_slip) then
9560 do concurrent (kk=1:kmax, J=js_Kh-1:je_Kh, I=is_Kh-1:ie_Kh)
9570 vort_xy_smooth(I,J,kk) = (2.0-G%mask2dBu(I,J)) * ( dvdx_smooth(I,J,kk) - dudy_smooth(I,J,kk) )
958 enddo
959 else
9600 do concurrent (kk=1:kmax, J=js_Kh-1:je_Kh, I=is_Kh-1:ie_Kh)
9610 vort_xy_smooth(I,J,kk) = G%mask2dBu(I,J) * ( dvdx_smooth(I,J,kk) - dudy_smooth(I,J,kk) )
962 enddo
963 endif
964 endif
965
966
9671875 if (use_Leith) then
968 call hor_visc_Leith_grad(G, GV, US, CS, VarMix, nkblock, kstart, kmax, &
969 is, ie, js, je, is_Kh, ie_Kh, js_Kh, je_Kh, Ieq, Jeq, &
970 h, dz, slope_x, slope_y, dudx, dvdy, vort_xy, vort_xy_smooth, &
971 grad_vort_mag_h, grad_vort_mag_h_2d, grad_div_mag_h, &
972 grad_vort_mag_q, grad_vort_mag_q_2d, grad_div_mag_q, &
9730 vert_vort_mag_smooth, Del2vort_q)
974 endif ! CS%Leith_Kh
975
9761875 if ((CS%Smagorinsky_Kh) .or. (CS%Smagorinsky_Ah)) then
9771875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(sh_xx_sq, sh_xy_sq))
97814182500 sh_xx_sq = sh_xx(i,j,kk)**2
979 sh_xy_sq = 0.25 * ( ((sh_xy(I-1,J-1,kk)**2) + (sh_xy(I,J,kk)**2)) &
98014182500 + ((sh_xy(I-1,J,kk)**2) + (sh_xy(I,J-1,kk)**2)) )
98128595625 Shear_mag(i,j,kk) = sqrt(sh_xx_sq + sh_xy_sq)
982 enddo
983 endif
984
9851875 if (CS%bound_Ah .or. CS%bound_Kh) then
9861875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(k, h_min))
98714182500 k = kstart + kk - 1
98814182500 h_min = min(h_u(I,j,kk), h_u(I-1,j,kk), h_v(i,J,kk), h_v(i,J-1,kk))
98928595625 hrat_min(i,j,kk) = min(1.0, h_min / (h(i,j,k) + h_neglect))
990 enddo
991 endif
992
9931875 if (CS%Laplacian) then
994 ! Determine the Laplacian viscosity at h points, using the
995 ! largest value from several parameterizations. Also get
996 ! the Laplacian component of str_xx.
997
9981875 if ((CS%Leith_Kh) .or. (CS%Leith_Ah) .or. (CS%use_Leithy)) then
9990 if (CS%use_QG_Leith_visc) then
10000 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(grad_vort, grad_vort_qg))
10010 grad_vort = grad_vort_mag_h(i,j,kk) + grad_div_mag_h(i,j,kk)
10020 grad_vort_qg = 3. * grad_vort_mag_h_2d(i,j,kk)
10030 vert_vort_mag(i,j,kk) = min(grad_vort, grad_vort_qg)
1004 enddo
1005 else
10060 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
10070 vert_vort_mag(i,j,kk) = grad_vort_mag_h(i,j,kk) + grad_div_mag_h(i,j,kk)
1008 enddo
1009 endif
1010 endif
1011
1012 ! Static (pre-computed) background viscosity
10131875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
101428595625 Kh(i,j,kk) = CS%Kh_bg_xx(i,j)
1015 enddo
1016
1017 ! NOTE: The following do-block can be decomposed and vectorized after the
1018 ! stack size has been reduced.
10191875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
102028595625 if (CS%add_LES_viscosity) then
10210 if (CS%Smagorinsky_Kh) &
10220 Kh(i,j,kk) = Kh(i,j,kk) + CS%Laplac2_const_xx(i,j) * Shear_mag(i,j,kk)
10230 if (CS%Leith_Kh) &
10240 Kh(i,j,kk) = Kh(i,j,kk) + CS%Laplac3_const_xx(i,j) * vert_vort_mag(i,j,kk) * inv_PI3
1025 else
102614182500 if (CS%Smagorinsky_Kh) &
10270 Kh(i,j,kk) = max(Kh(i,j,kk), CS%Laplac2_const_xx(i,j) * Shear_mag(i,j,kk))
102814182500 if (CS%Leith_Kh) &
10290 Kh(i,j,kk) = max(Kh(i,j,kk), CS%Laplac3_const_xx(i,j) * vert_vort_mag(i,j,kk) * inv_PI3)
1030 endif
1031 enddo
1032
1033 ! All viscosity contributions above are subject to resolution scaling
1034
10351875 if (rescale_Kh) then
1036 !$omp target update from(Kh)
103714302500 do kk=1,kmax ; do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh
103814298750 Kh(i,j,kk) = VarMix%Res_fn_h(i,j) * Kh(i,j,kk)
1039 enddo ; enddo ; enddo
1040 !$omp target update to(Kh)
1041 endif
1042
1043 ! Place a floor on the viscosity, if desired.
10441875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
104528595625 Kh(i,j,kk) = max(Kh(i,j,kk), CS%Kh_bg_min)
1046 enddo
1047
10481875 if (use_MEKE_Ku .and. .not. CS%EY24_EBT_BS) then
1049 !$omp target update from(Kh)
1050 ! *Add* the MEKE contribution (which might be negative)
10510 if (use_kh_struct) then
10520 if (CS%res_scale_MEKE) then
10530 do kk=1,kmax ; do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh
10540 k = kstart + kk - 1
10550 Kh(i,j,kk) = Kh(i,j,kk) + MEKE%Ku(i,j) * VarMix%Res_fn_h(i,j) * VarMix%BS_struct(i,j,k)
1056 enddo ; enddo ; enddo
1057 else
10580 do kk=1,kmax ; do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh
10590 k = kstart + kk - 1
10600 Kh(i,j,kk) = Kh(i,j,kk) + MEKE%Ku(i,j) * VarMix%BS_struct(i,j,k)
1061 enddo ; enddo ; enddo
1062 endif
1063 else
10640 if (CS%res_scale_MEKE) then
10650 do kk=1,kmax ; do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh
10660 Kh(i,j,kk) = Kh(i,j,kk) + MEKE%Ku(i,j) * VarMix%Res_fn_h(i,j)
1067 enddo ; enddo ; enddo
1068 else
10690 do kk=1,kmax ; do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh
10700 Kh(i,j,kk) = Kh(i,j,kk) + MEKE%Ku(i,j)
1071 enddo ; enddo ; enddo
1072 endif
1073 endif
1074 !$omp target update to(Kh)
1075 endif
1076
10771875 if (CS%anisotropic) then
10780 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
1079 ! *Add* the tension component of anisotropic viscosity
10800 Kh(i,j,kk) = Kh(i,j,kk) + CS%Kh_aniso * (1. - CS%n1n2_h(i,j)**2)
1081 enddo
1082 endif
1083
1084 ! Newer method of bounding for stability
10851875 if ((CS%bound_Kh) .and. (CS%bound_Ah)) then
10861875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(Kh_max_here))
108714182500 visc_bound_rem(i,j,kk) = 1.0
108814182500 Kh_max_here = hrat_min(i,j,kk) * CS%Kh_Max_xx(i,j)
108928595625 if (Kh(i,j,kk) >= Kh_max_here) then
10904713750 visc_bound_rem(i,j,kk) = 0.0
10914713750 Kh(i,j,kk) = Kh_max_here
10929468750 elseif ((Kh(i,j,kk) > 0.0) .or. (CS%backscatter_underbound .and. (Kh_max_here > 0.0))) then
10930 visc_bound_rem(i,j,kk) = 1.0 - Kh(i,j,kk) / Kh_max_here
1094 endif
1095 enddo
10960 elseif (CS%bound_Kh) then
10970 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
10980 Kh(i,j,kk) = min(Kh(i,j,kk), hrat_min(i,j,kk) * CS%Kh_Max_xx(i,j))
1099 enddo
1100 endif
1101
1102 ! In Leith+E parameterization Kh is computed after Ah in the biharmonic loop.
1103 ! The harmonic component of str_xx is added in the biharmonic loop.
11041875 if (CS%use_Leithy) then
11050 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
11060 Kh(i,j,kk) = 0.
1107 enddo
1108 endif
1109
11101875 if (CS%id_Kh_h>0 .or. CS%debug) then
11110 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(k))
11120 k = kstart + kk - 1
11130 Kh_h(i,j,k) = Kh(i,j,kk)
1114 enddo
1115 endif
1116
11171875 if (CS%id_grid_Re_Kh>0) then
11180 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k, KE, grid_Kh))
11190 k = kstart + kk - 1
11200 KE = 0.125*(((u(I,j,k)+u(I-1,j,k))**2) + ((v(i,J,k)+v(i,J-1,k))**2))
11210 grid_Kh = max(Kh(i,j,kk), CS%min_grid_Kh)
11220 grid_Re_Kh(i,j,k) = (sqrt(KE) * sqrt(CS%grid_sp_h2(i,j))) / grid_Kh
1123 enddo
1124 endif
1125
11261875 if (CS%id_div_xx_h>0) then
11270 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
11280 k = kstart + kk - 1
11290 div_xx_h(i,j,k) = dudx(i,j,kk) + dvdy(i,j,kk)
1130 enddo
1131 endif
1132
11331875 if (CS%id_sh_xx_h>0) then
11340 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
11350 k = kstart + kk - 1
11360 sh_xx_h(i,j,k) = sh_xx(i,j,kk)
1137 enddo
1138 endif
1139
1140230625 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1)
114128595625 str_xx(i,j,kk) = -Kh(i,j,kk) * sh_xx(i,j,kk)
1142 enddo
1143 else
11440 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1)
11450 str_xx(i,j,kk) = 0.0
1146 enddo
1147 endif ! Get Kh at h points and get Laplacian component of str_xx
1148
11491875 if (CS%anisotropic) then
11500 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1) DO_LOCALITY(local(local_strain))
1151 ! Shearing-strain averaged to h-points
11520 local_strain = 0.25 * ( (sh_xy(I,J,kk) + sh_xy(I-1,J-1,kk)) + (sh_xy(I-1,J,kk) + sh_xy(I,J-1,kk)) )
1153 ! *Add* the shear-strain contribution to the xx-component of stress
11540 str_xx(i,j,kk) = str_xx(i,j,kk) - CS%Kh_aniso * CS%n1n2_h(i,j) * CS%n1n1_m_n2n2_h(i,j) * local_strain
1155 enddo
1156 endif
1157
11581875 if (CS%biharmonic) then
1159 ! Determine the biharmonic viscosity at h points, using the
1160 ! largest value from several parameterizations. Also get the
1161 ! biharmonic component of str_xx.
11621875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
116328595625 Ah(i,j,kk) = CS%Ah_bg_xx(i,j)
1164 enddo
1165
11661875 if ((CS%Smagorinsky_Ah) .or. (CS%Leith_Ah) .or. (CS%use_Leithy)) then
11671875 if (CS%Smagorinsky_Ah) then
11681875 if (CS%bound_Coriolis) then
11691875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(AhSm))
1170 AhSm = Shear_mag(i,j,kk) * (CS%Biharm_const_xx(i,j) &
117114182500 + CS%Biharm_const2_xx(i,j) * Shear_mag(i,j,kk))
117228595625 Ah(i,j,kk) = max(Ah(i,j,kk), AhSm)
1173 enddo
1174 else
11750 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(AhSm))
11760 AhSm = CS%Biharm_const_xx(i,j) * Shear_mag(i,j,kk)
11770 Ah(i,j,kk) = max(Ah(i,j,kk), AhSm)
1178 enddo
1179 endif
1180 endif
1181
11821875 if (CS%Leith_Ah) then
11830 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(Del2vort_h, AhLth))
1184 Del2vort_h = 0.25 * ((Del2vort_q(I,J,kk) + Del2vort_q(I-1,J-1,kk)) + &
11850 (Del2vort_q(I-1,J,kk) + Del2vort_q(I,J-1,kk)))
11860 AhLth = CS%Biharm6_const_xx(i,j) * abs(Del2vort_h) * inv_PI6
11870 Ah(i,j,kk) = max(Ah(i,j,kk), AhLth)
1188 enddo
1189 endif
1190
11911875 if (CS%use_Leithy) then
1192 call hor_visc_Leithy_Ah(G, GV, CS, nkblock, kstart, kmax, is_Kh, ie_Kh, js_Kh, je_Kh, inv_PI6, &
1193 Del2vort_q, vert_vort_mag, vert_vort_mag_smooth, vort_xy_smooth, &
11940 Ah, Ah_h, m_leithy)
1195 endif
1196
1197 endif ! Smagorinsky_Ah or Leith_Ah or Leith+E
1198
11991875 if (use_MEKE_Au) then
1200 ! *Add* the MEKE contribution
1201 !$omp target update from(Ah)
12020 do kk=1,kmax ; do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh
12030 Ah(i,j,kk) = Ah(i,j,kk) + MEKE%Au(i,j)
1204 enddo ; enddo ; enddo
1205 !$omp target update to(Ah)
1206 endif
1207
12081875 if (CS%Re_Ah > 0.0) then
1209 !$omp target update from(Ah)
12100 do kk=1,kmax ; do j=js_Kh,je_Kh ; do i=is_Kh,ie_Kh
12110 k = kstart + kk - 1
12120 KE = 0.125*(((u(I,j,k)+u(I-1,j,k))**2) + ((v(i,J,k)+v(i,J-1,k))**2))
12130 Ah(i,j,kk) = sqrt(KE) * CS%Re_Ah_const_xx(i,j)
1214 enddo ; enddo ; enddo
1215 !$omp target update to(Ah)
1216 endif
1217
12181875 if (CS%bound_Ah) then
12191875 if (CS%bound_Kh) then
12201875 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
122128595625 Ah(i,j,kk) = min(Ah(i,j,kk), visc_bound_rem(i,j,kk) * hrat_min(i,j,kk) * CS%Ah_Max_xx(i,j))
1222 enddo
1223 else
12240 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
12250 Ah(i,j,kk) = min(Ah(i,j,kk), hrat_min(i,j,kk) * CS%Ah_Max_xx(i,j))
1226 enddo
1227 endif
1228 endif
1229
12301875 if (CS%EY24_EBT_BS) then
12310 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(k, tmp))
12320 k = kstart + kk - 1
12330 tmp = CS%KS_coef * hrat_min(i,j,kk) * CS%Ah_Max_xx_KS(i,j)
12340 visc_limit_h(i,j,k) = tmp
12350 visc_limit_h_frac(i,j,k) = Ah(i,j,kk) / (CS%KS_coef * hrat_min(i,j,kk) * CS%Ah_Max_xx_KS(i,j))
12360 if (Ah(i,j,kk) >= tmp) then
12370 visc_limit_h_flag(i,j,k) = 1.
1238 endif
1239 enddo
1240 endif
1241
12421875 if ((CS%id_Ah_h>0) .or. CS%debug .or. CS%use_Leithy) then
12430 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(k))
12440 k = kstart + kk - 1
12450 Ah_h(i,j,k) = Ah(i,j,kk)
1246 enddo
1247 endif
1248
12491875 if (CS%use_Leithy) then
1250 ! Compute Leith+E Kh after bounds have been applied to Ah
1251 ! and after it has been smoothed. Kh = -m_leithy * Ah
12520 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(k))
12530 k = kstart + kk - 1
12540 Kh(i,j,kk) = -m_leithy(i,j,kk) * Ah(i,j,kk)
12550 Kh_h(i,j,k) = Kh(i,j,kk)
1256 enddo
1257 endif
1258
12591875 if (CS%id_grid_Re_Ah > 0) then
12600 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k, KE, grid_Ah))
12610 k = kstart + kk - 1
12620 KE = 0.125 * (((u(I,j,k) + u(I-1,j,k))**2) + ((v(i,J,k) + v(i,J-1,k))**2))
12630 grid_Ah = max(Ah(i,j,kk), CS%min_grid_Ah)
12640 grid_Re_Ah(i,j,k) = (sqrt(KE) * CS%grid_sp_h3(i,j)) / grid_Ah
1265 enddo
1266 endif
1267
1268230625 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1) DO_LOCALITY(local(k, d_del2u, d_del2v, d_str))
126914182500 k = kstart + kk - 1
127014182500 d_del2u = (G%IdyCu(I,j) * Del2u(I,j,kk)) - (G%IdyCu(I-1,j) * Del2u(I-1,j,kk))
127114182500 d_del2v = (G%IdxCv(i,J) * Del2v(i,J,kk)) - (G%IdxCv(i,J-1) * Del2v(i,J-1,kk))
127214182500 d_str = Ah(i,j,kk) * ((CS%DY_dxT(i,j) * d_del2u) - (CS%DX_dyT(i,j) * d_del2v))
1273
127414182500 str_xx(i,j,kk) = str_xx(i,j,kk) + d_str
1275
127614182500 if (CS%use_Leithy) str_xx(i,j,kk) = str_xx(i,j,kk) - Kh(i,j,kk) * sh_xx_smooth(i,j,kk)
1277
1278 ! Keep a copy of the biharmonic contribution for backscatter parameterization
127928595625 bhstr_xx(i,j,kk) = d_str * (h(i,j,k) * CS%reduction_xx(i,j))
1280 enddo
1281 endif ! Get biharmonic coefficient at h points and biharmonic part of str_xx
1282
1283 ! Backscatter using MEKE
12841875 if (CS%EY24_EBT_BS) then
1285 call hor_visc_backscatter_h(G, CS, MEKE, VarMix, use_kh_struct, nkblock, kstart, kmax, &
12860 Isq, Ieq, Jsq, Jeq, visc_limit_h_flag, sh_xx, str_xx, BS_coeff_h)
1287 endif ! Backscatter
1288
12891875 if (CS%biharmonic) then
1290 ! Gradient of Laplacian, for use in bi-harmonic term
1291228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
129213839375 dDel2vdx(I,J,kk) = CS%DY_dxBu(I,J)*((Del2v(i+1,J,kk)*G%IdyCv(i+1,J)) - (Del2v(i,J,kk)*G%IdyCv(i,J)))
129327907500 dDel2udy(I,J,kk) = CS%DX_dyBu(I,J)*((Del2u(I,j+1,kk)*G%IdxCu(I,j+1)) - (Del2u(I,j,kk)*G%IdxCu(I,j)))
1294 enddo
1295 ! Adjust contributions to shearing strain on open boundaries.
12961875 if (apply_OBC) then ; if ((OBC%strain_config == OBC_STRAIN_ZERO) .or. &
1297 (OBC%strain_config == OBC_STRAIN_FREESLIP)) then
12980 do n=1,OBC%number_of_segments
12990 J = OBC%segment(n)%HI%JsdB ; I = OBC%segment(n)%HI%IsdB
13000 if (OBC%segment(n)%is_N_or_S .and. (J >= js-1) .and. (J <= Jeq)) then
13010 do concurrent (kk=1:kmax, I=OBC%segment(n)%HI%IsdB:OBC%segment(n)%HI%IedB)
13020 if (OBC%strain_config == OBC_STRAIN_ZERO) then
13030 dDel2vdx(I,J,kk) = 0. ; dDel2udy(I,J,kk) = 0.
13040 elseif (OBC%strain_config == OBC_STRAIN_FREESLIP) then
13050 dDel2udy(I,J,kk) = 0.
1306 endif
1307 enddo
13080 elseif (OBC%segment(n)%is_E_or_W .and. (I >= is-1) .and. (I <= Ieq)) then
13090 do concurrent (kk=1:kmax, J=OBC%segment(n)%HI%JsdB:OBC%segment(n)%HI%JedB)
13100 if (OBC%strain_config == OBC_STRAIN_ZERO) then
13110 dDel2vdx(I,J,kk) = 0. ; dDel2udy(I,J,kk) = 0.
13120 elseif (OBC%strain_config == OBC_STRAIN_FREESLIP) then
13130 dDel2vdx(I,J,kk) = 0.
1314 endif
1315 enddo
1316 endif
1317 enddo
1318 endif ; endif
1319 endif
1320
13211875 if ((CS%Smagorinsky_Kh) .or. (CS%Smagorinsky_Ah)) then
1322228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(sh_xy_sq, sh_xx_sq))
132313839375 sh_xy_sq = sh_xy(I,J,kk)**2
1324 sh_xx_sq = 0.25 * ( ((sh_xx(i,j,kk)**2) + (sh_xx(i+1,j+1,kk)**2)) &
132513839375 + ((sh_xx(i,j+1,kk)**2) + (sh_xx(i+1,j,kk)**2)) )
132627907500 Shear_mag(I,J,kk) = sqrt(sh_xy_sq + sh_xx_sq)
1327 enddo
1328 endif
1329
1330228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(h2uq, h2vq))
133113839375 h2uq = 4.0 * (h_u(I,j,kk) * h_u(I,j+1,kk))
133213839375 h2vq = 4.0 * (h_v(i,J,kk) * h_v(i+1,J,kk))
1333 hq(I,J,kk) = (2.0 * (h2uq * h2vq)) &
133427907500 / (h_neglect3 + (h2uq + h2vq) * ((h_u(I,j,kk) + h_u(I,j+1,kk)) + (h_v(i,J,kk) + h_v(i+1,J,kk))))
1335 enddo
1336
13371875 if (CS%bound_Ah .or. CS%bound_Kh) then
1338228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(h_min))
133913839375 h_min = min(h_u(I,j,kk), h_u(I,j+1,kk), h_v(i,J,kk), h_v(i+1,J,kk))
134027907500 hrat_min(I,J,kk) = min(1.0, h_min / (hq(I,J,kk) + h_neglect))
1341 enddo
1342
1343 endif
1344
13451875 if (CS%no_slip) then
13460 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(hu, hv))
13470 if (CS%no_slip .and. (G%mask2dBu(I,J) < 0.5)) then
13480 if ((G%mask2dCu(I,j) + G%mask2dCu(I,j+1)) + &
1349 (G%mask2dCv(i,J) + G%mask2dCv(i+1,J)) > 0.0) then
1350 ! This is a coastal vorticity point, so modify hq and hrat_min.
1351
13520 hu = G%mask2dCu(I,j) * h_u(I,j,kk) + G%mask2dCu(I,j+1) * h_u(I,j+1,kk)
13530 hv = G%mask2dCv(i,J) * h_v(i,J,kk) + G%mask2dCv(i+1,J) * h_v(i+1,J,kk)
13540 if ((G%mask2dCu(I,j) + G%mask2dCu(I,j+1)) * &
1355 (G%mask2dCv(i,J) + G%mask2dCv(i+1,J)) == 0.0) then
1356 ! Only one of hu and hv is nonzero, so just add them.
13570 hq(I,J,kk) = hu + hv
13580 hrat_min(I,J,kk) = 1.0
1359 else
1360 ! Both hu and hv are nonzero, so take the harmonic mean.
13610 hq(I,J,kk) = 2.0 * (hu * hv) / ((hu + hv) + h_neglect)
13620 hrat_min(I,J,kk) = min(1.0, min(hu, hv) / (hq(I,J,kk) + h_neglect) )
1363 endif
1364 endif
1365 endif
1366 enddo
1367 endif
1368
1369 ! Pass the velocity gradients and thickness to ZB2020
13701875 if (CS%use_ZB2020) then
13710 do kk=1,kmax
13720 k = kstart + kk - 1
1373 call ZB2020_copy_gradient_and_thickness(sh_xx(:,:,kk), sh_xy(:,:,kk), vort_xy(:,:,kk), hq(:,:,kk), &
13740 G, GV, CS%ZB2020, k)
1375 enddo
1376 endif
1377
13781875 if (CS%Laplacian) then
1379 ! Determine the Laplacian viscosity at q points, using the
1380 ! largest value from several parameterizations. Also get the
1381 ! Laplacian component of str_xy.
1382
13831875 if ((CS%Leith_Kh) .or. (CS%Leith_Ah)) then
13840 if (CS%use_QG_Leith_visc) then
13850 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(grad_vort, grad_vort_qg))
13860 grad_vort = grad_vort_mag_q(I,J,kk) + grad_div_mag_q(I,J,kk)
13870 grad_vort_qg = 3. * grad_vort_mag_q_2d(I,J,kk)
13880 vert_vort_mag(I,J,kk) = min(grad_vort, grad_vort_qg)
1389 enddo
1390 else
13910 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
13920 vert_vort_mag(I,J,kk) = grad_vort_mag_q(I,J,kk) + grad_div_mag_q(I,J,kk)
1393 enddo
1394 endif
1395 endif
1396
1397 ! Static (pre-computed) background viscosity
1398228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
139927907500 Kh(I,J,kk) = CS%Kh_bg_xy(I,J)
1400 enddo
1401
14021875 if (CS%Smagorinsky_Kh) then
14030 if (CS%add_LES_viscosity) then
14040 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
14050 Kh(I,J,kk) = Kh(I,J,kk) + CS%Laplac2_const_xy(I,J) * Shear_mag(I,J,kk)
1406 enddo
1407 else
14080 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
14090 Kh(I,J,kk) = max(Kh(I,J,kk), CS%Laplac2_const_xy(I,J) * Shear_mag(I,J,kk) )
1410 enddo
1411 endif
1412 endif
1413
14141875 if (CS%Leith_Kh) then
14150 if (CS%add_LES_viscosity) then
14160 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
14170 Kh(I,J,kk) = Kh(I,J,kk) + CS%Laplac3_const_xy(I,J) * vert_vort_mag(I,J,kk) * inv_PI3 ! Is this right? -AJA
1418 enddo
1419 else
14200 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
14210 Kh(I,J,kk) = max(Kh(I,J,kk), CS%Laplac3_const_xy(I,J) * vert_vort_mag(I,J,kk) * inv_PI3)
1422 enddo
1423 endif
1424 endif
1425
1426 ! All viscosity contributions above are subject to resolution scaling
1427
14281875 if (rescale_Kh) then
1429 !$omp target update from(Kh)
143013957500 do kk=1,kmax ; do J=js-1,Jeq ; do I=is-1,Ieq
143113953750 Kh(I,J,kk) = VarMix%Res_fn_q(I,J) * Kh(I,J,kk)
1432 enddo ; enddo ; enddo
1433 !$omp target update to(Kh)
1434 endif
1435
1436228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
143727907500 Kh(I,J,kk) = max(Kh(I,J,kk), CS%Kh_bg_min) ! Place a floor on the viscosity, if desired.
1438 enddo
1439
14401875 if (use_MEKE_Ku .and. .not. CS%EY24_EBT_BS) then
1441 !$omp target update from(Kh)
14420 if (use_kh_struct) then
14430 do kk=1,kmax ; do J=js-1,Jeq ; do I=is-1,Ieq
14440 k = kstart + kk - 1
14450 meke_res_fn = 1.
14460 if (CS%res_scale_MEKE) meke_res_fn = VarMix%Res_fn_q(I,J)
1447
1448 Kh(I,J,kk) = Kh(I,J,kk) + 0.25*( ((MEKE%Ku(i,j)*VarMix%BS_struct(i,j,k)) + &
1449 (MEKE%Ku(i+1,j+1)*VarMix%BS_struct(i+1,j+1,k))) + &
1450 ((MEKE%Ku(i+1,j)*VarMix%BS_struct(i+1,j,k)) + &
14510 (MEKE%Ku(i,j+1)*VarMix%BS_struct(i,j+1,k))) ) * meke_res_fn
1452 enddo ; enddo ; enddo
1453 else
14540 do kk=1,kmax ; do J=js-1,Jeq ; do I=is-1,Ieq
14550 meke_res_fn = 1.
14560 if (CS%res_scale_MEKE) meke_res_fn = VarMix%Res_fn_q(I,J)
1457
1458 Kh(I,J,kk) = Kh(I,J,kk) + 0.25 * ( &
1459 (MEKE%Ku(i,j) + MEKE%Ku(i+1,j+1)) + &
1460 (MEKE%Ku(i+1,j) + &
14610 MEKE%Ku(i,j+1)) ) * meke_res_fn
1462 enddo ; enddo ; enddo
1463 endif
1464 !$omp target update to(Kh)
1465 endif
1466
14671875 if (CS%anisotropic) then
1468 ! *Add* the shear component of anisotropic viscosity
14690 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
14700 Kh(I,J,kk) = Kh(I,J,kk) + CS%Kh_aniso * CS%n1n2_q(I,J)**2
1471 enddo
1472 endif
1473
1474228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(Kh_max_here))
1475 ! Newer method of bounding for stability
147627907500 if ((CS%bound_Kh) .and. (CS%bound_Ah)) then
147713839375 visc_bound_rem(I,J,kk) = 1.0
147813839375 Kh_max_here = hrat_min(I,J,kk) * CS%Kh_Max_xy(I,J)
147913839375 if (Kh(I,J,kk) >= Kh_max_here) then
14804185000 visc_bound_rem(I,J,kk) = 0.0
14814185000 Kh(I,J,kk) = Kh_max_here
14829654375 elseif ((Kh(I,J,kk) > 0.0) .or. (CS%backscatter_underbound .and. (Kh_max_here > 0.0))) then
14830 visc_bound_rem(I,J,kk) = 1.0 - Kh(I,J,kk) / Kh_max_here
1484 endif
14850 elseif (CS%bound_Kh) then
14860 Kh(I,J,kk) = min(Kh(I,J,kk), hrat_min(I,J,kk) * CS%Kh_Max_xy(I,J))
1487 endif
1488 enddo
1489
14901875 if (CS%use_Leithy) then
1491 ! Leith+E doesn't recompute Kh at q points, it just interpolates it from h to q points
14920 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k))
14930 k = kstart + kk - 1
14940 Kh(I,J,kk) = 0.25 * ((Kh_h(i,j,k) + Kh_h(i+1,j+1,k)) + (Kh_h(i,j+1,k) + Kh_h(i+1,j,k)))
1495 enddo
1496 endif
1497
14981875 if (CS%id_Kh_q > 0 .or. CS%debug) then
14990 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k))
15000 k = kstart + kk - 1
15010 Kh_q(I,J,k) = Kh(I,J,kk)
1502 enddo
1503 endif
1504
15051875 if (CS%id_vort_xy_q > 0) then
15060 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k))
15070 k = kstart + kk - 1
15080 vort_xy_q(I,J,k) = vort_xy(I,J,kk)
1509 enddo
1510 endif
1511
15121875 if (CS%id_sh_xy_q > 0) then
15130 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k))
15140 k = kstart + kk - 1
15150 sh_xy_q(I,J,k) = sh_xy(I,J,kk)
1516 enddo
1517 endif
1518
15191875 if (.not. CS%use_Leithy) then
1520228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
152127907500 str_xy(I,J,kk) = -Kh(I,J,kk) * sh_xy(I,J,kk)
1522 enddo
1523 else
15240 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
15250 str_xy(I,J,kk) = -Kh(I,J,kk) * sh_xy_smooth(I,J,kk)
1526 enddo
1527 endif
1528 else
15290 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
15300 str_xy(I,J,kk) = 0.
1531 enddo
1532 endif ! get harmonic coefficient Kh at q points and harmonic part of str_xy
1533
15341875 if (CS%anisotropic) then
15350 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(local_strain))
1536 ! Horizontal-tension averaged to q-points
15370 local_strain = 0.25 * ( (sh_xx(i,j,kk) + sh_xx(i+1,j+1,kk)) + (sh_xx(i+1,j,kk) + sh_xx(i,j+1,kk)) )
1538 ! *Add* the tension contribution to the xy-component of stress
15390 str_xy(I,J,kk) = str_xy(I,J,kk) - CS%Kh_aniso * CS%n1n2_q(I,J) * CS%n1n1_m_n2n2_q(I,J) * local_strain
1540 enddo
1541 endif
1542
15431875 if (CS%biharmonic) then
1544 ! Determine the biharmonic viscosity at q points, using the
1545 ! largest value from several parameterizations. Also get the
1546 ! biharmonic component of str_xy.
1547228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
154827907500 Ah(I,J,kk) = CS%Ah_bg_xy(I,J)
1549 enddo
1550
15511875 if (CS%Smagorinsky_Ah .or. CS%Leith_Ah) then
15521875 if (CS%Smagorinsky_Ah) then
15531875 if (CS%bound_Coriolis) then
1554228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(AhSm))
1555 AhSm = Shear_mag(I,J,kk) * (CS%Biharm_const_xy(I,J) &
155613839375 + CS%Biharm_const2_xy(I,J) * Shear_mag(I,J,kk))
155727907500 Ah(I,J,kk) = max(Ah(I,J,kk), AhSm)
1558 enddo
1559 else
15600 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(AhSm))
15610 AhSm = CS%Biharm_const_xy(I,J) * Shear_mag(I,J,kk)
15620 Ah(I,J,kk) = max(Ah(I,J,kk), AhSm)
1563 enddo
1564 endif
1565 endif
1566
15671875 if (CS%Leith_Ah) then
15680 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(AhLth))
15690 AhLth = CS%Biharm6_const_xy(I,J) * abs(Del2vort_q(I,J,kk)) * inv_PI6
15700 Ah(I,J,kk) = max(Ah(I,J,kk), AhLth)
1571 enddo
1572 endif
1573 endif ! Smagorinsky_Ah or Leith_Ah
1574
15751875 if (use_MEKE_Au) then
1576 ! *Add* the MEKE contribution
1577 !$omp target update from(Ah)
15780 do kk=1,kmax ; do J=js-1,Jeq ; do I=is-1,Ieq
1579 Ah(I,J,kk) = Ah(I,J,kk) + 0.25 * ( &
15800 (MEKE%Au(i,j) + MEKE%Au(i+1,j+1)) + (MEKE%Au(i+1,j) + MEKE%Au(i,j+1)) )
1581 enddo ; enddo ; enddo
1582 !$omp target update to(Ah)
1583 endif
1584
15851875 if (CS%Re_Ah > 0.0) then
15860 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k, KE))
15870 k = kstart + kk - 1
15880 KE = 0.125 * (((u(I,j,k) + u(I,j+1,k))**2) + ((v(i,J,k) + v(i+1,J,k))**2))
15890 Ah(I,J,kk) = sqrt(KE) * CS%Re_Ah_const_xy(I,J)
1590 enddo
1591 endif
1592
15931875 if (CS%bound_Ah) then
15941875 if (CS%bound_Kh) then
1595228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
159627907500 Ah(I,J,kk) = min(Ah(I,J,kk), visc_bound_rem(I,J,kk) * hrat_min(I,J,kk) * CS%Ah_Max_xy(I,J))
1597 enddo
1598 else
15990 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
16000 Ah(I,J,kk) = min(Ah(I,J,kk), hrat_min(I,J,kk) * CS%Ah_Max_xy(I,J))
1601 enddo
1602 endif
1603 endif
1604
16051875 if (CS%EY24_EBT_BS) then
16060 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k, tmp))
16070 k = kstart + kk - 1
16080 tmp = CS%KS_coef *hrat_min(I,J,kk) * CS%Ah_Max_xy_KS(I,J)
16090 visc_limit_q(I,J,k) = tmp
16100 visc_limit_q_frac(i,j,k) = Ah(i,j,kk) / (CS%KS_coef * hrat_min(i,j,kk) * CS%Ah_Max_xy_KS(i,j))
16110 if (Ah(I,J,kk) >= tmp) then
16120 visc_limit_q_flag(I,J,k) = 1.
1613 endif
1614 enddo
1615 endif
1616
1617 ! Leith+E doesn't recompute Ah at q points, it just interpolates it from h to q points
16181875 if (CS%use_Leithy) then
16190 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k))
16200 k = kstart + kk - 1
16210 Ah(I,J,kk) = 0.25 * ((Ah_h(i,j,k) + Ah_h(i+1,j+1,k)) + (Ah_h(i,j+1,k) + Ah_h(i+1,j,k)))
1622 enddo
1623 endif
1624
16251875 if (CS%id_Ah_q>0 .or. CS%debug) then
16260 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k))
16270 k = kstart + kk - 1
16280 Ah_q(I,J,k) = Ah(I,J,kk)
1629 enddo
1630 endif
1631
1632 ! Again, need to initialize str_xy as if its biharmonic
1633228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(d_str))
163413839375 d_str = Ah(I,J,kk) * (dDel2vdx(I,J,kk) + dDel2udy(I,J,kk))
1635
163613839375 str_xy(I,J,kk) = str_xy(I,J,kk) + d_str
1637
1638 ! Keep a copy of the biharmonic contribution for backscatter parameterization
163927907500 bhstr_xy(I,J,kk) = d_str * (hq(I,J,kk) * G%mask2dBu(I,J) * CS%reduction_xy(I,J))
1640 enddo
1641 endif ! Get Ah at q points and biharmonic part of str_xy
1642
1643 ! Backscatter using MEKE
16441875 if (CS%EY24_EBT_BS) then
1645 call hor_visc_backscatter_q(G, GV, CS, MEKE, VarMix, use_kh_struct, nkblock, kstart, kmax, &
16460 is, js, Ieq, Jeq, visc_limit_q_flag, sh_xy, str_xy, BS_coeff_q)
1647 endif ! Backscatter
1648
16491875 if (CS%use_GME) then
1650 ! The wider halo here is to permit one pass of smoothing without a halo update.
16510 do concurrent (kk=1:kmax, j=Jsq-1:Jeq+2, i=Isq-1:Ieq+2) DO_LOCALITY(local(k, GME_coeff))
16520 k = kstart + kk - 1
1653 GME_coeff = GME_effic_h(i,j) * 0.25 * &
16540 ((KH_u_GME(I,j,k)+KH_u_GME(I-1,j,k)) + (KH_v_GME(i,J,k)+KH_v_GME(i,J-1,k)))
16550 GME_coeff = MIN(GME_coeff, CS%GME_limiter)
1656
16570 if ((CS%id_GME_coeff_h>0) .or. find_FrictWork) GME_coeff_h(i,j,k) = GME_coeff
16580 str_xx_GME(i,j,kk) = GME_coeff * sh_xx_bt(i,j)
1659 enddo
1660
1661 ! The wider halo here is to permit one pass of smoothing without a halo update.
16620 do concurrent (kk=1:kmax, J=js-2:je+1, I=is-2:ie+1) DO_LOCALITY(local(k, GME_coeff))
16630 k = kstart + kk - 1
1664 GME_coeff = GME_effic_q(I,J) * 0.25 * &
16650 ((KH_u_GME(I,j,k)+KH_u_GME(I,j+1,k)) + (KH_v_GME(i,J,k)+KH_v_GME(i+1,J,k)))
16660 GME_coeff = MIN(GME_coeff, CS%GME_limiter)
1667
16680 if (CS%id_GME_coeff_q>0) GME_coeff_q(I,J,k) = GME_coeff
16690 str_xy_GME(I,J,kk) = GME_coeff * sh_xy_bt(I,J)
1670 enddo
1671
1672 ! Applying GME diagonal term. This is linear and the arguments can be rescaled.
1673 ! smooth_GME is an impure host routine, so str_xx_GME/str_xy_GME must be brought back
1674 ! from the device before this loop and pushed back afterward.
1675 !$omp target update from(str_xx_GME, str_xy_GME)
16760 do kk=1,kmax
16770 call smooth_GME(CS, G, GME_flux_h=str_xx_GME(:,:,kk))
16780 call smooth_GME(CS, G, GME_flux_q=str_xy_GME(:,:,kk))
1679 enddo
1680 !$omp target update to(str_xx_GME, str_xy_GME)
1681
1682 ! This changes the units of str_xx from [L2 T-2 ~> m2 s-2] to [H L2 T-2 ~> m3 s-2 or kg s-2].
16830 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1) DO_LOCALITY(local(k))
16840 k = kstart + kk - 1
16850 str_xx(i,j,kk) = (str_xx(i,j,kk) + str_xx_GME(i,j,kk)) * (h(i,j,k) * CS%reduction_xx(i,j))
1686 enddo
1687
1688 ! This adds in GME and changes the units of str_xx from [L2 T-2 ~> m2 s-2] to [H L2 T-2 ~> m3 s-2 or kg s-2].
16890 if (CS%no_slip) then
16900 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
16910 str_xy(I,J,kk) = (str_xy(I,J,kk) + str_xy_GME(I,J,kk)) * (hq(I,J,kk) * CS%reduction_xy(I,J))
1692 enddo
1693 else
16940 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
16950 str_xy(I,J,kk) = (str_xy(I,J,kk) + str_xy_GME(I,J,kk)) * (hq(I,J,kk) * G%mask2dBu(I,J) * CS%reduction_xy(I,J))
1696 enddo
1697 endif
1698
1699 else ! .not. use_GME
1700 ! This changes the units of str_xx from [L2 T-2 ~> m2 s-2] to [H L2 T-2 ~> m3 s-2 or kg s-2].
1701230625 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1) DO_LOCALITY(local(k))
170214182500 k = kstart + kk - 1
170328595625 str_xx(i,j,kk) = str_xx(i,j,kk) * (h(i,j,k) * CS%reduction_xx(i,j))
1704 enddo
1705
1706 ! This changes the units of str_xy from [L2 T-2 ~> m2 s-2] to [H L2 T-2 ~> m3 s-2 or kg s-2].
17071875 if (CS%no_slip) then
17080 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
17090 str_xy(I,J,kk) = str_xy(I,J,kk) * (hq(I,J,kk) * CS%reduction_xy(I,J))
1710 enddo
1711 else
1712228750 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
171327907500 str_xy(I,J,kk) = str_xy(I,J,kk) * (hq(I,J,kk) * G%mask2dBu(I,J) * CS%reduction_xy(I,J))
1714 enddo
1715 endif
1716 endif ! use_GME
1717
1718 ! Evaluate 1/h x.Div(h Grad u) or the biharmonic equivalent.
17191875 do concurrent (kk=1:kmax, j=js:je, I=Isq:Ieq) DO_LOCALITY(local(k))
172013612500 k = kstart + kk - 1
1721 diffu(I,j,k) = ((G%IdxCu(I,j)*((CS%dx2q(I,J-1)*str_xy(I,J-1,kk)) - (CS%dx2q(I,J)*str_xy(I,J,kk))) + &
1722 G%IdyCu(I,j)*((CS%dy2h(i,j)*str_xx(i,j,kk)) - (CS%dy2h(i+1,j)*str_xx(i+1,j,kk)))) * &
172327453750 G%IareaCu(I,j)) / (h_u(I,j,kk) + h_neglect)
1724 enddo
1725
17261875 if (apply_OBC) then
1727 ! This is not the right boundary condition. If all the masking of tendencies are done
1728 ! correctly later then eliminating this block should not change answers.
17290 do n=1,OBC%number_of_segments
17300 if (OBC%segment(n)%is_E_or_W) then
17310 I = OBC%segment(n)%HI%IsdB
17320 do concurrent (kk=1:kmax, j=OBC%segment(n)%HI%jsd:OBC%segment(n)%HI%jed) DO_LOCALITY(local(k))
17330 k = kstart + kk - 1
17340 diffu(I,j,k) = 0.
1735 enddo
1736 endif
1737 enddo
1738 endif
1739
1740 ! Evaluate 1/h y.Div(h Grad u) or the biharmonic equivalent.
17411875 do concurrent (kk=1:kmax, J=Jsq:Jeq, i=is:ie) DO_LOCALITY(local(k))
174213725000 k = kstart + kk - 1
1743 diffv(i,J,k) = ((G%IdyCv(i,J)*((CS%dy2q(I-1,J)*str_xy(I-1,J,kk)) - (CS%dy2q(I,J)*str_xy(I,J,kk))) - &
1744 G%IdxCv(i,J)*((CS%dx2h(i,j)*str_xx(i,j,kk)) - (CS%dx2h(i,j+1)*str_xx(i,j+1,kk)))) * &
174527676875 G%IareaCv(i,J)) / (h_v(i,J,kk) + h_neglect)
1746 enddo
1747
17481875 if (apply_OBC) then
1749 ! This is not the right boundary condition. If all the masking of tendencies are done
1750 ! correctly later then eliminating this block should not change answers.
17510 do n=1,OBC%number_of_segments
17520 if (OBC%segment(n)%is_N_or_S) then
17530 J = OBC%segment(n)%HI%JsdB
17540 do concurrent (kk=1:kmax, i=OBC%segment(n)%HI%isd:OBC%segment(n)%HI%ied) DO_LOCALITY(local(k))
17550 k = kstart + kk - 1
17560 diffv(i,J,k) = 0.
1757 enddo
1758 endif
1759 enddo
1760 endif
1761
17621875 if (find_FrictWork) then
17630 if (CS%FrictWork_bug) then
1764 ! Diagnose str_xx*d_x u - str_yy*d_y v + str_xy*(d_y u + d_x v)
1765 ! This is the old formulation that includes energy diffusion
17660 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
17670 k = kstart + kk - 1
1768 FrictWork(i,j,k) = GV%H_to_RZ * ( &
1769 ((str_xx(i,j,kk) * (u(I,j,k)-u(I-1,j,k))*G%IdxT(i,j)) &
1770 - (str_xx(i,j,kk) * (v(i,J,k)-v(i,J-1,k))*G%IdyT(i,j))) &
1771 + 0.25*(( (str_xy(I,J,kk) * &
1772 (((u(I,j+1,k)-u(I,j,k))*G%IdyBu(I,J)) &
1773 + ((v(i+1,J,k)-v(i,J,k))*G%IdxBu(I,J)))) &
1774 + (str_xy(I-1,J-1,kk) * &
1775 (((u(I-1,j,k)-u(I-1,j-1,k))*G%IdyBu(I-1,J-1)) &
1776 + ((v(i,J-1,k)-v(i-1,J-1,k))*G%IdxBu(I-1,J-1)))) ) &
1777 + ( (str_xy(I-1,J,kk) * &
1778 (((u(I-1,j+1,k)-u(I-1,j,k))*G%IdyBu(I-1,J)) &
1779 + ((v(i,J,k)-v(i-1,J,k))*G%IdxBu(I-1,J)))) &
1780 + (str_xy(I,J-1,kk) * &
1781 (((u(I,j,k)-u(I,j-1,k))*G%IdyBu(I,J-1)) &
17820 + ((v(i+1,J-1,k)-v(i,J-1,k))*G%IdxBu(I,J-1)))) ) ) )
1783 enddo
1784 else
17850 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
17860 k = kstart + kk - 1
1787 FrictWork(i,j,k) = GV%H_to_RZ * G%IareaT(i,j) * ( &
1788 ((str_xx(i,j,kk)*CS%dy2h(i,j) * ( &
1789 (uh(I,j,k)*G%dxCu(I,j)*G%IdyCu(I,j)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)) &
1790 - (uh(I-1,j,k)*G%dxCu(I-1,j)*G%IdyCu(I-1,j)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)) ) ) &
1791 - (str_xx(i,j,kk)*CS%dx2h(i,j) * ( &
1792 (vh(i,J,k)*G%dyCv(i,J)*G%IdxCv(i,J)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)) &
1793 - (vh(i,J-1,k)*G%dyCv(i,J-1)*G%IdxCv(i,J-1)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)) ) )) &
1794 + (0.25*(((str_xy(I,J,kk)*( &
1795 (CS%dx2q(I,J)*((uh(I,j+1,k)*G%IareaCu(I,j+1)/(h_u(I,j+1,kk)+h_neglect)) &
1796 - (uh(I,j,k)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)))) &
1797 + (CS%dy2q(I,J)*((vh(i+1,J,k)*G%IareaCv(i+1,J)/(h_v(i+1,J,kk)+h_neglect)) &
1798 - (vh(i,J,k)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)))) )) &
1799 +(str_xy(I-1,J-1,kk)*( &
1800 (CS%dx2q(I-1,J-1)*((uh(I-1,j,k)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)) &
1801 - (uh(I-1,j-1,k)*G%IareaCu(I-1,j-1)/(h_u(I-1,j-1,kk)+h_neglect)))) &
1802 + (CS%dy2q(I-1,J-1)*((vh(i,J-1,k)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)) &
1803 - (vh(i-1,J-1,k)*G%IareaCv(i-1,J-1)/(h_v(i-1,J-1,kk)+h_neglect)))) )) ) &
1804 +((str_xy(I-1,J,kk)*( &
1805 (CS%dx2q(I-1,J)*((uh(I-1,j+1,k)*G%IareaCu(I-1,j+1)/(h_u(I-1,j+1,kk)+h_neglect)) &
1806 - (uh(I-1,j,k)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)))) &
1807 + (CS%dy2q(I-1,J)*((vh(i,J,k)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)) &
1808 - (vh(i-1,J,k)*G%IareaCv(i-1,J)/(h_v(i-1,J,kk)+h_neglect)))) )) &
1809 +(str_xy(I,J-1,kk)*( &
1810 (CS%dx2q(I,J-1)*((uh(I,j,k)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)) &
1811 - (uh(I,j-1,k)*G%IareaCu(I,j-1)/(h_u(I,j-1,kk)+h_neglect)))) &
1812 + (CS%dy2q(I,J-1)*((vh(i+1,J-1,k)*G%IareaCv(i+1,J-1)/(h_v(i+1,J-1,kk)+h_neglect)) &
18130 - (vh(i,J-1,k)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)))) )) ) )) )
1814
1815 enddo
1816 endif
1817
18180 if (CS%EY24_EBT_BS) then
18190 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
18200 k = kstart + kk - 1
18210 FrictWork(i,j,k) = (1. - visc_limit_h_flag(i,j,k)) * FrictWork(i,j,k)
1822 enddo
1823 endif
1824 endif
1825
18261875 if (CS%id_FrictWork_bh>0 .or. CS%id_FrictWorkIntz_bh > 0 .or. allocated(MEKE%mom_src_bh)) then
18270 if (CS%FrictWork_bug) then
1828 ! Diagnose bhstr_xx*d_x u - bhstr_yy*d_y v + bhstr_xy*(d_y u + d_x v)
1829 ! This is the old formulation that includes energy diffusion !cyc
18300 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
18310 k = kstart + kk - 1
1832 FrictWork_bh(i,j,k) = GV%H_to_RZ * ( &
1833 ((bhstr_xx(i,j,kk) * (u(I,j,k)-u(I-1,j,k))*G%IdxT(i,j)) &
1834 - (bhstr_xx(i,j,kk) * (v(i,J,k)-v(i,J-1,k))*G%IdyT(i,j))) &
1835 + 0.25*(( (bhstr_xy(I,J,kk) * &
1836 (((u(I,j+1,k)-u(I,j,k))*G%IdyBu(I,J)) &
1837 + ((v(i+1,J,k)-v(i,J,k))*G%IdxBu(I,J)))) &
1838 + (bhstr_xy(I-1,J-1,kk) * &
1839 (((u(I-1,j,k)-u(I-1,j-1,k))*G%IdyBu(I-1,J-1)) &
1840 + ((v(i,J-1,k)-v(i-1,J-1,k))*G%IdxBu(I-1,J-1)))) ) &
1841 + ( (bhstr_xy(I-1,J,kk) * &
1842 (((u(I-1,j+1,k)-u(I-1,j,k))*G%IdyBu(I-1,J)) &
1843 + ((v(i,J,k)-v(i-1,J,k))*G%IdxBu(I-1,J)))) &
1844 + (bhstr_xy(I,J-1,kk) * &
1845 (((u(I,j,k)-u(I,j-1,k))*G%IdyBu(I,J-1)) &
18460 + ((v(i+1,J-1,k)-v(i,J-1,k))*G%IdxBu(I,J-1)))) ) ) )
1847 enddo
1848 else
18490 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
18500 k = kstart + kk - 1
1851 ! Diagnose bhstr_xx*d_x u - bhstr_yy*d_y v + bhstr_xy*(d_y u + d_x v)
1852 FrictWork_bh(i,j,k) = GV%H_to_RZ * G%IareaT(i,j) * ( &
1853 ((bhstr_xx(i,j,kk)*CS%dy2h(i,j) * ( &
1854 (uh(I,j,k)*G%dxCu(I,j)*G%IdyCu(I,j)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)) &
1855 - (uh(I-1,j,k)*G%dxCu(I-1,j)*G%IdyCu(I-1,j)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)) ) ) &
1856 - (bhstr_xx(i,j,kk)*CS%dx2h(i,j) * ( &
1857 (vh(i,J,k)*G%dyCv(i,J)*G%IdxCv(i,J)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)) &
1858 - (vh(i,J-1,k)*G%dyCv(i,J-1)*G%IdxCv(i,J-1)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)) ) )) &
1859 + (0.25*(((bhstr_xy(I,J,kk)*( &
1860 (CS%dx2q(I,J)*((uh(I,j+1,k)*G%IareaCu(I,j+1)/(h_u(I,j+1,kk)+h_neglect)) &
1861 - (uh(I,j,k)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)))) &
1862 + (CS%dy2q(I,J)*((vh(i+1,J,k)*G%IareaCv(i+1,J)/(h_v(i+1,J,kk)+h_neglect)) &
1863 - (vh(i,J,k)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)))) )) &
1864 +(bhstr_xy(I-1,J-1,kk)*( &
1865 (CS%dx2q(I-1,J-1)*((uh(I-1,j,k)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)) &
1866 - (uh(I-1,j-1,k)*G%IareaCu(I-1,j-1)/(h_u(I-1,j-1,kk)+h_neglect)))) &
1867 + (CS%dy2q(I-1,J-1)*((vh(i,J-1,k)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)) &
1868 - (vh(i-1,J-1,k)*G%IareaCv(i-1,J-1)/(h_v(i-1,J-1,kk)+h_neglect)))) )) ) &
1869 +((bhstr_xy(I-1,J,kk)*( &
1870 (CS%dx2q(I-1,J)*((uh(I-1,j+1,k)*G%IareaCu(I-1,j+1)/(h_u(I-1,j+1,kk)+h_neglect)) &
1871 - (uh(I-1,j,k)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)))) &
1872 + (CS%dy2q(I-1,J)*((vh(i,J,k)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)) &
1873 - (vh(i-1,J,k)*G%IareaCv(i-1,J)/(h_v(i-1,J,kk)+h_neglect)))) )) &
1874 +(bhstr_xy(I,J-1,kk)*( &
1875 (CS%dx2q(I,J-1)*((uh(I,j,k)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)) &
1876 - (uh(I,j-1,k)*G%IareaCu(I,j-1)/(h_u(I,j-1,kk)+h_neglect)))) &
1877 + (CS%dy2q(I,J-1)*((vh(i+1,J-1,k)*G%IareaCv(i+1,J-1)/(h_v(i+1,J-1,kk)+h_neglect)) &
18780 - (vh(i,J-1,k)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)))) )) ) )) )
1879 enddo
1880 endif
1881
18820 if (CS%EY24_EBT_BS) then
18830 do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
18840 k = kstart + kk - 1
18850 FrictWork_bh(i,j,k) = (1. - visc_limit_h_flag(i,j,k)) * FrictWork_bh(i,j,k)
1886 enddo
1887 endif
1888 endif
1889
18901875 if (CS%use_GME) then
18910 if (CS%FrictWork_bug) then ; do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
18920 k = kstart + kk - 1
1893 ! Diagnose str_xx_GME*d_x u - str_yy_GME*d_y v + str_xy_GME*(d_y u + d_x v)
1894 ! This is the old formulation that includes energy diffusion
1895 FrictWork_GME(i,j,k) = GV%H_to_RZ * ( &
1896 ((str_xx_GME(i,j,kk)*(u(I,j,k)-u(I-1,j,k))*G%IdxT(i,j)) &
1897 - (str_xx_GME(i,j,kk)*(v(i,J,k)-v(i,J-1,k))*G%IdyT(i,j))) &
1898 + 0.25*(( (str_xy_GME(I,J,kk) * &
1899 (((u(I,j+1,k)-u(I,j,k))*G%IdyBu(I,J)) &
1900 + ((v(i+1,J,k)-v(i,J,k))*G%IdxBu(I,J)))) &
1901 + (str_xy_GME(I-1,J-1,kk) * &
1902 (((u(I-1,j,k)-u(I-1,j-1,k))*G%IdyBu(I-1,J-1)) &
1903 + ((v(i,J-1,k)-v(i-1,J-1,k))*G%IdxBu(I-1,J-1)))) ) &
1904 + ( (str_xy_GME(I-1,J,kk) * &
1905 (((u(I-1,j+1,k)-u(I-1,j,k))*G%IdyBu(I-1,J)) &
1906 + ((v(i,J,k)-v(i-1,J,k))*G%IdxBu(I-1,J)))) &
1907 + (str_xy_GME(I,J-1,kk) * &
1908 (((u(I,j,k)-u(I,j-1,k))*G%IdyBu(I,J-1)) &
19090 + ((v(i+1,J-1,k)-v(i,J-1,k))*G%IdxBu(I,J-1)))) ) ) )
1910 enddo
19110 else ; do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
19120 k = kstart + kk - 1
1913 FrictWork_GME(i,j,k) = GV%H_to_RZ * G%IareaT(i,j) * ( &
1914 ((str_xx_GME(i,j,kk)*CS%dy2h(i,j) * ( &
1915 (uh(I,j,k)*G%dxCu(I,j)*G%IdyCu(I,j)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)) &
1916 - (uh(I-1,j,k)*G%dxCu(I-1,j)*G%IdyCu(I-1,j)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)) ) ) &
1917 - (str_xx_GME(i,j,kk)*CS%dx2h(i,j) * ( &
1918 (vh(i,J,k)*G%dyCv(i,J)*G%IdxCv(i,J)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)) &
1919 - (vh(i,J-1,k)*G%dyCv(i,J-1)*G%IdxCv(i,J-1)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)) ) )) &
1920 + (0.25*(((str_xy_GME(I,J,kk)*( &
1921 (CS%dx2q(I,J)*((uh(I,j+1,k)*G%IareaCu(I,j+1)/(h_u(I,j+1,kk)+h_neglect)) &
1922 - (uh(I,j,k)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)))) &
1923 + (CS%dy2q(I,J)*((vh(i+1,J,k)*G%IareaCv(i+1,J)/(h_v(i+1,J,kk)+h_neglect)) &
1924 - (vh(i,J,k)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)))) )) &
1925 +(str_xy_GME(I-1,J-1,kk)*( &
1926 (CS%dx2q(I-1,J-1)*((uh(I-1,j,k)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)) &
1927 - (uh(I-1,j-1,k)*G%IareaCu(I-1,j-1)/(h_u(I-1,j-1,kk)+h_neglect)))) &
1928 + (CS%dy2q(I-1,J-1)*((vh(i,J-1,k)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)) &
1929 - (vh(i-1,J-1,k)*G%IareaCv(i-1,J-1)/(h_v(i-1,J-1,kk)+h_neglect)))) )) ) &
1930 +((str_xy_GME(I-1,J,kk)*( &
1931 (CS%dx2q(I-1,J)*((uh(I-1,j+1,k)*G%IareaCu(I-1,j+1)/(h_u(I-1,j+1,kk)+h_neglect)) &
1932 - (uh(I-1,j,k)*G%IareaCu(I-1,j)/(h_u(I-1,j,kk)+h_neglect)))) &
1933 + (CS%dy2q(I-1,J)*((vh(i,J,k)*G%IareaCv(i,J)/(h_v(i,J,kk)+h_neglect)) &
1934 - (vh(i-1,J,k)*G%IareaCv(i-1,J)/(h_v(i-1,J,kk)+h_neglect)))) )) &
1935 +(str_xy_GME(I,J-1,kk)*( &
1936 (CS%dx2q(I,J-1)*((uh(I,j,k)*G%IareaCu(I,j)/(h_u(I,j,kk)+h_neglect)) &
1937 - (uh(I,j-1,k)*G%IareaCu(I,j-1)/(h_u(I,j-1,kk)+h_neglect)))) &
1938 + (CS%dy2q(I,J-1)*((vh(i+1,J-1,k)*G%IareaCv(i+1,J-1)/(h_v(i+1,J-1,kk)+h_neglect)) &
19390 - (vh(i,J-1,k)*G%IareaCv(i,J-1)/(h_v(i,J-1,kk)+h_neglect)))) )) ) )) )
1940 enddo ; endif
19410 if (find_FrictWork .and. allocated(MEKE%mom_src) .and. allocated(MEKE%GME_snk)) then
1942 !$omp target update from(FrictWork_GME)
19430 do kk=1,kmax ; do j=js,je ; do i=is,ie
19440 k = kstart+kk-1
19450 MEKE%GME_snk(i,j) = MEKE%GME_snk(i,j) + FrictWork_GME(i,j,k)
1946 enddo ; enddo ; enddo
1947 endif
1948 endif
1949
19501875 if (skeb_use_frict) then ; do concurrent (kk=1:kmax, j=js:je, i=is:ie) DO_LOCALITY(local(k))
19510 k = kstart + kk - 1
1952 ! Note that the sign convention is FrictWork < 0 means energy dissipation.
1953 STOCH%skeb_diss(i,j,k) = STOCH%skeb_diss(i,j,k) - STOCH%skeb_frict_coef * &
19540 FrictWork(i,j,k) / (GV%H_to_RZ * (h(i,j,k) + h_neglect))
1955 enddo ; endif
1956
1957 ! Make a similar calculation as for FrictWork above but accumulating into
1958 ! the vertically integrated MEKE source term, and adjusting for any
1959 ! energy loss seen as a reduction in the (biharmonic) frictional source term.
19601900 if (find_FrictWork .and. allocated(MEKE%mom_src)) then
19610 if (MEKE%backscatter_Ro_c /= 0.) then
1962 !$omp target update from(FrictWork, FrictWork_bh, sh_xx, sh_xy)
19630 do kk=1,kmax ; do j=js,je ; do i=is,ie
19640 k = kstart + kk - 1
1965 FatH = 0.25*( (abs(G%CoriolisBu(I-1,J-1)) + abs(G%CoriolisBu(I,J))) + &
19660 (abs(G%CoriolisBu(I-1,J)) + abs(G%CoriolisBu(I,J-1))) )
1967 Shear_mag_bc = sqrt(sh_xx(i,j,kk) * sh_xx(i,j,kk) + &
1968 0.25*(((sh_xy(I-1,J-1,kk)*sh_xy(I-1,J-1,kk)) + (sh_xy(I,J,kk)*sh_xy(I,J,kk))) + &
19690 ((sh_xy(I-1,J,kk)*sh_xy(I-1,J,kk)) + (sh_xy(I,J-1,kk)*sh_xy(I,J-1,kk)))))
19700 if ((CS%answer_date > 20190101) .and. (CS%answer_date < 20241201)) then
19710 FatH = (US%s_to_T*FatH)**MEKE%backscatter_Ro_pow ! f^n
1972 ! Note the hard-coded dimensional constant in the following line that can not
1973 ! be rescaled for dimensional consistency.
1974 Shear_mag_bc = (((US%s_to_T * Shear_mag_bc)**MEKE%backscatter_Ro_pow) + 1.e-30) &
19750 * MEKE%backscatter_Ro_c ! c * D^n
1976 ! The Rossby number function is g(Ro) = 1/(1+c.Ro^n)
1977 ! RoScl = 1 - g(Ro)
19780 RoScl = Shear_mag_bc / (FatH + Shear_mag_bc) ! = 1 - f^n/(f^n+c*D^n)
1979 else
19800 if (FatH <= backscat_subround*Shear_mag_bc) then
19810 RoScl = 1.0
1982 else
19830 Sh_F_pow = MEKE%backscatter_Ro_c * (Shear_mag_bc / FatH)**MEKE%backscatter_Ro_pow
19840 RoScl = Sh_F_pow / (1.0 + Sh_F_pow) ! = 1 - f^n/(f^n+c*D^n)
1985 endif
1986 endif
1987
19880 MEKE%mom_src(i,j) = MEKE%mom_src(i,j) + (FrictWork(i,j,k) - RoScl*FrictWork_bh(i,j,k))
1989
19900 if (allocated(MEKE%mom_src_bh)) &
1991 MEKE%mom_src_bh(i,j) = MEKE%mom_src_bh(i,j) &
19920 + (FrictWork_bh(i,j,k) - RoScl * FrictWork_bh(i,j,k))
1993 enddo ; enddo ; enddo
1994 else
1995 !$omp target update from(FrictWork)
19960 do kk=1,kmax ; do j=js,je ; do i=is,ie
19970 k = kstart + kk - 1
19980 MEKE%mom_src(i,j) = MEKE%mom_src(i,j) + FrictWork(i,j,k)
1999 enddo ; enddo ; enddo
2000
20010 if (allocated(MEKE%mom_src_bh)) then
2002 !$omp target update from(FrictWork_bh)
20030 do kk=1,kmax ; do j=js,je ; do i=is,ie
20040 k = kstart + kk - 1
20050 MEKE%mom_src_bh(i,j) = MEKE%mom_src_bh(i,j) + FrictWork_bh(i,j,k)
2006 enddo ; enddo ; enddo
2007 endif
2008 endif ! MEKE%backscatter_Ro_c
2009
2010 endif ! find_FrictWork and associated(mom_src)
2011 enddo ! end of kstart block loop
2012
2013 !$omp target exit data map(delete: dudx, dudy, dvdx, dvdy, sh_xx, sh_xy)
2014 !$omp target exit data map(delete: h_u, h_v, hq)
2015 !$omp target exit data map(delete: str_xx, str_xy, ShSt)
2016 !$omp target exit data map(delete: Del2u, Del2v) if (CS%biharmonic)
2017 !$omp target exit data map(delete: dDel2vdx, dDel2udy) if (CS%biharmonic)
2018 !$omp target exit data map(delete: Shear_mag) if (use_Smag)
2019 !$omp target exit data map(delete: Kh) if (CS%Laplacian .or. CS%biharmonic)
2020 !$omp target exit data map(delete: Ah) if (CS%biharmonic)
2021 !$omp target exit data map(delete: bhstr_xx, bhstr_xy) if (CS%biharmonic)
2022
2023 !$omp target exit data map(delete: hrat_min) &
2024 !$omp if (CS%bound_Kh .or. CS%bound_Ah)
2025 !$omp target exit data map(delete: visc_bound_rem) &
2026 !$omp if (CS%bound_Kh .or. CS%bound_Ah)
2027
2028 !$omp target exit data map(delete: vert_vort_mag)
2029 !$omp target exit data map(delete: sh_xx_smooth) if (CS%use_Leithy .or. CS%biharmonic)
2030
2031 ! Offer fields for diagnostic averaging.
203225 if (CS%id_normstress > 0) call post_data(CS%id_normstress, NoSt, CS%diag)
2033 !$omp target update from(ShSt) if (CS%id_shearstress > 0)
203425 if (CS%id_shearstress > 0) call post_data(CS%id_shearstress, ShSt, CS%diag)
203525 if (CS%id_diffu>0) call post_data(CS%id_diffu, diffu, CS%diag)
203625 if (CS%id_diffv>0) call post_data(CS%id_diffv, diffv, CS%diag)
203725 if (CS%id_FrictWork>0) call post_data(CS%id_FrictWork, FrictWork, CS%diag)
203825 if (CS%id_FrictWork_bh>0) call post_data(CS%id_FrictWork_bh, FrictWork_bh, CS%diag)
203925 if (CS%id_Ah_h>0) call post_data(CS%id_Ah_h, Ah_h, CS%diag)
204025 if (CS%id_grid_Re_Ah>0) call post_data(CS%id_grid_Re_Ah, grid_Re_Ah, CS%diag)
204125 if (CS%id_div_xx_h>0) call post_data(CS%id_div_xx_h, div_xx_h, CS%diag)
204225 if (CS%id_vort_xy_q>0) call post_data(CS%id_vort_xy_q, vort_xy_q, CS%diag)
204325 if (CS%id_sh_xx_h>0) call post_data(CS%id_sh_xx_h, sh_xx_h, CS%diag)
204425 if (CS%id_sh_xy_q>0) call post_data(CS%id_sh_xy_q, sh_xy_q, CS%diag)
204525 if (CS%id_Ah_q>0) call post_data(CS%id_Ah_q, Ah_q, CS%diag)
204625 if (CS%id_Kh_h>0) call post_data(CS%id_Kh_h, Kh_h, CS%diag)
204725 if (CS%id_grid_Re_Kh>0) call post_data(CS%id_grid_Re_Kh, grid_Re_Kh, CS%diag)
204825 if (CS%id_Kh_q>0) call post_data(CS%id_Kh_q, Kh_q, CS%diag)
204925 if (CS%use_GME) then ! post barotropic tension and strain
20500 if (CS%id_GME_coeff_h > 0) call post_data(CS%id_GME_coeff_h, GME_coeff_h, CS%diag)
20510 if (CS%id_GME_coeff_q > 0) call post_data(CS%id_GME_coeff_q, GME_coeff_q, CS%diag)
20520 if (CS%id_FrictWork_GME>0) call post_data(CS%id_FrictWork_GME, FrictWork_GME, CS%diag)
20530 if (CS%id_dudx_bt > 0) call post_data(CS%id_dudx_bt, dudx_bt, CS%diag)
20540 if (CS%id_dvdy_bt > 0) call post_data(CS%id_dvdy_bt, dvdy_bt, CS%diag)
20550 if (CS%id_dudy_bt > 0) call post_data(CS%id_dudy_bt, dudy_bt, CS%diag)
20560 if (CS%id_dvdx_bt > 0) call post_data(CS%id_dvdx_bt, dvdx_bt, CS%diag)
2057 endif
205825 if (CS%EY24_EBT_BS) then
20590 if (CS%id_visc_limit_h>0) call post_data(CS%id_visc_limit_h, visc_limit_h, CS%diag)
20600 if (CS%id_visc_limit_q>0) call post_data(CS%id_visc_limit_q, visc_limit_q, CS%diag)
20610 if (CS%id_visc_limit_h_frac>0) call post_data(CS%id_visc_limit_h_frac, visc_limit_h_frac, CS%diag)
20620 if (CS%id_visc_limit_q_frac>0) call post_data(CS%id_visc_limit_q_frac, visc_limit_q_frac, CS%diag)
20630 if (CS%id_visc_limit_h_flag>0) call post_data(CS%id_visc_limit_h_flag, visc_limit_h_flag, CS%diag)
20640 if (CS%id_visc_limit_q_flag>0) call post_data(CS%id_visc_limit_q_flag, visc_limit_q_flag, CS%diag)
20650 if (CS%id_BS_coeff_h>0) call post_data(CS%id_BS_coeff_h, BS_coeff_h, CS%diag)
20660 if (CS%id_BS_coeff_q>0) call post_data(CS%id_BS_coeff_q, BS_coeff_q, CS%diag)
2067 endif
2068
206925 if (CS%debug) then
20700 if (CS%Laplacian) then
20710 call hchksum(Kh_h, "Kh_h", G%HI, haloshift=1, unscale=US%L_to_m**2*US%s_to_T)
20720 call Bchksum(Kh_q, "Kh_q", G%HI, haloshift=0, symmetric=.true., unscale=US%L_to_m**2*US%s_to_T)
2073 endif
20740 if (CS%biharmonic) then
20750 call hchksum(Ah_h, "Ah_h", G%HI, haloshift=1, unscale=US%L_to_m**4*US%s_to_T)
20760 call Bchksum(Ah_q, "Ah_q", G%HI, haloshift=0, symmetric=.true., unscale=US%L_to_m**4*US%s_to_T)
2077 endif
2078 endif
2079
2080 !$omp target exit data map(delete: sh_xy_q) &
2081 !$omp if (CS%id_sh_xy_q > 0)
2082
208325 if (CS%id_FrictWorkIntz > 0) then
20840 do j=js,je
20850 do i=is,ie ; FrictWorkIntz(i,j,1) = FrictWork(i,j,1) ; enddo
20860 do k=2,nz ; do i=is,ie
20870 FrictWorkIntz(i,j,1) = FrictWorkIntz(i,j,1) + FrictWork(i,j,k)
2088 enddo ; enddo
2089 enddo
20900 call post_data(CS%id_FrictWorkIntz, FrictWorkIntz(:,:,1), CS%diag)
2091 endif
2092
209325 if (CS%id_FrictWorkIntz_bh > 0) then
20940 do j=js,je
20950 do i=is,ie ; FrictWorkIntz_bh(i,j,1) = FrictWork_bh(i,j,1) ; enddo
20960 do k=2,nz ; do i=is,ie
20970 FrictWorkIntz_bh(i,j,1) = FrictWorkIntz_bh(i,j,1) + FrictWork_bh(i,j,k)
2098 enddo ; enddo
2099 enddo
21000 call post_data(CS%id_FrictWorkIntz_bh, FrictWorkIntz_bh(:,:,1), CS%diag)
2101 endif
2102
210325 if (present(ADp)) then
2104 ! Diagnostics of the fractional thicknesses times momentum budget terms
2105 ! 3D diagnostics of hf_diffu(diffv) are commented because there is no clarity on proper remapping grid option.
2106 ! The code is retained for debugging purposes in the future.
2107 !if (CS%id_hf_diffu > 0) call post_product_u(CS%id_hf_diffu, diffu, ADp%diag_hfrac_u, G, nz, CS%diag)
2108 !if (CS%id_hf_diffv > 0) call post_product_v(CS%id_hf_diffv, diffv, ADp%diag_hfrac_v, G, nz, CS%diag)
2109
2110 ! Diagnostics for thickness-weighted vertically averaged momentum budget terms
211124 if (CS%id_hf_diffu_2d > 0) call post_product_sum_u(CS%id_hf_diffu_2d, diffu, ADp%diag_hfrac_u, G, nz, CS%diag)
211224 if (CS%id_hf_diffv_2d > 0) call post_product_sum_v(CS%id_hf_diffv_2d, diffv, ADp%diag_hfrac_v, G, nz, CS%diag)
2113
2114 ! Diagnostics for the vertical sum of layer thickness x momentum budget terms
211524 if (CS%id_intz_diffu_2d > 0) call post_product_sum_u(CS%id_intz_diffu_2d, diffu, ADp%diag_hu, G, nz, CS%diag)
211624 if (CS%id_intz_diffv_2d > 0) call post_product_sum_v(CS%id_intz_diffv_2d, diffv, ADp%diag_hv, G, nz, CS%diag)
2117
2118 ! Diagnostics for thickness x momentum budget terms
211924 if (CS%id_h_diffu > 0) call post_product_u(CS%id_h_diffu, diffu, ADp%diag_hu, G, nz, CS%diag)
212024 if (CS%id_h_diffv > 0) call post_product_v(CS%id_h_diffv, diffv, ADp%diag_hv, G, nz, CS%diag)
2121
2122 ! Diagnostics for momentum budget terms multiplied by visc_rem_[uv],
212324 if (CS%id_diffu_visc_rem > 0) call post_product_u(CS%id_diffu_visc_rem, diffu, ADp%visc_rem_u, G, nz, CS%diag)
212424 if (CS%id_diffv_visc_rem > 0) call post_product_v(CS%id_diffv_visc_rem, diffv, ADp%visc_rem_v, G, nz, CS%diag)
2125 endif
2126
212725 if (CS%use_ZB2020) then
2128 call ZB2020_lateral_stress(u, v, h, diffu, diffv, G, GV, CS%ZB2020, &
21290 CS%dx2h, CS%dy2h, CS%dx2q, CS%dy2q)
2130 endif
2131
213250end subroutine horizontal_viscosity
2133
2134!> Calculates the magnitude of the vorticity and divergence gradients, and the
2135!! Laplacian of vorticity, that are used within horizontal_viscosity by the Leith,
2136!! modified Leith, Leith+E, and QG Leith viscosity schemes. The caller must only
2137!! invoke this routine when CS%Leith_Kh, CS%Leith_Ah, or CS%use_Leithy is true.
21380subroutine hor_visc_Leith_grad(G, GV, US, CS, VarMix, nkblock, kstart, kmax, &
2139 is, ie, js, je, is_Kh, ie_Kh, js_Kh, je_Kh, Ieq, Jeq, &
21400 h, dz, slope_x, slope_y, dudx, dvdy, vort_xy, vort_xy_smooth, &
21410 grad_vort_mag_h, grad_vort_mag_h_2d, grad_div_mag_h, &
21420 grad_vort_mag_q, grad_vort_mag_q_2d, grad_div_mag_q, &
21430 vert_vort_mag_smooth, Del2vort_q)
2144 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2145 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2146 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2147 type(hor_visc_CS), intent(in) :: CS !< Horizontal viscosity control structure
2148 type(VarMix_CS), intent(inout) :: VarMix !< Variable mixing control structure
2149 integer, intent(in) :: nkblock !< The k-block size used to size the following arrays [nondim]
2150 integer, intent(in) :: kstart !< The first absolute k-layer of the current k-block
2151 integer, intent(in) :: kmax !< The number of active k-layers in the current k-block
2152 integer, intent(in) :: is !< Start i-loop index for the h-point viscosities
2153 integer, intent(in) :: ie !< End i-loop index for the h-point viscosities
2154 integer, intent(in) :: js !< Start j-loop index for the h-point viscosities
2155 integer, intent(in) :: je !< End j-loop index for the h-point viscosities
2156 integer, intent(in) :: is_Kh !< Start i-loop index for the thickness point viscosities
2157 integer, intent(in) :: ie_Kh !< End i-loop index for the thickness point viscosities
2158 integer, intent(in) :: js_Kh !< Start j-loop index for the thickness point viscosities
2159 integer, intent(in) :: je_Kh !< End j-loop index for the thickness point viscosities
2160 integer, intent(in) :: Ieq !< The last i-index at q-points
2161 integer, intent(in) :: Jeq !< The last j-index at q-points
2162 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
2163 intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2].
2164 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
2165 intent(in) :: dz !< Height change across layers [Z ~> m]
2166 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)+1), &
2167 intent(inout) :: slope_x !< Isopycnal slope in i-direction [Z L-1 ~> nondim]
2168 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)+1), &
2169 intent(inout) :: slope_y !< Isopycnal slope in j-direction [Z L-1 ~> nondim]
2170 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2171 intent(in) :: dudx !< x-derivative of the horizontal tension [T-1 ~> s-1]
2172 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2173 intent(in) :: dvdy !< y-derivative of the horizontal tension [T-1 ~> s-1]
2174 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2175 intent(in) :: vort_xy !< Vertical vorticity (dv/dx - du/dy) including
2176 !! metric terms [T-1 ~> s-1]
2177 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2178 intent(in) :: vort_xy_smooth !< Vertical vorticity including metric
2179 !! terms, smoothed [T-1 ~> s-1]
2180 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2181 intent(out) :: grad_vort_mag_h !< Magnitude of vorticity gradient at
2182 !! h-points [L-1 T-1 ~> m-1 s-1]
2183 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2184 intent(out) :: grad_vort_mag_h_2d !< Magnitude of 2d vorticity gradient
2185 !! at h-points [L-1 T-1 ~> m-1 s-1]
2186 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2187 intent(out) :: grad_div_mag_h !< Magnitude of divergence gradient at
2188 !! h-points [L-1 T-1 ~> m-1 s-1]
2189 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2190 intent(out) :: grad_vort_mag_q !< Magnitude of vorticity gradient at
2191 !! q-points [L-1 T-1 ~> m-1 s-1]
2192 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2193 intent(out) :: grad_vort_mag_q_2d !< Magnitude of 2d vorticity gradient
2194 !! at q-points [L-1 T-1 ~> m-1 s-1]
2195 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2196 intent(out) :: grad_div_mag_q !< Magnitude of divergence gradient at
2197 !! q-points [L-1 T-1 ~> m-1 s-1]
2198 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2199 intent(out) :: vert_vort_mag_smooth !< Magnitude of gradient of smoothed
2200 !! vertical vorticity (h or q) [L-1 T-1 ~> m-1 s-1]
2201 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2202 intent(out) :: Del2vort_q !< Laplacian of vorticity at q-points
2203 !! [L-2 T-1 ~> m-2 s-1]
2204 ! Local variables
2205 real, dimension(SZI_(G),SZJB_(G),nkblock) :: &
22060 vort_xy_dx, & ! x-derivative of vertical vorticity (d/dx(dv/dx - du/dy)) [L-1 T-1 ~> m-1 s-1]
22070 vort_xy_dx_smooth, & ! x-derivative of smoothed vertical vorticity [L-1 T-1 ~> m-1 s-1]
22080 div_xx_dy ! y-derivative of horizontal divergence (d/dy(du/dx + dv/dy)) [L-1 T-1 ~> m-1 s-1]
2209 real, dimension(SZIB_(G),SZJ_(G),nkblock) :: &
22100 vort_xy_dy, & ! y-derivative of vertical vorticity (d/dy(dv/dx - du/dy)) [L-1 T-1 ~> m-1 s-1]
22110 vort_xy_dy_smooth, & ! y-derivative of smoothed vertical vorticity [L-1 T-1 ~> m-1 s-1]
22120 div_xx_dx ! x-derivative of horizontal divergence (d/dx(du/dx + dv/dy)) [L-1 T-1 ~> m-1 s-1]
2213 real, dimension(SZI_(G),SZJ_(G),nkblock) :: &
22140 div_xx ! Estimate of horizontal divergence at h-points [T-1 ~> s-1]
2215 real :: DY_dxBu ! Ratio of meridional over zonal grid spacing at vertices [nondim]
2216 real :: DX_dyBu ! Ratio of zonal over meridional grid spacing at vertices [nondim]
2217 integer :: i, j, k, kk
2218
2219 ! Vorticity gradient
22200 do concurrent (kk=1:kmax, J=js-2:je_Kh, i=is_Kh-1:ie_Kh+1) DO_LOCALITY(local(DY_dxBu))
22210 DY_dxBu = G%dyBu(I,J) * G%IdxBu(I,J)
22220 vort_xy_dx(i,J,kk) = DY_dxBu * ((vort_xy(I,J,kk) * G%IdyCu(I,j)) - (vort_xy(I-1,J,kk) * G%IdyCu(I-1,j)))
2223 enddo
2224
22250 do concurrent (kk=1:kmax, j=js_Kh-1:je_Kh+1, I=is-2:ie_Kh) DO_LOCALITY(local(DX_dyBu))
22260 DX_dyBu = G%dxBu(I,J) * G%IdyBu(I,J)
22270 vort_xy_dy(I,j,kk) = DX_dyBu * ((vort_xy(I,J,kk) * G%IdxCv(i,J)) - (vort_xy(I,J-1,kk) * G%IdxCv(i,J-1)))
2228 enddo
2229
22300 if (CS%use_Leithy) then
2231 ! Gradient of smoothed vorticity
22320 do concurrent (kk=1:kmax, J=js_Kh-1:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(DY_dxBu))
22330 DY_dxBu = G%dyBu(I,J) * G%IdxBu(I,J)
2234 vort_xy_dx_smooth(i,J,kk) = DY_dxBu * &
22350 ((vort_xy_smooth(I,J,kk) * G%IdyCu(I,j)) - (vort_xy_smooth(I-1,J,kk) * G%IdyCu(I-1,j)))
2236 enddo
2237
22380 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, I=is_Kh-1:ie_Kh) DO_LOCALITY(local(DX_dyBu))
22390 DX_dyBu = G%dxBu(I,J) * G%IdyBu(I,J)
2240 vort_xy_dy_smooth(I,j,kk) = DX_dyBu * &
22410 ((vort_xy_smooth(I,J,kk) * G%IdxCv(i,J)) - (vort_xy_smooth(I,J-1,kk) * G%IdxCv(i,J-1)))
2242 enddo
2243 endif ! If Leithy
2244
2245 ! Laplacian of vorticity
2246 ! if (CS%Leith_Ah .or. CS%use_Leithy) then
22470 do concurrent (kk=1:kmax, J=js_Kh-1:je_Kh, I=is_Kh-1:ie_Kh) DO_LOCALITY(local(DY_dxBu, DX_dyBu))
22480 DY_dxBu = G%dyBu(I,J) * G%IdxBu(I,J)
22490 DX_dyBu = G%dxBu(I,J) * G%IdyBu(I,J)
2250
2251 Del2vort_q(I,J,kk) = DY_dxBu * ((vort_xy_dx(i+1,J,kk) * G%IdyCv(i+1,J)) - (vort_xy_dx(i,J,kk) * G%IdyCv(i,J))) + &
22520 DX_dyBu * ((vort_xy_dy(I,j+1,kk) * G%IdyCu(I,j+1)) - (vort_xy_dy(I,j,kk) * G%IdyCu(I,j)))
2253 enddo
2254 ! endif
2255
22560 if (CS%modified_Leith) then
2257
2258 ! Divergence
22590 do concurrent (kk=1:kmax, j=js_Kh-1:je_Kh+1, i=is_Kh-1:ie_Kh+1)
22600 div_xx(i,j,kk) = dudx(i,j,kk) + dvdy(i,j,kk)
2261 enddo
2262
2263 ! Divergence gradient
22640 do concurrent (kk=1:kmax, j=js-1:je+1, I=is_Kh-1:ie_Kh)
22650 div_xx_dx(I,j,kk) = G%IdxCu(I,j)*(div_xx(i+1,j,kk) - div_xx(i,j,kk))
2266 enddo
22670 do concurrent (kk=1:kmax, J=js_Kh-1:je_Kh, i=is-1:ie+1)
22680 div_xx_dy(i,J,kk) = G%IdyCv(i,J)*(div_xx(i,j+1,kk) - div_xx(i,j,kk))
2269 enddo
2270
2271 ! Magnitude of divergence gradient
22720 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
2273 grad_div_mag_h(i,j,kk) = sqrt(((0.5*(div_xx_dx(I,j,kk) + div_xx_dx(I-1,j,kk)))**2) + &
22740 ((0.5*(div_xx_dy(i,J,kk) + div_xx_dy(i,J-1,kk)))**2))
2275 enddo
22760 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
2277 grad_div_mag_q(I,J,kk) = sqrt(((0.5*(div_xx_dx(I,j,kk) + div_xx_dx(I,j+1,kk)))**2) + &
22780 ((0.5*(div_xx_dy(i,J,kk) + div_xx_dy(i+1,J,kk)))**2))
2279 enddo
2280
2281 else
2282
22830 do concurrent (kk=1:kmax, j=js-1:je+1, I=is_Kh-1:ie_Kh)
22840 div_xx_dx(I,j,kk) = 0.0
2285 enddo
22860 do concurrent (kk=1:kmax, J=js_Kh-1:je_Kh, i=is-1:ie+1)
22870 div_xx_dy(i,J,kk) = 0.0
2288 enddo
22890 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
22900 grad_div_mag_h(i,j,kk) = 0.0
2291 enddo
22920 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
22930 grad_div_mag_q(I,J,kk) = 0.0
2294 enddo
2295
2296 endif ! CS%modified_Leith
2297
2298 ! Add in beta for the Leith viscosity
22990 if (CS%use_beta_in_Leith) then
23000 do concurrent (kk=1:kmax, J=js-2:Jeq+1, i=is-1:ie+1)
23010 vort_xy_dx(i,J,kk) = vort_xy_dx(i,J,kk) + 0.5 * ( G%dF_dx(i,j) + G%dF_dx(i,j+1))
2302 enddo
23030 do concurrent (kk=1:kmax, j=js-1:je+1, I=is-2:Ieq+1)
23040 vort_xy_dy(I,j,kk) = vort_xy_dy(I,j,kk) + 0.5 * ( G%dF_dy(i,j) + G%dF_dy(i+1,j))
2305 enddo
2306 endif ! CS%use_beta_in_Leith
2307
23080 if (CS%use_QG_Leith_visc) then
2309
23100 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
2311 grad_vort_mag_h_2d(i,j,kk) = SQRT(((0.5*(vort_xy_dx(i,J,kk) + vort_xy_dx(i,J-1,kk)))**2) + &
23120 ((0.5*(vort_xy_dy(I,j,kk) + vort_xy_dy(I-1,j,kk)))**2) )
2313 enddo
23140 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
2315 grad_vort_mag_q_2d(I,J,kk) = SQRT(((0.5*(vort_xy_dx(i,J,kk) + vort_xy_dx(i+1,J,kk)))**2) + &
23160 ((0.5*(vort_xy_dy(I,j,kk) + vort_xy_dy(I,j+1,kk)))**2) )
2317 enddo
2318
2319 ! This accumulates terms, some of which are in VarMix.
23200 do kk=1,kmax
23210 k = kstart + kk - 1
2322 call calc_QG_Leith_viscosity(VarMix, G, GV, US, h, dz, k, div_xx_dx(:,:,kk), div_xx_dy(:,:,kk), &
23230 slope_x, slope_y, vort_xy_dx(:,:,kk), vort_xy_dy(:,:,kk))
2324 enddo
2325
2326 endif
2327
23280 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
2329 grad_vort_mag_h(i,j,kk) = SQRT(((0.5*(vort_xy_dx(i,J,kk) + vort_xy_dx(i,J-1,kk)))**2) + &
23300 ((0.5*(vort_xy_dy(I,j,kk) + vort_xy_dy(I-1,j,kk)))**2) )
2331 enddo
23320 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
2333 grad_vort_mag_q(I,J,kk) = SQRT(((0.5*(vort_xy_dx(i,J,kk) + vort_xy_dx(i+1,J,kk)))**2) + &
23340 ((0.5*(vort_xy_dy(I,j,kk) + vort_xy_dy(I,j+1,kk)))**2) )
2335 enddo
2336
23370 if (CS%use_Leithy) then
23380 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
2339 vert_vort_mag_smooth(i,j,kk) = SQRT(((0.5*(vort_xy_dx_smooth(i,J,kk) + &
2340 vort_xy_dx_smooth(i,J-1,kk)))**2) + &
2341 ((0.5*(vort_xy_dy_smooth(I,j,kk) + &
23420 vort_xy_dy_smooth(I-1,j,kk)))**2) )
2343 enddo
2344 endif ! Leithy
2345
23460end subroutine hor_visc_Leith_grad
2347
2348!> Adds the MEKE-based (EY24_EBT_BS) backscatter contribution to the diagonal term of
2349!! the stress tensor at h-points. The caller must only invoke this routine when
2350!! CS%EY24_EBT_BS is true.
23510subroutine hor_visc_backscatter_h(G, CS, MEKE, VarMix, use_kh_struct, nkblock, kstart, kmax, &
23520 Isq, Ieq, Jsq, Jeq, visc_limit_h_flag, sh_xx, str_xx, BS_coeff_h)
2353 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2354 type(hor_visc_CS), intent(in) :: CS !< Horizontal viscosity control structure
2355 type(MEKE_type), intent(in) :: MEKE !< MEKE fields related to Mesoscale Eddy Kinetic Energy.
2356 type(VarMix_CS), intent(in) :: VarMix !< Variable mixing control structure
2357 logical, intent(in) :: use_kh_struct !< If true, shape the backscatter coefficient
2358 !! with VarMix%BS_struct
2359 integer, intent(in) :: nkblock !< The k-block size used to size the following arrays [nondim]
2360 integer, intent(in) :: kstart !< The first absolute k-layer of the current k-block
2361 integer, intent(in) :: kmax !< The number of active k-layers in the current k-block
2362 integer, intent(in) :: Isq !< Start i-loop index for the stress tensor at h-points
2363 integer, intent(in) :: Ieq !< End i-loop index for the stress tensor at h-points
2364 integer, intent(in) :: Jsq !< Start j-loop index for the stress tensor at h-points
2365 integer, intent(in) :: Jeq !< End j-loop index for the stress tensor at h-points
2366 real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
2367 intent(in) :: visc_limit_h_flag !< determines whether backscatter is shut off [nondim]
2368 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2369 intent(in) :: sh_xx !< horizontal tension (du/dx - dv/dy) including
2370 !! metric terms [T-1 ~> s-1]
2371 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2372 intent(inout) :: str_xx !< The diagonal term in the stress tensor
2373 !! [H L2 T-2 ~> m3 s-2 or kg s-2]
2374 real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
2375 intent(inout) :: BS_coeff_h !< A diagnostic array of the backscatter
2376 !! coefficient [L2 T-1 ~> m2 s-1]
2377 ! Local variables
2378 real, dimension(SZI_(G),SZJ_(G),nkblock) :: &
23790 Kh_BS, & ! Laplacian antiviscosity [L2 T-1 ~> m2 s-1]
23800 str_xx_BS ! The diagonal term in the stress tensor due to backscatter [H L2 T-2 ~> m3 s-2 or kg s-2]
2381 integer :: i, j, k, kk
2382
23830 do kk=1,kmax ; do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
23840 k = kstart + kk - 1
23850 if (visc_limit_h_flag(i,j,k) > 0) then
23860 Kh_BS(i,j,kk) = 0.
2387 else
23880 if (use_kh_struct) then
23890 Kh_BS(i,j,kk) = MEKE%Ku(i,j) * VarMix%BS_struct(i,j,k)
2390 else
23910 Kh_BS(i,j,kk) = MEKE%Ku(i,j)
2392 endif
2393 endif
2394 enddo ; enddo ; enddo
2395
23960 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1)
23970 str_xx_BS(i,j,kk) = -Kh_BS(i,j,kk) * sh_xx(i,j,kk)
2398 enddo
2399
24000 if (CS%id_BS_coeff_h>0) then
24010 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1) DO_LOCALITY(local(k))
24020 k = kstart + kk - 1
24030 BS_coeff_h(i,j,k) = Kh_BS(i,j,kk)
2404 enddo
2405 endif
2406
24070 do concurrent (kk=1:kmax, j=Jsq:Jeq+1, i=Isq:Ieq+1)
24080 str_xx(i,j,kk) = str_xx(i,j,kk) + str_xx_BS(i,j,kk)
2409 enddo
2410
24110end subroutine hor_visc_backscatter_h
2412
2413!> Adds the MEKE-based (EY24_EBT_BS) backscatter contribution to the cross term of
2414!! the stress tensor at q-points. The caller must only invoke this routine when
2415!! CS%EY24_EBT_BS is true.
24160subroutine hor_visc_backscatter_q(G, GV, CS, MEKE, VarMix, use_kh_struct, nkblock, kstart, kmax, &
24170 is, js, Ieq, Jeq, visc_limit_q_flag, sh_xy, str_xy, BS_coeff_q)
2418 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2419 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2420 type(hor_visc_CS), intent(in) :: CS !< Horizontal viscosity control structure
2421 type(MEKE_type), intent(in) :: MEKE !< MEKE fields related to Mesoscale Eddy Kinetic Energy.
2422 type(VarMix_CS), intent(in) :: VarMix !< Variable mixing control structure
2423 logical, intent(in) :: use_kh_struct !< If true, shape the backscatter coefficient
2424 !! with VarMix%BS_struct
2425 integer, intent(in) :: nkblock !< The k-block size used to size the following arrays [nondim]
2426 integer, intent(in) :: kstart !< The first absolute k-layer of the current k-block
2427 integer, intent(in) :: kmax !< The number of active k-layers in the current k-block
2428 integer, intent(in) :: is !< Start i-loop index for the q-point stress tensor
2429 integer, intent(in) :: js !< Start j-loop index for the q-point stress tensor
2430 integer, intent(in) :: Ieq !< End i-loop index for the q-point stress tensor
2431 integer, intent(in) :: Jeq !< End j-loop index for the q-point stress tensor
2432 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)), &
2433 intent(in) :: visc_limit_q_flag !< determines whether backscatter is shut off [nondim]
2434 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2435 intent(in) :: sh_xy !< horizontal shearing strain (du/dy + dv/dx) including
2436 !! metric terms [T-1 ~> s-1]
2437 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2438 intent(inout) :: str_xy !< The cross term in the stress tensor
2439 !! [H L2 T-2 ~> m3 s-2 or kg s-2]
2440 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)), &
2441 intent(inout) :: BS_coeff_q !< A diagnostic array of the backscatter
2442 !! coefficient [L2 T-1 ~> m2 s-1]
2443 ! Local variables
2444 real, dimension(SZIB_(G),SZJB_(G),nkblock) :: &
24450 Kh_BS, & ! Laplacian antiviscosity [L2 T-1 ~> m2 s-1]
24460 str_xy_BS ! The cross term in the stress tensor due to backscatter [H L2 T-2 ~> m3 s-2 or kg s-2]
2447 integer :: i, j, k, kk
2448
24490 do kk=1,kmax ; do J=js-1,Jeq ; do I=is-1,Ieq
24500 k = kstart + kk - 1
24510 if (visc_limit_q_flag(I,J,k) > 0) then
24520 Kh_BS(I,J,kk) = 0.
2453 else
24540 if (use_kh_struct) then
2455 Kh_BS(I,J,kk) = 0.25*( ((MEKE%Ku(i,j)*VarMix%BS_struct(i,j,k)) + &
2456 (MEKE%Ku(i+1,j+1)*VarMix%BS_struct(i+1,j+1,k))) + &
2457 ((MEKE%Ku(i+1,j)*VarMix%BS_struct(i+1,j,k)) + &
24580 (MEKE%Ku(i,j+1)*VarMix%BS_struct(i,j+1,k))) )
2459 else
2460 Kh_BS(I,J,kk) = 0.25*( (MEKE%Ku(i,j) + MEKE%Ku(i+1,j+1)) + &
24610 (MEKE%Ku(i+1,j) + MEKE%Ku(i,j+1)) )
2462 endif
2463 endif
2464 enddo ; enddo ; enddo
2465
24660 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
24670 str_xy_BS(I,J,kk) = -Kh_BS(I,J,kk) * (sh_xy(I,J,kk))
2468 enddo
2469
24700 if (CS%id_BS_coeff_q>0) then
24710 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq) DO_LOCALITY(local(k))
24720 k = kstart + kk - 1
24730 BS_coeff_q(I,J,k) = Kh_BS(I,J,kk)
2474 enddo
2475 endif
2476
24770 do concurrent (kk=1:kmax, J=js-1:Jeq, I=is-1:Ieq)
24780 str_xy(I,J,kk) = str_xy(I,J,kk) + str_xy_BS(I,J,kk)
2479 enddo
2480
24810end subroutine hor_visc_backscatter_q
2482
2483!> Computes the Leith+E antisymmetric-viscosity ratio m_leithy, and updates the
2484!! biharmonic viscosity Ah (and Ah_h) to include the Leith+E contribution, optionally
2485!! smoothing m_leithy and Ah in the process. The caller must only invoke this
2486!! routine when CS%use_Leithy is true.
24870subroutine hor_visc_Leithy_Ah(G, GV, CS, nkblock, kstart, kmax, is_Kh, ie_Kh, js_Kh, je_Kh, inv_PI6, &
24880 Del2vort_q, vert_vort_mag, vert_vort_mag_smooth, vort_xy_smooth, &
24890 Ah, Ah_h, m_leithy)
2490 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2491 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2492 type(hor_visc_CS), intent(in) :: CS !< Horizontal viscosity control structure
2493 integer, intent(in) :: nkblock !< The k-block size used to size the following arrays [nondim]
2494 integer, intent(in) :: kstart !< The first absolute k-layer of the current k-block
2495 integer, intent(in) :: kmax !< The number of active k-layers in the current k-block
2496 integer, intent(in) :: is_Kh !< Start i-loop index for the thickness point viscosities
2497 integer, intent(in) :: ie_Kh !< End i-loop index for the thickness point viscosities
2498 integer, intent(in) :: js_Kh !< Start j-loop index for the thickness point viscosities
2499 integer, intent(in) :: je_Kh !< End j-loop index for the thickness point viscosities
2500 real, intent(in) :: inv_PI6 !< The inverse of pi to the sixth power [nondim]
2501 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2502 intent(in) :: Del2vort_q !< Laplacian of vorticity at q-points [L-2 T-1 ~> m-2 s-1]
2503 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2504 intent(in) :: vert_vort_mag !< Magnitude of the vertical vorticity
2505 !! gradient (h or q) [L-1 T-1 ~> m-1 s-1]
2506 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2507 intent(in) :: vert_vort_mag_smooth !< Magnitude of gradient of smoothed
2508 !! vertical vorticity (h or q) [L-1 T-1 ~> m-1 s-1]
2509 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2510 intent(in) :: vort_xy_smooth !< Vertical vorticity including metric
2511 !! terms, smoothed [T-1 ~> s-1]
2512 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2513 intent(inout) :: Ah !< biharmonic viscosity (h or q) [L4 T-1 ~> m4 s-1]
2514 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
2515 intent(inout) :: Ah_h !< biharmonic viscosity at thickness points [L4 T-1 ~> m4 s-1]
2516 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2517 intent(out) :: m_leithy !< Kh=m_leithy*Ah in Leith+E parameterization [L-2 ~> m-2]
2518 ! Local variables
2519 real, dimension(SZI_(G),SZJ_(G),nkblock) :: &
25200 Ah_sq ! The square of the biharmonic viscosity [L8 T-2 ~> m8 s-2]
2521 real :: Del2vort_h ! Laplacian of vorticity at h-points [L-2 T-1 ~> m-2 s-1]
2522 real :: AhLth ! 2D Leith biharmonic viscosity [L4 T-1 ~> m4 s-1]
2523 real :: AhLthy ! 2D Leith+E biharmonic viscosity [L4 T-1 ~> m4 s-1]
2524 integer :: i, j, k, kk
2525
2526 ! Get m_leithy
25270 if (CS%smooth_Ah) then
25280 do kk=1,kmax
25290 m_leithy(:,:,kk) = 0.0 ! This is here to initialize domain edge halo values.
2530 enddo
2531 endif
25320 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(Del2vort_h, AhLth))
2533 Del2vort_h = 0.25 * ((Del2vort_q(I,J,kk) + Del2vort_q(I-1,J-1,kk)) + &
25340 (Del2vort_q(I-1,J,kk) + Del2vort_q(I,J-1,kk)))
25350 AhLth = CS%Biharm6_const_xx(i,j) * inv_PI6 * abs(Del2vort_h)
25360 if (AhLth <= CS%Ah_bg_xx(i,j)) then
25370 m_leithy(i,j,kk) = 0.0
2538 else
25390 if ((CS%m_const_leithy(i,j)*vert_vort_mag(i,j,kk)) < abs(vort_xy_smooth(i,j,kk))) then
25400 m_leithy(i,j,kk) = CS%c_K * (vert_vort_mag(i,j,kk) / vort_xy_smooth(i,j,kk))**2
2541 else
25420 m_leithy(i,j,kk) = CS%m_leithy_max(i,j)
2543 endif
25440 m_leithy(i,j,kk) = G%mask2dBu(i,j) * m_leithy(i,j,kk)
2545 endif
2546 enddo
2547
25480 if (CS%smooth_Ah) then
25490 do kk=1,kmax
2550 ! Smooth m_leithy. A single call smoothes twice.
25510 call pass_var(m_leithy(:,:,kk), G%Domain, halo=2)
25520 call smooth_x9_h(G, m_leithy(:,:,kk), zero_land=.true.)
25530 call pass_var(m_leithy(:,:,kk), G%Domain)
2554 enddo
2555 endif
2556 ! Get Ah
25570 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(Del2vort_h, AhLthy))
2558 Del2vort_h = 0.25 * ((Del2vort_q(I,J,kk) + Del2vort_q(I-1,J-1,kk)) + &
25590 (Del2vort_q(I-1,J,kk) + Del2vort_q(I,J-1,kk)))
2560 AhLthy = CS%Biharm6_const_xx(i,j) * inv_PI6 * &
25610 sqrt(max(0.,Del2vort_h**2 - m_leithy(i,j,kk)*vert_vort_mag_smooth(i,j,kk)**2))
25620 Ah(i,j,kk) = max(CS%Ah_bg_xx(i,j), AhLthy)
2563 enddo
25640 if (CS%smooth_Ah) then
2565 ! Smooth Ah before applying upper bound. Square Ah, then smooth, then take its square root.
25660 do kk=1,kmax
25670 Ah_sq(:,:,kk) = 0.0 ! This is here to initialize domain edge halo values.
2568 enddo
25690 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh)
25700 Ah_sq(i,j,kk) = Ah(i,j,kk)**2
2571 enddo
25720 do kk=1,kmax
25730 call pass_var(Ah_sq(:,:,kk), G%Domain, halo=2)
2574 ! A single call smoothes twice.
25750 call smooth_x9_h(G, Ah_sq(:,:,kk), zero_land=.false.)
25760 call pass_var(Ah_sq(:,:,kk), G%Domain)
2577 enddo
25780 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(k))
25790 k = kstart + kk - 1
25800 Ah_h(i,j,k) = max(CS%Ah_bg_xx(i,j), sqrt(max(0., Ah_sq(i,j,kk))))
25810 Ah(i,j,kk) = Ah_h(i,j,k)
2582 enddo
2583 else
25840 do concurrent (kk=1:kmax, j=js_Kh:je_Kh, i=is_Kh:ie_Kh) DO_LOCALITY(local(k))
25850 k = kstart + kk - 1
25860 Ah_h(i,j,k) = Ah(i,j,kk)
2587 enddo
2588 endif
2589
25900end subroutine hor_visc_Leithy_Ah
2591
2592!> Returns the effective k-block size for horizontal_viscosity calls.
259325integer function hor_visc_nkblock(CS, GV)
2594 type(hor_visc_CS), intent(in) :: CS !< Horizontal viscosity control structure
2595 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
259625 hor_visc_nkblock = merge(GV%ke, CS%nkblock, CS%nkblock==0)
259725end function hor_visc_nkblock
2598
2599!> Calculates the barotropic tension and shearing strain fields and the GME
2600!! efficiency and isopycnal height diffusivity fields that are used within
2601!! horizontal_viscosity when GME (CS%use_GME) is active. The caller must
2602!! only invoke this routine when CS%use_GME is true.
26030subroutine hor_visc_GME_setup(G, GV, US, CS, h, BT, TD, nkblock, &
26040 dudx_bt, dvdy_bt, dvdx_bt, dudy_bt, sh_xx_bt, sh_xy_bt, &
26050 GME_effic_h, GME_effic_q, KH_u_GME, KH_v_GME, &
26060 GME_coeff_h, GME_coeff_q, str_xx_GME, str_xy_GME)
2607 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2608 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2609 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2610 type(hor_visc_CS), intent(inout) :: CS !< Horizontal viscosity control structure
2611 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
2612 intent(inout) :: h !< Layer thicknesses [H ~> m or kg m-2].
2613 type(barotropic_CS), optional, intent(in) :: BT !< Barotropic control structure
2614 type(thickness_diffuse_CS), optional, intent(in) :: TD !< Thickness diffusion control structure
2615 integer, intent(in) :: nkblock !< The k-block size used to size the following arrays [nondim]
2616 real, dimension(SZI_(G),SZJB_(G)), &
2617 intent(out) :: dudx_bt !< x-component in the barotropic
2618 !! horizontal tension [T-1 ~> s-1]
2619 real, dimension(SZI_(G),SZJB_(G)), &
2620 intent(out) :: dvdy_bt !< y-component in the barotropic
2621 !! horizontal tension [T-1 ~> s-1]
2622 real, dimension(SZIB_(G),SZJB_(G)), &
2623 intent(out) :: dvdx_bt !< x-component in the barotropic
2624 !! shearing strain [T-1 ~> s-1]
2625 real, dimension(SZIB_(G),SZJB_(G)), &
2626 intent(out) :: dudy_bt !< y-component in the barotropic
2627 !! shearing strain [T-1 ~> s-1]
2628 real, dimension(SZI_(G),SZJ_(G)), &
2629 intent(out) :: sh_xx_bt !< Barotropic horizontal tension
2630 !! (du/dx - dv/dy) including metric terms [T-1 ~> s-1]
2631 real, dimension(SZIB_(G),SZJB_(G)), &
2632 intent(out) :: sh_xy_bt !< Barotropic horizontal shearing strain
2633 !! (du/dy + dv/dx) including metric terms [T-1 ~> s-1]
2634 real, dimension(SZI_(G),SZJ_(G)), &
2635 intent(out) :: GME_effic_h !< The filtered efficiency of the
2636 !! GME terms at h points [nondim]
2637 real, dimension(SZIB_(G),SZJB_(G)), &
2638 intent(out) :: GME_effic_q !< The filtered efficiency of the
2639 !! GME terms at q points [nondim]
2640 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)+1), &
2641 intent(out) :: KH_u_GME !< Isopycnal height diffusivities in
2642 !! u-columns [L2 T-1 ~> m2 s-1]
2643 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)+1), &
2644 intent(out) :: KH_v_GME !< Isopycnal height diffusivities in
2645 !! v-columns [L2 T-1 ~> m2 s-1]
2646 real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
2647 intent(out) :: GME_coeff_h !< GME coefficient at h-points
2648 !! [L2 T-1 ~> m2 s-1]
2649 real, dimension(SZIB_(G),SZJB_(G),SZK_(GV)), &
2650 intent(out) :: GME_coeff_q !< GME coeff. at q-points [L2 T-1 ~> m2 s-1]
2651 real, dimension(SZI_(G),SZJ_(G),nkblock), &
2652 intent(out) :: str_xx_GME !< Smoothed diagonal term in the
2653 !! stress tensor from GME [L2 T-2 ~> m2 s-2]
2654 real, dimension(SZIB_(G),SZJB_(G),nkblock), &
2655 intent(out) :: str_xy_GME !< Smoothed cross term in the
2656 !! stress tensor from GME [L2 T-2 ~> m2 s-2]
2657 ! Local variables
2658 real, dimension(SZIB_(G),SZJ_(G)) :: &
26590 ubtav ! zonal barotropic velocity averaged over a baroclinic time-step [L T-1 ~> m s-1]
2660 real, dimension(SZI_(G),SZJB_(G)) :: &
26610 vbtav ! meridional barotropic velocity averaged over a baroclinic time-step [L T-1 ~> m s-1]
2662 real, dimension(SZI_(G),SZJ_(G)) :: &
26630 htot ! The total thickness of all layers [H ~> m or kg m-2]
2664 real :: grad_vel_mag_bt_h ! Magnitude of the barotropic velocity gradient tensor squared at h-points [T-2 ~> s-2]
2665 real :: boundary_mask_h ! A mask that zeroes out cells with at least one land edge [nondim]
2666 real :: grad_vel_mag_bt_q ! Magnitude of the barotropic velocity gradient tensor squared at q-points [T-2 ~> s-2]
2667 real :: boundary_mask_q ! A mask that zeroes out cells with at least one land edge [nondim]
2668 real :: h_arith_q ! The arithmetic mean total thickness at q points [H ~> m or kg m-2]
2669 real :: I_GME_h0 ! The inverse of GME tapering scale [H-1 ~> m-1 or m2 kg-1]
2670 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
2671
26720 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
26730 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
2674
2675 ! Initialize diagnostic arrays with zeros
26760 GME_coeff_h(:,:,:) = 0.0
26770 GME_coeff_q(:,:,:) = 0.0
26780 str_xx_GME(:,:,:) = 0.0
26790 str_xy_GME(:,:,:) = 0.0
2680
2681 ! Get barotropic velocities and their gradients
26820 call barotropic_get_tav(BT, ubtav, vbtav, G, US)
2683
26840 call pass_vector(ubtav, vbtav, G%Domain)
26850 call pass_var(h, G%domain, halo=2)
2686
2687 ! Calculate the barotropic horizontal tension
26880 do j=js-2,je+2 ; do i=is-2,ie+2
2689 dudx_bt(i,j) = CS%DY_dxT(i,j)*((G%IdyCu(I,j) * ubtav(I,j)) - &
26900 (G%IdyCu(I-1,j) * ubtav(I-1,j)))
2691 dvdy_bt(i,j) = CS%DX_dyT(i,j)*((G%IdxCv(i,J) * vbtav(i,J)) - &
26920 (G%IdxCv(i,J-1) * vbtav(i,J-1)))
2693 enddo ; enddo
26940 do j=Jsq-1,Jeq+2 ; do i=Isq-1,Ieq+2
26950 sh_xx_bt(i,j) = dudx_bt(i,j) - dvdy_bt(i,j)
2696 enddo ; enddo
2697
2698 ! Components for the barotropic shearing strain
26990 do J=Jsq-2,Jeq+2 ; do I=Isq-2,Ieq+2
2700 dvdx_bt(I,J) = CS%DY_dxBu(I,J)*((vbtav(i+1,J)*G%IdyCv(i+1,J)) &
27010 - (vbtav(i,J)*G%IdyCv(i,J)))
2702 dudy_bt(I,J) = CS%DX_dyBu(I,J)*((ubtav(I,j+1)*G%IdxCu(I,j+1)) &
27030 - (ubtav(I,j)*G%IdxCu(I,j)))
2704 enddo ; enddo
2705
27060 if (CS%no_slip) then
27070 do J=js-2,je+1 ; do I=is-2,ie+1
27080 sh_xy_bt(I,J) = (2.0-G%mask2dBu(I,J)) * ( dvdx_bt(I,J) + dudy_bt(I,J) )
2709 enddo ; enddo
2710 else
27110 do J=js-2,je+1 ; do I=is-2,ie+1
27120 sh_xy_bt(I,J) = G%mask2dBu(I,J) * ( dvdx_bt(I,J) + dudy_bt(I,J) )
2713 enddo ; enddo
2714 endif
2715
27160 do j=js-2,je+2 ; do i=is-2,ie+2
27170 htot(i,j) = 0.0
2718 enddo ; enddo
27190 do k=1,nz ; do j=js-2,je+2 ; do i=is-2,ie+2
27200 htot(i,j) = htot(i,j) + h(i,j,k)
2721 enddo ; enddo ; enddo
2722
27230 I_GME_h0 = 1.0 / CS%GME_h0
27240 do j=Jsq-1,Jeq+2 ; do i=Isq-1,Ieq+2
27250 boundary_mask_h = (G%mask2dCu(I,j) * G%mask2dCu(I-1,j)) * (G%mask2dCv(i,J) * G%mask2dCv(i,J-1))
2726 grad_vel_mag_bt_h = G%mask2dT(I,J) * boundary_mask_h * (dudx_bt(i,j)**2 + dvdy_bt(i,j)**2 + &
2727 (0.25*((dvdx_bt(I,J)+dvdx_bt(I-1,J-1)) + (dvdx_bt(I,J-1)+dvdx_bt(I-1,J))))**2 + &
27280 (0.25*((dudy_bt(I,J)+dudy_bt(I-1,J-1)) + (dudy_bt(I,J-1)+dudy_bt(I-1,J))))**2)
2729 ! Probably the following test could be simplified to
2730 ! if (boundary_mask_h * G%mask2dT(I,J) > 0.0) then
27310 if (grad_vel_mag_bt_h > 0.0) then
27320 GME_effic_h(i,j) = CS%GME_efficiency * G%mask2dT(I,J) * (MIN(htot(i,j) * I_GME_h0, 1.0)**2)
2733 else
27340 GME_effic_h(i,j) = 0.0
2735 endif
2736 enddo ; enddo
2737
27380 do J=js-2,je+1 ; do I=is-2,ie+1
27390 boundary_mask_q = (G%mask2dCv(i,J) * G%mask2dCv(i+1,J)) * (G%mask2dCu(I,j) * G%mask2dCu(I,j+1))
2740 grad_vel_mag_bt_q = G%mask2dBu(I,J) * boundary_mask_q * (dvdx_bt(I,J)**2 + dudy_bt(I,J)**2 + &
2741 (0.25*((dudx_bt(i,j)+dudx_bt(i+1,j+1)) + (dudx_bt(i,j+1)+dudx_bt(i+1,j))))**2 + &
27420 (0.25*((dvdy_bt(i,j)+dvdy_bt(i+1,j+1)) + (dvdy_bt(i,j+1)+dvdy_bt(i+1,j))))**2)
2743 ! Probably the following test could be simplified to
2744 ! if (boundary_mask_q * G%mask2dBu(I,J) > 0.0) then
27450 if (grad_vel_mag_bt_q > 0.0) then
27460 h_arith_q = 0.25 * ((htot(i,j) + htot(i+1,j+1)) + (htot(i+1,j) + htot(i,j+1)))
27470 GME_effic_q(I,J) = CS%GME_efficiency * G%mask2dBu(I,J) * (MIN(h_arith_q * I_GME_h0, 1.0)**2)
2748 else
27490 GME_effic_q(I,J) = 0.0
2750 endif
2751 enddo ; enddo
2752
27530 call thickness_diffuse_get_KH(TD, KH_u_GME, KH_v_GME, G, GV)
2754
27550 call pass_vector(KH_u_GME, KH_v_GME, G%domain, To_All+Scalar_Pair)
2756
27570 if (CS%debug) &
27580 call uvchksum("GME KH[u,v]_GME", KH_u_GME, KH_v_GME, G%HI, haloshift=2, unscale=US%L_to_m**2*US%s_to_T)
2759
27600end subroutine hor_visc_GME_setup
2761
2762!> Allocates space for and calculates static variables used by horizontal_viscosity.
2763!! hor_visc_init calculates and stores the values of a number of metric functions that
2764!! are used in horizontal_viscosity.
27651subroutine hor_visc_init(Time, G, GV, US, param_file, diag, CS, ADp)
2766 type(time_type), intent(in) :: Time !< Current model time.
2767 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
2768 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
2769 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2770 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
2771 !! parameters.
2772 type(diag_ctrl), target, intent(inout) :: diag !< Structure to regulate diagnostic output.
2773 type(hor_visc_CS), intent(inout) :: CS !< Horizontal viscosity control structure
2774 type(accel_diag_ptrs), intent(in), optional :: ADp !< Acceleration diagnostics
2775
2776 ! u0v is the Laplacian sensitivities to the v velocities at u points, with u0u, v0u, and v0v defined analogously.
27773 real, dimension(SZIB_(G),SZJ_(G)) :: u0u, u0v ! Laplacian sensitivities at u points [L-2 ~> m-2]
27781 real, dimension(SZI_(G),SZJB_(G)) :: v0u, v0v ! Laplacian sensitivities at v points [L-2 ~> m-2]
2779 real :: grid_sp_h2 ! Harmonic mean of the squares of the grid [L2 ~> m2]
2780 real :: grid_sp_h3 ! Harmonic mean of the squares of the grid^(3/2) [L3 ~> m3]
2781 real :: grid_sp_q2 ! spacings at h and q points [L2 ~> m2]
2782 real :: grid_sp_q3 ! spacings at h and q points^(3/2) [L3 ~> m3]
2783 real :: min_grid_sp_h2 ! Minimum value of grid_sp_h2 [L2 ~> m2]
2784 real :: min_grid_sp_h4 ! Minimum value of grid_sp_h2**2 [L4 ~> m4]
2785 real :: Kh_Limit ! A coefficient [T-1 ~> s-1] used, along with the
2786 ! grid spacing, to limit Laplacian viscosity.
2787 real :: fmax ! maximum absolute value of f at the four
2788 ! vorticity points around a thickness point [T-1 ~> s-1]
2789 real :: BoundCorConst ! A constant used when using viscosity to bound the Coriolis accelerations
2790 ! [T2 L-2 ~> s2 m-2]
2791 real :: Ah_Limit ! coefficient [T-1 ~> s-1] used, along with the
2792 ! grid spacing, to limit biharmonic viscosity
2793 real :: Kh ! Lapacian horizontal viscosity [L2 T-1 ~> m2 s-1]
2794 real :: Ah ! biharmonic horizontal viscosity [L4 T-1 ~> m4 s-1]
2795 real :: Kh_vel_scale ! this speed [L T-1 ~> m s-1] times grid spacing gives Laplacian viscosity
2796 real :: Ah_vel_scale ! this speed [L T-1 ~> m s-1] times grid spacing cubed gives biharmonic viscosity
2797 real :: Ah_time_scale ! damping time-scale for biharmonic visc [T ~> s]
2798 real :: Smag_Lap_const ! nondimensional Laplacian Smagorinsky constant [nondim]
2799 real :: Smag_bi_const ! nondimensional biharmonic Smagorinsky constant [nondim]
2800 real :: Leith_Lap_const ! nondimensional Laplacian Leith constant [nondim]
2801 real :: Leith_bi_const ! nondimensional biharmonic Leith constant [nondim]
2802 real :: dt ! The dynamics time step [T ~> s]
2803 real :: Idt ! The inverse of dt [T-1 ~> s-1]
2804 real :: denom ! work variable; the denominator of a fraction [L-2 ~> m-2] or [L-4 ~> m-4]
2805 real :: maxvel ! largest permitted velocity components [L T-1 ~> m s-1]
2806 real :: bound_Cor_vel ! grid-scale velocity variations at which value
2807 ! the quadratically varying biharmonic viscosity
2808 ! balances Coriolis acceleration [L T-1 ~> m s-1]
2809 real :: Kh_sin_lat ! Amplitude of latitudinally dependent viscosity [L2 T-1 ~> m2 s-1]
2810 real :: Kh_pwr_of_sine ! Power used to raise sin(lat) when using Kh_sin_lat [nondim]
2811 logical :: bound_Cor_def ! parameter setting of BOUND_CORIOLIS
2812 logical :: split ! If true, use the split time stepping scheme.
2813 ! If false and USE_GME = True, issue a FATAL error.
2814 logical :: use_MEKE ! If true, the MEKE parameterization is in use.
2815 logical :: enable_bugs ! If true, the defaults for recently added bug-fix flags are set to
2816 ! recreate the bugs, or if false bugs are only used if actively selected.
2817 real :: backscatter_Ro_c ! Coefficient in Rossby number function for backscatter [nondim]
2818 integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags
2819 character(len=200) :: inputdir, filename ! Input file names and paths
2820 character(len=80) :: Kh_var ! Input variable names
2821 real :: deg2rad ! Converts degrees to radians [radians degree-1]
2822 real :: slat_fn ! sin(lat)**Kh_pwr_of_sine [nondim]
2823 real :: aniso_grid_dir(2) ! Vector (n1,n2) for anisotropic direction [nondim]
2824 integer :: aniso_mode ! Selects the mode for setting the anisotropic direction
2825 integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
2826 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
2827 integer :: i, j
2828#ifdef __NVCOMPILER_OPENMP_GPU
2829 integer, parameter :: default_nkblock = 0
2830#else
2831 integer, parameter :: default_nkblock = 1
2832#endif
2833 ! This include declares and sets the variable "version".
2834# include "version_variable.h"
2835 character(len=40) :: mdl = "MOM_hor_visc" ! module name
28361 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
28371 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
28381 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
28391 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
2840
2841 ! init control structure
28421 call ZB2020_init(Time, G, GV, US, param_file, diag, CS%ZB2020, CS%use_ZB2020)
2843
28441 CS%initialized = .true.
2845
28461 CS%diag => diag
2847 ! Read parameters and write them to the model log.
28481 call log_version(param_file, mdl, version, "")
2849
2850 call get_param(param_file, mdl, "HORVISC_NKBLOCK", CS%nkblock, &
2851 "The k-direction block size used in horizontal viscosity calculations. "//&
2852 "The default 0 setting dynamically uses the full vertical column.", &
28531 default=default_nkblock, layoutParam=.true.)
28541 if (CS%nkblock < 0) call MOM_error(FATAL, "HORVISC_NKBLOCK must be >= 0.")
2855
2856 call get_param(param_file, mdl, "USE_CIRCULATION_IN_HORVISC", CS%use_circulation, &
2857 "Use circulation theorem to compute vorticity in horvisc module (for ZB20 or Leith)", &
28581 default=.False.)
2859
2860 ! All parameters are read in all cases to enable parameter spelling checks.
2861 call get_param(param_file, mdl, "DEFAULT_ANSWER_DATE", default_answer_date, &
2862 "This sets the default value for the various _ANSWER_DATE parameters.", &
28631 default=99991231)
2864
2865 ! Determine whether HOR_VISC_ANSWER_DATE is used, and avoid logging it if it is not used.
2866 call get_param(param_file, mdl, "USE_MEKE", use_MEKE, &
28671 default=.false., do_not_log=.true.)
28681 backscatter_Ro_c = 0.0
28691 if (use_MEKE) call get_param(param_file, mdl, "MEKE_BACKSCAT_RO_C", backscatter_Ro_c, &
2870 "The coefficient in the Rossby number function for scaling the biharmonic "//&
2871 "frictional energy source. Setting to non-zero enables the Rossby number function.", &
28721 units="nondim", default=0.0, do_not_log=.true.)
2873
2874 call get_param(param_file, mdl, "HOR_VISC_ANSWER_DATE", CS%answer_date, &
2875 "The vintage of the order of arithmetic and expressions in the horizontal "//&
2876 "viscosity calculations. Values between 20190102 and 20241201 recover the "//&
2877 "answers from the end of 2018, while higher values use updated and more robust "//&
2878 "forms of the same expressions.", &
28791 default=default_answer_date, do_not_log=(.not.GV%Boussinesq).or.(backscatter_Ro_c==0.0))
28801 if (.not.GV%Boussinesq) CS%answer_date = max(CS%answer_date, 20241201)
2881
28821 call get_param(param_file, mdl, "DEBUG", CS%debug, default=.false.)
2883 call get_param(param_file, mdl, "USE_CONT_THICKNESS", CS%use_cont_thick, &
2884 "If true, use thickness at velocity points from continuity solver. This option "//&
28851 "currently only works with split mode.", default=.false.)
2886 call get_param(param_file, mdl, "USE_CONT_THICKNESS_BUG", CS%use_cont_thick_bug, &
2887 "If true, retain an answer-changing halo update bug when "//&
2888 "USE_CONT_THICKNESS=True. This is not recommended.", &
28891 default=.false., do_not_log=.not.CS%use_cont_thick)
2890
2891 call get_param(param_file, mdl, "LAPLACIAN", CS%Laplacian, &
2892 "If true, use a Laplacian horizontal viscosity.", &
28931 default=.false.)
2894
2895 call get_param(param_file, mdl, "KH", Kh, &
2896 "The background Laplacian horizontal viscosity.", &
2897 units="m2 s-1", default=0.0, scale=US%m_to_L**2*US%T_to_s, &
28981 do_not_log=.not.CS%Laplacian)
2899 call get_param(param_file, mdl, "KH_BG_MIN", CS%Kh_bg_min, &
2900 "The minimum value allowed for Laplacian horizontal viscosity, KH.", &
2901 units="m2 s-1", default=0.0, scale=US%m_to_L**2*US%T_to_s, &
29021 do_not_log=.not.CS%Laplacian)
2903 call get_param(param_file, mdl, "KH_VEL_SCALE", Kh_vel_scale, &
2904 "The velocity scale which is multiplied by the grid "//&
2905 "spacing to calculate the Laplacian viscosity. "//&
2906 "The final viscosity is the largest of this scaled "//&
2907 "viscosity, the Smagorinsky and Leith viscosities, and KH.", &
2908 units="m s-1", default=0.0, scale=US%m_s_to_L_T, &
29091 do_not_log=.not.CS%Laplacian)
2910 call get_param(param_file, mdl, "KH_SIN_LAT", Kh_sin_lat, &
2911 "The amplitude of a latitudinally-dependent background "//&
2912 "viscosity of the form KH_SIN_LAT*(SIN(LAT)**KH_PWR_OF_SINE).", &
2913 units="m2 s-1", default=0.0, scale=US%m_to_L**2*US%T_to_s, &
29141 do_not_log=.not.CS%Laplacian)
2915 call get_param(param_file, mdl, "KH_PWR_OF_SINE", Kh_pwr_of_sine, &
2916 "The power used to raise SIN(LAT) when using a latitudinally "//&
2917 "dependent background viscosity.", &
2918 units="nondim", default=4.0, &
29191 do_not_log=.not.(CS%Laplacian .and. (Kh_sin_lat>0.)) )
2920 call get_param(param_file, mdl, "SMAGORINSKY_KH", CS%Smagorinsky_Kh, &
2921 "If true, use a Smagorinsky nonlinear eddy viscosity.", &
29221 default=.false., do_not_log=.not.CS%Laplacian)
29231 if (.not.CS%Laplacian) CS%Smagorinsky_Kh = .false.
2924 call get_param(param_file, mdl, "SMAG_LAP_CONST", Smag_Lap_const, &
2925 "The nondimensional Laplacian Smagorinsky constant, "//&
2926 "often 0.15.", units="nondim", default=0.0, &
29271 fail_if_missing=CS%Smagorinsky_Kh, do_not_log=.not.CS%Smagorinsky_Kh)
2928 call get_param(param_file, mdl, "LEITH_KH", CS%Leith_Kh, &
2929 "If true, use a Leith nonlinear eddy viscosity.", &
29301 default=.false., do_not_log=.not.CS%Laplacian)
29311 if (.not.CS%Laplacian) CS%Leith_Kh = .false.
2932 call get_param(param_file, mdl, "LEITH_LAP_CONST", Leith_Lap_const, &
2933 "The nondimensional Laplacian Leith constant, "//&
2934 "often set to 1.0", units="nondim", default=0.0, &
29351 fail_if_missing=CS%Leith_Kh, do_not_log=.not.CS%Leith_Kh)
2936 call get_param(param_file, mdl, "RES_SCALE_MEKE_VISC", CS%res_scale_MEKE, &
2937 "If true, the viscosity contribution from MEKE is scaled by "//&
2938 "the resolution function.", default=.false., &
29391 do_not_log=.not.(CS%Laplacian.and.use_MEKE))
29401 if (.not.(CS%Laplacian.and.use_MEKE)) CS%res_scale_MEKE = .false.
2941
2942 call get_param(param_file, mdl, "BOUND_KH", CS%bound_Kh, &
2943 "If true, the Laplacian coefficient is locally limited "//&
29441 "to be stable.", default=.true., do_not_log=.not.CS%Laplacian)
2945 call get_param(param_file, mdl, "EY24_EBT_BS", CS%EY24_EBT_BS, &
2946 "If true, use the backscatter scheme (EBT mode with kill switch) "//&
2947 "developed by Yankovsky et al. (2024). ", &
29481 default=.false., do_not_log=.not.CS%Laplacian)
29491 if (.not.CS%Laplacian) CS%bound_Kh = .false.
29501 if (.not.(CS%Laplacian.and.use_MEKE)) CS%EY24_EBT_BS = .false.
2951 call get_param(param_file, mdl, "ANISOTROPIC_VISCOSITY", CS%anisotropic, &
2952 "If true, allow anistropic viscosity in the Laplacian "//&
2953 "horizontal viscosity.", default=.false., &
29541 do_not_log=.not.CS%Laplacian)
29551 if (.not.CS%Laplacian) CS%anisotropic = .false. ! This replicates the prior code, but is it intended?
2956 call get_param(param_file, mdl, "ADD_LES_VISCOSITY", CS%add_LES_viscosity, &
2957 "If true, adds the viscosity from Smagorinsky and Leith to the "//&
2958 "background viscosity instead of taking the maximum.", default=.false., &
29591 do_not_log=.not.CS%Laplacian)
2960
2961 call get_param(param_file, mdl, "KH_ANISO", CS%Kh_aniso, &
2962 "The background Laplacian anisotropic horizontal viscosity.", &
2963 units="m2 s-1", default=0.0, scale=US%m_to_L**2*US%T_to_s, &
29641 do_not_log=.not.CS%anisotropic)
2965 call get_param(param_file, mdl, "ANISOTROPIC_MODE", aniso_mode, &
2966 "Selects the mode for setting the direction of anisotropy.\n"//&
2967 "\t 0 - Points along the grid i-direction.\n"//&
2968 "\t 1 - Points towards East.\n"//&
2969 "\t 2 - Points along the flow direction, U/|U|.", &
29701 default=0, do_not_log=.not.CS%anisotropic)
29711 if (aniso_mode == 0) then
2972 call get_param(param_file, mdl, "ANISO_GRID_DIR", aniso_grid_dir, &
2973 "The vector pointing in the direction of anisotropy for horizontal viscosity. "//&
2974 "n1,n2 are the i,j components relative to the grid.", &
29751 units="nondim", fail_if_missing=CS%anisotropic, do_not_log=.not.CS%anisotropic)
29760 elseif (aniso_mode == 1) then
2977 call get_param(param_file, mdl, "ANISO_GRID_DIR", aniso_grid_dir, &
2978 "The vector pointing in the direction of anisotropy for horizontal viscosity. "//&
2979 "n1,n2 are the i,j components relative to the spherical coordinates.", &
29800 units="nondim", fail_if_missing=CS%anisotropic, do_not_log=.not.CS%anisotropic)
2981 else
2982 call get_param(param_file, mdl, "ANISO_GRID_DIR", aniso_grid_dir, &
2983 "The vector pointing in the direction of anisotropy for horizontal viscosity.", &
29840 units="nondim", fail_if_missing=.false., do_not_log=.true.)
2985 endif
2986
2987 call get_param(param_file, mdl, "BIHARMONIC", CS%biharmonic, &
2988 "If true, use a biharmonic horizontal viscosity. "//&
2989 "BIHARMONIC may be used with LAPLACIAN.", &
29901 default=.true.)
2991 call get_param(param_file, mdl, "AH", Ah, &
2992 "The background biharmonic horizontal viscosity.", &
2993 units="m4 s-1", default=0.0, scale=US%m_to_L**4*US%T_to_s, &
29941 do_not_log=.not.CS%biharmonic)
2995 call get_param(param_file, mdl, "AH_VEL_SCALE", Ah_vel_scale, &
2996 "The velocity scale which is multiplied by the cube of "//&
2997 "the grid spacing to calculate the biharmonic viscosity. "//&
2998 "The final viscosity is the largest of this scaled "//&
2999 "viscosity, the Smagorinsky and Leith viscosities, and AH.", &
30001 units="m s-1", default=0.0, scale=US%m_s_to_L_T, do_not_log=.not.CS%biharmonic)
3001 call get_param(param_file, mdl, "AH_TIME_SCALE", Ah_time_scale, &
3002 "A time scale whose inverse is multiplied by the fourth "//&
3003 "power of the grid spacing to calculate biharmonic viscosity. "//&
3004 "The final viscosity is the largest of all viscosity "//&
3005 "formulations in use. 0.0 means that it's not used.", &
30061 units="s", default=0.0, scale=US%s_to_T, do_not_log=.not.CS%biharmonic)
3007 call get_param(param_file, mdl, "SMAGORINSKY_AH", CS%Smagorinsky_Ah, &
3008 "If true, use a biharmonic Smagorinsky nonlinear eddy "//&
30091 "viscosity.", default=.false., do_not_log=.not.CS%biharmonic)
30101 if (.not.CS%biharmonic) CS%Smagorinsky_Ah = .false.
3011 call get_param(param_file, mdl, "LEITH_AH", CS%Leith_Ah, &
3012 "If true, use a biharmonic Leith nonlinear eddy "//&
30131 "viscosity.", default=.false., do_not_log=.not.CS%biharmonic)
30141 if (.not.CS%biharmonic) CS%Leith_Ah = .false.
3015 call get_param(param_file, mdl, "USE_LEITHY", CS%use_Leithy, &
3016 "If true, use a biharmonic Leith nonlinear eddy "//&
3017 "viscosity together with a harmonic backscatter.", &
30181 default=.false.)
3019 call get_param(param_file, mdl, "BOUND_AH", CS%bound_Ah, &
3020 "If true, the biharmonic coefficient is locally limited "//&
30211 "to be stable.", default=.true., do_not_log=.not.CS%biharmonic)
30221 if (.not.CS%biharmonic) CS%bound_Ah = .false.
3023 call get_param(param_file, mdl, "RE_AH", CS%Re_Ah, &
3024 "If nonzero, the biharmonic coefficient is scaled "//&
3025 "so that the biharmonic Reynolds number is equal to this.", &
30261 units="nondim", default=0.0, do_not_log=.not.CS%biharmonic)
3027
3028 call get_param(param_file, mdl, "BACKSCATTER_UNDERBOUND", CS%backscatter_underbound, &
3029 "If true, the bounds on the biharmonic viscosity are allowed to "//&
3030 "increase where the Laplacian viscosity is negative (due to backscatter "//&
3031 "parameterizations) beyond the largest timestep-dependent stable values of "//&
3032 "biharmonic viscosity when no Laplacian viscosity is applied. The default "//&
3033 "is true for historical reasons, but this option probably should not be used "//&
3034 "because it can contribute to numerical instabilities.", &
30351 default=.false., do_not_log=.not.((CS%bound_Kh).and.(CS%bound_Ah)))
3036
3037 call get_param(param_file, mdl, "SMAG_BI_CONST",Smag_bi_const, &
3038 "The nondimensional biharmonic Smagorinsky constant, "//&
3039 "typically 0.015 - 0.06.", units="nondim", default=0.0, &
30401 fail_if_missing=CS%Smagorinsky_Ah, do_not_log=.not.CS%Smagorinsky_Ah)
3041
3042 call get_param(param_file, mdl, "USE_BETA_IN_LEITH", CS%use_beta_in_Leith, &
3043 "If true, include the beta term in the Leith nonlinear eddy viscosity.", &
30441 default=CS%Leith_Kh, do_not_log=.not.(CS%Leith_Kh .or. CS%Leith_Ah) )
3045 call get_param(param_file, mdl, "MODIFIED_LEITH", CS%modified_Leith, &
3046 "If true, add a term to Leith viscosity which is "//&
3047 "proportional to the gradient of divergence.", &
30481 default=.false., do_not_log=.not.(CS%Leith_Kh .or. CS%Leith_Ah) )
3049 call get_param(param_file, mdl, "USE_QG_LEITH_VISC", CS%use_QG_Leith_visc, &
3050 "If true, use QG Leith nonlinear eddy viscosity.", &
30511 default=.false., do_not_log=.not.(CS%Leith_Kh .or. CS%Leith_Ah) )
3052! if (CS%use_QG_Leith_visc) then
3053! call MOM_error(FATAL, "USE_QG_LEITH_VISC=True activates code that is a work-in-progress and "//&
3054! "should not be used until a number of bugs are fixed. Specifically it does not "//&
3055! "reproduce across PE count or layout, and may use arrays that have not been properly "//&
3056! "set or allocated. See github.com/mom-ocean/MOM6/issues/1590 for a discussion.")
3057! endif
30581 if (CS%use_QG_Leith_visc .and. .not. (CS%Leith_Kh .or. CS%Leith_Ah) ) then
3059 call MOM_error(FATAL, "MOM_hor_visc.F90, hor_visc_init: "//&
30600 "LEITH_KH or LEITH_AH must be True when USE_QG_LEITH_VISC=True.")
3061 endif
3062
30631 call get_param(param_file, mdl, "BOUND_CORIOLIS", bound_Cor_def, default=.false.)
3064 call get_param(param_file, mdl, "BOUND_CORIOLIS_BIHARM", CS%bound_Coriolis, &
3065 "If true use a viscosity that increases with the square "//&
3066 "of the velocity shears, so that the resulting viscous "//&
3067 "drag is of comparable magnitude to the Coriolis terms "//&
3068 "when the velocity differences between adjacent grid "//&
3069 "points is 0.5*BOUND_CORIOLIS_VEL. The default is the "//&
3070 "value of BOUND_CORIOLIS (or false).", default=bound_Cor_def, &
30711 do_not_log=.not.CS%Smagorinsky_Ah)
30721 if (.not.CS%Smagorinsky_Ah) CS%bound_Coriolis = .false.
3073 call get_param(param_file, mdl, "MAXVEL", maxvel, &
30741 units="m s-1", default=3.0e8, scale=US%m_s_to_L_T)
3075 call get_param(param_file, mdl, "BOUND_CORIOLIS_VEL", bound_Cor_vel, &
3076 "The velocity scale at which BOUND_CORIOLIS_BIHARM causes "//&
3077 "the biharmonic drag to have comparable magnitude to the "//&
3078 "Coriolis acceleration. The default is set by MAXVEL.", &
3079 units="m s-1", default=maxvel*US%L_T_to_m_s, scale=US%m_s_to_L_T, &
30801 do_not_log=.not.(CS%Smagorinsky_Ah .and. CS%bound_Coriolis))
3081 call get_param(param_file, mdl, "LEITH_BI_CONST", Leith_bi_const, &
3082 "The nondimensional biharmonic Leith constant, "//&
3083 "typical values are thus far undetermined.", units="nondim", default=0.0, &
3084 fail_if_missing=(CS%Leith_Ah .or. CS%use_Leithy), &
30851 do_not_log=.not.(CS%Leith_Ah .or. CS%use_Leithy))
3086 call get_param(param_file, mdl, "USE_LAND_MASK_FOR_HVISC", CS%use_land_mask, &
3087 "If true, use the land mask for the computation of thicknesses "//&
3088 "at velocity locations. This eliminates the dependence on arbitrary "//&
30891 "values over land or outside of the domain.", default=.true.)
3090 call get_param(param_file, mdl, "HORVISC_BOUND_COEF", CS%bound_coef, &
3091 "The nondimensional coefficient of the ratio of the "//&
3092 "viscosity bounds to the theoretical maximum for "//&
3093 "stability without considering other terms.", units="nondim", &
30941 default=0.8, do_not_log=.not.(CS%bound_Ah .or. CS%bound_Kh))
3095 call get_param(param_file, mdl, "KILL_SWITCH_COEF", CS%KS_coef, &
3096 "A nondimensional coefficient on the biharmonic viscosity that "// &
3097 "sets the kill switch for backscatter. Default is 1.0.", units="nondim", &
30981 default=1.0, do_not_log=.not.(CS%EY24_EBT_BS))
3099 call get_param(param_file, mdl, "NOSLIP", CS%no_slip, &
3100 "If true, no slip boundary conditions are used; otherwise "//&
3101 "free slip boundary conditions are assumed. The "//&
3102 "implementation of the free slip BCs on a C-grid is much "//&
3103 "cleaner than the no slip BCs. The use of free slip BCs "//&
3104 "is strongly encouraged, and no slip BCs are not used with "//&
31051 "the biharmonic viscosity.", default=.false.)
3106 call get_param(param_file, mdl, "USE_KH_BG_2D", CS%use_Kh_bg_2d, &
3107 "If true, read a file containing 2-d background harmonic "//&
3108 "viscosities. The final viscosity is the maximum of the other "//&
31091 "terms and this background value.", default=.false., do_not_log=.not.CS%Laplacian)
31101 if (.not.CS%Laplacian) CS%use_Kh_bg_2d = .false.
3111 call get_param(param_file, mdl, "KH_BG_2D_BUG", CS%Kh_bg_2d_bug, &
3112 "If true, retain an answer-changing horizontal indexing bug in setting "//&
3113 "the corner-point viscosities when USE_KH_BG_2D=True. This is "//&
31141 "not recommended.", default=.false., do_not_log=.not.CS%use_Kh_bg_2d)
3115 call get_param(param_file, mdl, "ENABLE_BUGS_BY_DEFAULT", enable_bugs, &
31161 default=.true., do_not_log=.true.) ! This is logged from MOM.F90.
3117 call get_param(param_file, mdl, "FRICTWORK_BUG", CS%FrictWork_bug, &
3118 "If true, retain an answer-changing bug in calculating the FrictWork, "//&
3119 "which cancels the h in thickness flux and the h at velocity point. This is "//&
31201 "not recommended.", default=.false.)
3121 call get_param(param_file, mdl, "OBC_SPECIFIED_STRAIN_BUG", CS%OBC_strain_bug, &
3122 "If true, recover a bug that specified shear strain option at open boundaries "//&
31231 "cannot be applied.", default=.true.)
3124 call get_param(param_file, mdl, "USE_GME", CS%use_GME, &
3125 "If true, use the GM+E backscatter scheme in association \n"//&
31261 "with the Gent and McWilliams parameterization.", default=.false.)
3127 call get_param(param_file, mdl, "SPLIT", split, &
31281 "Use the split time stepping if true.", default=.true., do_not_log=.true.)
31291 if (CS%use_Leithy) then
31300 if (.not.(CS%biharmonic .and. CS%Laplacian)) then
3131 call MOM_error(FATAL, "MOM_hor_visc.F90, hor_visc_init: "//&
31320 "LAPLACIAN and BIHARMONIC must both be True when USE_LEITHY=True.")
3133 endif
3134 endif
3135 call get_param(param_file, mdl, "LEITHY_CK", CS%c_K, &
3136 "Fraction of biharmonic dissipation that gets backscattered, "//&
31371 "in Leith+E.", units="nondim", default=1.0, do_not_log=.not.CS%use_Leithy)
3138 call get_param(param_file, mdl, "SMOOTH_AH", CS%smooth_Ah, &
3139 "If true, Ah and m_leithy are smoothed within Leith+E. This requires "//&
3140 "lots of blocking communications, which can be expensive", &
31411 default=.true., do_not_log=.not.CS%use_Leithy)
3142
31431 if (CS%use_GME .and. .not.split) call MOM_error(FATAL,"ERROR: Currently, USE_GME = True "// &
31440 "cannot be used with SPLIT=False.")
3145
31461 if (CS%use_GME) then
3147 call get_param(param_file, mdl, "GME_NUM_SMOOTHINGS", CS%num_smooth_gme, &
3148 "Number of smoothing passes for the GME fluxes.", &
31490 default=1)
3150 call get_param(param_file, mdl, "GME_H0", CS%GME_h0, &
3151 "The strength of GME tapers quadratically to zero when the bathymetric "//&
3152 "depth is shallower than GME_H0.", &
31530 units="m", scale=GV%m_to_H, default=1000.0)
3154 call get_param(param_file, mdl, "GME_EFFICIENCY", CS%GME_efficiency, &
3155 "The nondimensional prefactor multiplying the GME coefficient.", &
31560 units="nondim", default=1.0)
3157 call get_param(param_file, mdl, "GME_LIMITER", CS%GME_limiter, &
3158 "The absolute maximum value the GME coefficient is allowed to take.", &
31590 units="m2 s-1", scale=US%m_to_L**2*US%T_to_s, default=1.0e7)
3160 endif
3161
31621 if (CS%Laplacian .or. CS%biharmonic) then
3163 call get_param(param_file, mdl, "DT", dt, &
3164 "The (baroclinic) dynamics time step.", units="s", scale=US%s_to_T, &
31651 fail_if_missing=.true.)
31661 Idt = 1.0 / dt
3167 endif
3168 call get_param(param_file, mdl, "KILL_SWITCH_TIMESCALE", CS%KS_timescale, &
3169 "A timescale for computing the CFL limit for viscosity "// &
3170 "that determines when backscatter is shut off. Default is DT.", &
31711 default= dt , units="s", scale=US%s_to_T, do_not_log=.not.(CS%EY24_EBT_BS))
3172
31731 if (CS%no_slip .and. CS%biharmonic) &
3174 call MOM_error(FATAL,"ERROR: NOSLIP and BIHARMONIC cannot be defined "// &
31750 "at the same time in MOM.")
31761 if (.not.(CS%Laplacian .or. CS%biharmonic)) then
3177 ! Only issue inviscid warning if not in single column mode (usually 2x2 domain)
31780 if ( max(G%domain%niglobal, G%domain%njglobal)>2 ) call MOM_error(WARNING, &
3179 "hor_visc_init: It is usually a very bad idea not to use either "//&
31800 "LAPLACIAN or BIHARMONIC viscosity.")
31810 return ! We are not using either Laplacian or Bi-harmonic lateral viscosity
3182 endif
3183
3184 !$omp target update to(CS)
3185
31861 deg2rad = atan(1.0) / 45.
31878773 ALLOC_(CS%dx2h(isd:ied,jsd:jed)) ; CS%dx2h(:,:) = 0.0
31888773 ALLOC_(CS%dy2h(isd:ied,jsd:jed)) ; CS%dy2h(:,:) = 0.0
31898971 ALLOC_(CS%dx2q(IsdB:IedB,JsdB:JedB)) ; CS%dx2q(:,:) = 0.0
31908971 ALLOC_(CS%dy2q(IsdB:IedB,JsdB:JedB)) ; CS%dy2q(:,:) = 0.0
31918773 ALLOC_(CS%dx_dyT(isd:ied,jsd:jed)) ; CS%dx_dyT(:,:) = 0.0
31928773 ALLOC_(CS%dy_dxT(isd:ied,jsd:jed)) ; CS%dy_dxT(:,:) = 0.0
31938971 ALLOC_(CS%dx_dyBu(IsdB:IedB,JsdB:JedB)) ; CS%dx_dyBu(:,:) = 0.0
31948971 ALLOC_(CS%dy_dxBu(IsdB:IedB,JsdB:JedB)) ; CS%dy_dxBu(:,:) = 0.0
3195 !$omp target enter data map(alloc: CS%dx2h, CS%dy2h, CS%dx2q, CS%dy2q)
3196 !$omp target enter data map(alloc: CS%dx_dyT, CS%dy_dxT, CS%dx_dyBu, CS%dy_dxBu)
3197
31981 if (CS%Laplacian) then
31998773 ALLOC_(CS%grid_sp_h2(isd:ied,jsd:jed)) ; CS%grid_sp_h2(:,:) = 0.0
32008773 ALLOC_(CS%Kh_bg_xx(isd:ied,jsd:jed)) ; CS%Kh_bg_xx(:,:) = 0.0
32018971 ALLOC_(CS%Kh_bg_xy(IsdB:IedB,JsdB:JedB)) ; CS%Kh_bg_xy(:,:) = 0.0
32021 if (CS%bound_Kh .or. CS%EY24_EBT_BS) then
32038773 allocate(CS%Kh_Max_xx(Isd:Ied,Jsd:Jed), source=0.0)
32048971 allocate(CS%Kh_Max_xy(IsdB:IedB,JsdB:JedB), source=0.0)
3205 endif
32061 if (CS%Smagorinsky_Kh .or. CS%EY24_EBT_BS) then
32070 allocate(CS%Laplac2_const_xx(isd:ied,jsd:jed), source=0.0)
32080 allocate(CS%Laplac2_const_xy(IsdB:IedB,JsdB:JedB), source=0.0)
3209 endif
32101 if (CS%Leith_Kh) then
32110 allocate(CS%Laplac3_const_xx(isd:ied,jsd:jed), source=0.0)
32120 allocate(CS%Laplac3_const_xy(IsdB:IedB,JsdB:JedB), source=0.0)
3213 endif
3214 endif
32158773 ALLOC_(CS%reduction_xx(isd:ied,jsd:jed)) ; CS%reduction_xx(:,:) = 0.0
32168971 ALLOC_(CS%reduction_xy(IsdB:IedB,JsdB:JedB)) ; CS%reduction_xy(:,:) = 0.0
3217
32181 CS%dynamic_aniso = .false.
32191 if (CS%anisotropic) then
32200 allocate(CS%n1n2_h(isd:ied,jsd:jed), source=0.0)
32210 allocate(CS%n1n1_m_n2n2_h(isd:ied,jsd:jed), source=0.0)
32220 allocate(CS%n1n2_q(IsdB:IedB,JsdB:JedB), source=0.0)
32230 allocate(CS%n1n1_m_n2n2_q(IsdB:IedB,JsdB:JedB), source=0.0)
32240 select case (aniso_mode)
3225 case (0)
32260 call align_aniso_tensor_to_grid(CS, aniso_grid_dir(1), aniso_grid_dir(2))
3227 case (1)
3228 ! call align_aniso_tensor_to_grid(CS, aniso_grid_dir(1), aniso_grid_dir(2))
3229 case (2)
32300 CS%dynamic_aniso = .true.
3231 case default
3232 call MOM_error(FATAL, "MOM_hor_visc: "//&
32330 "Runtime parameter ANISOTROPIC_MODE is out of range.")
3234 end select
3235 endif
3236
3237 call get_param(param_file, mdl, "KH_BG_2D_FILENAME", filename, &
3238 'The filename containing a 2d map of "Kh".', &
32391 default='KH_background_2d.nc', do_not_log=.not.CS%use_Kh_bg_2d)
3240 call get_param(param_file, mdl, "KH_BG_2D_VARNAME", Kh_var, &
3241 'The name in the input file of the horizontal viscosity variable.', &
32421 default='Kh', do_not_log=.not.CS%use_Kh_bg_2d)
3243
32441 if (CS%use_Kh_bg_2d) then
32450 call get_param(param_file, mdl, "INPUTDIR", inputdir, default=".")
32460 inputdir = slasher(inputdir)
32470 allocate(CS%Kh_bg_2d(isd:ied,jsd:jed), source=0.0)
3248 call MOM_read_data(trim(inputdir)//trim(filename), Kh_var, CS%Kh_bg_2d, &
32490 G%domain, timelevel=1, scale=US%m_to_L**2*US%T_to_s)
32500 call pass_var(CS%Kh_bg_2d, G%domain)
3251 endif
32521 if (CS%biharmonic) then
32538841 ALLOC_(CS%Idx2dyCu(IsdB:IedB,jsd:jed)) ; CS%Idx2dyCu(:,:) = 0.0
32548902 ALLOC_(CS%Idx2dyCv(isd:ied,JsdB:JedB)) ; CS%Idx2dyCv(:,:) = 0.0
32558841 ALLOC_(CS%Idxdy2u(IsdB:IedB,jsd:jed)) ; CS%Idxdy2u(:,:) = 0.0
32568902 ALLOC_(CS%Idxdy2v(isd:ied,JsdB:JedB)) ; CS%Idxdy2v(:,:) = 0.0
32578773 ALLOC_(CS%Ah_bg_xx(isd:ied,jsd:jed)) ; CS%Ah_bg_xx(:,:) = 0.0
32588971 ALLOC_(CS%Ah_bg_xy(IsdB:IedB,JsdB:JedB)) ; CS%Ah_bg_xy(:,:) = 0.0
32598773 ALLOC_(CS%grid_sp_h3(isd:ied,jsd:jed)) ; CS%grid_sp_h3(:,:) = 0.0
32601 if (CS%bound_Ah) then
32618773 allocate(CS%Ah_Max_xx(isd:ied,jsd:jed), source=0.0)
32628971 allocate(CS%Ah_Max_xy(IsdB:IedB,JsdB:JedB), source=0.0)
3263 endif
32641 if (CS%EY24_EBT_BS) then
32650 allocate(CS%Ah_Max_xx_KS(isd:ied,jsd:jed), source=0.0)
32660 allocate(CS%Ah_Max_xy_KS(IsdB:IedB,JsdB:JedB), source=0.0)
3267 endif
32681 if (CS%Smagorinsky_Ah) then
32698773 allocate(CS%Biharm_const_xx(isd:ied,jsd:jed), source=0.0)
32708971 allocate(CS%Biharm_const_xy(IsdB:IedB,JsdB:JedB), source=0.0)
32711 if (CS%bound_Coriolis) then
32728773 allocate(CS%Biharm_const2_xx(isd:ied,jsd:jed), source=0.0)
32738971 allocate(CS%Biharm_const2_xy(IsdB:IedB,JsdB:JedB), source=0.0)
3274 endif
3275 endif
32761 if ((CS%Leith_Ah) .or. (CS%use_Leithy)) then
32770 allocate(CS%biharm6_const_xx(isd:ied,jsd:jed), source=0.0)
32780 allocate(CS%biharm6_const_xy(IsdB:IedB,JsdB:JedB), source=0.0)
3279 endif
32801 if (CS%use_Leithy) then
32810 allocate(CS%m_const_leithy(isd:ied,jsd:jed), source=0.0)
32820 allocate(CS%m_leithy_max(isd:ied,jsd:jed), source=0.0)
3283 endif
32841 if (CS%Re_Ah > 0.0) then
32850 allocate(CS%Re_Ah_const_xx(isd:ied,jsd:jed), source=0.0)
32860 allocate(CS%Re_Ah_const_xy(IsdB:IedB,JsdB:JedB), source=0.0)
3287 endif
3288 endif
3289
3290124 do concurrent (J=js-2:Jeq+1, I=is-2:Ieq+1)
32917873 CS%dx2q(I,J) = G%dxBu(I,J)*G%dxBu(I,J) ; CS%dy2q(I,J) = G%dyBu(I,J)*G%dyBu(I,J)
3292 enddo
3293
32941 if (((CS%Leith_Kh) .or. (CS%Leith_Ah) .or. (CS%use_Leithy)) .and. &
3295 ((G%isc-G%isd < 3) .or. (G%isc-G%isd < 3))) call MOM_error(FATAL, &
32960 "The minimum halo size is 3 when a Leith viscosity is being used.")
32971 if (CS%use_Leithy) then
32980 do concurrent (J=js-3:Jeq+2, I=is-3:Ieq+2)
32990 CS%DX_dyBu(I,J) = G%dxBu(I,J)*G%IdyBu(I,J) ; CS%DY_dxBu(I,J) = G%dyBu(I,J)*G%IdxBu(I,J)
3300 enddo
33011 elseif ((CS%Leith_Kh) .or. (CS%Leith_Ah)) then
33020 do concurrent (J=Jsq-2:Jeq+2, I=Isq-2:Ieq+2)
33030 CS%DX_dyBu(I,J) = G%dxBu(I,J)*G%IdyBu(I,J) ; CS%DY_dxBu(I,J) = G%dyBu(I,J)*G%IdxBu(I,J)
3304 enddo
3305 else
3306124 do concurrent (J=js-2:Jeq+1, I=is-2:Ieq+1)
33077873 CS%DX_dyBu(I,J) = G%dxBu(I,J)*G%IdyBu(I,J) ; CS%DY_dxBu(I,J) = G%dyBu(I,J)*G%IdxBu(I,J)
3308 enddo
3309 endif
3310
3311125 do concurrent (j=js-2:Jeq+2, i=is-2:Ieq+2)
33127936 CS%dx2h(i,j) = G%dxT(i,j)*G%dxT(i,j) ; CS%dy2h(i,j) = G%dyT(i,j)*G%dyT(i,j)
33138061 CS%DX_dyT(i,j) = G%dxT(i,j)*G%IdyT(i,j) ; CS%DY_dxT(i,j) = G%dyT(i,j)*G%IdxT(i,j)
3314 enddo
3315
3316 ! TODO: Remove this after every instance has been moved to GPU
3317 !$omp target update from(CS%dx2q, CS%dy2q, CS%dx_dyBu, CS%dy_dxBu)
3318 !$omp target update from(CS%dx2h, CS%dy2h, CS%dx_dyT, CS%dy_dxT)
3319
33207627 do j=Jsq,Jeq+1 ; do i=Isq,Ieq+1
33217564 CS%reduction_xx(i,j) = 1.0
33227564 if ((G%dy_Cu(I,j) > 0.0) .and. (G%dy_Cu(I,j) < G%dyCu(I,j)) .and. &
3323 (G%dy_Cu(I,j) < G%dyCu(I,j) * CS%reduction_xx(i,j))) &
33240 CS%reduction_xx(i,j) = G%dy_Cu(I,j) / (G%dyCu(I,j))
33257564 if ((G%dy_Cu(I-1,j) > 0.0) .and. (G%dy_Cu(I-1,j) < G%dyCu(I-1,j)) .and. &
3326 (G%dy_Cu(I-1,j) < G%dyCu(I-1,j) * CS%reduction_xx(i,j))) &
33270 CS%reduction_xx(i,j) = G%dy_Cu(I-1,j) / (G%dyCu(I-1,j))
33287564 if ((G%dx_Cv(i,J) > 0.0) .and. (G%dx_Cv(i,J) < G%dxCv(i,J)) .and. &
3329 (G%dx_Cv(i,J) < G%dxCv(i,J) * CS%reduction_xx(i,j))) &
33300 CS%reduction_xx(i,j) = G%dx_Cv(i,J) / (G%dxCv(i,J))
33317564 if ((G%dx_Cv(i,J-1) > 0.0) .and. (G%dx_Cv(i,J-1) < G%dxCv(i,J-1)) .and. &
3332 (G%dx_Cv(i,J-1) < G%dxCv(i,J-1) * CS%reduction_xx(i,j))) &
333362 CS%reduction_xx(i,j) = G%dx_Cv(i,J-1) / (G%dxCv(i,J-1))
3334 enddo ; enddo
3335
33367443 do J=js-1,Jeq ; do I=is-1,Ieq
33377381 CS%reduction_xy(I,J) = 1.0
33387381 if ((G%dy_Cu(I,j) > 0.0) .and. (G%dy_Cu(I,j) < G%dyCu(I,j)) .and. &
3339 (G%dy_Cu(I,j) < G%dyCu(I,j) * CS%reduction_xy(I,J))) &
33400 CS%reduction_xy(I,J) = G%dy_Cu(I,j) / (G%dyCu(I,j))
33417381 if ((G%dy_Cu(I,j+1) > 0.0) .and. (G%dy_Cu(I,j+1) < G%dyCu(I,j+1)) .and. &
3342 (G%dy_Cu(I,j+1) < G%dyCu(I,j+1) * CS%reduction_xy(I,J))) &
33430 CS%reduction_xy(I,J) = G%dy_Cu(I,j+1) / (G%dyCu(I,j+1))
33447381 if ((G%dx_Cv(i,J) > 0.0) .and. (G%dx_Cv(i,J) < G%dxCv(i,J)) .and. &
3345 (G%dx_Cv(i,J) < G%dxCv(i,J) * CS%reduction_xy(I,J))) &
33460 CS%reduction_xy(I,J) = G%dx_Cv(i,J) / (G%dxCv(i,J))
33477381 if ((G%dx_Cv(i+1,J) > 0.0) .and. (G%dx_Cv(i+1,J) < G%dxCv(i+1,J)) .and. &
3348 (G%dx_Cv(i+1,J) < G%dxCv(i+1,J) * CS%reduction_xy(I,J))) &
334961 CS%reduction_xy(I,J) = G%dx_Cv(i+1,J) / (G%dxCv(i+1,J))
3350 enddo ; enddo
33511 if (CS%Laplacian) then
3352 ! The 0.3 below was 0.4 in MOM1.10. The change in hq requires
3353 ! this to be less than 1/3, rather than 1/2 as before.
33541 if (CS%bound_Kh .or. CS%bound_Ah) Kh_Limit = 0.3 / (dt*4.0)
3355 ! Calculate and store the background viscosity at h-points
3356
33571 min_grid_sp_h2 = huge(1.)
33587627 do j=js-1,Jeq+1 ; do i=is-1,Ieq+1
3359 ! Static factors in the Smagorinsky and Leith schemes
33607564 grid_sp_h2 = (2.0*CS%dx2h(i,j)*CS%dy2h(i,j)) / (CS%dx2h(i,j) + CS%dy2h(i,j))
33617564 CS%grid_sp_h2(i,j) = grid_sp_h2
33627564 grid_sp_h3 = grid_sp_h2*sqrt(grid_sp_h2)
33637564 if (CS%Smagorinsky_Kh) CS%Laplac2_const_xx(i,j) = Smag_Lap_const * grid_sp_h2
33647564 if (CS%Leith_Kh) CS%Laplac3_const_xx(i,j) = Leith_Lap_const * grid_sp_h3
3365 ! Maximum of constant background and MICOM viscosity
33667564 CS%Kh_bg_xx(i,j) = MAX(Kh, Kh_vel_scale * sqrt(grid_sp_h2))
3367 ! Use the larger of the above and values read from a file
33687564 if (CS%use_Kh_bg_2d) CS%Kh_bg_xx(i,j) = MAX(CS%Kh_bg_2d(i,j), CS%Kh_bg_xx(i,j))
3369 ! Use the larger of the above and a function of sin(latitude)
33707564 if (Kh_sin_lat>0.) then
33710 slat_fn = abs( sin( deg2rad * G%geoLatT(i,j) ) ) ** Kh_pwr_of_sine
33720 CS%Kh_bg_xx(i,j) = MAX(Kh_sin_lat * slat_fn, CS%Kh_bg_xx(i,j))
3373 endif
33747626 min_grid_sp_h2 = min(grid_sp_h2, min_grid_sp_h2)
3375 enddo ; enddo
33761 call min_across_PEs(min_grid_sp_h2)
3377
3378 ! Calculate and store the background viscosity at q-points
33797443 do J=js-1,Jeq ; do I=is-1,Ieq
3380 ! Static factors in the Smagorinsky and Leith schemes
33817381 grid_sp_q2 = (2.0*CS%dx2q(I,J)*CS%dy2q(I,J)) / (CS%dx2q(I,J) + CS%dy2q(I,J))
33827381 grid_sp_q3 = grid_sp_q2*sqrt(grid_sp_q2)
33837381 if (CS%Smagorinsky_Kh) CS%Laplac2_const_xy(I,J) = Smag_Lap_const * grid_sp_q2
33847381 if (CS%Leith_Kh) CS%Laplac3_const_xy(I,J) = Leith_Lap_const * grid_sp_q3
3385 ! Maximum of constant background and MICOM viscosity
33867381 CS%Kh_bg_xy(I,J) = MAX(Kh, Kh_vel_scale * sqrt(grid_sp_q2))
3387 ! Use the larger of the above and values read from a file
33887381 if (CS%use_Kh_bg_2d) then
33890 if (CS%Kh_bg_2d_bug) then
3390 ! This option is unambiguously wrong but is needed to recover old answers
33910 CS%Kh_bg_xy(I,J) = MAX(CS%Kh_bg_2d(i,j), CS%Kh_bg_xy(I,J))
3392 else
3393 CS%Kh_bg_xy(I,J) = MAX(CS%Kh_bg_xy(I,J), &
3394 0.25*((CS%Kh_bg_2d(i,j) + CS%Kh_bg_2d(i+1,j+1)) + &
33950 (CS%Kh_bg_2d(i+1,j) + CS%Kh_bg_2d(i,j+1))) )
3396 endif
3397 endif
3398
3399 ! Use the larger of the above and a function of sin(latitude)
34007442 if (Kh_sin_lat>0.) then
34010 slat_fn = abs( sin( deg2rad * G%geoLatBu(I,J) ) ) ** Kh_pwr_of_sine
34020 CS%Kh_bg_xy(I,J) = MAX(Kh_sin_lat * slat_fn, CS%Kh_bg_xy(I,J))
3403 endif
3404 enddo ; enddo
3405 endif
34061 if (CS%biharmonic) then
34077689 do j=js-1,Jeq+1 ; do I=is-2,Ieq+1
34087626 CS%Idx2dyCu(I,j) = (G%IdxCu(I,j)*G%IdxCu(I,j)) * G%IdyCu(I,j)
34097688 CS%Idxdy2u(I,j) = G%IdxCu(I,j) * (G%IdyCu(I,j)*G%IdyCu(I,j))
3410 enddo ; enddo
34117750 do J=js-2,Jeq+1 ; do i=is-1,Ieq+1
34127686 CS%Idx2dyCv(i,J) = (G%IdxCv(i,J)*G%IdxCv(i,J)) * G%IdyCv(i,J)
34137749 CS%Idxdy2v(i,J) = G%IdxCv(i,J) * (G%IdyCv(i,J)*G%IdyCv(i,J))
3414 enddo ; enddo
34158971 CS%Ah_bg_xy(:,:) = 0.0
3416 ! The 0.3 below was 0.4 in HIM 1.10. The change in hq requires
3417 ! this to be less than 1/3, rather than 1/2 as before.
34181 if (CS%bound_Ah) Ah_Limit = 0.3 / (dt*64.0)
34191 if (CS%Smagorinsky_Ah .and. CS%bound_Coriolis) &
34201 BoundCorConst = 1.0 / (5.0*(bound_Cor_vel*bound_Cor_vel))
3421
34221 min_grid_sp_h4 = huge(1.)
34237627 do j=js-1,Jeq+1 ; do i=is-1,Ieq+1
34247564 grid_sp_h2 = (2.0*CS%dx2h(i,j)*CS%dy2h(i,j)) / (CS%dx2h(i,j)+CS%dy2h(i,j))
34257564 grid_sp_h3 = grid_sp_h2*sqrt(grid_sp_h2)
34267564 CS%grid_sp_h3(i,j) = grid_sp_h3
34277564 if (CS%Smagorinsky_Ah) then
34287564 CS%Biharm_const_xx(i,j) = Smag_bi_const * (grid_sp_h2 * grid_sp_h2)
34297564 if (CS%bound_Coriolis) then
3430 fmax = MAX(abs(G%CoriolisBu(I-1,J-1)), abs(G%CoriolisBu(I,J-1)), &
34317564 abs(G%CoriolisBu(I-1,J)), abs(G%CoriolisBu(I,J)))
3432 CS%Biharm_const2_xx(i,j) = (grid_sp_h2 * grid_sp_h2 * grid_sp_h2) * &
34337564 (fmax * BoundCorConst)
3434 endif
3435 endif
34367564 if (CS%Leith_Ah) then
34370 CS%biharm6_const_xx(i,j) = Leith_bi_const * (grid_sp_h3 * grid_sp_h3)
3438 endif
34397564 if (CS%use_Leithy) then
34400 CS%biharm6_const_xx(i,j) = Leith_bi_const * max(G%dxT(i,j),G%dyT(i,j))**6
34410 CS%m_const_leithy(i,j) = 0.5 * sqrt(CS%c_K) * max(G%dxT(i,j),G%dyT(i,j))
34420 CS%m_leithy_max(i,j) = 4. / max(G%dxT(i,j),G%dyT(i,j))**2
3443 endif
34447564 CS%Ah_bg_xx(i,j) = MAX(Ah, Ah_vel_scale * grid_sp_h2 * sqrt(grid_sp_h2))
34457564 if (CS%Re_Ah > 0.0) CS%Re_Ah_const_xx(i,j) = grid_sp_h3 / CS%Re_Ah
34467564 if (Ah_time_scale > 0.) CS%Ah_bg_xx(i,j) = &
34470 MAX(CS%Ah_bg_xx(i,j), (grid_sp_h2 * grid_sp_h2) / Ah_time_scale)
34487626 min_grid_sp_h4 = min(grid_sp_h2**2, min_grid_sp_h4)
3449 enddo ; enddo
34501 call min_across_PEs(min_grid_sp_h4)
3451
34527443 do J=js-1,Jeq ; do I=is-1,Ieq
34537381 grid_sp_q2 = (2.0*CS%dx2q(I,J)*CS%dy2q(I,J)) / (CS%dx2q(I,J)+CS%dy2q(I,J))
34547381 grid_sp_q3 = grid_sp_q2*sqrt(grid_sp_q2)
34557381 if (CS%Smagorinsky_Ah) then
34567381 CS%Biharm_const_xy(I,J) = Smag_bi_const * (grid_sp_q2 * grid_sp_q2)
34577381 if (CS%bound_Coriolis) then
3458 CS%Biharm_const2_xy(I,J) = (grid_sp_q2 * grid_sp_q2 * grid_sp_q2) * &
34597381 (abs(G%CoriolisBu(I,J)) * BoundCorConst)
3460 endif
3461 endif
34627381 if ((CS%Leith_Ah) .or. (CS%use_Leithy))then
34630 CS%biharm6_const_xy(I,J) = Leith_bi_const * (grid_sp_q3 * grid_sp_q3)
3464 endif
34657381 CS%Ah_bg_xy(I,J) = MAX(Ah, Ah_vel_scale * grid_sp_q2 * sqrt(grid_sp_q2))
34667381 if (CS%Re_Ah > 0.0) CS%Re_Ah_const_xy(i,j) = grid_sp_q3 / CS%Re_Ah
34677381 if (Ah_time_scale > 0.) CS%Ah_bg_xy(i,j) = &
346861 MAX(CS%Ah_bg_xy(i,j), (grid_sp_q2 * grid_sp_q2) / Ah_time_scale)
3469 enddo ; enddo
3470 endif
3471 ! The Laplacian bounds should avoid overshoots when CS%bound_coef < 1.
34721 if (CS%Laplacian .and. CS%bound_Kh) then
34737627 do j=js-1,Jeq+1 ; do i=is-1,Ieq+1
3474 denom = max( &
3475 (CS%dy2h(i,j) * CS%DY_dxT(i,j) * (G%IdyCu(I,j) + G%IdyCu(I-1,j)) * &
3476 max(G%IdyCu(I,j)*G%IareaCu(I,j), G%IdyCu(I-1,j)*G%IareaCu(I-1,j)) ), &
3477 (CS%dx2h(i,j) * CS%DX_dyT(i,j) * (G%IdxCv(i,J) + G%IdxCv(i,J-1)) * &
34787564 max(G%IdxCv(i,J)*G%IareaCv(i,J), G%IdxCv(i,J-1)*G%IareaCv(i,J-1)) ) )
34797564 CS%Kh_Max_xx(i,j) = 0.0
34807564 if (denom > 0.0) &
34815112 CS%Kh_Max_xx(i,j) = CS%bound_coef * 0.25 * Idt / denom
3482 enddo ; enddo
34837443 do J=js-1,Jeq ; do I=is-1,Ieq
3484 denom = max( &
3485 (CS%dx2q(I,J) * CS%DX_dyBu(I,J) * (G%IdxCu(I,j+1) + G%IdxCu(I,j)) * &
3486 max(G%IdxCu(I,j)*G%IareaCu(I,j), G%IdxCu(I,j+1)*G%IareaCu(I,j+1)) ), &
3487 (CS%dy2q(I,J) * CS%DY_dxBu(I,J) * (G%IdyCv(i+1,J) + G%IdyCv(i,J)) * &
34887381 max(G%IdyCv(i,J)*G%IareaCv(i,J), G%IdyCv(i+1,J)*G%IareaCv(i+1,J)) ) )
34897381 CS%Kh_Max_xy(I,J) = 0.0
34907381 if (denom > 0.0) &
34915210 CS%Kh_Max_xy(I,J) = CS%bound_coef * 0.25 * Idt / denom
3492 enddo ; enddo
34931 if (CS%debug) then
34940 call hchksum(CS%Kh_Max_xx, "Kh_Max_xx", G%HI, haloshift=0, unscale=US%L_to_m**2*US%s_to_T)
34950 call Bchksum(CS%Kh_Max_xy, "Kh_Max_xy", G%HI, haloshift=0, unscale=US%L_to_m**2*US%s_to_T)
3496 endif
3497 endif
3498 ! The biharmonic bounds should avoid overshoots when CS%bound_coef < 0.5, but
3499 ! empirically work for CS%bound_coef <~ 1.0
35001 if (CS%biharmonic .and. CS%bound_Ah) then
35017689 do j=js-1,Jeq+1 ; do I=is-2,Ieq+1
3502 u0u(I,j) = ((CS%Idxdy2u(I,j)*((CS%dy2h(i+1,j)*CS%DY_dxT(i+1,j)*(G%IdyCu(I+1,j) + G%IdyCu(I,j))) + &
3503 (CS%dy2h(i,j) * CS%DY_dxT(i,j) * (G%IdyCu(I,j) + G%IdyCu(I-1,j))) )) + &
3504 (CS%Idx2dyCu(I,j)*((CS%dx2q(I,J) * CS%DX_dyBu(I,J) * (G%IdxCu(I,j+1) + G%IdxCu(I,j))) + &
35057626 (CS%dx2q(I,J-1)*CS%DX_dyBu(I,J-1)*(G%IdxCu(I,j) + G%IdxCu(I,j-1))) )) )
3506 u0v(I,j) = ((CS%Idxdy2u(I,j)*((CS%dy2h(i+1,j)*CS%DX_dyT(i+1,j)*(G%IdxCv(i+1,J) + G%IdxCv(i+1,J-1))) + &
3507 (CS%dy2h(i,j) * CS%DX_dyT(i,j) * (G%IdxCv(i,J) + G%IdxCv(i,J-1))) )) + &
3508 (CS%Idx2dyCu(I,j)*((CS%dx2q(I,J) * CS%DY_dxBu(I,J) * (G%IdyCv(i+1,J) + G%IdyCv(i,J))) + &
35097688 (CS%dx2q(I,J-1)*CS%DY_dxBu(I,J-1)*(G%IdyCv(i+1,J-1) + G%IdyCv(i,J-1))) )) )
3510 enddo ; enddo
35117750 do J=js-2,Jeq+1 ; do i=is-1,Ieq+1
3512 v0u(i,J) = ((CS%Idxdy2v(i,J)*((CS%dy2q(I,J) * CS%DX_dyBu(I,J) * (G%IdxCu(I,j+1) + G%IdxCu(I,j))) + &
3513 (CS%dy2q(I-1,J)*CS%DX_dyBu(I-1,J)*(G%IdxCu(I-1,j+1) + G%IdxCu(I-1,j))) )) + &
3514 (CS%Idx2dyCv(i,J)*((CS%dx2h(i,j+1)*CS%DY_dxT(i,j+1)*(G%IdyCu(I,j+1) + G%IdyCu(I-1,j+1))) + &
35157686 (CS%dx2h(i,j) * CS%DY_dxT(i,j) * (G%IdyCu(I,j) + G%IdyCu(I-1,j))) ) ))
3516 v0v(i,J) = ((CS%Idxdy2v(i,J)*((CS%dy2q(I,J) * CS%DY_dxBu(I,J) * (G%IdyCv(i+1,J) + G%IdyCv(i,J))) + &
3517 (CS%dy2q(I-1,J)*CS%DY_dxBu(I-1,J)*(G%IdyCv(i,J) + G%IdyCv(i-1,J))) )) + &
3518 (CS%Idx2dyCv(i,J)*((CS%dx2h(i,j+1)*CS%DX_dyT(i,j+1)*(G%IdxCv(i,J+1) + G%IdxCv(i,J))) + &
35197749 (CS%dx2h(i,j) * CS%DX_dyT(i,j) * (G%IdxCv(i,J) + G%IdxCv(i,J-1))) )) )
3520 enddo ; enddo
35217627 do j=js-1,Jeq+1 ; do i=is-1,Ieq+1
3522 denom = max( &
3523 (CS%dy2h(i,j) * &
3524 ((CS%DY_dxT(i,j)*((G%IdyCu(I,j)*u0u(I,j)) + (G%IdyCu(I-1,j)*u0u(I-1,j)))) + &
3525 (CS%DX_dyT(i,j)*((G%IdxCv(i,J)*v0u(i,J)) + (G%IdxCv(i,J-1)*v0u(i,J-1))))) * &
3526 max(G%IdyCu(I,j)*G%IareaCu(I,j), G%IdyCu(I-1,j)*G%IareaCu(I-1,j)) ), &
3527 (CS%dx2h(i,j) * &
3528 ((CS%DY_dxT(i,j)*((G%IdyCu(I,j)*u0v(I,j)) + (G%IdyCu(I-1,j)*u0v(I-1,j)))) + &
3529 (CS%DX_dyT(i,j)*((G%IdxCv(i,J)*v0v(i,J)) + (G%IdxCv(i,J-1)*v0v(i,J-1))))) * &
35307564 max(G%IdxCv(i,J)*G%IareaCv(i,J), G%IdxCv(i,J-1)*G%IareaCv(i,J-1)) ) )
35317564 CS%Ah_Max_xx(I,J) = 0.0
35327626 if (denom > 0.0) then
35335050 CS%Ah_Max_xx(I,J) = CS%bound_coef * 0.5 * Idt / denom
35345050 if (CS%EY24_EBT_BS) then
35350 CS%Ah_Max_xx_KS(i,j) = CS%bound_coef * 0.5 / (CS%KS_timescale * denom)
3536 endif
3537 endif
3538
3539 enddo ; enddo
35407443 do J=js-1,Jeq ; do I=is-1,Ieq
3541 denom = max( &
3542 (CS%dx2q(I,J) * &
3543 ((CS%DX_dyBu(I,J)*((u0u(I,j+1)*G%IdxCu(I,j+1)) + (u0u(I,j)*G%IdxCu(I,j)))) + &
3544 (CS%DY_dxBu(I,J)*((v0u(i+1,J)*G%IdyCv(i+1,J)) + (v0u(i,J)*G%IdyCv(i,J))))) * &
3545 max(G%IdxCu(I,j)*G%IareaCu(I,j), G%IdxCu(I,j+1)*G%IareaCu(I,j+1)) ), &
3546 (CS%dy2q(I,J) * &
3547 ((CS%DX_dyBu(I,J)*((u0v(I,j+1)*G%IdxCu(I,j+1)) + (u0v(I,j)*G%IdxCu(I,j)))) + &
3548 (CS%DY_dxBu(I,J)*((v0v(i+1,J)*G%IdyCv(i+1,J)) + (v0v(i,J)*G%IdyCv(i,J))))) * &
35497381 max(G%IdyCv(i,J)*G%IareaCv(i,J), G%IdyCv(i+1,J)*G%IareaCv(i+1,J)) ) )
35507381 CS%Ah_Max_xy(I,J) = 0.0
35517442 if (denom > 0.0) then
35525149 CS%Ah_Max_xy(I,J) = CS%bound_coef * 0.5 * Idt / denom
35535149 if (CS%EY24_EBT_BS) then
35540 CS%Ah_Max_xy_KS(i,j) = CS%bound_coef * 0.5 / (CS%KS_timescale * denom)
3555 endif
3556 endif
3557
3558 enddo ; enddo
35591 if (CS%debug) then
35600 call hchksum(CS%Ah_Max_xx, "Ah_Max_xx", G%HI, haloshift=0, unscale=US%L_to_m**4*US%s_to_T)
35610 call Bchksum(CS%Ah_Max_xy, "Ah_Max_xy", G%HI, haloshift=0, unscale=US%L_to_m**4*US%s_to_T)
3562 endif
3563 endif
3564 ! Register fields for output from this module.
3565 CS%id_normstress = register_diag_field('ocean_model', 'NoSt', diag%axesTL, Time, &
35661 'Normal Stress', 's-1', conversion=US%s_to_T)
3567 CS%id_shearstress = register_diag_field('ocean_model', 'ShSt', diag%axesBL, Time, &
35681 'Shear Stress', 's-1', conversion=US%s_to_T)
3569 CS%id_diffu = register_diag_field('ocean_model', 'diffu', diag%axesCuL, Time, &
35701 'Zonal Acceleration from Horizontal Viscosity', 'm s-2', conversion=US%L_T2_to_m_s2)
3571 CS%id_diffv = register_diag_field('ocean_model', 'diffv', diag%axesCvL, Time, &
35721 'Meridional Acceleration from Horizontal Viscosity', 'm s-2', conversion=US%L_T2_to_m_s2)
3573
3574 !CS%id_hf_diffu = register_diag_field('ocean_model', 'hf_diffu', diag%axesCuL, Time, &
3575 ! 'Fractional Thickness-weighted Zonal Acceleration from Horizontal Viscosity', &
3576 ! 'm s-2', v_extensive=.true., conversion=US%L_T2_to_m_s2)
3577 !if ((CS%id_hf_diffu > 0) .and. (present(ADp))) then
3578 ! call safe_alloc_alloc(CS%hf_diffu,G%IsdB,G%IedB,G%jsd,G%jed,GV%ke)
3579 ! call safe_alloc_ptr(ADp%diag_hfrac_u,G%IsdB,G%IedB,G%jsd,G%jed,GV%ke)
3580 !endif
3581
3582 !CS%id_hf_diffv = register_diag_field('ocean_model', 'hf_diffv', diag%axesCvL, Time, &
3583 ! 'Fractional Thickness-weighted Meridional Acceleration from Horizontal Viscosity', &
3584 ! 'm s-2', v_extensive=.true., conversion=US%L_T2_to_m_s2)
3585 !if ((CS%id_hf_diffv > 0) .and. (present(ADp))) then
3586 ! call safe_alloc_alloc(CS%hf_diffv,G%isd,G%ied,G%JsdB,G%JedB,GV%ke)
3587 ! call safe_alloc_ptr(ADp%diag_hfrac_v,G%isd,G%ied,G%JsdB,G%JedB,GV%ke)
3588 !endif
3589
3590 CS%id_hf_diffu_2d = register_diag_field('ocean_model', 'hf_diffu_2d', diag%axesCu1, Time, &
3591 'Depth-sum Fractional Thickness-weighted Zonal Acceleration from Horizontal Viscosity', &
35921 'm s-2', conversion=US%L_T2_to_m_s2)
35931 if ((CS%id_hf_diffu_2d > 0) .and. (present(ADp))) then
35940 call safe_alloc_ptr(ADp%diag_hfrac_u,G%IsdB,G%IedB,G%jsd,G%jed,GV%ke)
3595 endif
3596
3597 CS%id_hf_diffv_2d = register_diag_field('ocean_model', 'hf_diffv_2d', diag%axesCv1, Time, &
3598 'Depth-sum Fractional Thickness-weighted Meridional Acceleration from Horizontal Viscosity', &
35991 'm s-2', conversion=US%L_T2_to_m_s2)
36001 if ((CS%id_hf_diffv_2d > 0) .and. (present(ADp))) then
36010 call safe_alloc_ptr(ADp%diag_hfrac_v,G%isd,G%ied,G%JsdB,G%JedB,GV%ke)
3602 endif
3603
3604 CS%id_h_diffu = register_diag_field('ocean_model', 'h_diffu', diag%axesCuL, Time, &
3605 'Thickness Multiplied Zonal Acceleration from Horizontal Viscosity', &
36061 'm2 s-2', conversion=GV%H_to_m*US%L_T2_to_m_s2)
36071 if ((CS%id_h_diffu > 0) .and. (present(ADp))) then
36080 call safe_alloc_ptr(ADp%diag_hu,G%IsdB,G%IedB,G%jsd,G%jed,GV%ke)
3609 endif
3610
3611 CS%id_h_diffv = register_diag_field('ocean_model', 'h_diffv', diag%axesCvL, Time, &
3612 'Thickness Multiplied Meridional Acceleration from Horizontal Viscosity', &
36131 'm2 s-2', conversion=GV%H_to_m*US%L_T2_to_m_s2)
36141 if ((CS%id_h_diffv > 0) .and. (present(ADp))) then
36150 call safe_alloc_ptr(ADp%diag_hv,G%isd,G%ied,G%JsdB,G%JedB,GV%ke)
3616 endif
3617
3618 CS%id_intz_diffu_2d = register_diag_field('ocean_model', 'intz_diffu_2d', diag%axesCu1, Time, &
3619 'Depth-integral of Zonal Acceleration from Horizontal Viscosity', &
36201 'm2 s-2', conversion=GV%H_to_m*US%L_T2_to_m_s2)
36211 if ((CS%id_intz_diffu_2d > 0) .and. (present(ADp))) then
36220 call safe_alloc_ptr(ADp%diag_hu,G%IsdB,G%IedB,G%jsd,G%jed,GV%ke)
3623 endif
3624
3625 CS%id_intz_diffv_2d = register_diag_field('ocean_model', 'intz_diffv_2d', diag%axesCv1, Time, &
3626 'Depth-integral of Meridional Acceleration from Horizontal Viscosity', &
36271 'm2 s-2', conversion=GV%H_to_m*US%L_T2_to_m_s2)
36281 if ((CS%id_intz_diffv_2d > 0) .and. (present(ADp))) then
36290 call safe_alloc_ptr(ADp%diag_hv,G%isd,G%ied,G%JsdB,G%JedB,GV%ke)
3630 endif
3631
3632 CS%id_diffu_visc_rem = register_diag_field('ocean_model', 'diffu_visc_rem', diag%axesCuL, Time, &
3633 'Zonal Acceleration from Horizontal Viscosity multiplied by viscous remnant', &
36341 'm s-2', conversion=US%L_T2_to_m_s2)
36351 if ((CS%id_diffu_visc_rem > 0) .and. (present(ADp))) then
36360 call safe_alloc_ptr(ADp%visc_rem_u,G%IsdB,G%IedB,G%jsd,G%jed,GV%ke)
3637 endif
3638
3639 CS%id_diffv_visc_rem = register_diag_field('ocean_model', 'diffv_visc_rem', diag%axesCvL, Time, &
3640 'Meridional Acceleration from Horizontal Viscosity multiplied by viscous remnant', &
36411 'm s-2', conversion=US%L_T2_to_m_s2)
36421 if ((CS%id_diffv_visc_rem > 0) .and. (present(ADp))) then
36430 call safe_alloc_ptr(ADp%visc_rem_v,G%isd,G%ied,G%JsdB,G%JedB,GV%ke)
3644 endif
3645
36461 if (CS%biharmonic) then
3647 CS%id_Ah_h = register_diag_field('ocean_model', 'Ahh', diag%axesTL, Time, &
3648 'Biharmonic Horizontal Viscosity at h Points', 'm4 s-1', conversion=US%L_to_m**4*US%s_to_T, &
3649 cmor_field_name='difmxybo', &
3650 cmor_long_name='Ocean lateral biharmonic viscosity', &
36511 cmor_standard_name='ocean_momentum_xy_biharmonic_diffusivity')
3652 CS%id_Ah_q = register_diag_field('ocean_model', 'Ahq', diag%axesBL, Time, &
36531 'Biharmonic Horizontal Viscosity at q Points', 'm4 s-1', conversion=US%L_to_m**4*US%s_to_T)
3654 CS%id_grid_Re_Ah = register_diag_field('ocean_model', 'grid_Re_Ah', diag%axesTL, Time, &
36551 'Grid Reynolds number for the Biharmonic horizontal viscosity at h points', 'nondim')
36561 if (CS%EY24_EBT_BS) then
3657 CS%id_visc_limit_h_flag = register_diag_field('ocean_model', 'visc_limit_h_flag', diag%axesTL, Time, &
36580 'Locations where the biharmonic viscosity reached the better_bound limiter at h points', 'nondim')
3659 CS%id_visc_limit_q_flag = register_diag_field('ocean_model', 'visc_limit_q_flag', diag%axesBL, Time, &
36600 'Locations where the biharmonic viscosity reached the better_bound limiter at q points', 'nondim')
3661 CS%id_visc_limit_h = register_diag_field('ocean_model', 'visc_limit_h', diag%axesTL, Time, &
36620 'Value of the biharmonic viscosity limiter at h points', 'nondim')
3663 CS%id_visc_limit_q = register_diag_field('ocean_model', 'visc_limit_q', diag%axesBL, Time, &
36640 'Value of the biharmonic viscosity limiter at q points', 'nondim')
3665 CS%id_visc_limit_h_frac = register_diag_field('ocean_model', 'visc_limit_h_frac', diag%axesTL, Time, &
36660 'Value of the biharmonic viscosity limiter at h points', 'nondim')
3667 CS%id_visc_limit_q_frac = register_diag_field('ocean_model', 'visc_limit_q_frac', diag%axesBL, Time, &
36680 'Value of the biharmonic viscosity limiter at q points', 'nondim')
3669 endif
3670
36711 if (CS%id_grid_Re_Ah > 0) &
3672 ! Compute the smallest biharmonic viscosity capable of modifying the
3673 ! velocity at floating point precision.
36740 CS%min_grid_Ah = spacing(1.) * min_grid_sp_h4 * Idt
3675 endif
36761 if (CS%Laplacian) then
3677 CS%id_Kh_h = register_diag_field('ocean_model', 'Khh', diag%axesTL, Time, &
3678 'Laplacian Horizontal Viscosity at h Points', 'm2 s-1', conversion=US%L_to_m**2*US%s_to_T, &
3679 cmor_field_name='difmxylo', &
3680 cmor_long_name='Ocean lateral Laplacian viscosity', &
36811 cmor_standard_name='ocean_momentum_xy_laplacian_diffusivity')
3682 CS%id_Kh_q = register_diag_field('ocean_model', 'Khq', diag%axesBL, Time, &
36831 'Laplacian Horizontal Viscosity at q Points', 'm2 s-1', conversion=US%L_to_m**2*US%s_to_T)
3684 CS%id_grid_Re_Kh = register_diag_field('ocean_model', 'grid_Re_Kh', diag%axesTL, Time, &
36851 'Grid Reynolds number for the Laplacian horizontal viscosity at h points', 'nondim')
3686 CS%id_vort_xy_q = register_diag_field('ocean_model', 'vort_xy_q', diag%axesBL, Time, &
36871 'Vertical vorticity at q Points', 's-1', conversion=US%s_to_T)
3688 CS%id_div_xx_h = register_diag_field('ocean_model', 'div_xx_h', diag%axesTL, Time, &
36891 'Horizontal divergence at h Points', 's-1', conversion=US%s_to_T)
3690 CS%id_sh_xy_q = register_diag_field('ocean_model', 'sh_xy_q', diag%axesBL, Time, &
36911 'Shearing strain at q Points', 's-1', conversion=US%s_to_T)
3692 CS%id_sh_xx_h = register_diag_field('ocean_model', 'sh_xx_h', diag%axesTL, Time, &
36931 'Horizontal tension at h Points', 's-1', conversion=US%s_to_T)
3694
36951 if (CS%id_grid_Re_Kh > 0) &
3696 ! Compute a smallest Laplacian viscosity capable of modifying the
3697 ! velocity at floating point precision.
36980 CS%min_grid_Kh = spacing(1.) * min_grid_sp_h2 * Idt
3699 endif
37001 if (CS%use_GME) then
3701 CS%id_dudx_bt = register_diag_field('ocean_model', 'dudx_bt', diag%axesT1, Time, &
3702 'Zonal component of the barotropic shearing strain at h points', 's-1', &
37030 conversion=US%s_to_T)
3704 CS%id_dudy_bt = register_diag_field('ocean_model', 'dudy_bt', diag%axesB1, Time, &
3705 'Zonal component of the barotropic shearing strain at q points', 's-1', &
37060 conversion=US%s_to_T)
3707 CS%id_dvdy_bt = register_diag_field('ocean_model', 'dvdy_bt', diag%axesT1, Time, &
3708 'Meridional component of the barotropic shearing strain at h points', 's-1', &
37090 conversion=US%s_to_T)
3710 CS%id_dvdx_bt = register_diag_field('ocean_model', 'dvdx_bt', diag%axesB1, Time, &
3711 'Meridional component of the barotropic shearing strain at q points', 's-1', &
37120 conversion=US%s_to_T)
3713 CS%id_GME_coeff_h = register_diag_field('ocean_model', 'GME_coeff_h', diag%axesTL, Time, &
37140 'GME coefficient at h Points', 'm2 s-1', conversion=US%L_to_m**2*US%s_to_T)
3715 CS%id_GME_coeff_q = register_diag_field('ocean_model', 'GME_coeff_q', diag%axesBL, Time, &
37160 'GME coefficient at q Points', 'm2 s-1', conversion=US%L_to_m**2*US%s_to_T)
3717 CS%id_FrictWork_GME = register_diag_field('ocean_model','FrictWork_GME',diag%axesTL,Time,&
3718 'Integral work done by lateral friction terms in GME (excluding diffusion of energy)', &
37190 'W m-2', conversion=US%RZ3_T3_to_W_m2*US%L_to_Z**2)
3720 endif
3721
37221 if (CS%EY24_EBT_BS) then
3723 CS%id_BS_coeff_h = register_diag_field('ocean_model', 'BS_coeff_h', diag%axesTL, Time, &
37240 'Backscatter coefficient at h points', units='m2 s-1', conversion=US%L_to_m**2*US%s_to_T)
3725 CS%id_BS_coeff_q = register_diag_field('ocean_model', 'BS_coeff_q', diag%axesBL, Time, &
37260 'Backscatter coefficient at q points', units='m2 s-1', conversion=US%L_to_m**2*US%s_to_T)
3727 endif
3728
3729 CS%id_FrictWork = register_diag_field('ocean_model','FrictWork',diag%axesTL,Time,&
3730 'Integral work done by lateral friction terms. If GME is turned on, this '//&
3731 'includes the GME contribution.', &
37321 'W m-2', conversion=US%RZ3_T3_to_W_m2*US%L_to_Z**2)
3733 CS%id_FrictWorkIntz = register_diag_field('ocean_model','FrictWorkIntz',diag%axesT1,Time, &
3734 'Depth integrated work done by lateral friction', &
3735 'W m-2', conversion=US%RZ3_T3_to_W_m2*US%L_to_Z**2, &
3736 cmor_field_name='dispkexyfo', &
3737 cmor_long_name='Depth integrated ocean kinetic energy dissipation due to lateral friction',&
37381 cmor_standard_name='ocean_kinetic_energy_dissipation_per_unit_area_due_to_xy_friction')
3739 CS%id_FrictWork_bh = register_diag_field('ocean_model','FrictWork_bh',diag%axesTL,Time,&
3740 'Integral work done by the biharmonic lateral friction terms.', &
37411 'W m-2', conversion=US%RZ3_T3_to_W_m2*US%L_to_Z**2)
3742 CS%id_FrictWorkIntz_bh = register_diag_field('ocean_model','FrictWorkIntz_bh',diag%axesT1,Time,&
3743 'Depth integrated work done by the biharmonic lateral friction', &
37441 'W m-2', conversion=US%RZ3_T3_to_W_m2*US%L_to_Z**2)
3745
3746
3747 ! TODO: Position these after their respective loops (and run loops on device)
3748 !$omp target enter data map(to: CS%Idxdy2u, CS%Idxdy2v) if (CS%biharmonic)
3749 !$omp target enter data map(to: CS%Idx2dyCu, CS%Idx2dyCv) if (CS%biharmonic)
3750
3751 !$omp target enter data map(to: CS%Kh_bg_xx, CS%Kh_bg_xy) if (CS%Laplacian)
3752 !$omp target enter data map(to: CS%Kh_max_xx) if (CS%Laplacian)
3753 !$omp target enter data map(to: CS%Kh_max_xy) &
3754 !$omp if (CS%Laplacian .and. CS%bound_Kh)
3755 !$omp target enter data map(to: CS%Laplac2_const_xx) if (CS%Laplacian)
3756 !$omp target enter data map(to: CS%Laplac3_const_xx) if (CS%Laplacian)
3757 !$omp target enter data map(to: CS%Laplac2_const_xy) if (CS%Smagorinsky_Kh)
3758
3759 !$omp target enter data map(to: CS%Ah_bg_xx, CS%Ah_bg_xy) if (CS%biharmonic)
3760 !$omp target enter data map(to: CS%reduction_xx, CS%reduction_xy)
3761 !$omp target enter data map(to: CS%Biharm_const_xx, CS%Biharm_const2_xx) &
3762 !$omp if (CS%Smagorinsky_Ah .or. CS%Leith_Ah .or. CS%use_Leithy)
3763 !$omp target enter data map(to: CS%Biharm_const_xy) &
3764 !$omp if (CS%Smagorinsky_Ah .or. CS%Leith_Ah)
3765 !$omp target enter data map(to: CS%Biharm_const2_xy) &
3766 !$omp if (CS%bound_Coriolis .and. (CS%Smagorinsky_Ah .or. CS%Leith_Ah))
3767 !$omp target enter data map(to: CS%Ah_max_xx) if (CS%bound_Ah)
3768 !$omp target enter data map(to: CS%Ah_max_xy) if (CS%bound_Ah)
3769
3770end subroutine hor_visc_init
3771
3772!> hor_visc_vel_stencil returns the horizontal viscosity input velocity stencil size
377324function hor_visc_vel_stencil(CS) result(stencil)
3774 type(hor_visc_CS), intent(in) :: CS !< Control structure for horizontal viscosity
3775 integer :: stencil !< The horizontal viscosity velocity stencil size with the current settings.
3776
377724 stencil = 2
3778
377924 if ((CS%Leith_Kh) .or. (CS%Leith_Ah) .or. (CS%use_Leithy)) then
37800 stencil = 3
3781 endif
378224end function hor_visc_vel_stencil
3783
3784!> Calculates factors in the anisotropic orientation tensor to be align with the grid.
3785!! With n1=1 and n2=0, this recovers the approach of Large et al, 2001.
37860subroutine align_aniso_tensor_to_grid(CS, n1, n2)
3787 type(hor_visc_CS), intent(inout) :: CS !< Control structure for horizontal viscosity
3788 real, intent(in) :: n1 !< i-component of direction vector [nondim]
3789 real, intent(in) :: n2 !< j-component of direction vector [nondim]
3790 ! Local variables
3791 real :: recip_n2_norm ! The inverse of the squared magnitude of n1 and n2 [nondim]
3792 ! For normalizing n=(n1,n2) in case arguments are not a unit vector
37930 recip_n2_norm = (n1**2) + (n2**2)
37940 if (recip_n2_norm > 0.) recip_n2_norm = 1. / recip_n2_norm
37950 CS%n1n2_h(:,:) = 2. * ( n1 * n2 ) * recip_n2_norm
37960 CS%n1n2_q(:,:) = 2. * ( n1 * n2 ) * recip_n2_norm
37970 CS%n1n1_m_n2n2_h(:,:) = ( (n1 * n1) - (n2 * n2) ) * recip_n2_norm
37980 CS%n1n1_m_n2n2_q(:,:) = ( (n1 * n1) - (n2 * n2) ) * recip_n2_norm
37990end subroutine align_aniso_tensor_to_grid
3800
3801!> Apply a 1-1-4-1-1 Laplacian filter one time on GME diffusive flux to reduce any
3802!! horizontal two-grid-point noise
38030subroutine smooth_GME(CS, G, GME_flux_h, GME_flux_q)
3804 type(hor_visc_CS), intent(in) :: CS !< Control structure
3805 type(ocean_grid_type), intent(in) :: G !< Ocean grid
3806 real, dimension(SZI_(G),SZJ_(G)), optional, intent(inout) :: GME_flux_h!< GME diffusive flux
3807 !! at h points [L2 T-2 ~> m2 s-2]
3808 real, dimension(SZIB_(G),SZJB_(G)), optional, intent(inout) :: GME_flux_q!< GME diffusive flux
3809 !! at q points [L2 T-2 ~> m2 s-2]
3810 ! local variables
38110 real, dimension(SZI_(G),SZJ_(G)) :: GME_flux_h_original ! The previous value of GME_flux_h [L2 T-2 ~> m2 s-2]
38120 real, dimension(SZIB_(G),SZJB_(G)) :: GME_flux_q_original ! The previous value of GME_flux_q [L2 T-2 ~> m2 s-2]
3813 real :: wc, ww, we, wn, ws ! averaging weights for smoothing [nondim]
3814 integer :: i, j, s, halosz
3815 integer :: xh, xq ! The number of valid extra halo points for h and q points.
3816 integer :: is, ie, js, je, Isq, Ieq, Jsq, Jeq
3817
38180 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
38190 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
38200 xh = 0 ; xq = 0
3821
38220 do s=1,CS%num_smooth_gme
38230 if (present(GME_flux_h)) then
38240 if (xh < 0) then
3825 ! Update halos if needed, but avoid doing so more often than is needed.
38260 halosz = min(G%isc-G%isd, G%jsc-G%jsd, 2+CS%num_smooth_gme-s)
38270 call pass_var(GME_flux_h, G%Domain, halo=halosz)
38280 xh = halosz - 2
3829 endif
38300 GME_flux_h_original(:,:) = GME_flux_h(:,:)
3831 ! apply smoothing on GME
38320 do j=Jsq-xh,Jeq+1+xh ; do i=Isq-xh,Ieq+1+xh
3833 ! skip land points
38340 if (G%mask2dT(i,j)==0.) cycle
3835 ! compute weights
38360 ww = 0.125 * G%mask2dT(i-1,j)
38370 we = 0.125 * G%mask2dT(i+1,j)
38380 ws = 0.125 * G%mask2dT(i,j-1)
38390 wn = 0.125 * G%mask2dT(i,j+1)
38400 wc = 1.0 - ((ww+we)+(wn+ws))
3841 GME_flux_h(i,j) = wc * GME_flux_h_original(i,j) &
3842 + ((ww * GME_flux_h_original(i-1,j) + we * GME_flux_h_original(i+1,j)) &
38430 + (ws * GME_flux_h_original(i,j-1) + wn * GME_flux_h_original(i,j+1)))
3844 enddo ; enddo
38450 xh = xh - 1
3846 endif
38470 if (present(GME_flux_q)) then
38480 if (xq < 0) then
3849 ! Update halos if needed, but avoid doing so more often than is needed.
38500 halosz = min(G%isc-G%isd, G%jsc-G%jsd, 2+CS%num_smooth_gme-s)
38510 call pass_var(GME_flux_q, G%Domain, position=CORNER, complete=.true., halo=halosz)
38520 xq = halosz - 2
3853 endif
38540 GME_flux_q_original(:,:) = GME_flux_q(:,:)
3855 ! apply smoothing on GME
38560 do J=js-1-xq,je+xq ; do I=is-1-xq,ie+xq
3857 ! skip land points
38580 if (G%mask2dBu(I,J)==0.) cycle
3859 ! compute weights
38600 ww = 0.125 * G%mask2dBu(I-1,J)
38610 we = 0.125 * G%mask2dBu(I+1,J)
38620 ws = 0.125 * G%mask2dBu(I,J-1)
38630 wn = 0.125 * G%mask2dBu(I,J+1)
38640 wc = 1.0 - ((ww+we)+(wn+ws))
3865 GME_flux_q(I,J) = wc * GME_flux_q_original(I,J) &
3866 + ((ww * GME_flux_q_original(I-1,J) + we * GME_flux_q_original(I+1,J)) &
38670 + (ws * GME_flux_q_original(I,J-1) + wn * GME_flux_q_original(I,J+1)))
3868 enddo ; enddo
38690 xq = xq - 1
3870 endif
3871 enddo ! s-loop
38720end subroutine smooth_GME
3873
3874!> Apply a 9-point smoothing filter twice to a field staggered at a thickness point to reduce
3875!! horizontal two-grid-point noise.
3876!! Note that this subroutine does not conserve mass, so don't use it in situations where you
3877!! need conservation. Also note that it assumes that the input field has valid values in the
3878!! first two halo points upon entry.
38790subroutine smooth_x9_h(G, field_h, zero_land)
3880 type(ocean_grid_type), intent(in) :: G !< Ocean grid
3881 real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: field_h !< h-point field to be smoothed [arbitrary]
3882 logical, optional, intent(in) :: zero_land !< If present and false, return the average
3883 !! of the surrounding ocean points when
3884 !! smoothing, otherwise use a value of 0 for
3885 !! land points and include them in the averages.
3886
3887 ! Local variables
38880 real :: fh_prev(SZI_(G),SZJ_(G)) ! The value of the h-point field at the previous iteration [arbitrary]
3889 real :: Iwts ! The inverse of the sum of the weights [nondim]
3890 logical :: zero_land_val ! The value of the zero_land optional argument or .true. if it is absent.
3891 integer :: i, j, s, is, ie, js, je
3892
38930 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
3894
38950 zero_land_val = .true. ; if (present(zero_land)) zero_land_val = zero_land
3896
38970 do s=1,0,-1
38980 fh_prev(:,:) = field_h(:,:)
3899 ! apply smoothing on field_h using rotationally symmetric expressions.
39000 do j=js-s,je+s ; do i=is-s,ie+s ; if (G%mask2dT(i,j) > 0.0) then
39010 Iwts = 0.0625
39020 if (.not. zero_land_val) &
3903 Iwts = 1.0 / ( (4.0*G%mask2dT(i,j) + &
3904 ( 2.0*((G%mask2dT(i-1,j) + G%mask2dT(i+1,j)) + &
3905 (G%mask2dT(i,j-1) + G%mask2dT(i,j+1))) + &
3906 ((G%mask2dT(i-1,j-1) + G%mask2dT(i+1,j+1)) + &
39070 (G%mask2dT(i-1,j+1) + G%mask2dT(i+1,j-1))) ) ) + 1.0e-16 )
3908 field_h(i,j) = Iwts * ( 4.0*G%mask2dT(i,j) * fh_prev(i,j) &
3909 + (2.0*((G%mask2dT(i-1,j) * fh_prev(i-1,j) + G%mask2dT(i+1,j) * fh_prev(i+1,j)) + &
3910 (G%mask2dT(i,j-1) * fh_prev(i,j-1) + G%mask2dT(i,j+1) * fh_prev(i,j+1))) &
3911 + ((G%mask2dT(i-1,j-1) * fh_prev(i-1,j-1) + G%mask2dT(i+1,j+1) * fh_prev(i+1,j+1)) + &
39120 (G%mask2dT(i-1,j+1) * fh_prev(i-1,j+1) + G%mask2dT(i+1,j-1) * fh_prev(i-1,j-1))) ))
3913 endif ; enddo ; enddo
3914 enddo
3915
39160end subroutine smooth_x9_h
3917
3918!> Apply a 9-point smoothing filter twice to a pair of velocity components to reduce
3919!! horizontal two-grid-point noise.
3920!! Note that this subroutine does not conserve angular momentum, so don't use it
3921!! in situations where you need conservation. Also note that it assumes that the
3922!! input fields have valid values in the first two halo points upon entry.
39230subroutine smooth_x9_uv(G, field_u, field_v, zero_land)
3924 type(ocean_grid_type), intent(in) :: G !< Ocean grid
3925 real, dimension(SZIB_(G),SZJ_(G)), intent(inout) :: field_u !< u-point field to be smoothed [arbitrary]
3926 real, dimension(SZI_(G),SZJB_(G)), intent(inout) :: field_v !< v-point field to be smoothed [arbitrary]
3927 logical, optional, intent(in) :: zero_land !< If present and false, return the average
3928 !! of the surrounding ocean points when
3929 !! smoothing, otherwise use a value of 0 for
3930 !! land points and include them in the averages.
3931
3932 ! Local variables.
39330 real :: fu_prev(SZIB_(G),SZJ_(G)) ! The value of the u-point field at the previous iteration [arbitrary]
39340 real :: fv_prev(SZI_(G),SZJB_(G)) ! The value of the v-point field at the previous iteration [arbitrary]
3935 real :: Iwts ! The inverse of the sum of the weights [nondim]
3936 logical :: zero_land_val ! The value of the zero_land optional argument or .true. if it is absent.
3937 integer :: i, j, s, is, ie, js, je, Isq, Ieq, Jsq, Jeq
3938
39390 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
39400 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
3941
39420 zero_land_val = .true. ; if (present(zero_land)) zero_land_val = zero_land
3943
39440 do s=1,0,-1
39450 fu_prev(:,:) = field_u(:,:)
3946 ! apply smoothing on field_u using the original non-rotationally symmetric expressions.
39470 do j=js-s,je+s ; do I=Isq-s,Ieq+s ; if (G%mask2dCu(I,j) > 0.0) then
39480 Iwts = 0.0625
39490 if (.not. zero_land_val) &
3950 Iwts = 1.0 / ( (4.0*G%mask2dCu(I,j) + &
3951 ( 2.0*((G%mask2dCu(I-1,j) + G%mask2dCu(I+1,j)) + &
3952 (G%mask2dCu(I,j-1) + G%mask2dCu(I,j+1))) + &
3953 ((G%mask2dCu(I-1,j-1) + G%mask2dCu(I+1,j+1)) + &
39540 (G%mask2dCu(I-1,j+1) + G%mask2dCu(I+1,j-1))) ) ) + 1.0e-16 )
3955 field_u(I,j) = Iwts * ( 4.0*G%mask2dCu(I,j) * fu_prev(I,j) &
3956 + (2.0*((G%mask2dCu(I-1,j) * fu_prev(I-1,j) + G%mask2dCu(I+1,j) * fu_prev(I+1,j)) + &
3957 (G%mask2dCu(I,j-1) * fu_prev(I,j-1) + G%mask2dCu(I,j+1) * fu_prev(I,j+1))) &
3958 + ((G%mask2dCu(I-1,j-1) * fu_prev(I-1,j-1) + G%mask2dCu(I+1,j+1) * fu_prev(I+1,j+1)) + &
39590 (G%mask2dCu(I-1,j+1) * fu_prev(I-1,j+1) + G%mask2dCu(I+1,j-1) * fu_prev(I-1,j-1))) ))
3960 endif ; enddo ; enddo
3961
39620 fv_prev(:,:) = field_v(:,:)
3963 ! apply smoothing on field_v using the original non-rotationally symmetric expressions.
39640 do J=Jsq-s,Jeq+s ; do i=is-s,ie+s ; if (G%mask2dCv(i,J) > 0.0) then
39650 Iwts = 0.0625
39660 if (.not. zero_land_val) &
3967 Iwts = 1.0 / ( (4.0*G%mask2dCv(i,J) + &
3968 ( 2.0*((G%mask2dCv(i-1,J) + G%mask2dCv(i+1,J)) + &
3969 (G%mask2dCv(i,J-1) + G%mask2dCv(i,J+1))) + &
3970 ((G%mask2dCv(i-1,J-1) + G%mask2dCv(i+1,J+1)) + &
39710 (G%mask2dCv(i-1,J+1) + G%mask2dCv(i+1,J-1))) ) ) + 1.0e-16 )
3972 field_v(i,J) = Iwts * ( 4.0*G%mask2dCv(i,J) * fv_prev(i,J) &
3973 + (2.0*((G%mask2dCv(i-1,J) * fv_prev(i-1,J) + G%mask2dCv(i+1,J) * fv_prev(i+1,J)) + &
3974 (G%mask2dCv(i,J-1) * fv_prev(i,J-1) + G%mask2dCv(i,J+1) * fv_prev(i,J+1))) &
3975 + ((G%mask2dCv(i-1,J-1) * fv_prev(i-1,J-1) + G%mask2dCv(i+1,J+1) * fv_prev(i+1,J+1)) + &
39760 (G%mask2dCv(i-1,J+1) * fv_prev(i-1,J+1) + G%mask2dCv(i+1,J-1) * fv_prev(i-1,J-1))) ))
3977 endif ; enddo ; enddo
3978 enddo
3979
39800end subroutine smooth_x9_uv
3981
3982!> Deallocates any variables allocated in hor_visc_init.
39831subroutine hor_visc_end(CS)
3984 type(hor_visc_CS), intent(inout) :: CS !< Horizontal viscosity control structure
3985
3986 !$omp target exit data map(delete: CS%DX_dyT, CS%DY_dxT)
3987 !$omp target exit data map(delete: CS%Dx_dyBu, CS%DY_dxBu)
3988
3989 !$omp target exit data map(delete: CS%Idxdy2u, CS%Idxdy2v) if (CS%biharmonic)
3990 !$omp target exit data map(delete: CS%Idx2dyCu, CS%Idx2dyCv) if (CS%biharmonic)
3991 !$omp target exit data map(delete: CS%dx2q, CS%dy2q)
3992 !$omp target exit data map(delete: CS%dx2h, CS%dy2h)
3993
3994 !$omp target exit data map(delete: CS%Kh_bg_xx, CS%Kh_bg_xy) if (CS%Laplacian)
3995 !$omp target exit data map(delete: CS%Kh_Max_xx) if (CS%Laplacian)
3996 !$omp target exit data map(delete: CS%Kh_max_xy) &
3997 !$omp if (CS%Laplacian .and. CS%bound_Kh)
3998 !$omp target exit data map(delete: CS%Laplac2_const_xx) if (CS%Laplacian)
3999 !$omp target exit data map(delete: CS%Laplac3_const_xx) if (CS%Laplacian)
4000 !$omp target exit data map(delete: CS%Laplac2_const_xy) if (CS%Smagorinsky_Kh)
4001
4002 !$omp target exit data map(delete: CS%Ah_bg_xx, CS%Ah_bg_xy) if (CS%biharmonic)
4003 !$omp target exit data map(delete: CS%reduction_xx, CS%reduction_xy)
4004 !$omp target exit data map(delete: CS%Biharm_const_xx, CS%Biharm_const2_xx) &
4005 !$omp if (CS%Smagorinsky_Ah .or. CS%Leith_Ah .or. CS%use_Leithy)
4006 !$omp target exit data map(delete: CS%Biharm_const_xy) &
4007 !$omp if (CS%Smagorinsky_Ah .or. CS%Leith_Ah)
4008 !$omp target exit data map(delete: CS%Biharm_const2_xy) &
4009 !$omp if (CS%bound_Coriolis .and. (CS%Smagorinsky_Ah .or. CS%Leith_Ah))
4010 !$omp target exit data map(delete: CS%Ah_max_xx) if (CS%bound_Ah)
4011 !$omp target exit data map(delete: CS%Ah_max_xy) if (CS%bound_Ah)
4012
40131 if (CS%Laplacian .or. CS%biharmonic) then
40141 DEALLOC_(CS%dx2h) ; DEALLOC_(CS%dx2q) ; DEALLOC_(CS%dy2h) ; DEALLOC_(CS%dy2q)
40151 DEALLOC_(CS%dx_dyT) ; DEALLOC_(CS%dy_dxT) ; DEALLOC_(CS%dx_dyBu) ; DEALLOC_(CS%dy_dxBu)
40161 DEALLOC_(CS%reduction_xx) ; DEALLOC_(CS%reduction_xy)
4017 endif
40181 if (CS%Laplacian) then
40191 DEALLOC_(CS%Kh_bg_xx) ; DEALLOC_(CS%Kh_bg_xy)
40201 DEALLOC_(CS%grid_sp_h2)
40211 if (allocated(CS%Kh_bg_2d)) deallocate(CS%Kh_bg_2d)
4022
40231 if (allocated(CS%Kh_Max_xx)) deallocate(CS%Kh_Max_xx)
40241 if (allocated(CS%Kh_Max_xy)) deallocate(CS%Kh_Max_xy)
40251 if (allocated(CS%Laplac2_const_xx)) deallocate(CS%Laplac2_const_xx)
40261 if (allocated(CS%Laplac2_const_xy)) deallocate(CS%Laplac2_const_xy)
40271 if (allocated(CS%Laplac3_const_xx)) deallocate(CS%Laplac3_const_xx)
40281 if (allocated(CS%Laplac3_const_xy)) deallocate(CS%Laplac3_const_xy)
4029 endif
40301 if (CS%biharmonic) then
40311 DEALLOC_(CS%grid_sp_h3)
40321 DEALLOC_(CS%Idx2dyCu) ; DEALLOC_(CS%Idx2dyCv)
40331 DEALLOC_(CS%Idxdy2u) ; DEALLOC_(CS%Idxdy2v)
40341 DEALLOC_(CS%Ah_bg_xx) ; DEALLOC_(CS%Ah_bg_xy)
4035
40361 if (allocated(CS%Ah_Max_xx)) deallocate(CS%Ah_Max_xx)
40371 if (allocated(CS%Ah_Max_xy)) deallocate(CS%Ah_Max_xy)
40381 if (allocated(CS%Ah_Max_xx_KS)) deallocate(CS%Ah_Max_xx_KS)
40391 if (allocated(CS%Ah_Max_xy_KS)) deallocate(CS%Ah_Max_xy_KS)
40401 if (allocated(CS%Biharm_const_xx)) deallocate(CS%Biharm_const_xx)
40411 if (allocated(CS%Biharm_const_xy)) deallocate(CS%Biharm_const_xy)
40421 if (allocated(CS%Biharm_const2_xx)) deallocate(CS%Biharm_const2_xx)
40431 if (allocated(CS%Biharm_const2_xy)) deallocate(CS%Biharm_const2_xy)
40441 if (allocated(CS%Biharm6_const_xx)) deallocate(CS%Biharm6_const_xx)
40451 if (allocated(CS%Biharm6_const_xy)) deallocate(CS%Biharm6_const_xy)
40461 if (allocated(CS%m_const_leithy)) deallocate(CS%m_const_leithy)
40471 if (allocated(CS%m_leithy_max)) deallocate(CS%m_leithy_max)
40481 if (allocated(CS%Re_Ah_const_xx)) deallocate(CS%Re_Ah_const_xx)
40491 if (allocated(CS%Re_Ah_const_xy)) deallocate(CS%Re_Ah_const_xy)
4050 endif
4051
40521 if (allocated(CS%n1n2_h)) deallocate(CS%n1n2_h)
40531 if (allocated(CS%n1n2_q)) deallocate(CS%n1n2_q)
40541 if (allocated(CS%n1n1_m_n2n2_h)) deallocate(CS%n1n1_m_n2n2_h)
40551 if (allocated(CS%n1n1_m_n2n2_q)) deallocate(CS%n1n1_m_n2n2_q)
4056
40571 if (CS%use_ZB2020) then
40580 call ZB2020_end(CS%ZB2020)
4059 endif
4060
40611end subroutine hor_visc_end
4062!> \namespace mom_hor_visc
4063!!
4064!! \section section_horizontal_viscosity Horizontal viscosity in MOM
4065!!
4066!! This module contains the subroutine horizontal_viscosity that calculates the
4067!! effects of horizontal viscosity, including parameterizations of the value of
4068!! the viscosity itself. Subroutine horizontal_viscosity calculates the acceleration due to
4069!! some combination of a biharmonic viscosity and a Laplacian viscosity. Either or
4070!! both may use a coefficient that depends on the shear and strain of the flow.
4071!! All metric terms are retained. The Laplacian is calculated as the divergence of
4072!! a stress tensor, using the form suggested by \cite Smagorinsky1993. The biharmonic
4073!! is calculated by twice applying the divergence of the stress tensor that is
4074!! used to calculate the Laplacian, but without the dependence on thickness in the
4075!! first pass. This form permits a variable viscosity, and indicates no
4076!! acceleration for either resting fluid or solid body rotation.
4077!!
4078!! The form of the viscous accelerations is discussed extensively in \cite griffies2000,
4079!! and the implementation here follows that discussion closely.
4080!! We use the notation of \cite Smith2003 with the exception that the
4081!! isotropic viscosity is \f$\kappa_h\f$.
4082!!
4083!! In general, the horizontal stress tensor can be written as
4084!! \f[
4085!! {\bf \sigma} =
4086!! \begin{pmatrix}
4087!! \frac{1}{2} \left( \sigma_D + \sigma_T \right) & \frac{1}{2} \sigma_S \\\\
4088!! \frac{1}{2} \sigma_S & \frac{1}{2} \left( \sigma_D - \sigma_T \right)
4089!! \end{pmatrix}
4090!! \f]
4091!! where \f$\sigma_D\f$, \f$\sigma_T\f$ and \f$\sigma_S\f$ are stresses associated with
4092!! invariant factors in the strain-rate tensor. For a Newtonian fluid, the stress
4093!! tensor is usually linearly related to the strain-rate tensor. The horizontal
4094!! strain-rate tensor is
4095!! \f[
4096!! \dot{\bf e} =
4097!! \begin{pmatrix}
4098!! \frac{1}{2} \left( \dot{e}_D + \dot{e}_T \right) & \frac{1}{2} \dot{e}_S \\\\
4099!! \frac{1}{2} \dot{e}_S & \frac{1}{2} \left( \dot{e}_D - \dot{e}_T \right)
4100!! \end{pmatrix}
4101!! \f]
4102!! where \f$\dot{e}_D = \partial_x u + \partial_y v\f$ is the horizontal divergence,
4103!! \f$\dot{e}_T = \partial_x u - \partial_y v\f$ is the horizontal tension, and
4104!! \f$\dot{e}_S = \partial_y u + \partial_x v\f$ is the horizontal shear strain.
4105!!
4106!! The trace of the stress tensor, \f$tr(\bf \sigma) = \sigma_D\f$, is usually
4107!! absorbed into the pressure and only the deviatoric stress tensor considered.
4108!! From here on, we drop \f$\sigma_D\f$. The trace of the strain tensor, \f$tr(\bf e) =
4109!! \dot{e}_D\f$ is non-zero for horizontally divergent flow but only enters the
4110!! stress tensor through \f$\sigma_D\f$ and so we will drop \f$\sigma_D\f$ from
4111!! calculations of the strain tensor in the code. Therefore the horizontal stress
4112!! tensor can be considered to be
4113!! \f[
4114!! {\bf \sigma} =
4115!! \begin{pmatrix}
4116!! \frac{1}{2} \sigma_T & \frac{1}{2} \sigma_S \\\\
4117!! \frac{1}{2} \sigma_S & - \frac{1}{2} \sigma_T
4118!! \end{pmatrix}
4119!! .\f]
4120!!
4121!! The stresses above are linearly related to the strain through a viscosity
4122!! coefficient, \f$\kappa_h\f$:
4123!! \f{eqnarray*}{
4124!! \sigma_T & = & 2 \kappa_h \dot{e}_T \\\\
4125!! \sigma_S & = & 2 \kappa_h \dot{e}_S
4126!! .
4127!! \f}
4128!!
4129!! The viscosity \f$\kappa_h\f$ may either be a constant or variable. For example,
4130!! \f$\kappa_h\f$ may vary with the shear, as proposed by \cite Smagorinsky1993.
4131!!
4132!! The accelerations resulting form the divergence of the stress tensor are
4133!! \f{eqnarray*}{
4134!! \hat{\bf x} \cdot \left( \nabla \cdot {\bf \sigma} \right)
4135!! & = &
4136!! \partial_x \left( \frac{1}{2} \sigma_T \right)
4137!! + \partial_y \left( \frac{1}{2} \sigma_S \right)
4138!! \\\\
4139!! & = &
4140!! \partial_x \left( \kappa_h \dot{e}_T \right)
4141!! + \partial_y \left( \kappa_h \dot{e}_S \right)
4142!! \\\\
4143!! \hat{\bf y} \cdot \left( \nabla \cdot {\bf \sigma} \right)
4144!! & = &
4145!! \partial_x \left( \frac{1}{2} \sigma_S \right)
4146!! + \partial_y \left( - \frac{1}{2} \sigma_T \right)
4147!! \\\\
4148!! & = &
4149!! \partial_x \left( \kappa_h \dot{e}_S \right)
4150!! + \partial_y \left( - \kappa_h \dot{e}_T \right)
4151!! .
4152!! \f}
4153!!
4154!! The form of the Laplacian viscosity in general coordinates is:
4155!! \f{eqnarray*}{
4156!! \hat{\bf x} \cdot \left( \nabla \cdot \sigma \right)
4157!! & = &
4158!! \frac{1}{h} \left[ \partial_x \left( \kappa_h h \dot{e}_T \right)
4159!! + \partial_y \left( \kappa_h h \dot{e}_S \right) \right]
4160!! \\\\
4161!! \hat{\bf y} \cdot \left( \nabla \cdot \sigma \right)
4162!! & = &
4163!! \frac{1}{h} \left[ \partial_x \left( \kappa_h h \dot{e}_S \right)
4164!! - \partial_y \left( \kappa_h h \dot{e}_T \right) \right]
4165!! .
4166!! \f}
4167!!
4168!! \subsection section_laplacian_viscosity_coefficient Laplacian viscosity coefficient
4169!!
4170!! The horizontal viscosity coefficient, \f$\kappa_h\f$, can have multiple components.
4171!! The isotropic components are:
4172!! - A uniform background component, \f$\kappa_{bg}\f$.
4173!! - A constant but spatially variable 2D map, \f$\kappa_{2d}(x,y)\f$.
4174!! - A ''MICOM'' viscosity, \f$U_\nu \Delta(x,y)\f$, which uses a constant
4175!! velocity scale, \f$U_\nu\f$ and a measure of the grid-spacing \f$\Delta(x,y)^2 =
4176!! \frac{2 \Delta x^2 \Delta y^2}{\Delta x^2 + \Delta y^2}\f$.
4177!! - A function of
4178!! latitude, \f$\kappa_{\phi}(x,y) = \kappa_{\pi/2} |\sin(\phi)|^n\f$.
4179!! - A dynamic Smagorinsky viscosity, \f$\kappa_{Sm}(x,y,t) = C_{Sm} \Delta^2 \sqrt{\dot{e}_T^2 + \dot{e}_S^2}\f$.
4180!! - A dynamic Leith viscosity, \f$\kappa_{Lth}(x,y,t) =
4181!! C_{Lth} \Delta^3 \sqrt{|\nabla \zeta|^2 + |\nabla \dot{e}_D|^2}\f$.
4182!!
4183!! A maximum stable viscosity, \f$\kappa_{max}(x,y)\f$ is calculated based on the
4184!! grid-spacing and time-step and used to clip calculated viscosities.
4185!!
4186!! The static components of \f$\kappa_h\f$ are first combined as follows:
4187!! \f[
4188!! \kappa_{static} = \min \left[ \max\left(
4189!! \kappa_{bg},
4190!! U_\nu \Delta(x,y),
4191!! \kappa_{2d}(x,y),
4192!! \kappa_\phi(x,y)
4193!! \right)
4194!! , \kappa_{max}(x,y) \right]
4195!! \f]
4196!! and stored in the module control structure as variables <code>Kh_bg_xx</code> and
4197!! <code>Kh_bg_xy</code> for the tension (h-points) and shear (q-points) components
4198!! respectively.
4199!!
4200!! The full viscosity includes the dynamic components as follows:
4201!! \f[
4202!! \kappa_h(x,y,t) = r(\Delta,L_d)
4203!! \max \left( \kappa_{static}, \kappa_{Sm}, \kappa_{Lth} \right)
4204!! \f]
4205!! where \f$r(\Delta,L_d)\f$ is a resolution function.
4206!!
4207!! The dynamic Smagorinsky and Leith viscosity schemes are exclusive with each
4208!! other.
4209!!
4210!! \subsection section_viscous_boundary_conditions Viscous boundary conditions
4211!!
4212!! Free slip boundary conditions have been coded, although no slip boundary
4213!! conditions can be used with the Laplacian viscosity based on the 2D land-sea
4214!! mask. For a western boundary, for example, the boundary conditions with the
4215!! biharmonic operator would be written as:
4216!! \f[
4217!! \partial_x v = 0 ; \partial_x^3 v = 0 ; u = 0 ; \partial_x^2 u = 0 ,
4218!! \f]
4219!! while for a Laplacian operator, they are simply
4220!! \f[
4221!! \partial_x v = 0 ; u = 0 .
4222!! \f]
4223!! These boundary conditions are largely dictated by the use of an Arakawa
4224!! C-grid and by the varying layer thickness.
4225!!
4226!! \subsection section_anisotropic_viscosity Anisotropic viscosity
4227!!
4228!! \cite Large2001 proposed enhancing viscosity in a particular direction and the
4229!! approach was generalized in \cite Smith2003. We use the second form of their
4230!! two coefficient anisotropic viscosity (section 4.3). We also replace their
4231!! \f$A^\prime\f$ and $D$ such that \f$2A^\prime = 2 \kappa_h + D\f$ and
4232!! \f$\kappa_a = D\f$ so that \f$\kappa_h\f$ can be considered the isotropic
4233!! viscosity and \f$\kappa_a=D\f$ can be consider the anisotropic viscosity. The
4234!! direction of anisotropy is defined by a unit vector \f$\hat{\bf
4235!! n}=(n_1,n_2)\f$.
4236!!
4237!! The contributions to the stress tensor are
4238!! \f[
4239!! \begin{pmatrix}
4240!! \sigma_T \\\\ \sigma_S
4241!! \end{pmatrix}
4242!! =
4243!! \left[
4244!! \begin{pmatrix}
4245!! 2 \kappa_h + \kappa_a & 0 \\\\
4246!! 0 & 2 \kappa_h
4247!! \end{pmatrix}
4248!! + 2 \kappa_a n_1 n_2
4249!! \begin{pmatrix}
4250!! - 2 n_1 n_2 & n_1^2 - n_2^2 \\\\
4251!! n_1^2 - n_2^2 & 2 n_1 n_2
4252!! \end{pmatrix}
4253!! \right]
4254!! \begin{pmatrix}
4255!! \dot{e}_T \\\\ \dot{e}_S
4256!! \end{pmatrix}
4257!! \f]
4258!! Dissipation of kinetic energy requires \f$\kappa_h \geq 0\f$ and \f$2 \kappa_h + \kappa_a \geq 0\f$.
4259!! Note that when anisotropy is aligned with the x-direction, \f$n_1 = \pm 1\f$, then
4260!! \f$n_2 = 0\f$ and the cross terms vanish. The accelerations in this aligned limit
4261!! with constant coefficients become
4262!! \f{eqnarray*}{
4263!! \hat{\bf x} \cdot \nabla \cdot {\bf \sigma}
4264!! & = &
4265!! \partial_x \left( \left( \kappa_h + \frac{1}{2} \kappa_a \right) \dot{e}_T \right)
4266!! + \partial_y \left( \kappa_h \dot{e}_S \right)
4267!! \\\\
4268!! & = &
4269!! \left( \kappa_h + \kappa_a \right) \partial_{xx} u
4270!! + \kappa_h \partial_{yy} u
4271!! - \frac{1}{2} \kappa_a \partial_x \left( \partial_x u + \partial_y v \right)
4272!! \\\\
4273!! \hat{\bf y} \cdot \nabla \cdot {\bf \sigma}
4274!! & = &
4275!! \partial_x \left( \kappa_h \dot{e}_S \right)
4276!! - \partial_y \left( \left( \kappa_h + \frac{1}{2} \kappa_a \right) \dot{e}_T \right)
4277!! \\\\
4278!! & = &
4279!! \kappa_h \partial_{xx} v
4280!! + \left( \kappa_h + \kappa_a \right) \partial_{yy} v
4281!! - \frac{1}{2} \kappa_a \partial_y \left( \partial_x u + \partial_y v \right)
4282!! \f}
4283!! which has contributions akin to a negative divergence damping (a divergence
4284!! enhancement?) but which is weaker than the enhanced tension terms by half.
4285!!
4286!! \subsection section_viscous_discretization Discretization
4287!!
4288!! The horizontal tension, \f$\dot{e}_T\f$, is stored in variable <code>sh_xx</code> and
4289!! discretized as
4290!! \f[
4291!! \dot{e}_T
4292!! = \frac{\Delta y}{\Delta x} \delta_i \left( \frac{1}{\Delta y} u \right)
4293!! - \frac{\Delta x}{\Delta y} \delta_j \left( \frac{1}{\Delta x} v \right)
4294!! .
4295!! \f]
4296!! The horizontal divergent strain, \f$\dot{e}_D\f$, is stored in variable
4297!! <code>div_xx</code> and discretized as
4298!! \f[
4299!! \dot{e}_D
4300!! = \frac{1}{h A} \left( \delta_i \left( \overline{h}^i \Delta y \, u \right)
4301!! + \delta_j \left( \overline{h}^j\Delta x \, v \right) \right)
4302!! .
4303!! \f]
4304!! Note that for expediency this is the exact discretization used in the
4305!! continuity equation.
4306!!
4307!! The horizontal shear strain, \f$\dot{e}_S\f$, is stored in variable <code>sh_xy</code>
4308!! and discretized as
4309!! \f[
4310!! \dot{e}_S = v_x + u_y
4311!! \f]
4312!! where
4313!! \f{align*}{
4314!! v_x &= \frac{\Delta y}{\Delta x} \delta_i \left( \frac{1}{\Delta y} v \right) \\\\
4315!! u_y &= \frac{\Delta x}{\Delta y} \delta_j \left( \frac{1}{\Delta x} u \right)
4316!! \f}
4317!! which are calculated separately so that no-slip or free-slip boundary
4318!! conditions can be applied to \f$v_x\f$ and \f$u_y\f$ where appropriate.
4319!!
4320!! The tendency for the x-component of the divergence of stress is stored in
4321!! variable <code>diffu</code> and discretized as
4322!! \f[
4323!! \hat{\bf x} \cdot \left( \nabla \cdot {\bf \sigma} \right) =
4324!! \frac{1}{A \overline{h}^i} \left(
4325!! \frac{1}{\Delta y} \delta_i \left( h \Delta y^2 \kappa_h \dot{e}_T \right) +
4326!! \frac{1}{\Delta x} \delta_j \left( \tilde{h}^{ij} \Delta x^2 \kappa_h \dot{e}_S \right)
4327!! \right)
4328!! .
4329!! \f]
4330!!
4331!! The tendency for the y-component of the divergence of stress is stored in
4332!! variable <code>diffv</code> and discretized as
4333!! \f[
4334!! \hat{\bf y} \cdot \left( \nabla \cdot {\bf \sigma} \right) =
4335!! \frac{1}{A \overline{h}^j} \left(
4336!! \frac{1}{\Delta y} \delta_i \left( \tilde{h}^{ij} \Delta y^2 A_M \dot{e}_S \right)
4337!! - \frac{1}{\Delta x} \delta_j \left( h \Delta x^2 A_M \dot{e}_T \right)
4338!! \right)
4339!! .
4340!! \f]
4341!!
4342!! \subsection section_viscous_refs References
4343!!
4344!! Griffies, S.M., and Hallberg, R.W., 2000: Biharmonic friction with a
4345!! Smagorinsky-like viscosity for use in large-scale eddy-permitting ocean models.
4346!! Monthly Weather Review, 128(8), 2935-2946.
4347!! https://doi.org/10.1175/1520-0493(2000)128%3C2935:BFWASL%3E2.0.CO;2
4348!!
4349!! Large, W.G., Danabasoglu, G., McWilliams, J.C., Gent, P.R. and Bryan, F.O.,
4350!! 2001: Equatorial circulation of a global ocean climate model with
4351!! anisotropic horizontal viscosity.
4352!! Journal of Physical Oceanography, 31(2), pp.518-536.
4353!! https://doi.org/10.1175/1520-0485(2001)031%3C0518:ECOAGO%3E2.0.CO;2
4354!!
4355!! Smagorinsky, J., 1993: Some historical remarks on the use of nonlinear
4356!! viscosities. Large eddy simulation of complex engineering and geophysical
4357!! flows, 1, 69-106.
4358!!
4359!! Smith, R.D., and McWilliams, J.C., 2003: Anisotropic horizontal viscosity for
4360!! ocean models. Ocean Modelling, 5(2), 129-156.
4361!! https://doi.org/10.1016/S1463-5003(02)00016-1
43620end module MOM_hor_visc