MOM6
MOM_KPP.F90
Go to the documentation of this file.
1 !> Provides the K-Profile Parameterization (KPP) of Large et al., 1994, via CVMix.
2 module mom_kpp
3 
4 ! License goes here?
5 
6 use mom_coms, only : max_across_pes
7 use mom_debugging, only : hchksum, is_nan
8 use mom_diag_mediator, only : time_type, diag_ctrl, safe_alloc_ptr, post_data
10 use mom_error_handler, only : mom_error, mom_mesg, fatal, warning, is_root_pe
16 
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
25 
26 implicit none ; private
27 
28 #include "MOM_memory.h"
29 
30 public :: kpp_init
31 public :: kpp_calculate
32 public :: kpp_end
35 
36 ! Enumerated constants
37 integer, private, parameter :: nlt_shape_cvmix = 0 !< Use the CVmix profile
38 integer, private, parameter :: nlt_shape_linear = 1 !< Linear, \f$ G(\sigma) = 1-\sigma \f$
39 integer, private, parameter :: nlt_shape_parabolic = 2 !< Parabolic, \f$ G(\sigma) = (1-\sigma)^2 \f$
40 integer, private, parameter :: nlt_shape_cubic = 3 !< Cubic, \f$ G(\sigma) = 1 + (2\sigma-3) \sigma^2\f$
41 integer, private, parameter :: nlt_shape_cubic_lmd = 4 !< Original shape, \f$ G(\sigma) = \frac{27}{4} \sigma (1-\sigma)^2 \f$
42 
43 integer, private, parameter :: sw_method_all_sw = 0 !< Use all shortwave radiation
44 integer, private, parameter :: sw_method_mxl_sw = 1 !< Use shortwave radiation absorbed in mixing layer
45 integer, private, parameter :: sw_method_lv1_sw = 2 !< Use shortwave radiation absorbed in layer 1
46 
47 !> Control structure for containing KPP parameters/data
48 type, public :: kpp_cs ; private
49 
50  ! Parameters
51  real :: ri_crit !< Critical bulk Richardson number (defines OBL depth)
52  real :: vonkarman !< von Karman constant (dimensionless)
53  real :: cs !< Parameter for computing velocity scale function (dimensionless)
54  real :: cs2 !< Parameter for multiplying by non-local term
55  ! This is active for NLT_SHAPE_CUBIC_LMD only
56  logical :: enhance_diffusion !< If True, add enhanced diffusivity at base of boundary layer.
57  character(len=10) :: interptype !< Type of interpolation in determining OBL depth
58  logical :: computeekman !< If True, compute Ekman depth limit for OBLdepth
59  logical :: computemoninobukhov !< If True, compute Monin-Obukhov limit for OBLdepth
60  logical :: passivemode !< If True, makes KPP passive meaning it does NOT alter the diffusivity
61  real :: deepobloffset !< If non-zero, is a distance from the bottom that the OBL can not penetrate through (m)
62  real :: minobldepth !< If non-zero, is a minimum depth for the OBL (m)
63  real :: surf_layer_ext !< Fraction of OBL depth considered in the surface layer (nondim)
64  real :: minvtsqr !< Min for the squared unresolved velocity used in Rib CVMix calculation (m2/s2)
65  logical :: fixedobldepth !< If True, will fix the OBL depth at fixedOBLdepth_value
66  real :: fixedobldepth_value !< value for the fixed OBL depth when fixedOBLdepth==True.
67  logical :: debug !< If True, calculate checksums and write debugging information
68  character(len=30) :: matchtechnique !< Method used in CVMix for setting diffusivity and NLT profile functions
69  integer :: nlt_shape !< MOM6 over-ride of CVMix NLT shape function
70  logical :: applynonlocaltrans !< If True, apply non-local transport to heat and scalars
71  logical :: kppzerodiffusivity !< If True, will set diffusivity and viscosity from KPP to zero; for testing purposes.
72  logical :: kppisadditive !< If True, will add KPP diffusivity to initial diffusivity.
73  !! If False, will replace initial diffusivity wherever KPP diffusivity is non-zero.
74  real :: min_thickness !< A minimum thickness used to avoid division by small numbers in the vicinity of vanished layers.
75  ! smg: obsolete below
76  logical :: correctsurflayeravg !< If true, applies a correction to the averaging of surface layer properties
77  real :: surflayerdepth !< A guess at the depth of the surface layer (which should 0.1 of OBLdepth) (m)
78  ! smg: obsolete above
79  integer :: sw_method !<Sets method for using shortwave radiation in surface buoyancy flux
80 
81  !> CVmix parameters
82  type(cvmix_kpp_params_type), pointer :: kpp_params => null()
83 
84  ! Diagnostic handles and pointers
85  type(diag_ctrl), pointer :: diag => 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
103 
104  ! Diagnostics arrays
105  real, allocatable, dimension(:,:) :: obldepth !< Depth (positive) of OBL (m)
106  real, allocatable, dimension(:,:,:) :: drho !< Bulk difference in density (kg/m3)
107  real, allocatable, dimension(:,:,:) :: uz2 !< Square of bulk difference in resolved velocity (m2/s2)
108  real, allocatable, dimension(:,:,:) :: bulkri !< Bulk Richardson number for each layer (dimensionless)
109  real, allocatable, dimension(:,:,:) :: sigma !< Sigma coordinate (dimensionless)
110  real, allocatable, dimension(:,:,:) :: ws !< Turbulent velocity scale for scalars (m/s)
111  real, allocatable, dimension(:,:,:) :: n !< Brunt-Vaisala frequency (1/s)
112  real, allocatable, dimension(:,:,:) :: n2 !< Squared Brunt-Vaisala frequency (1/s2)
113  real, allocatable, dimension(:,:,:) :: vt2 !< Unresolved squared turbulence velocity for bulk Ri (m2/s2)
114  real, allocatable, dimension(:,:,:) :: kt_kpp !< Temp diffusivity from KPP (m2/s)
115  real, allocatable, dimension(:,:,:) :: ks_kpp !< Scalar diffusivity from KPP (m2/s)
116  real, allocatable, dimension(:,:,:) :: kv_kpp !< Viscosity due to KPP (m2/s)
117  real, allocatable, dimension(:,:) :: tsurf !< Temperature of surface layer (C)
118  real, allocatable, dimension(:,:) :: ssurf !< Salinity of surface layer (ppt)
119  real, allocatable, dimension(:,:) :: usurf !< i-velocity of surface layer (m/s)
120  real, allocatable, dimension(:,:) :: vsurf !< j-velocity of surface layer (m/s)
121 
122 end type kpp_cs
123 
124 ! Module data used for debugging only
125 logical, parameter :: verbose = .false.
126 #define __DO_SAFETY_CHECKS__
127 
128 contains
129 
130 !> Initialize the CVmix KPP module and set up diagnostics
131 !! Returns True if KPP is to be used, False otherwise.
132 logical function kpp_init(paramFile, G, diag, Time, CS, passive)
134  ! Arguments
135  type(param_file_type), intent(in) :: paramFile !< File parser
136  type(ocean_grid_type), intent(in) :: G !< Ocean grid
137  type(diag_ctrl), target, intent(in) :: diag !< Diagnostics
138  type(time_type), intent(in) :: Time !< Time
139  type(kpp_cs), pointer :: CS !< Control structure
140  logical, optional, intent(out) :: passive !< Copy of %passiveMode
141 
142  ! Local variables
143 #include "version_variable.h"
144  character(len=40) :: mdl = 'MOM_KPP' ! name of this module
145  character(len=20) :: string ! local temporary string
146  logical :: CS_IS_ONE=.false.
147 
148  if (associated(cs)) call mom_error(fatal, 'MOM_KPP, KPP_init: '// &
149  'Control structure has already been initialized')
150  allocate(cs)
151 
152  ! Read parameters
153  call log_version(paramfile, mdl, version, 'This is the MOM wrapper to CVmix:KPP\n' // &
154  'See http://code.google.com/p/cvmix/')
155  call get_param(paramfile, mdl, "USE_KPP", kpp_init, &
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.", &
158  default=.false.)
159  ! Forego remainder of initialization if not using this scheme
160  if (.not. kpp_init) return
161 
162  call openparameterblock(paramfile,'KPP')
163  call get_param(paramfile, mdl, 'PASSIVE', cs%passiveMode, &
164  'If True, puts KPP into a passive-diagnostic mode.', &
165  default=.false.)
166  if (present(passive)) passive=cs%passiveMode ! This is passed back to the caller so
167  ! the caller knows to not use KPP output
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.', &
182  default=.true.)
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.', &
186  default='cubic')
187  call get_param(paramfile, mdl, 'COMPUTE_EKMAN', cs%computeEkman, &
188  'If True, limit OBL depth to be no deeper than Ekman depth.', &
189  default=.false.)
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.', &
193  default=.false.)
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.', &
208  default=.false.)
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)
225 
226 ! smg: for removal below
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.)
235 ! smg: for removal above
236 
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', &
245  default='CVMIX')
246  select case ( trim(string) )
247  case ("CVMIX") ; cs%NLT_shape = nlt_shape_cvmix
248  case ("LINEAR") ; cs%NLT_shape = nlt_shape_linear
249  case ("PARABOLIC") ; cs%NLT_shape = nlt_shape_parabolic
250  case ("CUBIC") ; cs%NLT_shape = nlt_shape_cubic
251  case ("CUBIC_LMD") ; cs%NLT_shape = nlt_shape_cubic_lmd
252  case default ; call mom_error(fatal,"KPP_init: "// &
253  "Unrecognized NLT_SHAPE option"//trim(string))
254  end select
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
264  ! This forces Cs2 (Cs in non-local computation) to equal 1 for parabolic non-local option.
265  ! May be used during CVmix initialization.
266  cs_is_one=.true.
267  endif
268  call get_param(paramfile, mdl, 'KPP_ZERO_DIFFUSIVITY', cs%KPPzeroDiffusivity, &
269  'If True, zeroes the KPP diffusivity and viscosity; for testing purpose.',&
270  default=.false.)
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.', &
274  default=.true.)
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', &
281  default='MXL_SW')
282  select case ( trim(string) )
283  case ("ALL_SW") ; cs%SW_METHOD = sw_method_all_sw
284  case ("MXL_SW") ; cs%SW_METHOD = sw_method_mxl_sw
285  case ("LV1_SW") ; cs%SW_METHOD = sw_method_lv1_sw
286  case default ; call mom_error(fatal,"KPP_init: "// &
287  "Unrecognized KPP_SHORTWAVE_METHOD option"//trim(string))
288  end select
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.)
293 
294  call closeparameterblock(paramfile)
295  call get_param(paramfile, mdl, 'DEBUG', cs%debug, default=.false., do_not_log=.true.)
296 
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 )
309 
310  ! Register diagnostics
311  cs%diag => diag
312  cs%id_OBLdepth = register_diag_field('ocean_model', 'KPP_OBLdepth', diag%axesT1, time, &
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')
316  ! CMOR names are placeholders; must be modified by time period
317  ! for CMOR compliance. Diag manager will be used for omlmax and
318  ! omldamax.
319  cs%id_BulkDrho = register_diag_field('ocean_model', 'KPP_BulkDrho', diag%axesTL, time, &
320  'Bulk difference in density used in Bulk Richardson number, as used by [CVmix] KPP', 'kg/m3')
321  cs%id_BulkUz2 = register_diag_field('ocean_model', 'KPP_BulkUz2', diag%axesTL, time, &
322  'Square of bulk difference in resolved velocity used in Bulk Richardson number via [CVmix] KPP', 'm2/s2')
323  cs%id_BulkRi = register_diag_field('ocean_model', 'KPP_BulkRi', diag%axesTL, time, &
324  'Bulk Richardson number used to find the OBL depth used by [CVmix] KPP', 'nondim')
325  cs%id_Sigma = register_diag_field('ocean_model', 'KPP_sigma', diag%axesTi, time, &
326  'Sigma coordinate used by [CVmix] KPP', 'nondim')
327  cs%id_Ws = register_diag_field('ocean_model', 'KPP_Ws', diag%axesTL, time, &
328  'Turbulent vertical velocity scale for scalars used by [CVmix] KPP', 'm/s')
329  cs%id_N = register_diag_field('ocean_model', 'KPP_N', diag%axesTi, time, &
330  '(Adjusted) Brunt-Vaisala frequency used by [CVmix] KPP', '1/s')
331  cs%id_N2 = register_diag_field('ocean_model', 'KPP_N2', diag%axesTi, time, &
332  'Square of Brunt-Vaisala frequency used by [CVmix] KPP', '1/s2')
333  cs%id_Vt2 = register_diag_field('ocean_model', 'KPP_Vt2', diag%axesTL, time, &
334  'Unresolved shear turbulence used by [CVmix] KPP', 'm2/s2')
335  cs%id_uStar = register_diag_field('ocean_model', 'KPP_uStar', diag%axesT1, time, &
336  'Friction velocity, u*, as used by [CVmix] KPP', 'm/s')
337  cs%id_buoyFlux = register_diag_field('ocean_model', 'KPP_buoyFlux', diag%axesTi, time, &
338  'Surface (and penetrating) buoyancy flux, as used by [CVmix] KPP', 'm2/s3')
339  cs%id_QminusSW = register_diag_field('ocean_model', 'KPP_QminusSW', diag%axesT1, time, &
340  'Net temperature flux ignoring short-wave, as used by [CVmix] KPP', 'K m/s')
341  cs%id_netS = register_diag_field('ocean_model', 'KPP_netSalt', diag%axesT1, time, &
342  'Effective net surface salt flux, as used by [CVmix] KPP', 'ppt m/s')
343  cs%id_Kt_KPP = register_diag_field('ocean_model', 'KPP_Kheat', diag%axesTi, time, &
344  'Heat diffusivity due to KPP, as calculated by [CVmix] KPP', 'm2/s')
345  cs%id_Kd_in = register_diag_field('ocean_model', 'KPP_Kd_in', diag%axesTi, time, &
346  'Diffusivity passed to KPP', 'm2/s')
347  cs%id_Ks_KPP = register_diag_field('ocean_model', 'KPP_Ksalt', diag%axesTi, time, &
348  'Salt diffusivity due to KPP, as calculated by [CVmix] KPP', 'm2/s')
349  cs%id_Kv_KPP = register_diag_field('ocean_model', 'KPP_Kv', diag%axesTi, time, &
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')
355  cs%id_NLT_dTdt = register_diag_field('ocean_model', 'KPP_NLT_dTdt', diag%axesTL, time, &
356  'Temperature tendency due to non-local transport of heat, as calculated by [CVmix] KPP', 'K/s')
357  cs%id_NLT_dSdt = register_diag_field('ocean_model', 'KPP_NLT_dSdt', diag%axesTL, time, &
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)')
363  cs%id_Tsurf = register_diag_field('ocean_model', 'KPP_Tsurf', diag%axesT1, time, &
364  'Temperature of surface layer (10% of OBL depth) as passed to [CVmix] KPP', 'C')
365  cs%id_Ssurf = register_diag_field('ocean_model', 'KPP_Ssurf', diag%axesT1, time, &
366  'Salinity of surface layer (10% of OBL depth) as passed to [CVmix] KPP', 'ppt')
367  cs%id_Usurf = register_diag_field('ocean_model', 'KPP_Usurf', diag%axesCu1, time, &
368  'i-component flow of surface layer (10% of OBL depth) as passed to [CVmix] KPP', 'm/s')
369  cs%id_Vsurf = register_diag_field('ocean_model', 'KPP_Vsurf', diag%axesCv1, time, &
370  'j-component flow of surface layer (10% of OBL depth) as passed to [CVmix] KPP', 'm/s')
371 
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.
404 
405 end function kpp_init
406 
407 
408 
409 !> KPP vertical diffusivity/viscosity and non-local tracer transport
410 subroutine kpp_calculate(CS, G, GV, h, Temp, Salt, u, v, EOS, uStar, &
411  buoyFlux, Kt, Ks, Kv, nonLocalTransHeat,&
412  nonLocalTransScalar)
414  ! Arguments
415  type(kpp_cs), pointer :: CS !< Control structure
416  type(ocean_grid_type), intent(in) :: G !< Ocean grid
417  type(verticalgrid_type), intent(in) :: GV !< Ocean vertical grid
418  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer/level thicknesses (units of H)
419  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: Temp !< potential/cons temp (deg C)
420  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: Salt !< Salinity (ppt)
421  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(in) :: u !< Velocity i-component (m/s)
422  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(in) :: v !< Velocity j-component (m/s)
423  type(eos_type), pointer :: EOS !< Equation of state
424  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: uStar !< Surface friction velocity (m/s)
425  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(in) :: buoyFlux !< Surface buoyancy flux (m2/s3)
426  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(inout) :: Kt !< (in) Vertical diffusivity of heat w/o KPP (m2/s)
427  !< (out) Vertical diffusivity including KPP (m2/s)
428  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(inout) :: Ks !< (in) Vertical diffusivity of salt w/o KPP (m2/s)
429  !< (out) Vertical diffusivity including KPP (m2/s)
430  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(inout) :: Kv !< (in) Vertical viscosity w/o KPP (m2/s)
431  !< (out) Vertical viscosity including KPP (m2/s)
432  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(inout) :: nonLocalTransHeat !< Temp non-local transport (m/s)
433  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(inout) :: nonLocalTransScalar !< scalar non-local transport (m/s)
434 
435  ! Local variables
436  integer :: i, j, k, km1,kp1 ! Loop indices
437  real, dimension( G%ke ) :: cellHeight ! Cell center heights referenced to surface (m) (negative in ocean)
438  real, dimension( G%ke+1 ) :: iFaceHeight ! Interface heights referenced to surface (m) (negative in ocean)
439  real, dimension( G%ke+1 ) :: N2_1d ! Brunt-Vaisala frequency squared, at interfaces (1/s2)
440  real, dimension( G%ke+1 ) :: N_1d ! Brunt-Vaisala frequency at interfaces (1/s) (floored at 0)
441  real, dimension( G%ke ) :: Ws_1d ! Profile of vertical velocity scale for scalars (m/s)
442  real, dimension( G%ke ) :: Wm_1d ! Profile of vertical velocity scale for momentum (m/s)
443  real, dimension( G%ke ) :: Vt2_1d ! Unresolved velocity for bulk Ri calculation/diagnostic (m2/s2)
444  real, dimension( G%ke ) :: BulkRi_1d ! Bulk Richardson number for each layer
445  real, dimension( G%ke ) :: deltaRho ! delta Rho in numerator of Bulk Ri number
446  real, dimension( G%ke ) :: deltaU2 ! square of delta U (shear) in denominator of Bulk Ri (m2/s2)
447  real, dimension( G%ke+1, 2) :: Kdiffusivity ! Vertical diffusivity at interfaces (m2/s)
448  real, dimension( G%ke+1 ) :: Kviscosity ! Vertical viscosity at interfaces (m2/s)
449  real, dimension( G%ke+1, 2) :: nonLocalTrans ! Non-local transport for heat/salt at interfaces (non-dimensional)
450  real, dimension( G%ke ) :: surfBuoyFlux2
451 
452  ! for EOS calculation
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
457 
458  real :: kOBL, OBLdepth_0d, surfFricVel, surfBuoyFlux, Coriolis
459  real :: GoRho, pRef, rho1, rhoK, rhoKm1, Uk, Vk, sigma
460 
461  real :: zBottomMinusOffset ! Height of bottom plus a little bit (m)
462  real :: SLdepth_0d ! Surface layer depth = surf_layer_ext*OBLdepth.
463  real :: hTot ! Running sum of thickness used in the surface layer average (m)
464  real :: delH ! Thickness of a layer (m)
465  real :: surfHtemp, surfTemp ! Integral and average of temp over the surface layer
466  real :: surfHsalt, surfSalt ! Integral and average of saln over the surface layer
467  real :: surfHu, surfU ! Integral and average of u over the surface layer
468  real :: surfHv, surfV ! Integral and average of v over the surface layer
469  real :: dh ! The local thickness used for calculating interface positions (m)
470  real :: hcorr ! A cumulative correction arising from inflation of vanished layers (m)
471  integer :: kk, ksfc, ktmp
472 
473 #ifdef __DO_SAFETY_CHECKS__
474  if (cs%debug) then
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)
484  endif
485 #endif
486 
487  ! some constants
488  gorho = gv%g_Earth / gv%Rho0
489  nonlocaltrans(:,:) = 0.0
490 
491  if (cs%id_Kd_in > 0) call post_data(cs%id_Kd_in, kt, cs%diag)
492 
493 !$OMP parallel do default(none) shared(G,GV,CS,EOS,uStar,Temp,Salt,u,v,h,GoRho, &
494 !$OMP buoyFlux, nonLocalTransHeat, &
495 !$OMP nonLocalTransScalar,Kt,Ks,Kv) &
496 !$OMP firstprivate(nonLocalTrans) &
497 !$OMP private(Coriolis,surfFricVel,SLdepth_0d,hTot,surfTemp, &
498 !$OMP surfHtemp,surfSalt,surfHsalt,surfU, &
499 !$OMP surfHu,surfV,surfHv,iFaceHeight, &
500 !$OMP pRef,km1,cellHeight,Uk,Vk,deltaU2, &
501 !$OMP rho1,rhoK,rhoKm1,deltaRho,N2_1d,N_1d,delH, &
502 !$OMP surfBuoyFlux,Ws_1d,Vt2_1d,BulkRi_1d, &
503 !$OMP OBLdepth_0d,zBottomMinusOffset,Kdiffusivity, &
504 !$OMP Kviscosity,sigma,kOBL,kk,pres_1D,Temp_1D, &
505 !$OMP Salt_1D,rho_1D,surfBuoyFlux2,ksfc,dh,hcorr)
506 
507  ! loop over horizontal points on processor
508  do j = g%jsc, g%jec
509  do i = g%isc, g%iec
510 
511  ! skip calling KPP for land points
512  if (g%mask2dT(i,j)==0.) cycle
513 
514  ! things independent of position within the column
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)
518 
519  ! Bullk Richardson number computed for each cell in a column,
520  ! assuming OBLdepth = grid cell depth. After Rib(k) is
521  ! known for the column, then CVMix interpolates to find
522  ! the actual OBLdepth. This approach avoids need to iterate
523  ! on the OBLdepth calculation. It follows that used in MOM5
524  ! and POP.
525  ifaceheight(1) = 0.0 ! BBL is all relative to the surface
526  pref = 0.
527  hcorr = 0.
528  do k=1,g%ke
529 
530  ! cell center and cell bottom in meters (negative values in the ocean)
531  dh = h(i,j,k) * gv%H_to_m ! Nominal thickness to use for increment
532  dh = dh + hcorr ! Take away the accumulated error (could temporarily make dh<0)
533  hcorr = min( dh - cs%min_thickness, 0. ) ! If inflating then hcorr<0
534  dh = max( dh, cs%min_thickness ) ! Limit increment dh>=min_thickness
535  cellheight(k) = ifaceheight(k) - 0.5 * dh
536  ifaceheight(k+1) = ifaceheight(k) - dh
537 
538  ! find ksfc for cell where "surface layer" sits
539  sldepth_0d = cs%surf_layer_ext*max( max(-cellheight(k),-ifaceheight(2) ), cs%minOBLdepth )
540  ksfc = k
541  do ktmp = 1,k
542  if (-1.0*ifaceheight(ktmp+1) >= sldepth_0d) then
543  ksfc = ktmp
544  exit
545  endif
546  enddo
547 
548  ! average temp, saln, u, v over surface layer
549  ! use C-grid average to get u,v on T-points.
550  surfhtemp=0.0
551  surfhsalt=0.0
552  surfhu =0.0
553  surfhv =0.0
554  htot =0.0
555  do ktmp = 1,ksfc
556 
557  ! SLdepth_0d can be between cell interfaces
558  delh = min( max(0.0, sldepth_0d - htot), h(i,j,ktmp)*gv%H_to_m )
559 
560  ! surface layer thickness
561  htot = htot + delh
562 
563  ! surface averaged fields
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
568 
569  enddo
570  surftemp = surfhtemp / htot
571  surfsalt = surfhsalt / htot
572  surfu = surfhu / htot
573  surfv = surfhv / htot
574 
575  ! vertical shear between present layer and
576  ! surface layer averaged surfU,surfV.
577  ! C-grid average to get Uk and Vk on T-points.
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
581 
582  ! pressure, temp, and saln for EOS
583  ! kk+1 = surface fields
584  ! kk+2 = k fields
585  ! kk+3 = km1 fields
586  km1 = max(1, k-1)
587  kk = 3*(k-1)
588  pres_1d(kk+1) = pref
589  pres_1d(kk+2) = pref
590  pres_1d(kk+3) = pref
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)
597 
598  ! pRef is pressure at interface between k and km1.
599  ! iterate pRef for next pass through k-loop.
600  pref = pref + gv%H_to_Pa * h(i,j,k)
601 
602  ! this difference accounts for penetrating SW
603  surfbuoyflux2(k) = buoyflux(i,j,1) - buoyflux(i,j,k+1)
604 
605  enddo ! k-loop finishes
606 
607  ! compute in-situ density
608  call calculate_density(temp_1d, salt_1d, pres_1d, rho_1d, 1, 3*g%ke, eos)
609 
610  ! N2 (can be negative) and N (non-negative) on interfaces.
611  ! deltaRho is non-local rho difference used for bulk Richardson number.
612  ! N_1d is local N (with floor) used for unresolved shear calculation.
613  do k = 1, g%ke
614  km1 = max(1, k-1)
615  kk = 3*(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.) )
620  enddo
621  n2_1d(g%ke+1 ) = 0.0
622  n_1d(g%ke+1 ) = 0.0
623 
624  ! turbulent velocity scales w_s and w_m computed at the cell centers.
625  ! Note that if sigma > CS%surf_layer_ext, then CVmix_kpp_compute_turbulent_scales
626  ! computes w_s and w_m velocity scale at sigma=CS%surf_layer_ext. So we only pass
627  ! sigma=CS%surf_layer_ext for this calculation.
628  call cvmix_kpp_compute_turbulent_scales( &
629  cs%surf_layer_ext, & ! (in) Normalized surface layer depth; sigma = CS%surf_layer_ext
630  -cellheight, & ! (in) Assume here that OBL depth (m) = -cellHeight(k)
631  surfbuoyflux2, & ! (in) Buoyancy flux at surface (m2/s3)
632  surffricvel, & ! (in) Turbulent friction velocity at surface (m/s)
633  w_s=ws_1d, & ! (out) Turbulent velocity scale profile (m/s)
634  cvmix_kpp_params_user=cs%KPP_params )
635 
636  ! Calculate Bulk Richardson number from eq (21) of LMD94
637  bulkri_1d = cvmix_kpp_compute_bulk_richardson( &
638  cellheight(1:g%ke), & ! Depth of cell center (m)
639  gorho*deltarho, & ! Bulk buoyancy difference, Br-B(z) (1/s)
640  deltau2, & ! Square of resolved velocity difference (m2/s2)
641  ws_cntr=ws_1d, & ! Turbulent velocity scale profile (m/s)
642  n_iface=n_1d) ! Buoyancy frequency (1/s)
643 
644 
645  surfbuoyflux = buoyflux(i,j,1) ! This is only used in kpp_compute_OBL_depth to limit
646  ! h to Monin-Obukov (default is false, ie. not used)
647 
648  call cvmix_kpp_compute_obl_depth( &
649  bulkri_1d, & ! (in) Bulk Richardson number
650  ifaceheight, & ! (in) Height of interfaces (m)
651  obldepth_0d, & ! (out) OBL depth (m)
652  kobl, & ! (out) level (+fraction) of OBL extent
653  zt_cntr=cellheight, & ! (in) Height of cell centers (m)
654  surf_fric=surffricvel, & ! (in) Turbulent friction velocity at surface (m/s)
655  surf_buoy=surfbuoyflux, & ! (in) Buoyancy flux at surface (m2/s3)
656  coriolis=coriolis, & ! (in) Coriolis parameter (1/s)
657  cvmix_kpp_params_user=cs%KPP_params ) ! KPP parameters
658 
659  ! A hack to avoid KPP reaching the bottom. It was needed during development
660  ! because KPP was unable to handle vanishingly small layers near the bottom.
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 )
664  endif
665 
666  ! apply some constraints on OBLdepth
667  if(cs%fixedOBLdepth) obldepth_0d = cs%fixedOBLdepth_value
668  obldepth_0d = max( obldepth_0d, -ifaceheight(2) ) ! no shallower than top layer
669  obldepth_0d = min( obldepth_0d, -ifaceheight(g%ke+1) ) ! no deeper than bottom
670  kobl = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, obldepth_0d )
671 
672 !*************************************************************************
673 ! smg: remove code below
674 
675 ! Following "correction" step has been found to be unnecessary.
676 ! Code should be removed after further testing.
677  if (cs%correctSurfLayerAvg) then
678 
679  sldepth_0d = cs%surf_layer_ext * obldepth_0d
680  htot = h(i,j,1)
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
685  pref = 0.0
686 
687  do k = 2, g%ke
688 
689  ! Recalculate differences with surface layer
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)
694  call calculate_density(surftemp, surfsalt, pref, rho1, eos)
695  call calculate_density(temp(i,j,k), salt(i,j,k), pref, rhok, eos)
696  deltarho(k) = rhok - rho1
697 
698  ! Surface layer averaging (needed for next k+1 iteration of this loop)
699  if (htot < sldepth_0d) then
700  delh = min( max(0., sldepth_0d - htot), h(i,j,k)*gv%H_to_m )
701  htot = htot + delh
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
706  endif
707 
708  enddo
709 
710  bulkri_1d = cvmix_kpp_compute_bulk_richardson( &
711  cellheight(1:g%ke), & ! Depth of cell center (m)
712  gorho*deltarho, & ! Bulk buoyancy difference, Br-B(z) (1/s)
713  deltau2, & ! Square of resolved velocity difference (m2/s2)
714  ws_cntr=ws_1d, & ! Turbulent velocity scale profile (m/s)
715  n_iface=n_1d ) ! Buoyancy frequency (1/s)
716 
717  surfbuoyflux = buoyflux(i,j,1) ! This is only used in kpp_compute_OBL_depth to limit
718  ! h to Monin-Obukov (default is false, ie. not used)
719 
720  call cvmix_kpp_compute_obl_depth( &
721  bulkri_1d, & ! (in) Bulk Richardson number
722  ifaceheight, & ! (in) Height of interfaces (m)
723  obldepth_0d, & ! (out) OBL depth (m)
724  kobl, & ! (out) level (+fraction) of OBL extent
725  zt_cntr=cellheight, & ! (in) Height of cell centers (m)
726  surf_fric=surffricvel, & ! (in) Turbulent friction velocity at surface (m/s)
727  surf_buoy=surfbuoyflux, & ! (in) Buoyancy flux at surface (m2/s3)
728  coriolis=coriolis, & ! (in) Coriolis parameter (1/s)
729  cvmix_kpp_params_user=cs%KPP_params ) ! KPP parameters
730 
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 )
735  endif
736 
737  ! apply some constraints on OBLdepth
738  if(cs%fixedOBLdepth) obldepth_0d = cs%fixedOBLdepth_value
739  obldepth_0d = max( obldepth_0d, -ifaceheight(2) ) ! no shallower than top layer
740  obldepth_0d = min( obldepth_0d, -ifaceheight(g%ke+1) ) ! no deep than bottom
741  kobl = cvmix_kpp_compute_kobl_depth( ifaceheight, cellheight, obldepth_0d )
742 
743  endif ! endif for "correction" step
744 
745 ! smg: remove code above
746 ! **********************************************************************
747 
748 
749  ! Call CVMix/KPP to obtain OBL diffusivities, viscosities and non-local transports
750 
751  ! Unlike LMD94, we do not match to interior diffusivities. If using the original
752  ! LMD94 shape function, not matching is equivalent to matching to a zero diffusivity.
753 
754  !BGR/ Add option for use of surface buoyancy flux with total sw flux.
755  if (cs%SW_METHOD .eq. sw_method_all_sw) then
756  surfbuoyflux = buoyflux(i,j,1)
757  elseif (cs%SW_METHOD .eq. sw_method_mxl_sw) then
758  surfbuoyflux = buoyflux(i,j,1) - buoyflux(i,j,int(kobl)+1) ! We know the actual buoyancy flux into the OBL
759  elseif (cs%SW_METHOD .eq. sw_method_lv1_sw) then
760  surfbuoyflux = buoyflux(i,j,1) - buoyflux(i,j,2)
761  endif
762 
763  ! If option "MatchBoth" is selected in CVMix, MOM should be capable of matching.
764  if (.not. (cs%MatchTechnique.eq.'MatchBoth')) then
765  kdiffusivity(:,:) = 0. ! Diffusivities for heat and salt (m2/s)
766  kviscosity(:) = 0. ! Viscosity (m2/s)
767  else
768  kdiffusivity(:,1) = kt(i,j,:)
769  kdiffusivity(:,2) = ks(i,j,:)
770  kviscosity(:)=kv(i,j,:)
771  endif
772 
773  call cvmix_coeffs_kpp(kviscosity, & ! (inout) Total viscosity (m2/s)
774  kdiffusivity(:,1), & ! (inout) Total heat diffusivity (m2/s)
775  kdiffusivity(:,2), & ! (inout) Total salt diffusivity (m2/s)
776  ifaceheight, & ! (in) Height of interfaces (m)
777  cellheight, & ! (in) Height of level centers (m)
778  kviscosity, & ! (in) Original viscosity (m2/s)
779  kdiffusivity(:,1), & ! (in) Original heat diffusivity (m2/s)
780  kdiffusivity(:,2), & ! (in) Original salt diffusivity (m2/s)
781  obldepth_0d, & ! (in) OBL depth (m)
782  kobl, & ! (in) level (+fraction) of OBL extent
783  nonlocaltrans(:,1),& ! (out) Non-local heat transport (non-dimensional)
784  nonlocaltrans(:,2),& ! (out) Non-local salt transport (non-dimensional)
785  surffricvel, & ! (in) Turbulent friction velocity at surface (m/s)
786  surfbuoyflux, & ! (in) Buoyancy flux at surface (m2/s3)
787  g%ke, & ! (in) Number of levels to compute coeffs for
788  g%ke, & ! (in) Number of levels in array shape
789  cvmix_kpp_params_user=cs%KPP_params )
790 
791 
792  ! Over-write CVMix NLT shape function with one of the following choices.
793  ! The CVMix code has yet to update for thse options, so we compute in MOM6.
794  ! Note that nonLocalTrans = Cs * G(sigma) (LMD94 notation), with
795  ! Cs = 6.32739901508.
796  ! Start do-loop at k=2, since k=1 is ocean surface (sigma=0)
797  ! and we do not wish to double-count the surface forcing.
798  ! Only compute nonlocal transport for 0 <= sigma <= 1.
799  ! MOM6 recommended shape is the parabolic; it gives deeper boundary layer
800  ! and no spurious extrema.
801  if (surfbuoyflux < 0.0) then
802  if (cs%NLT_shape == nlt_shape_cubic) then
803  do k = 2, g%ke
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)
807  enddo
808  elseif (cs%NLT_shape == nlt_shape_parabolic) then
809  do k = 2, g%ke
810  sigma = min(1.0,-ifaceheight(k)/obldepth_0d)
811  nonlocaltrans(k,1) = (1.0 - sigma)**2 !*CS%CS2
812  nonlocaltrans(k,2) = nonlocaltrans(k,1)
813  enddo
814  elseif (cs%NLT_shape == nlt_shape_linear) then
815  do k = 2, g%ke
816  sigma = min(1.0,-ifaceheight(k)/obldepth_0d)
817  nonlocaltrans(k,1) = (1.0 - sigma)!*CS%CS2
818  nonlocaltrans(k,2) = nonlocaltrans(k,1)
819  enddo
820  elseif (cs%NLT_shape == nlt_shape_cubic_lmd) then
821  ! Sanity check (should agree with CVMix result using simple matching)
822  do k = 2, g%ke
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)
826  enddo
827  endif
828  endif
829 
830  ! we apply nonLocalTrans in subroutines
831  ! KPP_NonLocalTransport_temp and KPP_NonLocalTransport_saln
832  nonlocaltransheat(i,j,:) = nonlocaltrans(:,1) ! temp
833  nonlocaltransscalar(i,j,:) = nonlocaltrans(:,2) ! saln
834 
835  ! set the KPP diffusivity and viscosity to zero for testing purposes
836  if(cs%KPPzeroDiffusivity) then
837  kdiffusivity(:,1) = 0.0
838  kdiffusivity(:,2) = 0.0
839  kviscosity(:) = 0.0
840  endif
841 
842  ! recompute wscale for diagnostics, now that we in fact know boundary layer depth
843  if (cs%id_Ws > 0) then
844  call cvmix_kpp_compute_turbulent_scales( &
845  -cellheight/obldepth_0d, & ! (in) Normalized boundary layer coordinate
846  obldepth_0d, & ! (in) OBL depth (m)
847  surfbuoyflux, & ! (in) Buoyancy flux at surface (m2/s3)
848  surffricvel, & ! (in) Turbulent friction velocity at surface (m/s)
849  w_s=ws_1d, & ! (out) Turbulent velocity scale profile (m/s)
850  cvmix_kpp_params_user=cs%KPP_params & ! KPP parameters
851  )
852  cs%Ws(i,j,:) = ws_1d(:)
853  endif
854 
855  ! compute unresolved squared velocity for diagnostics
856  if (cs%id_Vt2 > 0) then
857  vt2_1d(:) = cvmix_kpp_compute_unresolved_shear( &
858  cellheight(1:g%ke), & ! Depth of cell center (m)
859  ws_cntr=ws_1d, & ! Turbulent velocity scale profile, at centers (m/s)
860  n_iface=n_1d, & ! Buoyancy frequency at interface (1/s)
861  cvmix_kpp_params_user=cs%KPP_params ) ! KPP parameters
862  cs%Vt2(i,j,:) = vt2_1d(:)
863  endif
864 
865  ! Copy 1d data into 3d diagnostic arrays
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
871  cs%sigma(i,j,:) = 0.
872  if (obldepth_0d>0.) cs%sigma(i,j,:) = -ifaceheight/obldepth_0d
873  endif
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
883 
884 
885  ! Update output of routine
886  if (.not. cs%passiveMode) then
887  if (cs%KPPisAdditive) then
888  do k=1, g%ke+1
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)
892  enddo
893  else ! KPP replaces prior diffusivity when former is non-zero
894  do k=1, g%ke+1
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)
898  enddo
899  endif
900  endif
901 
902 
903  ! end of the horizontal do-loops over the vertical columns
904  enddo ! i
905  enddo ! j
906 
907 
908 #ifdef __DO_SAFETY_CHECKS__
909  if (cs%debug) then
910  call hchksum(kt, "KPP out: Kt",g%HI,haloshift=0)
911  call hchksum(ks, "KPP out: Ks",g%HI,haloshift=0)
912  endif
913 #endif
914 
915  ! send diagnostics to post_data
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)
936 
937 end subroutine kpp_calculate
938 
939 
940 
941 !> Apply KPP non-local transport of surface fluxes for temperature.
942 subroutine kpp_nonlocaltransport_temp(CS, G, GV, h, nonLocalTrans, surfFlux, &
943  dt, scalar, C_p)
945  type(kpp_cs), intent(in) :: CS !< Control structure
946  type(ocean_grid_type), intent(in) :: G !< Ocean grid
947  type(verticalgrid_type), intent(in) :: GV !< Ocean vertical grid
948  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer/level thickness (units of H)
949  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(in) :: nonLocalTrans !< Non-local transport (non-dimensional)
950  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: surfFlux !< Surface flux of scalar (H/s * scalar)
951  real, intent(in) :: dt !< Time-step (s)
952  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: scalar !< temperature
953  real, intent(in) :: C_p !< Seawater specific heat capacity (J/(kg*K))
954 
955  integer :: i, j, k
956  real, dimension( SZI_(G), SZJ_(G), SZK_(G) ) :: dtracer
957 
958 
959  dtracer(:,:,:) = 0.0
960 !$OMP parallel do default(none) shared(G,GV,dtracer,nonLocalTrans,h,surfFlux,CS,scalar,dt)
961  do k = 1, g%ke
962  do j = g%jsc, g%jec
963  do i = g%isc, g%iec
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)
966  enddo
967  enddo
968  enddo
969 
970  ! Update tracer due to non-local redistribution of surface flux
971  if (cs%applyNonLocalTrans) then
972  do k = 1, g%ke
973  do j = g%jsc, g%jec
974  do i = g%isc, g%iec
975  scalar(i,j,k) = scalar(i,j,k) + dt * dtracer(i,j,k)
976  enddo
977  enddo
978  enddo
979  endif
980 
981  ! Diagnostics
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
985  dtracer(:,:,:) = 0.0
986  do k = 1, g%ke
987  do j = g%jsc, g%jec
988  do i = g%isc, g%iec
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
991  enddo
992  enddo
993  enddo
994  call post_data(cs%id_NLT_temp_budget, dtracer, cs%diag)
995  endif
996 
997 end subroutine kpp_nonlocaltransport_temp
998 
999 
1000 !> Apply KPP non-local transport of surface fluxes for salinity.
1001 !> This routine is a useful prototype for other material tracers.
1002 subroutine kpp_nonlocaltransport_saln(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar)
1004  type(kpp_cs), intent(in) :: CS !< Control structure
1005  type(ocean_grid_type), intent(in) :: G !< Ocean grid
1006  type(verticalgrid_type), intent(in) :: GV !< Ocean vertical grid
1007  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< Layer/level thickness (units of H)
1008  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), intent(in) :: nonLocalTrans !< Non-local transport (non-dimensional)
1009  real, dimension(SZI_(G),SZJ_(G)), intent(in) :: surfFlux !< Surface flux of scalar (H/s * scalar)
1010  real, intent(in) :: dt !< Time-step (s)
1011  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: scalar !< Scalar (scalar units)
1012 
1013  integer :: i, j, k
1014  real, dimension( SZI_(G), SZJ_(G), SZK_(G) ) :: dtracer
1015 
1016 
1017  dtracer(:,:,:) = 0.0
1018 !$OMP parallel do default(none) shared(G,GV,dtracer,nonLocalTrans,h,surfFlux,CS,scalar,dt)
1019  do k = 1, g%ke
1020  do j = g%jsc, g%jec
1021  do i = g%isc, g%iec
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)
1024  enddo
1025  enddo
1026  enddo
1027 
1028  ! Update tracer due to non-local redistribution of surface flux
1029  if (cs%applyNonLocalTrans) then
1030  do k = 1, g%ke
1031  do j = g%jsc, g%jec
1032  do i = g%isc, g%iec
1033  scalar(i,j,k) = scalar(i,j,k) + dt * dtracer(i,j,k)
1034  enddo
1035  enddo
1036  enddo
1037  endif
1038 
1039  ! Diagnostics
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
1044  do k = 1, g%ke
1045  do j = g%jsc, g%jec
1046  do i = g%isc, g%iec
1047  dtracer(i,j,k) = (nonlocaltrans(i,j,k) - nonlocaltrans(i,j,k+1)) * &
1048  surfflux(i,j) * gv%H_to_kg_m2
1049  enddo
1050  enddo
1051  enddo
1052  call post_data(cs%id_NLT_saln_budget, dtracer, cs%diag)
1053  endif
1054 
1055 end subroutine kpp_nonlocaltransport_saln
1056 
1057 
1058 
1059 
1060 !> Clear pointers, deallocate memory
1061 subroutine kpp_end(CS)
1062  type(kpp_cs), pointer :: CS !< Control structure
1063 
1064  deallocate(cs)
1065 end subroutine kpp_end
1066 
1067 !> \namespace mom_kpp
1068 !!
1069 !! \section section_KPP The K-Profile Parameterization
1070 !!
1071 !! The K-Profile Parameterization (KPP) of Large et al., 1994, (http://dx.doi.org/10.1029/94RG01872) is
1072 !! implemented via the Community Vertical Mixing package, [CVmix](https://code.google.com/p/cvmix),
1073 !! which is called directly by this module.
1074 !!
1075 !! The formulation and implementation of KPP is described in great detail in the
1076 !! [CVMix manual](https://cvmix.googlecode.com/svn/trunk/manual/cvmix.pdf) (written by our own Stephen Griffies).
1077 !!
1078 !! \subsection section_KPP_nutshell KPP in a nutshell
1079 !!
1080 !! Large et al., 1994, decompose the parameterized boundary layer turbulent flux of a scalar, \f$ s \f$, as
1081 !! \f[ \overline{w^\prime s^\prime} = -K \partial_z s + K \gamma_s(\sigma), \f]
1082 !! where \f$ \sigma = -z/h \f$ is a non-dimensional coordinate within the boundary layer of depth \f$ h \f$.
1083 !! \f$ K \f$ is the eddy diffusivity and is a function of position within the boundary layer as well as a
1084 !! function of the surface forcing:
1085 !! \f[ K = h w_s(\sigma) G(\sigma) . \f]
1086 !! Here, \f$ w_s \f$ is the vertical velocity scale of the boundary layer turbulence and \f$ G(\sigma) \f$ is
1087 !! a "shape function" which is described later.
1088 !! The last term is the "non-local transport" which involves a function \f$ \gamma_s(\sigma) \f$ that is matched
1089 !! to the forcing but is not actually needed in the final implementation.
1090 !! Instead, the entire non-local transport term can be equivalently written
1091 !! \f[ K \gamma_s(\sigma) = C_s G(\sigma) Q_s \f]
1092 !! where \f$ Q_s \f$ is the surface flux of \f$ s \f$ and \f$ C_s \f$ is a constant.
1093 !! The vertical structure of the redistribution (non-local) term is solely due to the shape function, \f$ G(\sigma) \f$.
1094 !! In our implementation of KPP, we allow the shape functions used for \f$ K \f$ and for the non-local transport
1095 !! to be chosen independently.
1096 !!
1097 !! [google_thread_NLT]: https://groups.google.com/forum/#!msg/cvmix-dev/i6rF-eHOtKI/Ti8BeyksrhAJ "Extreme values of non-local transport"
1098 !!
1099 !! The particular shape function most widely used in the atmospheric community is
1100 !! \f[ G(\sigma) = \sigma (1-\sigma)^2 \f]
1101 !! which satisfies the boundary conditions
1102 !! \f$ G(0) = 0 \f$,
1103 !! \f$ G(1) = 0 \f$,
1104 !! \f$ G^\prime(0) = 1 \f$, and
1105 !! \f$ G^\prime(1) = 0 \f$.
1106 !! Large et al, 1994, alter the function so as to match interior diffusivities but we have found that this leads
1107 !! to inconsistencies within the formulation (see google groups thread [Extreme values of non-local transport][google_thread_NLT]).
1108 !! Instead, we use either the above form, or even simpler forms that use alternative upper boundary conditions.
1109 !!
1110 !! The KPP boundary layer depth is a function of the bulk Richardson number, Rib.
1111 !! But to compute Rib, we need the boundary layer depth. To address this circular
1112 !! logic, we compute Rib for each vertical cell in a column, assuming the BL depth
1113 !! equals to the depth of the given grid cell. Once we have a vertical array of Rib(k),
1114 !! we then call the OBLdepth routine from CVMix to compute the actual
1115 !! OBLdepth. We optionally then "correct" the OBLdepth by cycling through once more,
1116 !! this time knowing the OBLdepth from the first pass. This "correction" step is not
1117 !! used by NCAR. It has been found in idealized MOM6 tests to not be necessary.
1118 !!
1119 !! \sa
1120 !! kpp_calculate(), kpp_applynonlocaltransport()
1121 end module mom_kpp
logical function, public ispointincell(G, i, j, x, y)
Returns true if the coordinates (x,y) are within the h-cell (i,j)
Definition: MOM_grid.F90:406
integer, parameter, private sw_method_all_sw
Use all shortwave radiation.
Definition: MOM_KPP.F90:43
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Control structure for containing KPP parameters/data.
Definition: MOM_KPP.F90:48
integer, parameter, private sw_method_mxl_sw
Use shortwave radiation absorbed in mixing layer.
Definition: MOM_KPP.F90:44
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.
Definition: MOM_KPP.F90:413
integer, parameter, private sw_method_lv1_sw
Use shortwave radiation absorbed in layer 1.
Definition: MOM_KPP.F90:45
logical function, public query_averaging_enabled(diag_cs, time_int, time_end)
integer, parameter, private nlt_shape_cvmix
Use the CVmix profile.
Definition: MOM_KPP.F90:37
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.
Definition: MOM_KPP.F90:1062
integer, parameter, private nlt_shape_cubic_lmd
Original shape, .
Definition: MOM_KPP.F90:41
subroutine, public mom_mesg(message, verb, all_print)
logical, parameter verbose
Definition: MOM_KPP.F90:125
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...
Definition: MOM_KPP.F90:133
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
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.
Definition: MOM_KPP.F90:944
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 ...
Definition: MOM_KPP.F90:1003
Provides the K-Profile Parameterization (KPP) of Large et al., 1994, via CVMix.
Definition: MOM_KPP.F90:2
integer function, public register_diag_field(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name, cell_methods, x_cell_method, y_cell_method, v_cell_method, conversion, v_extensive)
Returns the "diag_mediator" handle for a group (native, CMOR, z-coord, ...) of diagnostics derived fr...
subroutine, public mom_error(level, message, all_print)
A control structure for the equation of state.
Definition: MOM_EOS.F90:55
integer, parameter, private nlt_shape_parabolic
Parabolic, .
Definition: MOM_KPP.F90:39
integer, parameter, private nlt_shape_linear
Linear, .
Definition: MOM_KPP.F90:38
integer, parameter, private nlt_shape_cubic
Cubic, .
Definition: MOM_KPP.F90:40