17 use cvmix_kpp
, only : cvmix_init_kpp, cvmix_put_kpp, cvmix_get_kpp_real
18 use cvmix_kpp
, only : cvmix_coeffs_kpp
19 use cvmix_kpp
, only : cvmix_kpp_compute_obl_depth
20 use cvmix_kpp
, only : cvmix_kpp_compute_turbulent_scales
21 use cvmix_kpp
, only : cvmix_kpp_compute_bulk_richardson
22 use cvmix_kpp
, only : cvmix_kpp_compute_unresolved_shear
23 use cvmix_kpp
, only : cvmix_kpp_params_type
24 use cvmix_kpp
, only : cvmix_kpp_compute_kobl_depth
26 implicit none ;
private 28 #include "MOM_memory.h" 56 logical :: enhance_diffusion
57 character(len=10) :: interptype
58 logical :: computeekman
59 logical :: computemoninobukhov
60 logical :: passivemode
63 real :: surf_layer_ext
65 logical :: fixedobldepth
66 real :: fixedobldepth_value
68 character(len=30) :: matchtechnique
70 logical :: applynonlocaltrans
71 logical :: kppzerodiffusivity
72 logical :: kppisadditive
76 logical :: correctsurflayeravg
77 real :: surflayerdepth
82 type(cvmix_kpp_params_type),
pointer :: kpp_params => null()
86 integer :: id_obldepth = -1, id_bulkri = -1
87 integer :: id_n = -1, id_n2 = -1
88 integer :: id_ws = -1, id_vt2 = -1
89 integer :: id_bulkuz2 = -1, id_bulkdrho = -1
90 integer :: id_ustar = -1, id_buoyflux = -1
91 integer :: id_qminussw = -1, id_nets = -1
92 integer :: id_sigma = -1, id_kv_kpp = -1
93 integer :: id_kt_kpp = -1, id_ks_kpp = -1
94 integer :: id_tsurf = -1, id_ssurf = -1
95 integer :: id_usurf = -1, id_vsurf = -1
96 integer :: id_kd_in = -1
97 integer :: id_nltt = -1
98 integer :: id_nlts = -1
99 integer :: id_nlt_dsdt = -1
100 integer :: id_nlt_dtdt = -1
101 integer :: id_nlt_temp_budget = -1
102 integer :: id_nlt_saln_budget = -1
105 real,
allocatable,
dimension(:,:) :: obldepth
106 real,
allocatable,
dimension(:,:,:) :: drho
107 real,
allocatable,
dimension(:,:,:) :: uz2
108 real,
allocatable,
dimension(:,:,:) :: bulkri
109 real,
allocatable,
dimension(:,:,:) :: sigma
110 real,
allocatable,
dimension(:,:,:) :: ws
111 real,
allocatable,
dimension(:,:,:) :: n
112 real,
allocatable,
dimension(:,:,:) :: n2
113 real,
allocatable,
dimension(:,:,:) :: vt2
114 real,
allocatable,
dimension(:,:,:) :: kt_kpp
115 real,
allocatable,
dimension(:,:,:) :: ks_kpp
116 real,
allocatable,
dimension(:,:,:) :: kv_kpp
117 real,
allocatable,
dimension(:,:) :: tsurf
118 real,
allocatable,
dimension(:,:) :: ssurf
119 real,
allocatable,
dimension(:,:) :: usurf
120 real,
allocatable,
dimension(:,:) :: vsurf
126 #define __DO_SAFETY_CHECKS__ 132 logical function kpp_init(paramFile, G, diag, Time, CS, passive)
137 type(
diag_ctrl),
target,
intent(in) :: diag
138 type(time_type),
intent(in) :: Time
139 type(
kpp_cs),
pointer :: CS
140 logical,
optional,
intent(out) :: passive
143 #include "version_variable.h" 144 character(len=40) :: mdl =
'MOM_KPP' 145 character(len=20) :: string
146 logical :: CS_IS_ONE=.false.
148 if (
associated(cs))
call mom_error(fatal,
'MOM_KPP, KPP_init: '// &
149 'Control structure has already been initialized')
153 call log_version(paramfile, mdl, version,
'This is the MOM wrapper to CVmix:KPP\n' // &
154 'See http://code.google.com/p/cvmix/')
156 "If true, turns on the [CVmix] KPP scheme of Large et al., 1994,\n"// &
157 "to calculate diffusivities and non-local transport in the OBL.", &
163 call get_param(paramfile, mdl,
'PASSIVE', cs%passiveMode, &
164 'If True, puts KPP into a passive-diagnostic mode.', &
166 if (
present(passive)) passive=cs%passiveMode
168 call get_param(paramfile, mdl,
'APPLY_NONLOCAL_TRANSPORT', cs%applyNonLocalTrans, &
169 'If True, applies the non-local transport to heat and scalars.\n'// &
170 'If False, calculates the non-local transport and tendencies but\n'//&
171 'purely for diagnostic purposes.', &
172 default=.not. cs%passiveMode)
173 call get_param(paramfile, mdl,
'RI_CRIT', cs%Ri_crit, &
174 'Critical bulk Richardson number used to define depth of the\n'// &
175 'surface Ocean Boundary Layer (OBL).', &
176 units=
'nondim', default=0.3)
177 call get_param(paramfile, mdl,
'VON_KARMAN', cs%vonKarman, &
178 'von Karman constant.', &
179 units=
'nondim', default=0.40)
180 call get_param(paramfile, mdl,
'ENHANCE_DIFFUSION', cs%enhance_diffusion, &
181 'If True, adds enhanced diffusion at the based of the boundary layer.', &
183 call get_param(paramfile, mdl,
'INTERP_TYPE', cs%interpType, &
184 'Type of interpolation to determine the OBL depth.\n'// &
185 'Allowed types are: linear, quadratic, cubic.', &
187 call get_param(paramfile, mdl,
'COMPUTE_EKMAN', cs%computeEkman, &
188 'If True, limit OBL depth to be no deeper than Ekman depth.', &
190 call get_param(paramfile, mdl,
'COMPUTE_MONIN_OBUKHOV', cs%computeMoninObukhov, &
191 'If True, limit the OBL depth to be no deeper than\n'// &
192 'Monin-Obukhov depth.', &
194 call get_param(paramfile, mdl,
'CS', cs%cs, &
195 'Parameter for computing velocity scale function.', &
196 units=
'nondim', default=98.96)
197 call get_param(paramfile, mdl,
'CS2', cs%cs2, &
198 'Parameter for computing non-local term.', &
199 units=
'nondim', default=6.32739901508)
200 call get_param(paramfile, mdl,
'DEEP_OBL_OFFSET', cs%deepOBLoffset, &
201 'If non-zero, the distance above the bottom to which the OBL is clipped\n'// &
202 'if it would otherwise reach the bottom. The smaller of this and 0.1D is used.', &
203 units=
'm',default=0.)
204 call get_param(paramfile, mdl,
'FIXED_OBLDEPTH', cs%fixedOBLdepth, &
205 'If True, fix the OBL depth to FIXED_OBLDEPTH_VALUE\n'// &
206 'rather than using the OBL depth from CVMix.\n'// &
207 'This option is just for testing purposes.', &
209 call get_param(paramfile, mdl,
'FIXED_OBLDEPTH_VALUE', cs%fixedOBLdepth_value, &
210 'Value for the fixed OBL depth when fixedOBLdepth==True. \n'// &
211 'This parameter is for just for testing purposes. \n'// &
212 'It will over-ride the OBLdepth computed from CVMix.', &
213 units=
'm',default=30.0)
214 call get_param(paramfile, mdl,
'SURF_LAYER_EXTENT', cs%surf_layer_ext, &
215 'Fraction of OBL depth considered in the surface layer.', &
216 units=
'nondim',default=0.10)
217 call get_param(paramfile, mdl,
'MINIMUM_OBL_DEPTH', cs%minOBLdepth, &
218 'If non-zero, a minimum depth to use for KPP OBL depth. Independent of\n'// &
219 'this parameter, the OBL depth is always at least as deep as the first layer.', &
220 units=
'm',default=0.)
221 call get_param(paramfile, mdl,
'MINIMUM_VT2', cs%minVtsqr, &
222 'Min of the unresolved velocity Vt2 used in Rib CVMix calculation. \n'// &
223 'Scaling: MINIMUM_VT2 = const1*d*N*ws, with d=1m, N=1e-5/s, ws=1e-6 m/s.', &
224 units=
'm2/s2',default=1e-10)
227 call get_param(paramfile, mdl,
'CORRECT_SURFACE_LAYER_AVERAGE', cs%correctSurfLayerAvg, &
228 'If true, applies a correction step to the averaging of surface layer\n'// &
229 'properties. This option is obsolete.', default=.false.)
230 call get_param(paramfile, mdl,
'FIRST_GUESS_SURFACE_LAYER_DEPTH', cs%surfLayerDepth, &
231 'The first guess at the depth of the surface layer used for averaging\n'// &
232 'the surface layer properties. If =0, the top model level properties\n'// &
233 'will be used for the surface layer. If CORRECT_SURFACE_LAYER_AVERAGE=True, a\n'// &
234 'subsequent correction is applied. This parameter is obsolete', units=
'm', default=0.)
237 call get_param(paramfile, mdl,
'NLT_SHAPE', string, &
238 'MOM6 method to set nonlocal transport profile.\n'// &
239 'Over-rides the result from CVMix. Allowed values are: \n'// &
240 '\t CVMIX - Uses the profiles from CVmix specified by MATCH_TECHNIQUE\n'//&
241 '\t LINEAR - A linear profile, 1-sigma\n'// &
242 '\t PARABOLIC - A parablic profile, (1-sigma)^2\n'// &
243 '\t CUBIC - A cubic profile, (1-sigma)^2(1+2*sigma)\n'// &
244 '\t CUBIC_LMD - The original KPP profile', &
246 select case ( trim(string) )
252 case default ;
call mom_error(fatal,
"KPP_init: "// &
253 "Unrecognized NLT_SHAPE option"//trim(string))
255 call get_param(paramfile, mdl,
'MATCH_TECHNIQUE', cs%MatchTechnique, &
256 'CVMix method to set profile function for diffusivity and NLT,\n'// &
257 'as well as matching across OBL base. Allowed values are: \n'// &
258 '\t SimpleShapes = sigma*(1-sigma)^2 for both diffusivity and NLT\n'// &
259 '\t MatchGradient = sigma*(1-sigma)^2 for NLT; diffusivity profile from matching\n'//&
260 '\t MatchBoth = match gradient for both diffusivity and NLT\n'// &
261 '\t ParabolicNonLocal = sigma*(1-sigma)^2 for diffusivity; (1-sigma)^2 for NLT', &
262 default=
'SimpleShapes')
263 if (cs%MatchTechnique.eq.
'ParabolicNonLocal')
then 268 call get_param(paramfile, mdl,
'KPP_ZERO_DIFFUSIVITY', cs%KPPzeroDiffusivity, &
269 'If True, zeroes the KPP diffusivity and viscosity; for testing purpose.',&
271 call get_param(paramfile, mdl,
'KPP_IS_ADDITIVE', cs%KPPisAdditive, &
272 'If true, adds KPP diffusivity to diffusivity from other schemes.'//&
273 'If false, KPP is the only diffusivity wherever KPP is non-zero.', &
275 call get_param(paramfile, mdl,
'KPP_SHORTWAVE_METHOD',string, &
276 'Determines contribution of shortwave radiation to KPP surface '// &
277 'buoyancy flux. Options include:\n'// &
278 ' ALL_SW: use total shortwave radiation\n'// &
279 ' MXL_SW: use shortwave radiation absorbed by mixing layer\n'// &
280 ' LV1_SW: use shortwave radiation absorbed by top model layer', &
282 select case ( trim(string) )
286 case default ;
call mom_error(fatal,
"KPP_init: "// &
287 "Unrecognized KPP_SHORTWAVE_METHOD option"//trim(string))
289 call get_param(paramfile, mdl,
'CVMIX_ZERO_H_WORK_AROUND', cs%min_thickness, &
290 'A minimum thickness used to avoid division by small numbers in the vicinity\n'// &
291 'of vanished layers. This is independent of MIN_THICKNESS used in other parts of MOM.', &
292 units=
'm', default=0.)
295 call get_param(paramfile, mdl,
'DEBUG', cs%debug, default=.false., do_not_log=.true.)
297 call cvmix_init_kpp( ri_crit=cs%Ri_crit, &
298 minobldepth=cs%minOBLdepth, &
299 minvtsqr=cs%minVtsqr, &
300 vonkarman=cs%vonKarman, &
301 surf_layer_ext=cs%surf_layer_ext, &
302 interp_type=cs%interpType, &
303 lekman=cs%computeEkman, &
304 lmonob=cs%computeMoninObukhov, &
305 matchtechnique=cs%MatchTechnique, &
306 lenhanced_diff=cs%enhance_diffusion,&
307 lnonzero_surf_nonlocal=cs_is_one ,&
308 cvmix_kpp_params_user=cs%KPP_params )
313 'Thickness of the surface Ocean Boundary Layer calculated by [CVmix] KPP',
'meter', &
314 cmor_field_name=
'oml', cmor_long_name=
'ocean_mixed_layer_thickness_defined_by_mixing_scheme', &
315 cmor_units=
'm', cmor_standard_name=
'Ocean Mixed Layer Thickness Defined by Mixing Scheme')
320 'Bulk difference in density used in Bulk Richardson number, as used by [CVmix] KPP',
'kg/m3')
322 'Square of bulk difference in resolved velocity used in Bulk Richardson number via [CVmix] KPP',
'm2/s2')
324 'Bulk Richardson number used to find the OBL depth used by [CVmix] KPP',
'nondim')
326 'Sigma coordinate used by [CVmix] KPP',
'nondim')
328 'Turbulent vertical velocity scale for scalars used by [CVmix] KPP',
'm/s')
330 '(Adjusted) Brunt-Vaisala frequency used by [CVmix] KPP',
'1/s')
332 'Square of Brunt-Vaisala frequency used by [CVmix] KPP',
'1/s2')
334 'Unresolved shear turbulence used by [CVmix] KPP',
'm2/s2')
336 'Friction velocity, u*, as used by [CVmix] KPP',
'm/s')
338 'Surface (and penetrating) buoyancy flux, as used by [CVmix] KPP',
'm2/s3')
340 'Net temperature flux ignoring short-wave, as used by [CVmix] KPP',
'K m/s')
342 'Effective net surface salt flux, as used by [CVmix] KPP',
'ppt m/s')
344 'Heat diffusivity due to KPP, as calculated by [CVmix] KPP',
'm2/s')
346 'Diffusivity passed to KPP',
'm2/s')
348 'Salt diffusivity due to KPP, as calculated by [CVmix] KPP',
'm2/s')
350 'Vertical viscosity due to KPP, as calculated by [CVmix] KPP',
'm2/s')
351 cs%id_NLTt =
register_diag_field(
'ocean_model',
'KPP_NLtransport_heat', diag%axesTi, time, &
352 'Non-local transport (Cs*G(sigma)) for heat, as calculated by [CVmix] KPP',
'nondim')
353 cs%id_NLTs =
register_diag_field(
'ocean_model',
'KPP_NLtransport_salt', diag%axesTi, time, &
354 'Non-local tranpsort (Cs*G(sigma)) for scalars, as calculated by [CVmix] KPP',
'nondim')
356 'Temperature tendency due to non-local transport of heat, as calculated by [CVmix] KPP',
'K/s')
358 'Salinity tendency due to non-local transport of salt, as calculated by [CVmix] KPP',
'ppt/s')
359 cs%id_NLT_temp_budget =
register_diag_field(
'ocean_model',
'KPP_NLT_temp_budget', diag%axesTL, time, &
360 'Heat content change due to non-local transport, as calculated by [CVmix] KPP',
'W/m^2')
361 cs%id_NLT_saln_budget =
register_diag_field(
'ocean_model',
'KPP_NLT_saln_budget', diag%axesTL, time, &
362 'Salt content change due to non-local transport, as calculated by [CVmix] KPP',
'kg/(sec*m^2)')
364 'Temperature of surface layer (10% of OBL depth) as passed to [CVmix] KPP',
'C')
366 'Salinity of surface layer (10% of OBL depth) as passed to [CVmix] KPP',
'ppt')
368 'i-component flow of surface layer (10% of OBL depth) as passed to [CVmix] KPP',
'm/s')
370 'j-component flow of surface layer (10% of OBL depth) as passed to [CVmix] KPP',
'm/s')
372 if (cs%id_OBLdepth > 0)
allocate( cs%OBLdepth( szi_(g), szj_(g) ) )
373 if (cs%id_OBLdepth > 0) cs%OBLdepth(:,:) = 0.
374 if (cs%id_BulkDrho > 0)
allocate( cs%dRho( szi_(g), szj_(g), szk_(g) ) )
375 if (cs%id_BulkDrho > 0) cs%dRho(:,:,:) = 0.
376 if (cs%id_BulkUz2 > 0)
allocate( cs%Uz2( szi_(g), szj_(g), szk_(g) ) )
377 if (cs%id_BulkUz2 > 0) cs%Uz2(:,:,:) = 0.
378 if (cs%id_BulkRi > 0)
allocate( cs%BulkRi( szi_(g), szj_(g), szk_(g) ) )
379 if (cs%id_BulkRi > 0) cs%BulkRi(:,:,:) = 0.
380 if (cs%id_Sigma > 0)
allocate( cs%sigma( szi_(g), szj_(g), szk_(g)+1 ) )
381 if (cs%id_Sigma > 0) cs%sigma(:,:,:) = 0.
382 if (cs%id_Ws > 0)
allocate( cs%Ws( szi_(g), szj_(g), szk_(g) ) )
383 if (cs%id_Ws > 0) cs%Ws(:,:,:) = 0.
384 if (cs%id_N > 0)
allocate( cs%N( szi_(g), szj_(g), szk_(g)+1 ) )
385 if (cs%id_N > 0) cs%N(:,:,:) = 0.
386 if (cs%id_N2 > 0)
allocate( cs%N2( szi_(g), szj_(g), szk_(g)+1 ) )
387 if (cs%id_N2 > 0) cs%N2(:,:,:) = 0.
388 if (cs%id_Vt2 > 0)
allocate( cs%Vt2( szi_(g), szj_(g), szk_(g) ) )
389 if (cs%id_Vt2 > 0) cs%Vt2(:,:,:) = 0.
390 if (cs%id_Kt_KPP > 0)
allocate( cs%Kt_KPP( szi_(g), szj_(g), szk_(g)+1 ) )
391 if (cs%id_Kt_KPP > 0) cs%Kt_KPP(:,:,:) = 0.
392 if (cs%id_Ks_KPP > 0)
allocate( cs%Ks_KPP( szi_(g), szj_(g), szk_(g)+1 ) )
393 if (cs%id_Ks_KPP > 0) cs%Ks_KPP(:,:,:) = 0.
394 if (cs%id_Kv_KPP > 0)
allocate( cs%Kv_KPP( szi_(g), szj_(g), szk_(g)+1 ) )
395 if (cs%id_Kv_KPP > 0) cs%Kv_KPP(:,:,:) = 0.
396 if (cs%id_Tsurf > 0)
allocate( cs%Tsurf( szi_(g), szj_(g)) )
397 if (cs%id_Tsurf > 0) cs%Tsurf(:,:) = 0.
398 if (cs%id_Ssurf > 0)
allocate( cs%Ssurf( szi_(g), szj_(g)) )
399 if (cs%id_Ssurf > 0) cs%Ssurf(:,:) = 0.
400 if (cs%id_Usurf > 0)
allocate( cs%Usurf( szib_(g), szj_(g)) )
401 if (cs%id_Usurf > 0) cs%Usurf(:,:) = 0.
402 if (cs%id_Vsurf > 0)
allocate( cs%Vsurf( szi_(g), szjb_(g)) )
403 if (cs%id_Vsurf > 0) cs%Vsurf(:,:) = 0.
410 subroutine kpp_calculate(CS, G, GV, h, Temp, Salt, u, v, EOS, uStar, &
411 buoyFlux, Kt, Ks, Kv, nonLocalTransHeat,&
415 type(
kpp_cs),
pointer :: CS
418 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
419 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: Temp
420 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: Salt
421 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(in) :: u
422 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(in) :: v
424 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: uStar
425 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: buoyFlux
426 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: Kt
428 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: Ks
430 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: Kv
432 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: nonLocalTransHeat
433 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(inout) :: nonLocalTransScalar
436 integer :: i, j, k, km1,kp1
437 real,
dimension( G%ke ) :: cellHeight
438 real,
dimension( G%ke+1 ) :: iFaceHeight
439 real,
dimension( G%ke+1 ) :: N2_1d
440 real,
dimension( G%ke+1 ) :: N_1d
441 real,
dimension( G%ke ) :: Ws_1d
442 real,
dimension( G%ke ) :: Wm_1d
443 real,
dimension( G%ke ) :: Vt2_1d
444 real,
dimension( G%ke ) :: BulkRi_1d
445 real,
dimension( G%ke ) :: deltaRho
446 real,
dimension( G%ke ) :: deltaU2
447 real,
dimension( G%ke+1, 2) :: Kdiffusivity
448 real,
dimension( G%ke+1 ) :: Kviscosity
449 real,
dimension( G%ke+1, 2) :: nonLocalTrans
450 real,
dimension( G%ke ) :: surfBuoyFlux2
453 real,
dimension( 3*G%ke ) :: rho_1D
454 real,
dimension( 3*G%ke ) :: pres_1D
455 real,
dimension( 3*G%ke ) :: Temp_1D
456 real,
dimension( 3*G%ke ) :: Salt_1D
458 real :: kOBL, OBLdepth_0d, surfFricVel, surfBuoyFlux, Coriolis
459 real :: GoRho, pRef, rho1, rhoK, rhoKm1, Uk, Vk, sigma
461 real :: zBottomMinusOffset
465 real :: surfHtemp, surfTemp
466 real :: surfHsalt, surfSalt
467 real :: surfHu, surfU
468 real :: surfHv, surfV
471 integer :: kk, ksfc, ktmp
473 #ifdef __DO_SAFETY_CHECKS__ 475 call hchksum(h,
"KPP in: h",g%HI,haloshift=0, scale=gv%H_to_m)
476 call hchksum(temp,
"KPP in: T",g%HI,haloshift=0)
477 call hchksum(salt,
"KPP in: S",g%HI,haloshift=0)
478 call hchksum(u,
"KPP in: u",g%HI,haloshift=0)
479 call hchksum(v,
"KPP in: v",g%HI,haloshift=0)
480 call hchksum(ustar,
"KPP in: uStar",g%HI,haloshift=0)
481 call hchksum(buoyflux,
"KPP in: buoyFlux",g%HI,haloshift=0)
482 call hchksum(kt,
"KPP in: Kt",g%HI,haloshift=0)
483 call hchksum(ks,
"KPP in: Ks",g%HI,haloshift=0)
488 gorho = gv%g_Earth / gv%Rho0
489 nonlocaltrans(:,:) = 0.0
491 if (cs%id_Kd_in > 0)
call post_data(cs%id_Kd_in, kt, cs%diag)
512 if (g%mask2dT(i,j)==0.) cycle
515 coriolis = 0.25*( (g%CoriolisBu(i,j) + g%CoriolisBu(i-1,j-1)) &
516 +(g%CoriolisBu(i-1,j) + g%CoriolisBu(i,j-1)) )
517 surffricvel = ustar(i,j)
531 dh = h(i,j,k) * gv%H_to_m
533 hcorr = min( dh - cs%min_thickness, 0. )
534 dh = max( dh, cs%min_thickness )
535 cellheight(k) = ifaceheight(k) - 0.5 * dh
536 ifaceheight(k+1) = ifaceheight(k) - dh
539 sldepth_0d = cs%surf_layer_ext*max( max(-cellheight(k),-ifaceheight(2) ), cs%minOBLdepth )
542 if (-1.0*ifaceheight(ktmp+1) >= sldepth_0d)
then 558 delh = min( max(0.0, sldepth_0d - htot), h(i,j,ktmp)*gv%H_to_m )
564 surfhtemp = surfhtemp + temp(i,j,ktmp) * delh
565 surfhsalt = surfhsalt + salt(i,j,ktmp) * delh
566 surfhu = surfhu + 0.5*(u(i,j,ktmp)+u(i-1,j,ktmp)) * delh
567 surfhv = surfhv + 0.5*(v(i,j,ktmp)+v(i,j-1,ktmp)) * delh
570 surftemp = surfhtemp / htot
571 surfsalt = surfhsalt / htot
572 surfu = surfhu / htot
573 surfv = surfhv / htot
578 uk = 0.5*(u(i,j,k)+u(i-1,j,k)) - surfu
579 vk = 0.5*(v(i,j,k)+v(i,j-1,k)) - surfv
580 deltau2(k) = uk**2 + vk**2
591 temp_1d(kk+1) = surftemp
592 temp_1d(kk+2) = temp(i,j,k)
593 temp_1d(kk+3) = temp(i,j,km1)
594 salt_1d(kk+1) = surfsalt
595 salt_1d(kk+2) = salt(i,j,k)
596 salt_1d(kk+3) = salt(i,j,km1)
600 pref = pref + gv%H_to_Pa * h(i,j,k)
603 surfbuoyflux2(k) = buoyflux(i,j,1) - buoyflux(i,j,k+1)
616 deltarho(k) = rho_1d(kk+2) - rho_1d(kk+1)
617 n2_1d(k) = (gorho * (rho_1d(kk+2) - rho_1d(kk+3)) ) / &
618 ((0.5*(h(i,j,km1) + h(i,j,k))+gv%H_subroundoff)*gv%H_to_m)
619 n_1d(k) = sqrt( max( n2_1d(k), 0.) )
628 call cvmix_kpp_compute_turbulent_scales( &
634 cvmix_kpp_params_user=cs%KPP_params )
637 bulkri_1d = cvmix_kpp_compute_bulk_richardson( &
638 cellheight(1:g%ke), &
645 surfbuoyflux = buoyflux(i,j,1)
648 call cvmix_kpp_compute_obl_depth( &
653 zt_cntr=cellheight, &
654 surf_fric=surffricvel, &
655 surf_buoy=surfbuoyflux, &
657 cvmix_kpp_params_user=cs%KPP_params )
661 if (cs%deepOBLoffset>0.)
then 662 zbottomminusoffset = ifaceheight(g%ke+1) + min(cs%deepOBLoffset,-0.1*ifaceheight(g%ke+1))
663 obldepth_0d = min( obldepth_0d, -zbottomminusoffset )
667 if(cs%fixedOBLdepth) obldepth_0d = cs%fixedOBLdepth_value
668 obldepth_0d = max( obldepth_0d, -ifaceheight(2) )
669 obldepth_0d = min( obldepth_0d, -ifaceheight(g%ke+1) )
670 kobl = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, obldepth_0d )
677 if (cs%correctSurfLayerAvg)
then 679 sldepth_0d = cs%surf_layer_ext * obldepth_0d
681 surftemp = temp(i,j,1) ; surfhtemp = surftemp * htot
682 surfsalt = salt(i,j,1) ; surfhsalt = surfsalt * htot
683 surfu = 0.5*(u(i,j,1)+u(i-1,j,1)) ; surfhu = surfu * htot
684 surfv = 0.5*(v(i,j,1)+v(i,j-1,1)) ; surfhv = surfv * htot
690 uk = 0.5*(u(i,j,k)+u(i-1,j,k)) - surfu
691 vk = 0.5*(v(i,j,k)+v(i,j-1,k)) - surfv
692 deltau2(k) = uk**2 + vk**2
693 pref = pref + gv%H_to_Pa * h(i,j,k)
696 deltarho(k) = rhok - rho1
699 if (htot < sldepth_0d)
then 700 delh = min( max(0., sldepth_0d - htot), h(i,j,k)*gv%H_to_m )
702 surfhtemp = surfhtemp + temp(i,j,k) * delh ; surftemp = surfhtemp / htot
703 surfhsalt = surfhsalt + salt(i,j,k) * delh ; surfsalt = surfhsalt / htot
704 surfhu = surfhu + 0.5*(u(i,j,k)+u(i-1,j,k)) * delh ; surfu = surfhu / htot
705 surfhv = surfhv + 0.5*(v(i,j,k)+v(i,j-1,k)) * delh ; surfv = surfhv / htot
710 bulkri_1d = cvmix_kpp_compute_bulk_richardson( &
711 cellheight(1:g%ke), &
717 surfbuoyflux = buoyflux(i,j,1)
720 call cvmix_kpp_compute_obl_depth( &
725 zt_cntr=cellheight, &
726 surf_fric=surffricvel, &
727 surf_buoy=surfbuoyflux, &
729 cvmix_kpp_params_user=cs%KPP_params )
731 if (cs%deepOBLoffset>0.)
then 732 zbottomminusoffset = ifaceheight(g%ke+1) + min(cs%deepOBLoffset,-0.1*ifaceheight(g%ke+1))
733 obldepth_0d = min( obldepth_0d, -zbottomminusoffset )
734 kobl = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, obldepth_0d )
738 if(cs%fixedOBLdepth) obldepth_0d = cs%fixedOBLdepth_value
739 obldepth_0d = max( obldepth_0d, -ifaceheight(2) )
740 obldepth_0d = min( obldepth_0d, -ifaceheight(g%ke+1) )
741 kobl = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, obldepth_0d )
756 surfbuoyflux = buoyflux(i,j,1)
758 surfbuoyflux = buoyflux(i,j,1) - buoyflux(i,j,int(kobl)+1)
760 surfbuoyflux = buoyflux(i,j,1) - buoyflux(i,j,2)
764 if (.not. (cs%MatchTechnique.eq.
'MatchBoth'))
then 765 kdiffusivity(:,:) = 0.
768 kdiffusivity(:,1) = kt(i,j,:)
769 kdiffusivity(:,2) = ks(i,j,:)
770 kviscosity(:)=kv(i,j,:)
773 call cvmix_coeffs_kpp(kviscosity, &
789 cvmix_kpp_params_user=cs%KPP_params )
801 if (surfbuoyflux < 0.0)
then 804 sigma = min(1.0,-ifaceheight(k)/obldepth_0d)
805 nonlocaltrans(k,1) = (1.0 - sigma)**2 * (1.0 + 2.0*sigma)
806 nonlocaltrans(k,2) = nonlocaltrans(k,1)
810 sigma = min(1.0,-ifaceheight(k)/obldepth_0d)
811 nonlocaltrans(k,1) = (1.0 - sigma)**2
812 nonlocaltrans(k,2) = nonlocaltrans(k,1)
816 sigma = min(1.0,-ifaceheight(k)/obldepth_0d)
817 nonlocaltrans(k,1) = (1.0 - sigma)
818 nonlocaltrans(k,2) = nonlocaltrans(k,1)
823 sigma = min(1.0,-ifaceheight(k)/obldepth_0d)
824 nonlocaltrans(k,1) = cs%CS2 * sigma*(1.0 -sigma)**2
825 nonlocaltrans(k,2) = nonlocaltrans(k,1)
832 nonlocaltransheat(i,j,:) = nonlocaltrans(:,1)
833 nonlocaltransscalar(i,j,:) = nonlocaltrans(:,2)
836 if(cs%KPPzeroDiffusivity)
then 837 kdiffusivity(:,1) = 0.0
838 kdiffusivity(:,2) = 0.0
843 if (cs%id_Ws > 0)
then 844 call cvmix_kpp_compute_turbulent_scales( &
845 -cellheight/obldepth_0d, &
850 cvmix_kpp_params_user=cs%KPP_params &
852 cs%Ws(i,j,:) = ws_1d(:)
856 if (cs%id_Vt2 > 0)
then 857 vt2_1d(:) = cvmix_kpp_compute_unresolved_shear( &
858 cellheight(1:g%ke), &
861 cvmix_kpp_params_user=cs%KPP_params )
862 cs%Vt2(i,j,:) = vt2_1d(:)
866 if (cs%id_OBLdepth > 0) cs%OBLdepth(i,j) = obldepth_0d
867 if (cs%id_BulkDrho > 0) cs%dRho(i,j,:) = deltarho(:)
868 if (cs%id_BulkUz2 > 0) cs%Uz2(i,j,:) = deltau2(:)
869 if (cs%id_BulkRi > 0) cs%BulkRi(i,j,:) = bulkri_1d(:)
870 if (cs%id_sigma > 0)
then 872 if (obldepth_0d>0.) cs%sigma(i,j,:) = -ifaceheight/obldepth_0d
874 if (cs%id_N > 0) cs%N(i,j,:) = n_1d(:)
875 if (cs%id_N2 > 0) cs%N2(i,j,:) = n2_1d(:)
876 if (cs%id_Kt_KPP > 0) cs%Kt_KPP(i,j,:) = kdiffusivity(:,1)
877 if (cs%id_Ks_KPP > 0) cs%Ks_KPP(i,j,:) = kdiffusivity(:,2)
878 if (cs%id_Kv_KPP > 0) cs%Kv_KPP(i,j,:) = kviscosity(:)
879 if (cs%id_Tsurf > 0) cs%Tsurf(i,j) = surftemp
880 if (cs%id_Ssurf > 0) cs%Ssurf(i,j) = surfsalt
881 if (cs%id_Usurf > 0) cs%Usurf(i,j) = surfu
882 if (cs%id_Vsurf > 0) cs%Vsurf(i,j) = surfv
886 if (.not. cs%passiveMode)
then 887 if (cs%KPPisAdditive)
then 889 kt(i,j,k) = kt(i,j,k) + kdiffusivity(k,1)
890 ks(i,j,k) = ks(i,j,k) + kdiffusivity(k,2)
891 kv(i,j,k) = kv(i,j,k) + kviscosity(k)
895 if (kdiffusivity(k,1) /= 0.) kt(i,j,k) = kdiffusivity(k,1)
896 if (kdiffusivity(k,2) /= 0.) ks(i,j,k) = kdiffusivity(k,2)
897 if (kviscosity(k) /= 0.) kv(i,j,k) = kviscosity(k)
908 #ifdef __DO_SAFETY_CHECKS__ 910 call hchksum(kt,
"KPP out: Kt",g%HI,haloshift=0)
911 call hchksum(ks,
"KPP out: Ks",g%HI,haloshift=0)
916 if (cs%id_OBLdepth > 0)
call post_data(cs%id_OBLdepth, cs%OBLdepth, cs%diag)
917 if (cs%id_BulkDrho > 0)
call post_data(cs%id_BulkDrho, cs%dRho, cs%diag)
918 if (cs%id_BulkUz2 > 0)
call post_data(cs%id_BulkUz2, cs%Uz2, cs%diag)
919 if (cs%id_BulkRi > 0)
call post_data(cs%id_BulkRi, cs%BulkRi, cs%diag)
920 if (cs%id_sigma > 0)
call post_data(cs%id_sigma, cs%sigma, cs%diag)
921 if (cs%id_Ws > 0)
call post_data(cs%id_Ws, cs%Ws, cs%diag)
922 if (cs%id_N > 0)
call post_data(cs%id_N, cs%N, cs%diag)
923 if (cs%id_N2 > 0)
call post_data(cs%id_N2, cs%N2, cs%diag)
924 if (cs%id_Vt2 > 0)
call post_data(cs%id_Vt2, cs%Vt2, cs%diag)
925 if (cs%id_uStar > 0)
call post_data(cs%id_uStar, ustar, cs%diag)
926 if (cs%id_buoyFlux > 0)
call post_data(cs%id_buoyFlux, buoyflux, cs%diag)
927 if (cs%id_Kt_KPP > 0)
call post_data(cs%id_Kt_KPP, cs%Kt_KPP, cs%diag)
928 if (cs%id_Ks_KPP > 0)
call post_data(cs%id_Ks_KPP, cs%Ks_KPP, cs%diag)
929 if (cs%id_Kv_KPP > 0)
call post_data(cs%id_Kv_KPP, cs%Kv_KPP, cs%diag)
930 if (cs%id_NLTt > 0)
call post_data(cs%id_NLTt, nonlocaltransheat, cs%diag)
931 if (cs%id_NLTs > 0)
call post_data(cs%id_NLTs, nonlocaltransscalar,cs%diag)
932 if (cs%id_Tsurf > 0)
call post_data(cs%id_Tsurf, cs%Tsurf, cs%diag)
933 if (cs%id_Ssurf > 0)
call post_data(cs%id_Ssurf, cs%Ssurf, cs%diag)
934 if (cs%id_Usurf > 0)
call post_data(cs%id_Usurf, cs%Usurf, cs%diag)
935 if (cs%id_Vsurf > 0)
call post_data(cs%id_Vsurf, cs%Vsurf, cs%diag)
945 type(
kpp_cs),
intent(in) :: CS
948 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
949 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: nonLocalTrans
950 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: surfFlux
951 real,
intent(in) :: dt
952 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: scalar
953 real,
intent(in) :: C_p
956 real,
dimension( SZI_(G), SZJ_(G), SZK_(G) ) :: dtracer
964 dtracer(i,j,k) = ( nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1) ) / &
965 ( h(i,j,k) + gv%H_subroundoff ) * surfflux(i,j)
971 if (cs%applyNonLocalTrans)
then 975 scalar(i,j,k) = scalar(i,j,k) + dt * dtracer(i,j,k)
982 if (cs%id_QminusSW > 0)
call post_data(cs%id_QminusSW, surfflux, cs%diag)
983 if (cs%id_NLT_dTdt > 0)
call post_data(cs%id_NLT_dTdt, dtracer, cs%diag)
984 if (cs%id_NLT_temp_budget > 0)
then 989 dtracer(i,j,k) = (nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1)) * &
990 surfflux(i,j) * c_p * gv%H_to_kg_m2
994 call post_data(cs%id_NLT_temp_budget, dtracer, cs%diag)
1004 type(
kpp_cs),
intent(in) :: CS
1007 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(in) :: h
1008 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)+1),
intent(in) :: nonLocalTrans
1009 real,
dimension(SZI_(G),SZJ_(G)),
intent(in) :: surfFlux
1010 real,
intent(in) :: dt
1011 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: scalar
1014 real,
dimension( SZI_(G), SZJ_(G), SZK_(G) ) :: dtracer
1017 dtracer(:,:,:) = 0.0
1022 dtracer(i,j,k) = ( nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1) ) / &
1023 ( h(i,j,k) + gv%H_subroundoff ) * surfflux(i,j)
1029 if (cs%applyNonLocalTrans)
then 1033 scalar(i,j,k) = scalar(i,j,k) + dt * dtracer(i,j,k)
1040 if (cs%id_netS > 0)
call post_data(cs%id_netS, surfflux, cs%diag)
1041 if (cs%id_NLT_dSdt > 0)
call post_data(cs%id_NLT_dSdt, dtracer, cs%diag)
1042 if (cs%id_NLT_saln_budget > 0)
then 1043 dtracer(:,:,:) = 0.0
1047 dtracer(i,j,k) = (nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1)) * &
1048 surfflux(i,j) * gv%H_to_kg_m2
1052 call post_data(cs%id_NLT_saln_budget, dtracer, cs%diag)
logical function, public ispointincell(G, i, j, x, y)
Returns true if the coordinates (x,y) are within the h-cell (i,j)
integer, parameter, private sw_method_all_sw
Use all shortwave radiation.
Ocean grid type. See mom_grid for details.
Calculates density of sea water from T, S and P.
Provides the ocean grid type.
Control structure for containing KPP parameters/data.
integer, parameter, private sw_method_mxl_sw
Use shortwave radiation absorbed in mixing layer.
subroutine, public kpp_calculate(CS, G, GV, h, Temp, Salt, u, v, EOS, uStar, buoyFlux, Kt, Ks, Kv, nonLocalTransHeat, nonLocalTransScalar)
KPP vertical diffusivity/viscosity and non-local tracer transport.
integer, parameter, private sw_method_lv1_sw
Use shortwave radiation absorbed in layer 1.
integer, parameter, private nlt_shape_cvmix
Use the CVmix profile.
subroutine, public closeparameterblock(CS)
subroutine, public openparameterblock(CS, blockName, desc)
logical function, public is_root_pe()
subroutine, public kpp_end(CS)
Clear pointers, deallocate memory.
integer, parameter, private nlt_shape_cubic_lmd
Original shape, .
subroutine, public mom_mesg(message, verb, all_print)
logical, parameter verbose
logical function, public kpp_init(paramFile, G, diag, Time, CS, passive)
Initialize the CVmix KPP module and set up diagnostics Returns True if KPP is to be used...
Provides subroutines for quantities specific to the equation of state.
subroutine, public kpp_nonlocaltransport_temp(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar, C_p)
Apply KPP non-local transport of surface fluxes for temperature.
subroutine, public kpp_nonlocaltransport_saln(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar)
Apply KPP non-local transport of surface fluxes for salinity. This routine is a useful prototype for ...
Provides the K-Profile Parameterization (KPP) of Large et al., 1994, via CVMix.
subroutine, public mom_error(level, message, all_print)
A control structure for the equation of state.
integer, parameter, private nlt_shape_parabolic
Parabolic, .
integer, parameter, private nlt_shape_linear
Linear, .
integer, parameter, private nlt_shape_cubic
Cubic, .