20 use cvmix_kpp,
only : cvmix_init_kpp, cvmix_put_kpp, cvmix_get_kpp_real
21 use cvmix_kpp,
only : cvmix_coeffs_kpp
22 use cvmix_kpp,
only : cvmix_kpp_compute_obl_depth
23 use cvmix_kpp,
only : cvmix_kpp_compute_turbulent_scales
24 use cvmix_kpp,
only : cvmix_kpp_compute_bulk_richardson
25 use cvmix_kpp,
only : cvmix_kpp_compute_unresolved_shear
26 use cvmix_kpp,
only : cvmix_kpp_params_type
27 use cvmix_kpp,
only : cvmix_kpp_compute_kobl_depth
29 implicit none ;
private
31 #include "MOM_memory.h"
34 public :: kpp_compute_bld
35 public :: kpp_calculate
37 public :: kpp_nonlocaltransport_temp
38 public :: kpp_nonlocaltransport_saln
42 integer,
private,
parameter :: nlt_shape_cvmix = 0
43 integer,
private,
parameter :: nlt_shape_linear = 1
44 integer,
private,
parameter :: nlt_shape_parabolic = 2
45 integer,
private,
parameter :: nlt_shape_cubic = 3
46 integer,
private,
parameter :: nlt_shape_cubic_lmd = 4
49 integer,
private,
parameter :: sw_method_all_sw = 0
50 integer,
private,
parameter :: sw_method_mxl_sw = 1
51 integer,
private,
parameter :: sw_method_lv1_sw = 2
52 integer,
private,
parameter :: lt_k_constant = 1, & !< Constant enhance K through column
54 lt_k_mode_constant = 1, &
59 lt_vt2_mode_constant = 1, &
60 lt_vt2_mode_vr12 = 2, &
62 lt_vt2_mode_rw16 = 3, &
76 logical :: enhance_diffusion
77 character(len=10) :: interptype
78 character(len=10) :: interptype2
79 logical :: computeekman
80 logical :: computemoninobukhov
81 logical :: passivemode
85 real :: surf_layer_ext
87 logical :: fixedobldepth
88 real :: fixedobldepth_value
90 character(len=30) :: matchtechnique
92 logical :: applynonlocaltrans
94 logical :: deepen_only
95 logical :: kppzerodiffusivity
97 logical :: kppisadditive
100 real :: min_thickness
103 logical :: correctsurflayeravg
104 real :: surflayerdepth
107 logical :: lt_k_enhancement
108 integer :: lt_k_shape
109 integer :: lt_k_method
110 real :: kpp_k_enh_fac
111 logical :: lt_vt2_enhancement
112 integer :: lt_vt2_method
113 real :: kpp_vt2_enh_fac
114 logical :: stokes_mixing
118 type(cvmix_kpp_params_type),
pointer :: kpp_params => null()
122 integer :: id_obldepth = -1, id_bulkri = -1
123 integer :: id_n = -1, id_n2 = -1
124 integer :: id_ws = -1, id_vt2 = -1
125 integer :: id_bulkuz2 = -1, id_bulkdrho = -1
126 integer :: id_ustar = -1, id_buoyflux = -1
127 integer :: id_qminussw = -1, id_nets = -1
128 integer :: id_sigma = -1, id_kv_kpp = -1
129 integer :: id_kt_kpp = -1, id_ks_kpp = -1
130 integer :: id_tsurf = -1, id_ssurf = -1
131 integer :: id_usurf = -1, id_vsurf = -1
132 integer :: id_kd_in = -1
133 integer :: id_nltt = -1
134 integer :: id_nlts = -1
135 integer :: id_nlt_dsdt = -1
136 integer :: id_nlt_dtdt = -1
137 integer :: id_nlt_temp_budget = -1
138 integer :: id_nlt_saln_budget = -1
139 integer :: id_enhk = -1, id_enhvt2 = -1
140 integer :: id_enhw = -1
141 integer :: id_la_sl = -1
142 integer :: id_obldepth_original = -1
146 real,
allocatable,
dimension(:,:) :: obldepth
147 real,
allocatable,
dimension(:,:) :: obldepth_original
148 real,
allocatable,
dimension(:,:) :: kobl
149 real,
allocatable,
dimension(:,:) :: obldepthprev
150 real,
allocatable,
dimension(:,:) :: la_sl
151 real,
allocatable,
dimension(:,:,:) :: drho
152 real,
allocatable,
dimension(:,:,:) :: uz2
153 real,
allocatable,
dimension(:,:,:) :: bulkri
154 real,
allocatable,
dimension(:,:,:) :: sigma
155 real,
allocatable,
dimension(:,:,:) :: ws
156 real,
allocatable,
dimension(:,:,:) :: n
157 real,
allocatable,
dimension(:,:,:) :: n2
158 real,
allocatable,
dimension(:,:,:) :: vt2
159 real,
allocatable,
dimension(:,:,:) :: kt_kpp
160 real,
allocatable,
dimension(:,:,:) :: ks_kpp
161 real,
allocatable,
dimension(:,:,:) :: kv_kpp
162 real,
allocatable,
dimension(:,:) :: tsurf
163 real,
allocatable,
dimension(:,:) :: ssurf
164 real,
allocatable,
dimension(:,:) :: usurf
165 real,
allocatable,
dimension(:,:) :: vsurf
166 real,
allocatable,
dimension(:,:,:) :: enhk
167 real,
allocatable,
dimension(:,:,:) :: enhvt2
171 #define __DO_SAFETY_CHECKS__
177 logical function kpp_init(paramFile, G, GV, US, diag, Time, CS, passive, Waves)
184 type(
diag_ctrl),
target,
intent(in) :: diag
185 type(time_type),
intent(in) :: time
186 type(
kpp_cs),
pointer :: cs
187 logical,
optional,
intent(out) :: passive
191 #include "version_variable.h"
192 character(len=40) :: mdl =
'MOM_CVMix_KPP'
193 character(len=20) :: string
194 logical :: cs_is_one=.false.
195 logical :: lnodgat1=.false.
197 if (
associated(cs))
call mom_error(fatal,
'MOM_CVMix_KPP, KPP_init: '// &
198 'Control structure has already been initialized')
202 call log_version(paramfile, mdl, version,
'This is the MOM wrapper to CVMix:KPP\n' // &
203 'See http://cvmix.github.io/')
204 call get_param(paramfile, mdl,
"USE_KPP", kpp_init, &
205 "If true, turns on the [CVMix] KPP scheme of Large et al., 1994, "// &
206 "to calculate diffusivities and non-local transport in the OBL.", &
209 if (.not. kpp_init)
return
211 call openparameterblock(paramfile,
'KPP')
212 call get_param(paramfile, mdl,
'PASSIVE', cs%passiveMode, &
213 'If True, puts KPP into a passive-diagnostic mode.', &
217 if (
present(passive)) passive=cs%passiveMode
219 call get_param(paramfile, mdl,
'APPLY_NONLOCAL_TRANSPORT', cs%applyNonLocalTrans, &
220 'If True, applies the non-local transport to heat and scalars. '// &
221 'If False, calculates the non-local transport and tendencies but '//&
222 'purely for diagnostic purposes.', &
223 default=.not. cs%passiveMode)
224 call get_param(paramfile, mdl,
'N_SMOOTH', cs%n_smooth, &
225 'The number of times the 1-1-4-1-1 Laplacian filter is applied on '// &
228 if (cs%n_smooth > 0)
then
229 call get_param(paramfile, mdl,
'DEEPEN_ONLY_VIA_SMOOTHING', cs%deepen_only, &
230 'If true, apply OBLdepth smoothing at a cell only if the OBLdepth '// &
231 'gets deeper via smoothing.', &
234 call get_param(paramfile, mdl,
'RI_CRIT', cs%Ri_crit, &
235 'Critical bulk Richardson number used to define depth of the '// &
236 'surface Ocean Boundary Layer (OBL).', &
237 units=
'nondim', default=0.3)
238 call get_param(paramfile, mdl,
'VON_KARMAN', cs%vonKarman, &
239 'von Karman constant.', &
240 units=
'nondim', default=0.40)
241 call get_param(paramfile, mdl,
'ENHANCE_DIFFUSION', cs%enhance_diffusion, &
242 'If True, adds enhanced diffusion at the based of the boundary layer.', &
244 call get_param(paramfile, mdl,
'INTERP_TYPE', cs%interpType, &
245 'Type of interpolation to determine the OBL depth.\n'// &
246 'Allowed types are: linear, quadratic, cubic.', &
248 call get_param(paramfile, mdl,
'INTERP_TYPE2', cs%interpType2, &
249 'Type of interpolation to compute diff and visc at OBL_depth.\n'// &
250 'Allowed types are: linear, quadratic, cubic or LMD94.', &
252 call get_param(paramfile, mdl,
'COMPUTE_EKMAN', cs%computeEkman, &
253 'If True, limit OBL depth to be no deeper than Ekman depth.', &
255 call get_param(paramfile, mdl,
'COMPUTE_MONIN_OBUKHOV', cs%computeMoninObukhov, &
256 'If True, limit the OBL depth to be no deeper than '// &
257 'Monin-Obukhov depth.', &
259 call get_param(paramfile, mdl,
'CS', cs%cs, &
260 'Parameter for computing velocity scale function.', &
261 units=
'nondim', default=98.96)
262 call get_param(paramfile, mdl,
'CS2', cs%cs2, &
263 'Parameter for computing non-local term.', &
264 units=
'nondim', default=6.32739901508)
265 call get_param(paramfile, mdl,
'DEEP_OBL_OFFSET', cs%deepOBLoffset, &
266 'If non-zero, the distance above the bottom to which the OBL is clipped '// &
267 'if it would otherwise reach the bottom. The smaller of this and 0.1D is used.', &
268 units=
'm',default=0.)
269 call get_param(paramfile, mdl,
'FIXED_OBLDEPTH', cs%fixedOBLdepth, &
270 'If True, fix the OBL depth to FIXED_OBLDEPTH_VALUE '// &
271 'rather than using the OBL depth from CVMix. '// &
272 'This option is just for testing purposes.', &
274 call get_param(paramfile, mdl,
'FIXED_OBLDEPTH_VALUE', cs%fixedOBLdepth_value, &
275 'Value for the fixed OBL depth when fixedOBLdepth==True. '// &
276 'This parameter is for just for testing purposes. '// &
277 'It will over-ride the OBLdepth computed from CVMix.', &
278 units=
'm',default=30.0)
279 call get_param(paramfile, mdl,
'SURF_LAYER_EXTENT', cs%surf_layer_ext, &
280 'Fraction of OBL depth considered in the surface layer.', &
281 units=
'nondim',default=0.10)
282 call get_param(paramfile, mdl,
'MINIMUM_OBL_DEPTH', cs%minOBLdepth, &
283 'If non-zero, a minimum depth to use for KPP OBL depth. Independent of '// &
284 'this parameter, the OBL depth is always at least as deep as the first layer.', &
285 units=
'm',default=0.)
286 call get_param(paramfile, mdl,
'MINIMUM_VT2', cs%minVtsqr, &
287 'Min of the unresolved velocity Vt2 used in Rib CVMix calculation.\n'// &
288 'Scaling: MINIMUM_VT2 = const1*d*N*ws, with d=1m, N=1e-5/s, ws=1e-6 m/s.', &
289 units=
'm2/s2',default=1e-10)
292 call get_param(paramfile, mdl,
'CORRECT_SURFACE_LAYER_AVERAGE', cs%correctSurfLayerAvg, &
293 'If true, applies a correction step to the averaging of surface layer '// &
294 'properties. This option is obsolete.', default=.false.)
295 if (cs%correctSurfLayerAvg) &
296 call mom_error(fatal,
'Correct surface layer average disabled in code. To recover \n'// &
297 ' feature will require code intervention.')
298 call get_param(paramfile, mdl,
'FIRST_GUESS_SURFACE_LAYER_DEPTH', cs%surfLayerDepth, &
299 'The first guess at the depth of the surface layer used for averaging '// &
300 'the surface layer properties. If =0, the top model level properties '// &
301 'will be used for the surface layer. If CORRECT_SURFACE_LAYER_AVERAGE=True, a '// &
302 'subsequent correction is applied. This parameter is obsolete', units=
'm', default=0.)
305 call get_param(paramfile, mdl,
'NLT_SHAPE', string, &
306 'MOM6 method to set nonlocal transport profile. '// &
307 'Over-rides the result from CVMix. Allowed values are: \n'// &
308 '\t CVMix - Uses the profiles from CVMix specified by MATCH_TECHNIQUE\n'//&
309 '\t LINEAR - A linear profile, 1-sigma\n'// &
310 '\t PARABOLIC - A parablic profile, (1-sigma)^2\n'// &
311 '\t CUBIC - A cubic profile, (1-sigma)^2(1+2*sigma)\n'// &
312 '\t CUBIC_LMD - The original KPP profile', &
314 select case ( trim(string) )
315 case (
"CVMix") ; cs%NLT_shape = nlt_shape_cvmix
316 case (
"LINEAR") ; cs%NLT_shape = nlt_shape_linear
317 case (
"PARABOLIC") ; cs%NLT_shape = nlt_shape_parabolic
318 case (
"CUBIC") ; cs%NLT_shape = nlt_shape_cubic
319 case (
"CUBIC_LMD") ; cs%NLT_shape = nlt_shape_cubic_lmd
320 case default ;
call mom_error(fatal,
"KPP_init: "// &
321 "Unrecognized NLT_SHAPE option"//trim(string))
323 call get_param(paramfile, mdl,
'MATCH_TECHNIQUE', cs%MatchTechnique, &
324 'CVMix method to set profile function for diffusivity and NLT, '// &
325 'as well as matching across OBL base. Allowed values are: \n'// &
326 '\t SimpleShapes = sigma*(1-sigma)^2 for both diffusivity and NLT\n'// &
327 '\t MatchGradient = sigma*(1-sigma)^2 for NLT; diffusivity profile from matching\n'//&
328 '\t MatchBoth = match gradient for both diffusivity and NLT\n'// &
329 '\t ParabolicNonLocal = sigma*(1-sigma)^2 for diffusivity; (1-sigma)^2 for NLT', &
330 default=
'SimpleShapes')
331 if (cs%MatchTechnique ==
'ParabolicNonLocal')
then
336 if (cs%MatchTechnique ==
'ParabolicNonLocal' .or. cs%MatchTechnique ==
'SimpleShapes')
then
342 if (cs%MatchTechnique ==
'MatchBoth' .and. (cs%interpType2 ==
'cubic' .or. &
343 cs%interpType2 ==
'quadratic'))
then
344 call mom_error(fatal,
"If MATCH_TECHNIQUE=MatchBoth, INTERP_TYPE2 must be set to \n"//&
345 "linear or LMD94 (recommended) to avoid negative viscosity and diffusivity.\n"//&
346 "Please select one of these valid options." )
349 call get_param(paramfile, mdl,
'KPP_ZERO_DIFFUSIVITY', cs%KPPzeroDiffusivity, &
350 'If True, zeroes the KPP diffusivity and viscosity; for testing purpose.',&
352 call get_param(paramfile, mdl,
'KPP_IS_ADDITIVE', cs%KPPisAdditive, &
353 'If true, adds KPP diffusivity to diffusivity from other schemes.\n'//&
354 'If false, KPP is the only diffusivity wherever KPP is non-zero.', &
356 call get_param(paramfile, mdl,
'KPP_SHORTWAVE_METHOD',string, &
357 'Determines contribution of shortwave radiation to KPP surface '// &
358 'buoyancy flux. Options include:\n'// &
359 ' ALL_SW: use total shortwave radiation\n'// &
360 ' MXL_SW: use shortwave radiation absorbed by mixing layer\n'// &
361 ' LV1_SW: use shortwave radiation absorbed by top model layer', &
363 select case ( trim(string) )
364 case (
"ALL_SW") ; cs%SW_METHOD = sw_method_all_sw
365 case (
"MXL_SW") ; cs%SW_METHOD = sw_method_mxl_sw
366 case (
"LV1_SW") ; cs%SW_METHOD = sw_method_lv1_sw
367 case default ;
call mom_error(fatal,
"KPP_init: "// &
368 "Unrecognized KPP_SHORTWAVE_METHOD option"//trim(string))
370 call get_param(paramfile, mdl,
'CVMix_ZERO_H_WORK_AROUND', cs%min_thickness, &
371 'A minimum thickness used to avoid division by small numbers in the vicinity '// &
372 'of vanished layers. This is independent of MIN_THICKNESS used in other parts of MOM.', &
373 units=
'm', default=0.)
377 call get_param(paramfile, mdl,
"USE_KPP_LT_K", cs%LT_K_Enhancement, &
378 'Flag for Langmuir turbulence enhancement of turbulent'//&
379 'mixing coefficient.', units=
"", default=.false.)
380 call get_param(paramfile, mdl,
"STOKES_MIXING", cs%STOKES_MIXING, &
381 'Flag for Langmuir turbulence enhancement of turbulent'//&
382 'mixing coefficient.', units=
"", default=.false.)
383 if (cs%LT_K_Enhancement)
then
384 call get_param(paramfile, mdl,
'KPP_LT_K_SHAPE', string, &
385 'Vertical dependence of LT enhancement of mixing. '// &
386 'Valid options are: \n'// &
387 '\t CONSTANT = Constant value for full OBL\n'// &
388 '\t SCALED = Varies based on normalized shape function.', &
390 select case ( trim(string))
391 case (
"CONSTANT") ; cs%LT_K_SHAPE = lt_k_constant
392 case (
"SCALED") ; cs%LT_K_SHAPE = lt_k_scaled
393 case default ;
call mom_error(fatal,
"KPP_init: "//&
394 "Unrecognized KPP_LT_K_SHAPE option: "//trim(string))
396 call get_param(paramfile, mdl,
"KPP_LT_K_METHOD", string , &
397 'Method to enhance mixing coefficient in KPP. '// &
398 'Valid options are: \n'// &
399 '\t CONSTANT = Constant value (KPP_K_ENH_FAC) \n'// &
400 '\t VR12 = Function of Langmuir number based on VR12\n'// &
401 '\t RW16 = Function of Langmuir number based on RW16', &
403 select case ( trim(string))
404 case (
"CONSTANT") ; cs%LT_K_METHOD = lt_k_mode_constant
405 case (
"VR12") ; cs%LT_K_METHOD = lt_k_mode_vr12
406 case (
"RW16") ; cs%LT_K_METHOD = lt_k_mode_rw16
407 case default ;
call mom_error(fatal,
"KPP_init: "//&
408 "Unrecognized KPP_LT_K_METHOD option: "//trim(string))
410 if (cs%LT_K_METHOD==lt_k_mode_constant)
then
411 call get_param(paramfile, mdl,
"KPP_K_ENH_FAC",cs%KPP_K_ENH_FAC , &
412 'Constant value to enhance mixing coefficient in KPP.', &
417 call get_param(paramfile, mdl,
"USE_KPP_LT_VT2", cs%LT_Vt2_Enhancement, &
418 'Flag for Langmuir turbulence enhancement of Vt2'//&
419 'in Bulk Richardson Number.', units=
"", default=.false.)
420 if (cs%LT_Vt2_Enhancement)
then
421 call get_param(paramfile, mdl,
"KPP_LT_VT2_METHOD",string , &
422 'Method to enhance Vt2 in KPP. '// &
423 'Valid options are: \n'// &
424 '\t CONSTANT = Constant value (KPP_VT2_ENH_FAC) \n'// &
425 '\t VR12 = Function of Langmuir number based on VR12\n'// &
426 '\t RW16 = Function of Langmuir number based on RW16\n'// &
427 '\t LF17 = Function of Langmuir number based on LF17', &
429 select case ( trim(string))
430 case (
"CONSTANT") ; cs%LT_VT2_METHOD = lt_vt2_mode_constant
431 case (
"VR12") ; cs%LT_VT2_METHOD = lt_vt2_mode_vr12
432 case (
"RW16") ; cs%LT_VT2_METHOD = lt_vt2_mode_rw16
433 case (
"LF17") ; cs%LT_VT2_METHOD = lt_vt2_mode_lf17
434 case default ;
call mom_error(fatal,
"KPP_init: "//&
435 "Unrecognized KPP_LT_VT2_METHOD option: "//trim(string))
437 if (cs%LT_VT2_METHOD==lt_vt2_mode_constant)
then
438 call get_param(paramfile, mdl,
"KPP_VT2_ENH_FAC",cs%KPP_VT2_ENH_FAC , &
439 'Constant value to enhance VT2 in KPP.', &
444 call closeparameterblock(paramfile)
445 call get_param(paramfile, mdl,
'DEBUG', cs%debug, default=.false., do_not_log=.true.)
447 call cvmix_init_kpp( ri_crit=cs%Ri_crit, &
448 minobldepth=cs%minOBLdepth, &
449 minvtsqr=cs%minVtsqr, &
450 vonkarman=cs%vonKarman, &
451 surf_layer_ext=cs%surf_layer_ext, &
452 interp_type=cs%interpType, &
453 interp_type2=cs%interpType2, &
454 lekman=cs%computeEkman, &
455 lmonob=cs%computeMoninObukhov, &
456 matchtechnique=cs%MatchTechnique, &
457 lenhanced_diff=cs%enhance_diffusion,&
458 lnonzero_surf_nonlocal=cs_is_one ,&
460 cvmix_kpp_params_user=cs%KPP_params )
464 cs%id_OBLdepth = register_diag_field(
'ocean_model',
'KPP_OBLdepth', diag%axesT1, time, &
465 'Thickness of the surface Ocean Boundary Layer calculated by [CVMix] KPP',
'meter', &
466 cmor_field_name=
'oml', cmor_long_name=
'ocean_mixed_layer_thickness_defined_by_mixing_scheme', &
467 cmor_units=
'm', cmor_standard_name=
'Ocean Mixed Layer Thickness Defined by Mixing Scheme')
471 if (cs%n_smooth > 0)
then
472 cs%id_OBLdepth_original = register_diag_field(
'ocean_model',
'KPP_OBLdepth_original', diag%axesT1, time, &
473 'Thickness of the surface Ocean Boundary Layer without smoothing calculated by [CVMix] KPP',
'meter', &
474 cmor_field_name=
'oml', cmor_long_name=
'ocean_mixed_layer_thickness_defined_by_mixing_scheme', &
475 cmor_units=
'm', cmor_standard_name=
'Ocean Mixed Layer Thickness Defined by Mixing Scheme')
477 cs%id_BulkDrho = register_diag_field(
'ocean_model',
'KPP_BulkDrho', diag%axesTL, time, &
478 'Bulk difference in density used in Bulk Richardson number, as used by [CVMix] KPP',
'kg/m3')
479 cs%id_BulkUz2 = register_diag_field(
'ocean_model',
'KPP_BulkUz2', diag%axesTL, time, &
480 'Square of bulk difference in resolved velocity used in Bulk Richardson number via [CVMix] KPP',
'm2/s2')
481 cs%id_BulkRi = register_diag_field(
'ocean_model',
'KPP_BulkRi', diag%axesTL, time, &
482 'Bulk Richardson number used to find the OBL depth used by [CVMix] KPP',
'nondim')
483 cs%id_Sigma = register_diag_field(
'ocean_model',
'KPP_sigma', diag%axesTi, time, &
484 'Sigma coordinate used by [CVMix] KPP',
'nondim')
485 cs%id_Ws = register_diag_field(
'ocean_model',
'KPP_Ws', diag%axesTL, time, &
486 'Turbulent vertical velocity scale for scalars used by [CVMix] KPP',
'm/s')
487 cs%id_N = register_diag_field(
'ocean_model',
'KPP_N', diag%axesTi, time, &
488 '(Adjusted) Brunt-Vaisala frequency used by [CVMix] KPP',
'1/s')
489 cs%id_N2 = register_diag_field(
'ocean_model',
'KPP_N2', diag%axesTi, time, &
490 'Square of Brunt-Vaisala frequency used by [CVMix] KPP',
'1/s2')
491 cs%id_Vt2 = register_diag_field(
'ocean_model',
'KPP_Vt2', diag%axesTL, time, &
492 'Unresolved shear turbulence used by [CVMix] KPP',
'm2/s2')
493 cs%id_uStar = register_diag_field(
'ocean_model',
'KPP_uStar', diag%axesT1, time, &
494 'Friction velocity, u*, as used by [CVMix] KPP',
'm/s', conversion=us%Z_to_m*us%s_to_T)
495 cs%id_buoyFlux = register_diag_field(
'ocean_model',
'KPP_buoyFlux', diag%axesTi, time, &
496 'Surface (and penetrating) buoyancy flux, as used by [CVMix] KPP',
'm2/s3', conversion=us%L_to_m**2*us%s_to_T**3)
497 cs%id_QminusSW = register_diag_field(
'ocean_model',
'KPP_QminusSW', diag%axesT1, time, &
498 'Net temperature flux ignoring short-wave, as used by [CVMix] KPP',
'K m/s')
499 cs%id_netS = register_diag_field(
'ocean_model',
'KPP_netSalt', diag%axesT1, time, &
500 'Effective net surface salt flux, as used by [CVMix] KPP',
'ppt m/s')
501 cs%id_Kt_KPP = register_diag_field(
'ocean_model',
'KPP_Kheat', diag%axesTi, time, &
502 'Heat diffusivity due to KPP, as calculated by [CVMix] KPP',
'm2/s')
503 cs%id_Kd_in = register_diag_field(
'ocean_model',
'KPP_Kd_in', diag%axesTi, time, &
504 'Diffusivity passed to KPP',
'm2/s', conversion=us%Z2_T_to_m2_s)
505 cs%id_Ks_KPP = register_diag_field(
'ocean_model',
'KPP_Ksalt', diag%axesTi, time, &
506 'Salt diffusivity due to KPP, as calculated by [CVMix] KPP',
'm2/s')
507 cs%id_Kv_KPP = register_diag_field(
'ocean_model',
'KPP_Kv', diag%axesTi, time, &
508 'Vertical viscosity due to KPP, as calculated by [CVMix] KPP',
'm2/s')
509 cs%id_NLTt = register_diag_field(
'ocean_model',
'KPP_NLtransport_heat', diag%axesTi, time, &
510 'Non-local transport (Cs*G(sigma)) for heat, as calculated by [CVMix] KPP',
'nondim')
511 cs%id_NLTs = register_diag_field(
'ocean_model',
'KPP_NLtransport_salt', diag%axesTi, time, &
512 'Non-local tranpsort (Cs*G(sigma)) for scalars, as calculated by [CVMix] KPP',
'nondim')
513 cs%id_NLT_dTdt = register_diag_field(
'ocean_model',
'KPP_NLT_dTdt', diag%axesTL, time, &
514 'Temperature tendency due to non-local transport of heat, as calculated by [CVMix] KPP',
'K/s')
515 cs%id_NLT_dSdt = register_diag_field(
'ocean_model',
'KPP_NLT_dSdt', diag%axesTL, time, &
516 'Salinity tendency due to non-local transport of salt, as calculated by [CVMix] KPP',
'ppt/s')
517 cs%id_NLT_temp_budget = register_diag_field(
'ocean_model',
'KPP_NLT_temp_budget', diag%axesTL, time, &
518 'Heat content change due to non-local transport, as calculated by [CVMix] KPP',
'W/m^2')
519 cs%id_NLT_saln_budget = register_diag_field(
'ocean_model',
'KPP_NLT_saln_budget', diag%axesTL, time, &
520 'Salt content change due to non-local transport, as calculated by [CVMix] KPP',
'kg/(sec*m^2)')
521 cs%id_Tsurf = register_diag_field(
'ocean_model',
'KPP_Tsurf', diag%axesT1, time, &
522 'Temperature of surface layer (10% of OBL depth) as passed to [CVMix] KPP',
'C')
523 cs%id_Ssurf = register_diag_field(
'ocean_model',
'KPP_Ssurf', diag%axesT1, time, &
524 'Salinity of surface layer (10% of OBL depth) as passed to [CVMix] KPP',
'ppt')
525 cs%id_Usurf = register_diag_field(
'ocean_model',
'KPP_Usurf', diag%axesCu1, time, &
526 'i-component flow of surface layer (10% of OBL depth) as passed to [CVMix] KPP',
'm/s')
527 cs%id_Vsurf = register_diag_field(
'ocean_model',
'KPP_Vsurf', diag%axesCv1, time, &
528 'j-component flow of surface layer (10% of OBL depth) as passed to [CVMix] KPP',
'm/s')
529 cs%id_EnhK = register_diag_field(
'ocean_model',
'EnhK', diag%axesTI, time, &
530 'Langmuir number enhancement to K as used by [CVMix] KPP',
'nondim')
531 cs%id_EnhVt2 = register_diag_field(
'ocean_model',
'EnhVt2', diag%axesTL, time, &
532 'Langmuir number enhancement to Vt2 as used by [CVMix] KPP',
'nondim')
533 cs%id_La_SL = register_diag_field(
'ocean_model',
'KPP_La_SL', diag%axesT1, time, &
534 'Surface-layer Langmuir number computed in [CVMix] KPP',
'nondim')
536 allocate( cs%N( szi_(g), szj_(g), szk_(g)+1 ) )
538 allocate( cs%OBLdepth( szi_(g), szj_(g) ) )
539 cs%OBLdepth(:,:) = 0.
540 allocate( cs%kOBL( szi_(g), szj_(g) ) )
542 allocate( cs%La_SL( szi_(g), szj_(g) ) )
544 allocate( cs%Vt2( szi_(g), szj_(g), szk_(g) ) )
546 if (cs%id_OBLdepth_original > 0)
allocate( cs%OBLdepth_original( szi_(g), szj_(g) ) )
548 allocate( cs%OBLdepthprev( szi_(g), szj_(g) ) ) ; cs%OBLdepthprev(:,:) = 0.0
549 if (cs%id_BulkDrho > 0)
allocate( cs%dRho( szi_(g), szj_(g), szk_(g) ) )
550 if (cs%id_BulkDrho > 0) cs%dRho(:,:,:) = 0.
551 if (cs%id_BulkUz2 > 0)
allocate( cs%Uz2( szi_(g), szj_(g), szk_(g) ) )
552 if (cs%id_BulkUz2 > 0) cs%Uz2(:,:,:) = 0.
553 if (cs%id_BulkRi > 0)
allocate( cs%BulkRi( szi_(g), szj_(g), szk_(g) ) )
554 if (cs%id_BulkRi > 0) cs%BulkRi(:,:,:) = 0.
555 if (cs%id_Sigma > 0)
allocate( cs%sigma( szi_(g), szj_(g), szk_(g)+1 ) )
556 if (cs%id_Sigma > 0) cs%sigma(:,:,:) = 0.
557 if (cs%id_Ws > 0)
allocate( cs%Ws( szi_(g), szj_(g), szk_(g) ) )
558 if (cs%id_Ws > 0) cs%Ws(:,:,:) = 0.
559 if (cs%id_N2 > 0)
allocate( cs%N2( szi_(g), szj_(g), szk_(g)+1 ) )
560 if (cs%id_N2 > 0) cs%N2(:,:,:) = 0.
561 if (cs%id_Kt_KPP > 0)
allocate( cs%Kt_KPP( szi_(g), szj_(g), szk_(g)+1 ) )
562 if (cs%id_Kt_KPP > 0) cs%Kt_KPP(:,:,:) = 0.
563 if (cs%id_Ks_KPP > 0)
allocate( cs%Ks_KPP( szi_(g), szj_(g), szk_(g)+1 ) )
564 if (cs%id_Ks_KPP > 0) cs%Ks_KPP(:,:,:) = 0.
565 if (cs%id_Kv_KPP > 0)
allocate( cs%Kv_KPP( szi_(g), szj_(g), szk_(g)+1 ) )
566 if (cs%id_Kv_KPP > 0) cs%Kv_KPP(:,:,:) = 0.
567 if (cs%id_Tsurf > 0)
allocate( cs%Tsurf( szi_(g), szj_(g)) )
568 if (cs%id_Tsurf > 0) cs%Tsurf(:,:) = 0.
569 if (cs%id_Ssurf > 0)
allocate( cs%Ssurf( szi_(g), szj_(g)) )
570 if (cs%id_Ssurf > 0) cs%Ssurf(:,:) = 0.
571 if (cs%id_Usurf > 0)
allocate( cs%Usurf( szib_(g), szj_(g)) )
572 if (cs%id_Usurf > 0) cs%Usurf(:,:) = 0.
573 if (cs%id_Vsurf > 0)
allocate( cs%Vsurf( szi_(g), szjb_(g)) )
574 if (cs%id_Vsurf > 0) cs%Vsurf(:,:) = 0.
575 if (cs%id_EnhVt2 > 0)
allocate( cs%EnhVt2( szi_(g), szj_(g), szk_(g)) )
576 if (cs%id_EnhVt2 > 0) cs%EnhVt2(:,:,:) = 0.
577 if (cs%id_EnhK > 0)
allocate( cs%EnhK( szi_(g), szj_(g), szk_(g)+1 ) )
578 if (cs%id_EnhK > 0) cs%EnhK(:,:,:) = 0.
581 end function kpp_init
584 subroutine kpp_calculate(CS, G, GV, US, h, uStar, &
585 buoyFlux, Kt, Ks, Kv, nonLocalTransHeat,&
586 nonLocalTransScalar, waves)
589 type(
kpp_cs),
pointer :: cs
594 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
595 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: ustar
596 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: buoyflux
597 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: kt
600 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: ks
603 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: kv
606 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: nonlocaltransheat
607 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: nonlocaltransscalar
611 real,
dimension( G%ke ) :: cellheight
612 real,
dimension( G%ke+1 ) :: ifaceheight
613 real,
dimension( G%ke+1, 2) :: kdiffusivity
614 real,
dimension( G%ke+1 ) :: kviscosity
615 real,
dimension( G%ke+1, 2) :: nonlocaltrans
617 real :: surffricvel, surfbuoyflux
618 real :: sigma, sigmaratio
627 #ifdef __DO_SAFETY_CHECKS__
629 call hchksum(h,
"KPP in: h",g%HI,haloshift=0, scale=gv%H_to_m)
630 call hchksum(ustar,
"KPP in: uStar",g%HI,haloshift=0, scale=us%Z_to_m*us%s_to_T)
631 call hchksum(buoyflux,
"KPP in: buoyFlux",g%HI,haloshift=0)
632 call hchksum(kt,
"KPP in: Kt",g%HI,haloshift=0, scale=us%Z2_T_to_m2_s)
633 call hchksum(ks,
"KPP in: Ks",g%HI,haloshift=0, scale=us%Z2_T_to_m2_s)
637 nonlocaltrans(:,:) = 0.0
639 if (cs%id_Kd_in > 0)
call post_data(cs%id_Kd_in, kt, cs%diag)
641 buoy_scale = us%L_to_m**2*us%s_to_T**3
649 if (g%mask2dT(i,j)==0.) cycle
652 surffricvel = us%Z_to_m*us%s_to_T * ustar(i,j)
659 dh = h(i,j,k) * gv%H_to_m
661 hcorr = min( dh - cs%min_thickness, 0. )
662 dh = max( dh, cs%min_thickness )
663 cellheight(k) = ifaceheight(k) - 0.5 * dh
664 ifaceheight(k+1) = ifaceheight(k) - dh
668 surfbuoyflux = buoy_scale*buoyflux(i,j,1)
677 if (cs%SW_METHOD == sw_method_all_sw)
then
678 surfbuoyflux = buoy_scale * buoyflux(i,j,1)
679 elseif (cs%SW_METHOD == sw_method_mxl_sw)
then
681 surfbuoyflux = buoy_scale * (buoyflux(i,j,1) - buoyflux(i,j,int(cs%kOBL(i,j))+1))
682 elseif (cs%SW_METHOD == sw_method_lv1_sw)
then
683 surfbuoyflux = buoy_scale * (buoyflux(i,j,1) - buoyflux(i,j,2))
687 if (.not. (cs%MatchTechnique ==
'MatchBoth'))
then
688 kdiffusivity(:,:) = 0.
691 kdiffusivity(:,1) = us%Z2_T_to_m2_s * kt(i,j,:)
692 kdiffusivity(:,2) = us%Z2_T_to_m2_s * ks(i,j,:)
693 kviscosity(:) = us%Z2_T_to_m2_s * kv(i,j,:)
696 call cvmix_coeffs_kpp(kviscosity(:), &
712 cvmix_kpp_params_user=cs%KPP_params )
716 if (kviscosity(k) < 0. .or. kdiffusivity(k,1) < 0.)
then
717 call mom_error(fatal,
"KPP_calculate, after CVMix_coeffs_kpp: "// &
718 "Negative vertical viscosity or diffusivity has been detected. " // &
719 "This is likely related to the choice of MATCH_TECHNIQUE and INTERP_TYPE2." //&
720 "You might consider using the default options for these parameters." )
724 IF (cs%LT_K_ENHANCEMENT)
then
725 if (cs%LT_K_METHOD==lt_k_mode_constant)
then
726 langenhk = cs%KPP_K_ENH_FAC
727 elseif (cs%LT_K_METHOD==lt_k_mode_vr12)
then
729 langenhk = sqrt(1.+(1.5*cs%La_SL(i,j))**(-2) + &
730 (5.4*cs%La_SL(i,j))**(-4))
731 elseif (cs%LT_K_METHOD==lt_k_mode_rw16)
then
733 langenhk = min(2.25, 1. + 1./cs%La_SL(i,j))
740 if (cs%LT_K_SHAPE== lt_k_constant)
then
741 if (cs%id_EnhK > 0) cs%EnhK(i,j,:) = langenhk
742 kdiffusivity(k,1) = kdiffusivity(k,1) * langenhk
743 kdiffusivity(k,2) = kdiffusivity(k,2) * langenhk
744 kviscosity(k) = kviscosity(k) * langenhk
745 elseif (cs%LT_K_SHAPE == lt_k_scaled)
then
746 sigma = min(1.0,-ifaceheight(k)/cs%OBLdepth(i,j))
747 sigmaratio = sigma * (1. - sigma)**2 / 0.148148037
748 if (cs%id_EnhK > 0) cs%EnhK(i,j,k) = (1.0 + (langenhk - 1.)*sigmaratio)
749 kdiffusivity(k,1) = kdiffusivity(k,1) * ( 1. + &
750 ( langenhk - 1.)*sigmaratio)
751 kdiffusivity(k,2) = kdiffusivity(k,2) * ( 1. + &
752 ( langenhk - 1.)*sigmaratio)
753 kviscosity(k) = kviscosity(k) * ( 1. + &
754 ( langenhk - 1.)*sigmaratio)
768 if (surfbuoyflux < 0.0)
then
769 if (cs%NLT_shape == nlt_shape_cubic)
then
771 sigma = min(1.0,-ifaceheight(k)/cs%OBLdepth(i,j))
772 nonlocaltrans(k,1) = (1.0 - sigma)**2 * (1.0 + 2.0*sigma)
773 nonlocaltrans(k,2) = nonlocaltrans(k,1)
775 elseif (cs%NLT_shape == nlt_shape_parabolic)
then
777 sigma = min(1.0,-ifaceheight(k)/cs%OBLdepth(i,j))
778 nonlocaltrans(k,1) = (1.0 - sigma)**2
779 nonlocaltrans(k,2) = nonlocaltrans(k,1)
781 elseif (cs%NLT_shape == nlt_shape_linear)
then
783 sigma = min(1.0,-ifaceheight(k)/cs%OBLdepth(i,j))
784 nonlocaltrans(k,1) = (1.0 - sigma)
785 nonlocaltrans(k,2) = nonlocaltrans(k,1)
787 elseif (cs%NLT_shape == nlt_shape_cubic_lmd)
then
790 sigma = min(1.0,-ifaceheight(k)/cs%OBLdepth(i,j))
791 nonlocaltrans(k,1) = cs%CS2 * sigma*(1.0 -sigma)**2
792 nonlocaltrans(k,2) = nonlocaltrans(k,1)
799 nonlocaltransheat(i,j,:) = nonlocaltrans(:,1)
800 nonlocaltransscalar(i,j,:) = nonlocaltrans(:,2)
803 if (cs%KPPzeroDiffusivity)
then
804 kdiffusivity(:,1) = 0.0
805 kdiffusivity(:,2) = 0.0
811 if (cs%id_Vt2 > 0)
then
823 cs%OBLdepthprev(i,j)=cs%OBLdepth(i,j)
824 if (cs%id_sigma > 0)
then
826 if (cs%OBLdepth(i,j)>0.) cs%sigma(i,j,:) = -ifaceheight/cs%OBLdepth(i,j)
828 if (cs%id_Kt_KPP > 0) cs%Kt_KPP(i,j,:) = kdiffusivity(:,1)
829 if (cs%id_Ks_KPP > 0) cs%Ks_KPP(i,j,:) = kdiffusivity(:,2)
830 if (cs%id_Kv_KPP > 0) cs%Kv_KPP(i,j,:) = kviscosity(:)
833 if (.not. cs%passiveMode)
then
834 if (cs%KPPisAdditive)
then
836 kt(i,j,k) = kt(i,j,k) + us%m2_s_to_Z2_T * kdiffusivity(k,1)
837 ks(i,j,k) = ks(i,j,k) + us%m2_s_to_Z2_T * kdiffusivity(k,2)
838 kv(i,j,k) = kv(i,j,k) + us%m2_s_to_Z2_T * kviscosity(k)
839 if (cs%Stokes_Mixing) waves%KvS(i,j,k) = kv(i,j,k)
843 if (kdiffusivity(k,1) /= 0.) kt(i,j,k) = us%m2_s_to_Z2_T * kdiffusivity(k,1)
844 if (kdiffusivity(k,2) /= 0.) ks(i,j,k) = us%m2_s_to_Z2_T * kdiffusivity(k,2)
845 if (kviscosity(k) /= 0.) kv(i,j,k) = us%m2_s_to_Z2_T * kviscosity(k)
846 if (cs%Stokes_Mixing) waves%KvS(i,j,k) = kv(i,j,k)
857 #ifdef __DO_SAFETY_CHECKS__
859 call hchksum(kt,
"KPP out: Kt", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
860 call hchksum(ks,
"KPP out: Ks", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
865 if (cs%id_OBLdepth > 0)
call post_data(cs%id_OBLdepth, cs%OBLdepth, cs%diag)
866 if (cs%id_OBLdepth_original > 0)
call post_data(cs%id_OBLdepth_original,cs%OBLdepth_original,cs%diag)
867 if (cs%id_sigma > 0)
call post_data(cs%id_sigma, cs%sigma, cs%diag)
868 if (cs%id_Ws > 0)
call post_data(cs%id_Ws, cs%Ws, cs%diag)
869 if (cs%id_Vt2 > 0)
call post_data(cs%id_Vt2, cs%Vt2, cs%diag)
870 if (cs%id_uStar > 0)
call post_data(cs%id_uStar, ustar, cs%diag)
871 if (cs%id_buoyFlux > 0)
call post_data(cs%id_buoyFlux, buoyflux, cs%diag)
872 if (cs%id_Kt_KPP > 0)
call post_data(cs%id_Kt_KPP, cs%Kt_KPP, cs%diag)
873 if (cs%id_Ks_KPP > 0)
call post_data(cs%id_Ks_KPP, cs%Ks_KPP, cs%diag)
874 if (cs%id_Kv_KPP > 0)
call post_data(cs%id_Kv_KPP, cs%Kv_KPP, cs%diag)
875 if (cs%id_NLTt > 0)
call post_data(cs%id_NLTt, nonlocaltransheat, cs%diag)
876 if (cs%id_NLTs > 0)
call post_data(cs%id_NLTs, nonlocaltransscalar,cs%diag)
879 end subroutine kpp_calculate
883 subroutine kpp_compute_bld(CS, G, GV, US, h, Temp, Salt, u, v, EOS, uStar, buoyFlux, Waves)
886 type(
kpp_cs),
pointer :: cs
890 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
891 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: temp
892 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: salt
893 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
894 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
896 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: ustar
897 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: buoyflux
901 integer :: i, j, k, km1
902 real,
dimension( G%ke ) :: cellheight
903 real,
dimension( G%ke+1 ) :: ifaceheight
904 real,
dimension( G%ke+1 ) :: n2_1d
905 real,
dimension( G%ke ) :: ws_1d
906 real,
dimension( G%ke ) :: deltarho
907 real,
dimension( G%ke ) :: deltau2
908 real,
dimension( G%ke ) :: surfbuoyflux2
909 real,
dimension( G%ke ) :: bulkri_1d
912 real,
dimension( 3*G%ke ) :: rho_1d
913 real,
dimension( 3*G%ke ) :: pres_1d
914 real,
dimension( 3*G%ke ) :: temp_1d
915 real,
dimension( 3*G%ke ) :: salt_1d
917 real :: surffricvel, surfbuoyflux, coriolis
919 real :: pref, rho1, rhok, uk, vk, sigma, sigmaratio
921 real :: zbottomminusoffset
926 real :: surfhtemp, surftemp
927 real :: surfhsalt, surfsalt
928 real :: surfhu, surfu
929 real :: surfhv, surfv
932 integer :: kk, ksfc, ktmp
936 real,
dimension(G%ke) :: langenhvt2
937 real,
dimension(G%ke) :: u_h, v_h
938 real :: mld_guess, la
939 real :: surfhus, surfhvs, surfus, surfvs, wavedir, currentdir
940 real :: varup, vardn, m, varlo, varavg
941 real :: h10pct, h20pct,cmnfact, usx20pct, usy20pct, enhvt2
946 #ifdef __DO_SAFETY_CHECKS__
948 call hchksum(salt,
"KPP in: S",g%HI,haloshift=0)
949 call hchksum(temp,
"KPP in: T",g%HI,haloshift=0)
950 call hchksum(u,
"KPP in: u",g%HI,haloshift=0)
951 call hchksum(v,
"KPP in: v",g%HI,haloshift=0)
956 gorho = gv%mks_g_Earth / gv%Rho0
957 buoy_scale = us%L_to_m**2*us%s_to_T**3
965 if (g%mask2dT(i,j)==0.) cycle
968 u_h(k) = 0.5 * (u(i,j,k)+u(i-1,j,k))
969 v_h(k) = 0.5 * (v(i,j,k)+v(i,j-1,k))
973 coriolis = 0.25*us%s_to_T*( (g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j-1)) + &
974 (g%CoriolisBu(i-1,j) + g%CoriolisBu(i,j-1)) )
975 surffricvel = us%Z_to_m*us%s_to_T * ustar(i,j)
989 dh = h(i,j,k) * gv%H_to_m
991 hcorr = min( dh - cs%min_thickness, 0. )
992 dh = max( dh, cs%min_thickness )
993 cellheight(k) = ifaceheight(k) - 0.5 * dh
994 ifaceheight(k+1) = ifaceheight(k) - dh
997 sldepth_0d = cs%surf_layer_ext*max( max(-cellheight(k),-ifaceheight(2) ), cs%minOBLdepth )
1000 if (-1.0*ifaceheight(ktmp+1) >= sldepth_0d)
then
1018 delh = min( max(0.0, sldepth_0d - htot), h(i,j,ktmp)*gv%H_to_m )
1024 surfhtemp = surfhtemp + temp(i,j,ktmp) * delh
1025 surfhsalt = surfhsalt + salt(i,j,ktmp) * delh
1026 surfhu = surfhu + 0.5*(u(i,j,ktmp)+u(i-1,j,ktmp)) * delh
1027 surfhv = surfhv + 0.5*(v(i,j,ktmp)+v(i,j-1,ktmp)) * delh
1028 if (cs%Stokes_Mixing)
then
1029 surfhus = surfhus + 0.5*(waves%US_x(i,j,ktmp)+waves%US_x(i-1,j,ktmp)) * delh
1030 surfhvs = surfhvs + 0.5*(waves%US_y(i,j,ktmp)+waves%US_y(i,j-1,ktmp)) * delh
1034 surftemp = surfhtemp / htot
1035 surfsalt = surfhsalt / htot
1036 surfu = surfhu / htot
1037 surfv = surfhv / htot
1038 surfus = surfhus / htot
1039 surfvs = surfhvs / htot
1044 uk = 0.5*(u(i,j,k)+u(i-1,j,k)) - surfu
1045 vk = 0.5*(v(i,j,k)+v(i,j-1,k)) - surfv
1047 if (cs%Stokes_Mixing)
then
1051 uk = uk + (0.5*(waves%Us_x(i,j,k)+waves%US_x(i-1,j,k)) -surfus )
1052 vk = vk + (0.5*(waves%Us_y(i,j,k)+waves%Us_y(i,j-1,k)) -surfvs )
1055 deltau2(k) = uk**2 + vk**2
1063 pres_1d(kk+1) = pref
1064 pres_1d(kk+2) = pref
1065 pres_1d(kk+3) = pref
1066 temp_1d(kk+1) = surftemp
1067 temp_1d(kk+2) = temp(i,j,k)
1068 temp_1d(kk+3) = temp(i,j,km1)
1069 salt_1d(kk+1) = surfsalt
1070 salt_1d(kk+2) = salt(i,j,k)
1071 salt_1d(kk+3) = salt(i,j,km1)
1075 pref = pref + gv%H_to_Pa * h(i,j,k)
1078 surfbuoyflux2(k) = buoy_scale * (buoyflux(i,j,1) - buoyflux(i,j,k+1))
1082 if (cs%LT_K_ENHANCEMENT .or. cs%LT_VT2_ENHANCEMENT)
then
1083 mld_guess = max( 1.*us%m_to_Z, abs(us%m_to_Z*cs%OBLdepthprev(i,j) ) )
1084 call get_langmuir_number(la, g, gv, us, mld_guess, ustar(i,j), i, j, &
1085 h=h(i,j,:), u_h=u_h, v_h=v_h, waves=waves)
1099 deltarho(k) = rho_1d(kk+2) - rho_1d(kk+1)
1100 n2_1d(k) = (gorho * (rho_1d(kk+2) - rho_1d(kk+3)) ) / &
1101 ((0.5*(h(i,j,km1) + h(i,j,k))+gv%H_subroundoff)*gv%H_to_m)
1102 cs%N(i,j,k) = sqrt( max( n2_1d(k), 0.) )
1104 n2_1d(g%ke+1 ) = 0.0
1105 cs%N(i,j,g%ke+1 ) = 0.0
1111 call cvmix_kpp_compute_turbulent_scales( &
1112 cs%surf_layer_ext, &
1117 cvmix_kpp_params_user=cs%KPP_params )
1120 cs%Vt2(i,j,:) = cvmix_kpp_compute_unresolved_shear( &
1121 zt_cntr=cellheight(1:g%ke), &
1123 n_iface=cs%N(i,j,:), &
1124 cvmix_kpp_params_user=cs%KPP_params )
1127 IF (cs%LT_VT2_ENHANCEMENT)
then
1128 IF (cs%LT_VT2_METHOD==lt_vt2_mode_constant)
then
1130 langenhvt2(k) = cs%KPP_VT2_ENH_FAC
1132 elseif (cs%LT_VT2_METHOD==lt_vt2_mode_vr12)
then
1134 enhvt2 = sqrt(1.+(1.5*cs%La_SL(i,j))**(-2) + &
1135 (5.4*cs%La_SL(i,j))**(-4))
1137 langenhvt2(k) = enhvt2
1139 elseif (cs%LT_VT2_METHOD==lt_vt2_mode_rw16)
then
1141 enhvt2 = 1. + 2.3*cs%La_SL(i,j)**(-0.5)
1143 langenhvt2(k) = enhvt2
1145 elseif (cs%LT_VT2_METHOD==lt_vt2_mode_lf17)
then
1146 cs%CS=cvmix_get_kpp_real(
'c_s',cs%KPP_params)
1148 wst = (max(0.,-buoy_scale*buoyflux(i,j,1))*(-cellheight(k)))**(1./3.)
1149 langenhvt2(k) = sqrt((0.15*wst**3. + 0.17*surffricvel**3.* &
1150 (1.+0.49*cs%La_SL(i,j)**(-2.))) / &
1151 (0.2*ws_1d(k)**3/(cs%cs*cs%surf_layer_ext*cs%vonKarman**4.)))
1163 cs%Vt2(i,j,k)=cs%Vt2(i,j,k)*langenhvt2(k)
1164 if (cs%id_EnhVt2 > 0) cs%EnhVt2(i,j,k)=langenhvt2(k)
1168 bulkri_1d = cvmix_kpp_compute_bulk_richardson( &
1169 zt_cntr = cellheight(1:g%ke), &
1170 delta_buoy_cntr=gorho*deltarho, &
1171 delta_vsqr_cntr=deltau2, &
1172 vt_sqr_cntr=cs%Vt2(i,j,:), &
1174 n_iface=cs%N(i,j,:))
1177 surfbuoyflux = buoy_scale * buoyflux(i,j,1)
1180 call cvmix_kpp_compute_obl_depth( &
1185 zt_cntr=cellheight, &
1186 surf_fric=surffricvel, &
1187 surf_buoy=surfbuoyflux, &
1188 coriolis=coriolis, &
1189 cvmix_kpp_params_user=cs%KPP_params )
1193 if (cs%deepOBLoffset>0.)
then
1194 zbottomminusoffset = ifaceheight(g%ke+1) + min(cs%deepOBLoffset,-0.1*ifaceheight(g%ke+1))
1195 cs%OBLdepth(i,j) = min( cs%OBLdepth(i,j), -zbottomminusoffset )
1199 if(cs%fixedOBLdepth) cs%OBLdepth(i,j) = cs%fixedOBLdepth_value
1200 cs%OBLdepth(i,j) = max( cs%OBLdepth(i,j), -ifaceheight(2) )
1201 cs%OBLdepth(i,j) = min( cs%OBLdepth(i,j), -ifaceheight(g%ke+1) )
1202 cs%kOBL(i,j) = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, cs%OBLdepth(i,j) )
1287 if (cs%id_Ws > 0)
then
1288 call cvmix_kpp_compute_turbulent_scales( &
1289 -cellheight/cs%OBLdepth(i,j), &
1294 cvmix_kpp_params_user=cs%KPP_params)
1295 cs%Ws(i,j,:) = ws_1d(:)
1299 if (cs%id_N2 > 0) cs%N2(i,j,:) = n2_1d(:)
1300 if (cs%id_BulkDrho > 0) cs%dRho(i,j,:) = deltarho(:)
1301 if (cs%id_BulkRi > 0) cs%BulkRi(i,j,:) = bulkri_1d(:)
1302 if (cs%id_BulkUz2 > 0) cs%Uz2(i,j,:) = deltau2(:)
1303 if (cs%id_Tsurf > 0) cs%Tsurf(i,j) = surftemp
1304 if (cs%id_Ssurf > 0) cs%Ssurf(i,j) = surfsalt
1305 if (cs%id_Usurf > 0) cs%Usurf(i,j) = surfu
1306 if (cs%id_Vsurf > 0) cs%Vsurf(i,j) = surfv
1312 if (cs%id_BulkRi > 0)
call post_data(cs%id_BulkRi, cs%BulkRi, cs%diag)
1313 if (cs%id_N > 0)
call post_data(cs%id_N, cs%N, cs%diag)
1314 if (cs%id_N2 > 0)
call post_data(cs%id_N2, cs%N2, cs%diag)
1315 if (cs%id_Tsurf > 0)
call post_data(cs%id_Tsurf, cs%Tsurf, cs%diag)
1316 if (cs%id_Ssurf > 0)
call post_data(cs%id_Ssurf, cs%Ssurf, cs%diag)
1317 if (cs%id_Usurf > 0)
call post_data(cs%id_Usurf, cs%Usurf, cs%diag)
1318 if (cs%id_Vsurf > 0)
call post_data(cs%id_Vsurf, cs%Vsurf, cs%diag)
1319 if (cs%id_BulkDrho > 0)
call post_data(cs%id_BulkDrho, cs%dRho, cs%diag)
1320 if (cs%id_BulkUz2 > 0)
call post_data(cs%id_BulkUz2, cs%Uz2, cs%diag)
1321 if (cs%id_EnhK > 0)
call post_data(cs%id_EnhK, cs%EnhK, cs%diag)
1322 if (cs%id_EnhVt2 > 0)
call post_data(cs%id_EnhVt2, cs%EnhVt2, cs%diag)
1323 if (cs%id_La_SL > 0)
call post_data(cs%id_La_SL, cs%La_SL, cs%diag)
1326 if (cs%n_smooth > 0)
call kpp_smooth_bld(cs,g,gv,h)
1328 end subroutine kpp_compute_bld
1332 subroutine kpp_smooth_bld(CS,G,GV,h)
1334 type(
kpp_cs),
pointer :: CS
1337 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1340 real,
dimension(SZI_(G),SZJ_(G)) :: OBLdepth_original
1341 real,
dimension( G%ke ) :: cellHeight
1343 real,
dimension( G%ke+1 ) :: iFaceHeight
1345 real :: wc, ww, we, wn, ws
1349 integer :: i, j, k, s
1354 call pass_var(cs%OBLdepth, g%Domain)
1356 obldepth_original = cs%OBLdepth
1357 if (cs%id_OBLdepth_original > 0) cs%OBLdepth_original = obldepth_original
1364 if (g%mask2dT(i,j)==0.) cycle
1366 ifaceheight(1) = 0.0
1372 dh = h(i,j,k) * gv%H_to_m
1374 hcorr = min( dh - cs%min_thickness, 0. )
1375 dh = max( dh, cs%min_thickness )
1376 cellheight(k) = ifaceheight(k) - 0.5 * dh
1377 ifaceheight(k+1) = ifaceheight(k) - dh
1381 ww = 0.125 * g%mask2dT(i-1,j)
1382 we = 0.125 * g%mask2dT(i+1,j)
1383 ws = 0.125 * g%mask2dT(i,j-1)
1384 wn = 0.125 * g%mask2dT(i,j+1)
1385 wc = 1.0 - (ww+we+wn+ws)
1387 cs%OBLdepth(i,j) = wc * obldepth_original(i,j) &
1388 + ww * obldepth_original(i-1,j) &
1389 + we * obldepth_original(i+1,j) &
1390 + ws * obldepth_original(i,j-1) &
1391 + wn * obldepth_original(i,j+1)
1394 if (cs%deepen_only) cs%OBLdepth(i,j) = max(cs%OBLdepth(i,j),cs%OBLdepth_original(i,j))
1397 cs%OBLdepth(i,j) = min( cs%OBLdepth(i,j), -ifaceheight(g%ke+1) )
1398 cs%kOBL(i,j) = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, cs%OBLdepth(i,j) )
1409 if (g%mask2dT(i,j)==0.) cycle
1411 ifaceheight(1) = 0.0
1416 dh = h(i,j,k) * gv%H_to_m
1418 hcorr = min( dh - cs%min_thickness, 0. )
1419 dh = max( dh, cs%min_thickness )
1420 cellheight(k) = ifaceheight(k) - 0.5 * dh
1421 ifaceheight(k+1) = ifaceheight(k) - dh
1424 cs%kOBL(i,j) = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, cs%OBLdepth(i,j) )
1429 end subroutine kpp_smooth_bld
1434 subroutine kpp_get_bld(CS, BLD, G)
1438 real,
dimension(SZI_(G),SZJ_(G)),
intent(inout) :: bld
1441 do j = g%jsc, g%jec ;
do i = g%isc, g%iec
1442 bld(i,j) = cs%OBLdepth(i,j)
1444 end subroutine kpp_get_bld
1447 subroutine kpp_nonlocaltransport_temp(CS, G, GV, h, nonLocalTrans, surfFlux, &
1450 type(
kpp_cs),
intent(in) :: cs
1453 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1454 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: nonlocaltrans
1455 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: surfflux
1457 real,
intent(in) :: dt
1458 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: scalar
1459 real,
intent(in) :: c_p
1462 real,
dimension( SZI_(G), SZJ_(G), SZK_(G) ) :: dtracer
1465 dtracer(:,:,:) = 0.0
1470 dtracer(i,j,k) = ( nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1) ) / &
1471 ( h(i,j,k) + gv%H_subroundoff ) * surfflux(i,j)
1477 if (cs%applyNonLocalTrans)
then
1481 scalar(i,j,k) = scalar(i,j,k) + dt * dtracer(i,j,k)
1488 if (cs%id_QminusSW > 0)
call post_data(cs%id_QminusSW, surfflux, cs%diag)
1489 if (cs%id_NLT_dTdt > 0)
call post_data(cs%id_NLT_dTdt, dtracer, cs%diag)
1490 if (cs%id_NLT_temp_budget > 0)
then
1491 dtracer(:,:,:) = 0.0
1495 dtracer(i,j,k) = (nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1)) * &
1496 surfflux(i,j) * c_p * gv%H_to_kg_m2
1500 call post_data(cs%id_NLT_temp_budget, dtracer, cs%diag)
1503 end subroutine kpp_nonlocaltransport_temp
1508 subroutine kpp_nonlocaltransport_saln(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar)
1510 type(
kpp_cs),
intent(in) :: cs
1513 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1514 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: nonlocaltrans
1515 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: surfflux
1517 real,
intent(in) :: dt
1518 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: scalar
1521 real,
dimension( SZI_(G), SZJ_(G), SZK_(G) ) :: dtracer
1524 dtracer(:,:,:) = 0.0
1529 dtracer(i,j,k) = ( nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1) ) / &
1530 ( h(i,j,k) + gv%H_subroundoff ) * surfflux(i,j)
1536 if (cs%applyNonLocalTrans)
then
1540 scalar(i,j,k) = scalar(i,j,k) + dt * dtracer(i,j,k)
1547 if (cs%id_netS > 0)
call post_data(cs%id_netS, surfflux, cs%diag)
1548 if (cs%id_NLT_dSdt > 0)
call post_data(cs%id_NLT_dSdt, dtracer, cs%diag)
1549 if (cs%id_NLT_saln_budget > 0)
then
1550 dtracer(:,:,:) = 0.0
1554 dtracer(i,j,k) = (nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1)) * &
1555 surfflux(i,j) * gv%H_to_kg_m2
1559 call post_data(cs%id_NLT_saln_budget, dtracer, cs%diag)
1562 end subroutine kpp_nonlocaltransport_saln
1568 subroutine kpp_end(CS)
1571 if (.not.
associated(cs))
return
1575 end subroutine kpp_end