MOM6
MOM_energetic_PBL.F90
1 !> Energetically consistent planetary boundary layer parameterization
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, clock_routine
7 use mom_coms, only : efp_type, real_to_efp, efp_to_real, operator(+), assignment(=), efp_sum_across_pes
8 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_alloc
9 use mom_diag_mediator, only : time_type, diag_ctrl
10 use mom_domains, only : create_group_pass, do_group_pass, group_pass_type
11 use mom_error_handler, only : mom_error, fatal, warning, mom_mesg
13 use mom_forcing_type, only : forcing
14 use mom_grid, only : ocean_grid_type
15 use mom_string_functions, only : uppercase
19 use mom_wave_interface, only: wave_parameters_cs, get_langmuir_number
20 
21 implicit none ; private
22 
23 #include <MOM_memory.h>
24 
25 public energetic_pbl, energetic_pbl_init, energetic_pbl_end
26 public energetic_pbl_get_mld
27 
28 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
29 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
30 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
31 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
32 
33 !> This control structure holds parameters for the MOM_energetic_PBL module
34 type, public :: energetic_pbl_cs ; private
35 
36  !/ Constants
37  real :: vonkar = 0.41 !< The von Karman coefficient. This should be a runtime parameter,
38  !! but because it is set to 0.4 at runtime in KPP it might change answers.
39  real :: omega !< The Earth's rotation rate [T-1 ~> s-1].
40  real :: omega_frac !< When setting the decay scale for turbulence, use this fraction of
41  !! the absolute rotation rate blended with the local value of f, as
42  !! sqrt((1-omega_frac)*f^2 + omega_frac*4*omega^2) [nondim].
43 
44  !/ Convection related terms
45  real :: nstar !< The fraction of the TKE input to the mixed layer available to drive
46  !! entrainment [nondim]. This quantity is the vertically integrated
47  !! buoyancy production minus the vertically integrated dissipation of
48  !! TKE produced by buoyancy.
49 
50  !/ Mixing Length terms
51  logical :: use_mld_iteration !< If true, use the proximity to the bottom of the actively turbulent
52  !! surface boundary layer to constrain the mixing lengths.
53  logical :: mld_iteration_guess !< False to default to guessing half the
54  !! ocean depth for the first iteration.
55  logical :: mld_bisection !< If true, use bisection with the iterative determination of the
56  !! self-consistent mixed layer depth. Otherwise use the false position
57  !! after a maximum and minimum bound have been evaluated and the
58  !! returned value from the previous guess or bisection before this.
59  integer :: max_mld_its !< The maximum number of iterations that can be used to find a
60  !! self-consistent mixed layer depth with Use_MLD_iteration.
61  real :: mixlenexponent !< Exponent in the mixing length shape-function.
62  !! 1 is law-of-the-wall at top and bottom,
63  !! 2 is more KPP like.
64  real :: mke_to_tke_effic !< The efficiency with which mean kinetic energy released by
65  !! mechanically forced entrainment of the mixed layer is converted to
66  !! TKE [nondim].
67  real :: ustar_min !< A minimum value of ustar to avoid numerical problems [Z T-1 ~> m s-1].
68  !! If the value is small enough, this should not affect the solution.
69  real :: ekman_scale_coef !< A nondimensional scaling factor controlling the inhibition of the
70  !! diffusive length scale by rotation. Making this larger decreases
71  !! the diffusivity in the planetary boundary layer.
72  real :: translay_scale !< A scale for the mixing length in the transition layer
73  !! at the edge of the boundary layer as a fraction of the
74  !! boundary layer thickness. The default is 0, but a
75  !! value of 0.1 might be better justified by observations.
76  real :: mld_tol !< A tolerance for determining the boundary layer thickness when
77  !! Use_MLD_iteration is true [Z ~> m].
78  real :: min_mix_len !< The minimum mixing length scale that will be used by ePBL [Z ~> m].
79  !! The default (0) does not set a minimum.
80 
81  !/ Velocity scale terms
82  integer :: wt_scheme !< An enumerated value indicating the method for finding the turbulent
83  !! velocity scale. There are currently two options:
84  !! wT_mwT_from_cRoot_TKE is the original (TKE_remaining)^1/3
85  !! wT_from_RH18 is the version described by Reichl and Hallberg, 2018
86  real :: wstar_ustar_coef !< A ratio relating the efficiency with which convectively released
87  !! energy is converted to a turbulent velocity, relative to
88  !! mechanically forced turbulent kinetic energy [nondim].
89  !! Making this larger increases the diffusivity.
90  real :: vstar_surf_fac !< If (wT_scheme == wT_from_RH18) this is the proportionality coefficient between
91  !! ustar and the surface mechanical contribution to vstar [nondim]
92  real :: vstar_scale_fac !< An overall nondimensional scaling factor for vstar times a unit
93  !! conversion factor [Z s T-1 m-1 ~> nondim]. Making this larger increases
94  !! the diffusivity.
95 
96  !mstar related options
97  integer :: mstar_scheme !< An encoded integer to determine which formula is used to set mstar
98  logical :: mstar_flatcap=.true. !< Set false to use asymptotic mstar cap.
99  real :: mstar_cap !< Since MSTAR is restoring undissipated energy to mixing,
100  !! there must be a cap on how large it can be. This
101  !! is definitely a function of latitude (Ekman limit),
102  !! but will be taken as constant for now.
103 
104  !/ vertical decay related options
105  real :: tke_decay !< The ratio of the natural Ekman depth to the TKE decay scale [nondim].
106 
107  !/ mstar_scheme == 0
108  real :: fixed_mstar !< Mstar is the ratio of the friction velocity cubed to the TKE available to
109  !! drive entrainment, nondimensional. This quantity is the vertically
110  !! integrated shear production minus the vertically integrated
111  !! dissipation of TKE produced by shear. This value is used if the option
112  !! for using a fixed mstar is used.
113 
114  !/ mstar_scheme == 2
115  real :: c_ek = 0.17 !< MSTAR Coefficient in rotation limit for mstar_scheme=OM4
116  real :: mstar_coef = 0.3 !< MSTAR coefficient in rotation/stabilizing balance for mstar_scheme=OM4
117 
118  !/ mstar_scheme == 3
119  real :: rh18_mstar_cn1 !< MSTAR_N coefficient 1 (outter-most coefficient for fit).
120  !! Value of 0.275 in RH18. Increasing this
121  !! coefficient increases mechanical mixing for all values of Hf/ust,
122  !! but is most effective at low values (weakly developed OSBLs).
123  real :: rh18_mstar_cn2 !< MSTAR_N coefficient 2 (coefficient outside of exponential decay).
124  !! Value of 8.0 in RH18. Increasing this coefficient increases MSTAR
125  !! for all values of HF/ust, with a consistent affect across
126  !! a wide range of Hf/ust.
127  real :: rh18_mstar_cn3 !< MSTAR_N coefficient 3 (exponential decay coefficient). Value of
128  !! -5.0 in RH18. Increasing this increases how quickly the value
129  !! of MSTAR decreases as Hf/ust increases.
130  real :: rh18_mstar_cs1 !< MSTAR_S coefficient for RH18 in stabilizing limit.
131  !! Value of 0.2 in RH18.
132  real :: rh18_mstar_cs2 !< MSTAR_S exponent for RH18 in stabilizing limit.
133  !! Value of 0.4 in RH18.
134 
135  !/ Coefficient for shear/convective turbulence interaction
136  real :: mstar_convect_coef !< Factor to reduce mstar when statically unstable.
137 
138  !/ Langmuir turbulence related parameters
139  logical :: use_lt = .false. !< Flag for using LT in Energy calculation
140  integer :: lt_enhance_form !< Integer for Enhancement functional form (various options)
141  real :: lt_enhance_coef !< Coefficient in fit for Langmuir Enhancment
142  real :: lt_enhance_exp !< Exponent in fit for Langmuir Enhancement
143  real :: lac_mldoek !< Coefficient for Langmuir number modification based on the ratio of
144  !! the mixed layer depth over the Ekman depth.
145  real :: lac_mldoob_stab !< Coefficient for Langmuir number modification based on the ratio of
146  !! the mixed layer depth over the Obukov depth with stablizing forcing.
147  real :: lac_ekoob_stab !< Coefficient for Langmuir number modification based on the ratio of
148  !! the Ekman depth over the Obukov depth with stablizing forcing.
149  real :: lac_mldoob_un !< Coefficient for Langmuir number modification based on the ratio of
150  !! the mixed layer depth over the Obukov depth with destablizing forcing.
151  real :: lac_ekoob_un !< Coefficient for Langmuir number modification based on the ratio of
152  !! the Ekman depth over the Obukov depth with destablizing forcing.
153  real :: max_enhance_m = 5. !< The maximum allowed LT enhancement to the mixing.
154 
155  !/ Others
156  type(time_type), pointer :: time=>null() !< A pointer to the ocean model's clock.
157 
158  logical :: tke_diagnostics = .false. !< If true, diagnostics of the TKE budget are being calculated.
159  logical :: answers_2018 !< If true, use the order of arithmetic and expressions that recover the
160  !! answers from the end of 2018. Otherwise, use updated and more robust
161  !! forms of the same expressions.
162  logical :: orig_pe_calc !< If true, the ePBL code uses the original form of the
163  !! potential energy change code. Otherwise, it uses a newer version
164  !! that can work with successive increments to the diffusivity in
165  !! upward or downward passes.
166  type(diag_ctrl), pointer :: diag=>null() !< A structure that is used to regulate the
167  !! timing of diagnostic output.
168 
169  real, allocatable, dimension(:,:) :: &
170  ml_depth !< The mixed layer depth determined by active mixing in ePBL [Z ~> m].
171 
172  ! These are terms in the mixed layer TKE budget, all in [R Z3 T-3 ~> W m-2 = kg s-3].
173  real, allocatable, dimension(:,:) :: &
174  diag_tke_wind, & !< The wind source of TKE [R Z3 T-3 ~> W m-2].
175  diag_tke_mke, & !< The resolved KE source of TKE [R Z3 T-3 ~> W m-2].
176  diag_tke_conv, & !< The convective source of TKE [R Z3 T-3 ~> W m-2].
177  diag_tke_forcing, & !< The TKE sink required to mix surface penetrating shortwave heating
178  !! [R Z3 T-3 ~> W m-2].
179  diag_tke_mech_decay, & !< The decay of mechanical TKE [R Z3 T-3 ~> W m-2].
180  diag_tke_conv_decay, & !< The decay of convective TKE [R Z3 T-3 ~> W m-2].
181  diag_tke_mixing, & !< The work done by TKE to deepen the mixed layer [R Z3 T-3 ~> W m-2].
182  ! These additional diagnostics are also 2d.
183  mstar_mix, & !< Mstar used in EPBL [nondim]
184  mstar_lt, & !< Mstar due to Langmuir turbulence [nondim]
185  la, & !< Langmuir number [nondim]
186  la_mod !< Modified Langmuir number [nondim]
187 
188  type(efp_type), dimension(2) :: sum_its !< The total number of iterations and columns worked on
189 
190  real, allocatable, dimension(:,:,:) :: &
191  velocity_scale, & !< The velocity scale used in getting Kd [Z T-1 ~> m s-1]
192  mixing_length !< The length scale used in getting Kd [Z ~> m]
193  !>@{ Diagnostic IDs
194  integer :: id_ml_depth = -1, id_hml_depth = -1, id_tke_wind = -1, id_tke_mixing = -1
195  integer :: id_tke_mke = -1, id_tke_conv = -1, id_tke_forcing = -1
196  integer :: id_tke_mech_decay = -1, id_tke_conv_decay = -1
197  integer :: id_mixing_length = -1, id_velocity_scale = -1
198  integer :: id_mstar_mix = -1, id_la_mod = -1, id_la = -1, id_mstar_lt = -1
199  !>@}
200 end type energetic_pbl_cs
201 
202 !>@{ Enumeration values for mstar_Scheme
203 integer, parameter :: use_fixed_mstar = 0 !< The value of mstar_scheme to use a constant mstar
204 integer, parameter :: mstar_from_ekman = 2 !< The value of mstar_scheme to base mstar on the ratio
205  !! of the Ekman layer depth to the Obukhov depth
206 integer, parameter :: mstar_from_rh18 = 3 !< The value of mstar_scheme to base mstar of of RH18
207 integer, parameter :: no_langmuir = 0 !< The value of LT_ENHANCE_FORM not use Langmuir turbolence.
208 integer, parameter :: langmuir_rescale = 2 !< The value of LT_ENHANCE_FORM to use a multiplicative
209  !! rescaling of mstar to account for Langmuir turbulence.
210 integer, parameter :: langmuir_add = 3 !< The value of LT_ENHANCE_FORM to add a contribution to
211  !! mstar from Langmuir turblence to other contributions.
212 integer, parameter :: wt_from_croot_tke = 0 !< Use a constant times the cube root of remaining TKE
213  !! to calculate the turbulent velocity.
214 integer, parameter :: wt_from_rh18 = 1 !< Use a scheme based on a combination of w* and v* as
215  !! documented in Reichl & Hallberg (2018) to calculate
216  !! the turbulent velocity.
217 character*(20), parameter :: constant_string = "CONSTANT"
218 character*(20), parameter :: om4_string = "OM4"
219 character*(20), parameter :: rh18_string = "REICHL_H18"
220 character*(20), parameter :: root_tke_string = "CUBE_ROOT_TKE"
221 character*(20), parameter :: none_string = "NONE"
222 character*(20), parameter :: rescaled_string = "RESCALE"
223 character*(20), parameter :: additive_string = "ADDITIVE"
224 !>@}
225 
226 logical :: report_avg_its = .false. !< Report the average number of ePBL iterations for debugging.
227 
228 !> A type for conveniently passing around ePBL diagnostics for a column.
229 type, public :: epbl_column_diags ; private
230  !>@{ Local column copies of energy change diagnostics, all in [R Z3 T-3 ~> W m-2].
231  real :: dtke_conv, dtke_forcing, dtke_wind, dtke_mixing
232  real :: dtke_mke, dtke_mech_decay, dtke_conv_decay
233  !>@}
234  real :: la !< The value of the Langmuir number [nondim]
235  real :: lamod !< The modified Langmuir number by convection [nondim]
236  real :: mstar !< The value of mstar used in ePBL [nondim]
237  real :: mstar_lt !< The portion of mstar due to Langmuir turbulence [nondim]
238  real, allocatable, dimension(:) :: dt_expect !< Expected temperature changes [degC]
239  real, allocatable, dimension(:) :: ds_expect !< Expected salinity changes [ppt]
240 end type epbl_column_diags
241 
242 contains
243 
244 !> This subroutine determines the diffusivities from the integrated energetics
245 !! mixed layer model. It assumes that heating, cooling and freshwater fluxes
246 !! have already been applied. All calculations are done implicitly, and there
247 !! is no stability limit on the time step.
248 subroutine energetic_pbl(h_3d, u_3d, v_3d, tv, fluxes, dt, Kd_int, G, GV, US, CS, &
249  dSV_dT, dSV_dS, TKE_forced, buoy_flux, dt_diag, last_call, &
250  dT_expected, dS_expected, Waves )
251  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure.
252  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
253  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
254  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
255  intent(inout) :: h_3d !< Layer thicknesses [H ~> m or kg m-2].
256  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
257  intent(in) :: u_3d !< Zonal velocities interpolated to h points
258  !! [L T-1 ~> m s-1].
259  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
260  intent(in) :: v_3d !< Zonal velocities interpolated to h points
261  !! [L T-1 ~> m s-1].
262  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
263  intent(in) :: dsv_dt !< The partial derivative of in-situ specific
264  !! volume with potential temperature
265  !! [R-1 degC-1 ~> m3 kg-1 degC-1].
266  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
267  intent(in) :: dsv_ds !< The partial derivative of in-situ specific
268  !! volume with salinity [R-1 ppt-1 ~> m3 kg-1 ppt-1].
269  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
270  intent(in) :: tke_forced !< The forcing requirements to homogenize the
271  !! forcing that has been applied to each layer
272  !! [R Z3 T-2 ~> J m-2].
273  type(thermo_var_ptrs), intent(inout) :: tv !< A structure containing pointers to any
274  !! available thermodynamic fields. Absent fields
275  !! have NULL ptrs.
276  type(forcing), intent(inout) :: fluxes !< A structure containing pointers to any
277  !! possible forcing fields. Unused fields have
278  !! NULL ptrs.
279  real, intent(in) :: dt !< Time increment [T ~> s].
280  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
281  intent(out) :: kd_int !< The diagnosed diffusivities at interfaces
282  !! [Z2 s-1 ~> m2 s-1].
283  type(energetic_pbl_cs), pointer :: cs !< The control structure returned by a previous
284  !! call to mixedlayer_init.
285  real, dimension(SZI_(G),SZJ_(G)), &
286  intent(in) :: buoy_flux !< The surface buoyancy flux [Z2 T-3 ~> m2 s-3].
287  real, optional, intent(in) :: dt_diag !< The diagnostic time step, which may be less
288  !! than dt if there are two calls to mixedlayer [T ~> s].
289  logical, optional, intent(in) :: last_call !< If true, this is the last call to
290  !! mixedlayer in the current time step, so
291  !! diagnostics will be written. The default
292  !! is .true.
293  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
294  optional, intent(out) :: dt_expected !< The values of temperature change that
295  !! should be expected when the returned
296  !! diffusivities are applied [degC].
297  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
298  optional, intent(out) :: ds_expected !< The values of salinity change that
299  !! should be expected when the returned
300  !! diffusivities are applied [ppt].
301  type(wave_parameters_cs), &
302  optional, pointer :: waves !< Wave CS
303 
304 ! This subroutine determines the diffusivities from the integrated energetics
305 ! mixed layer model. It assumes that heating, cooling and freshwater fluxes
306 ! have already been applied. All calculations are done implicitly, and there
307 ! is no stability limit on the time step.
308 !
309 ! For each interior interface, first discard the TKE to account for mixing
310 ! of shortwave radiation through the next denser cell. Next drive mixing based
311 ! on the local? values of ustar + wstar, subject to available energy. This
312 ! step sets the value of Kd(K). Any remaining energy is then subject to decay
313 ! before being handed off to the next interface. mech_TKE and conv_PErel are treated
314 ! separately for the purposes of decay, but are used proportionately to drive
315 ! mixing.
316 !
317 ! The key parameters for the mixed layer are found in the control structure.
318 ! To use the classic constant mstar mixied layers choose MSTAR_SCHEME=CONSTANT.
319 ! The key parameters then include mstar, nstar, TKE_decay, and conv_decay.
320 ! For the Oberhuber (1993) mixed layer,the values of these are:
321 ! mstar = 1.25, nstar = 1, TKE_decay = 2.5, conv_decay = 0.5
322 ! TKE_decay is 1/kappa in eq. 28 of Oberhuber (1993), while conv_decay is 1/mu.
323 ! For a traditional Kraus-Turner mixed layer, the values are:
324 ! mstar = 1.25, nstar = 0.4, TKE_decay = 0.0, conv_decay = 0.0
325 
326  ! Local variables
327  real, dimension(SZI_(G),SZK_(GV)) :: &
328  h_2d, & ! A 2-d slice of the layer thickness [H ~> m or kg m-2].
329  t_2d, & ! A 2-d slice of the layer temperatures [degC].
330  s_2d, & ! A 2-d slice of the layer salinities [ppt].
331  tke_forced_2d, & ! A 2-d slice of TKE_forced [R Z3 T-2 ~> J m-2].
332  dsv_dt_2d, & ! A 2-d slice of dSV_dT [R-1 degC-1 ~> m3 kg-1 degC-1].
333  dsv_ds_2d, & ! A 2-d slice of dSV_dS [R-1 ppt-1 ~> m3 kg-1 ppt-1].
334  u_2d, & ! A 2-d slice of the zonal velocity [L T-1 ~> m s-1].
335  v_2d ! A 2-d slice of the meridional velocity [L T-1 ~> m s-1].
336  real, dimension(SZI_(G),SZK_(GV)+1) :: &
337  kd_2d ! A 2-d version of the diapycnal diffusivity [Z2 T-1 ~> m2 s-1].
338  real, dimension(SZK_(GV)) :: &
339  h, & ! The layer thickness [H ~> m or kg m-2].
340  t0, & ! The initial layer temperatures [degC].
341  s0, & ! The initial layer salinities [ppt].
342  dsv_dt_1d, & ! The partial derivatives of specific volume with temperature [R-1 degC-1 ~> m3 kg-1 degC-1].
343  dsv_ds_1d, & ! The partial derivatives of specific volume with salinity [R-1 ppt-1 ~> m3 kg-1 ppt-1].
344  tke_forcing, & ! Forcing of the TKE in the layer coming from TKE_forced [R Z3 T-2 ~> J m-2].
345  u, & ! The zonal velocity [L T-1 ~> m s-1].
346  v ! The meridional velocity [L T-1 ~> m s-1].
347  real, dimension(SZK_(GV)+1) :: &
348  kd, & ! The diapycnal diffusivity [Z2 T-1 ~> m2 s-1].
349  mixvel, & ! A turbulent mixing veloxity [Z T-1 ~> m s-1].
350  mixlen ! A turbulent mixing length [Z ~> m].
351  real :: h_neglect ! A thickness that is so small it is usually lost
352  ! in roundoff and can be neglected [H ~> m or kg m-2].
353 
354  real :: absf ! The absolute value of f [T-1 ~> s-1].
355  real :: u_star ! The surface friction velocity [Z T-1 ~> m s-1].
356  real :: u_star_mean ! The surface friction without gustiness [Z T-1 ~> m s-1].
357  real :: b_flux ! The surface buoyancy flux [Z2 T-3 ~> m2 s-3]
358  real :: mld_io ! The mixed layer depth found by ePBL_column [Z ~> m].
359 
360 ! The following are only used for diagnostics.
361  real :: dt__diag ! A copy of dt_diag (if present) or dt [T ~> s].
362  logical :: write_diags ! If true, write out diagnostics with this step.
363  logical :: reset_diags ! If true, zero out the accumulated diagnostics.
364 
365  logical :: debug=.false. ! Change this hard-coded value for debugging.
366  type(epbl_column_diags) :: ecd ! A container for passing around diagnostics.
367 
368  integer :: i, j, k, is, ie, js, je, nz
369 
370  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
371 
372  if (.not. associated(cs)) call mom_error(fatal, "energetic_PBL: "//&
373  "Module must be initialized before it is used.")
374 
375  if (.not. associated(tv%eqn_of_state)) call mom_error(fatal, &
376  "energetic_PBL: Temperature, salinity and an equation of state "//&
377  "must now be used.")
378  if (.NOT. associated(fluxes%ustar)) call mom_error(fatal, &
379  "energetic_PBL: No surface TKE fluxes (ustar) defined in mixedlayer!")
380  debug = .false. ; if (present(dt_expected) .or. present(ds_expected)) debug = .true.
381 
382  if (debug) allocate(ecd%dT_expect(nz), ecd%dS_expect(nz))
383 
384  h_neglect = gv%H_subroundoff
385 
386  dt__diag = dt ; if (present(dt_diag)) dt__diag = dt_diag
387  write_diags = .true. ; if (present(last_call)) write_diags = last_call
388 
389 
390  ! Determine whether to zero out diagnostics before accumulation.
391  reset_diags = .true.
392  if (present(dt_diag) .and. write_diags .and. (dt__diag > dt)) &
393  reset_diags = .false. ! This is the second call to mixedlayer.
394 
395  if (reset_diags) then
396  if (cs%TKE_diagnostics) then
397 !!OMP parallel do default(none) shared(is,ie,js,je,CS)
398  do j=js,je ; do i=is,ie
399  cs%diag_TKE_wind(i,j) = 0.0 ; cs%diag_TKE_MKE(i,j) = 0.0
400  cs%diag_TKE_conv(i,j) = 0.0 ; cs%diag_TKE_forcing(i,j) = 0.0
401  cs%diag_TKE_mixing(i,j) = 0.0 ; cs%diag_TKE_mech_decay(i,j) = 0.0
402  cs%diag_TKE_conv_decay(i,j) = 0.0 !; CS%diag_TKE_unbalanced(i,j) = 0.0
403  enddo ; enddo
404  endif
405  endif
406  ! if (CS%id_Mixing_Length>0) CS%Mixing_Length(:,:,:) = 0.0
407  ! if (CS%id_Velocity_Scale>0) CS%Velocity_Scale(:,:,:) = 0.0
408 
409 !!OMP parallel do default(private) shared(js,je,nz,is,ie,h_3d,u_3d,v_3d,tv,dt, &
410 !!OMP CS,G,GV,US,fluxes,debug, &
411 !!OMP TKE_forced,dSV_dT,dSV_dS,Kd_int)
412  do j=js,je
413  ! Copy the thicknesses and other fields to 2-d arrays.
414  do k=1,nz ; do i=is,ie
415  h_2d(i,k) = h_3d(i,j,k) ; u_2d(i,k) = u_3d(i,j,k) ; v_2d(i,k) = v_3d(i,j,k)
416  t_2d(i,k) = tv%T(i,j,k) ; s_2d(i,k) = tv%S(i,j,k)
417  tke_forced_2d(i,k) = tke_forced(i,j,k)
418  dsv_dt_2d(i,k) = dsv_dt(i,j,k) ; dsv_ds_2d(i,k) = dsv_ds(i,j,k)
419  enddo ; enddo
420 
421  ! Determine the initial mech_TKE and conv_PErel, including the energy required
422  ! to mix surface heating through the topmost cell, the energy released by mixing
423  ! surface cooling & brine rejection down through the topmost cell, and
424  ! homogenizing the shortwave heating within that cell. This sets the energy
425  ! and ustar and wstar available to drive mixing at the first interior
426  ! interface.
427  do i=is,ie ; if (g%mask2dT(i,j) > 0.5) then
428 
429  ! Copy the thicknesses and other fields to 1-d arrays.
430  do k=1,nz
431  h(k) = h_2d(i,k) + gv%H_subroundoff ; u(k) = u_2d(i,k) ; v(k) = v_2d(i,k)
432  t0(k) = t_2d(i,k) ; s0(k) = s_2d(i,k) ; tke_forcing(k) = tke_forced_2d(i,k)
433  dsv_dt_1d(k) = dsv_dt_2d(i,k) ; dsv_ds_1d(k) = dsv_ds_2d(i,k)
434  enddo
435  do k=1,nz+1 ; kd(k) = 0.0 ; enddo
436 
437  ! Make local copies of surface forcing and process them.
438  u_star = fluxes%ustar(i,j)
439  u_star_mean = fluxes%ustar_gustless(i,j)
440  b_flux = buoy_flux(i,j)
441  if (associated(fluxes%ustar_shelf) .and. associated(fluxes%frac_shelf_h)) then
442  if (fluxes%frac_shelf_h(i,j) > 0.0) &
443  u_star = (1.0 - fluxes%frac_shelf_h(i,j)) * u_star + &
444  fluxes%frac_shelf_h(i,j) * fluxes%ustar_shelf(i,j)
445  endif
446  if (u_star < cs%ustar_min) u_star = cs%ustar_min
447  if (cs%omega_frac >= 1.0) then
448  absf = 2.0*cs%omega
449  else
450  absf = 0.25*((abs(g%CoriolisBu(i,j)) + abs(g%CoriolisBu(i-1,j-1))) + &
451  (abs(g%CoriolisBu(i,j-1)) + abs(g%CoriolisBu(i-1,j))))
452  if (cs%omega_frac > 0.0) &
453  absf = sqrt(cs%omega_frac*4.0*cs%omega**2 + (1.0-cs%omega_frac)*absf**2)
454  endif
455 
456  ! Perhaps provide a first guess for MLD based on a stored previous value.
457  mld_io = -1.0
458  if (cs%MLD_iteration_guess .and. (cs%ML_Depth(i,j) > 0.0)) mld_io = cs%ML_Depth(i,j)
459 
460  call epbl_column(h, u, v, t0, s0, dsv_dt_1d, dsv_ds_1d, tke_forcing, b_flux, absf, &
461  u_star, u_star_mean, dt, mld_io, kd, mixvel, mixlen, gv, &
462  us, cs, ecd, dt_diag=dt_diag, waves=waves, g=g, i=i, j=j)
463 
464 
465  ! Copy the diffusivities to a 2-d array.
466  do k=1,nz+1
467  kd_2d(i,k) = kd(k)
468  enddo
469  cs%ML_depth(i,j) = mld_io
470 
471  if (present(dt_expected)) then
472  do k=1,nz ; dt_expected(i,j,k) = ecd%dT_expect(k) ; enddo
473  endif
474  if (present(ds_expected)) then
475  do k=1,nz ; ds_expected(i,j,k) = ecd%dS_expect(k) ; enddo
476  endif
477 
478  if (cs%TKE_diagnostics) then
479  cs%diag_TKE_MKE(i,j) = cs%diag_TKE_MKE(i,j) + ecd%dTKE_MKE
480  cs%diag_TKE_conv(i,j) = cs%diag_TKE_conv(i,j) + ecd%dTKE_conv
481  cs%diag_TKE_forcing(i,j) = cs%diag_TKE_forcing(i,j) + ecd%dTKE_forcing
482  cs%diag_TKE_wind(i,j) = cs%diag_TKE_wind(i,j) + ecd%dTKE_wind
483  cs%diag_TKE_mixing(i,j) = cs%diag_TKE_mixing(i,j) + ecd%dTKE_mixing
484  cs%diag_TKE_mech_decay(i,j) = cs%diag_TKE_mech_decay(i,j) + ecd%dTKE_mech_decay
485  cs%diag_TKE_conv_decay(i,j) = cs%diag_TKE_conv_decay(i,j) + ecd%dTKE_conv_decay
486  ! CS%diag_TKE_unbalanced(i,j) = CS%diag_TKE_unbalanced(i,j) + eCD%dTKE_unbalanced
487  endif
488  ! Write to 3-D for outputing Mixing length and velocity scale.
489  if (cs%id_Mixing_Length>0) then ; do k=1,nz
490  cs%Mixing_Length(i,j,k) = mixlen(k)
491  enddo ; endif
492  if (cs%id_Velocity_Scale>0) then ; do k=1,nz
493  cs%Velocity_Scale(i,j,k) = mixvel(k)
494  enddo ; endif
495  if (allocated(cs%mstar_mix)) cs%mstar_mix(i,j) = ecd%mstar
496  if (allocated(cs%mstar_lt)) cs%mstar_lt(i,j) = ecd%mstar_LT
497  if (allocated(cs%La)) cs%La(i,j) = ecd%LA
498  if (allocated(cs%La_mod)) cs%La_mod(i,j) = ecd%LAmod
499  else ! End of the ocean-point part of the i-loop
500  ! For masked points, Kd_int must still be set (to 0) because it has intent out.
501  do k=1,nz+1 ; kd_2d(i,k) = 0. ; enddo
502  cs%ML_depth(i,j) = 0.0
503 
504  if (present(dt_expected)) then
505  do k=1,nz ; dt_expected(i,j,k) = 0.0 ; enddo
506  endif
507  if (present(ds_expected)) then
508  do k=1,nz ; ds_expected(i,j,k) = 0.0 ; enddo
509  endif
510  endif ; enddo ! Close of i-loop - Note unusual loop order!
511 
512  do k=1,nz+1 ; do i=is,ie ; kd_int(i,j,k) = kd_2d(i,k) ; enddo ; enddo
513 
514  enddo ! j-loop
515 
516  if (write_diags) then
517  if (cs%id_ML_depth > 0) call post_data(cs%id_ML_depth, cs%ML_depth, cs%diag)
518  if (cs%id_hML_depth > 0) call post_data(cs%id_hML_depth, cs%ML_depth, cs%diag)
519  if (cs%id_TKE_wind > 0) call post_data(cs%id_TKE_wind, cs%diag_TKE_wind, cs%diag)
520  if (cs%id_TKE_MKE > 0) call post_data(cs%id_TKE_MKE, cs%diag_TKE_MKE, cs%diag)
521  if (cs%id_TKE_conv > 0) call post_data(cs%id_TKE_conv, cs%diag_TKE_conv, cs%diag)
522  if (cs%id_TKE_forcing > 0) call post_data(cs%id_TKE_forcing, cs%diag_TKE_forcing, cs%diag)
523  if (cs%id_TKE_mixing > 0) call post_data(cs%id_TKE_mixing, cs%diag_TKE_mixing, cs%diag)
524  if (cs%id_TKE_mech_decay > 0) &
525  call post_data(cs%id_TKE_mech_decay, cs%diag_TKE_mech_decay, cs%diag)
526  if (cs%id_TKE_conv_decay > 0) &
527  call post_data(cs%id_TKE_conv_decay, cs%diag_TKE_conv_decay, cs%diag)
528  if (cs%id_Mixing_Length > 0) call post_data(cs%id_Mixing_Length, cs%Mixing_Length, cs%diag)
529  if (cs%id_Velocity_Scale >0) call post_data(cs%id_Velocity_Scale, cs%Velocity_Scale, cs%diag)
530  if (cs%id_MSTAR_MIX > 0) call post_data(cs%id_MSTAR_MIX, cs%MSTAR_MIX, cs%diag)
531  if (cs%id_LA > 0) call post_data(cs%id_LA, cs%LA, cs%diag)
532  if (cs%id_LA_MOD > 0) call post_data(cs%id_LA_MOD, cs%LA_MOD, cs%diag)
533  if (cs%id_MSTAR_LT > 0) call post_data(cs%id_MSTAR_LT, cs%MSTAR_LT, cs%diag)
534  endif
535 
536  if (debug) deallocate(ecd%dT_expect, ecd%dS_expect)
537 
538 end subroutine energetic_pbl
539 
540 
541 
542 !> This subroutine determines the diffusivities from the integrated energetics
543 !! mixed layer model for a single column of water.
544 subroutine epbl_column(h, u, v, T0, S0, dSV_dT, dSV_dS, TKE_forcing, B_flux, absf, &
545  u_star, u_star_mean, dt, MLD_io, Kd, mixvel, mixlen, GV, US, CS, eCD, &
546  dt_diag, Waves, G, i, j)
547  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
548  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
549  real, dimension(SZK_(GV)), intent(in) :: h !< Layer thicknesses [H ~> m or kg m-2].
550  real, dimension(SZK_(GV)), intent(in) :: u !< Zonal velocities interpolated to h points
551  !! [L T-1 ~> m s-1].
552  real, dimension(SZK_(GV)), intent(in) :: v !< Zonal velocities interpolated to h points
553  !! [L T-1 ~> m s-1].
554  real, dimension(SZK_(GV)), intent(in) :: T0 !< The initial layer temperatures [degC].
555  real, dimension(SZK_(GV)), intent(in) :: S0 !< The initial layer salinities [ppt].
556 
557  real, dimension(SZK_(GV)), intent(in) :: dSV_dT !< The partial derivative of in-situ specific
558  !! volume with potential temperature
559  !! [R-1 degC-1 ~> m3 kg-1 degC-1].
560  real, dimension(SZK_(GV)), intent(in) :: dSV_dS !< The partial derivative of in-situ specific
561  !! volume with salinity [R-1 ppt-1 ~> m3 kg-1 ppt-1].
562  real, dimension(SZK_(GV)), intent(in) :: TKE_forcing !< The forcing requirements to homogenize the
563  !! forcing that has been applied to each layer
564  !! [R Z3 T-2 ~> J m-2].
565  real, intent(in) :: B_flux !< The surface buoyancy flux [Z2 T-3 ~> m2 s-3]
566  real, intent(in) :: absf !< The absolute value of the Coriolis parameter [T-1 ~> s-1].
567  real, intent(in) :: u_star !< The surface friction velocity [Z T-1 ~> m s-1].
568  real, intent(in) :: u_star_mean !< The surface friction velocity without any
569  !! contribution from unresolved gustiness [Z T-1 ~> m s-1].
570  real, intent(inout) :: MLD_io !< A first guess at the mixed layer depth on input, and
571  !! the calculated mixed layer depth on output [Z ~> m].
572  real, intent(in) :: dt !< Time increment [T ~> s].
573  real, dimension(SZK_(GV)+1), &
574  intent(out) :: Kd !< The diagnosed diffusivities at interfaces
575  !! [Z2 T-1 ~> m2 s-1].
576  real, dimension(SZK_(GV)+1), &
577  intent(out) :: mixvel !< The mixing velocity scale used in Kd
578  !! [Z T-1 ~> m s-1].
579  real, dimension(SZK_(GV)+1), &
580  intent(out) :: mixlen !< The mixing length scale used in Kd [Z ~> m].
581  type(energetic_PBL_CS), pointer :: CS !< The control structure returned by a previous
582  !! call to mixedlayer_init.
583  type(ePBL_column_diags), intent(inout) :: eCD !< A container for passing around diagnostics.
584  real, optional, intent(in) :: dt_diag !< The diagnostic time step, which may be less
585  !! than dt if there are two calls to mixedlayer [T ~> s].
586  type(wave_parameters_CS), &
587  optional, pointer :: Waves !< Wave CS for Langmuir turbulence
588  type(ocean_grid_type), &
589  optional, intent(inout) :: G !< The ocean's grid structure.
590  integer, optional, intent(in) :: i !< The i-index to work on (used for Waves)
591  integer, optional, intent(in) :: j !< The i-index to work on (used for Waves)
592 
593 ! This subroutine determines the diffusivities in a single column from the integrated energetics
594 ! planetary boundary layer (ePBL) model. It assumes that heating, cooling and freshwater fluxes
595 ! have already been applied. All calculations are done implicitly, and there
596 ! is no stability limit on the time step.
597 !
598 ! For each interior interface, first discard the TKE to account for mixing
599 ! of shortwave radiation through the next denser cell. Next drive mixing based
600 ! on the local? values of ustar + wstar, subject to available energy. This
601 ! step sets the value of Kd(K). Any remaining energy is then subject to decay
602 ! before being handed off to the next interface. mech_TKE and conv_PErel are treated
603 ! separately for the purposes of decay, but are used proportionately to drive
604 ! mixing.
605 
606  ! Local variables
607  real, dimension(SZK_(GV)+1) :: &
608  pres_Z, & ! Interface pressures with a rescaling factor to convert interface height
609  ! movements into changes in column potential energy [R Z2 T-2 ~> kg m-1 s-2].
610  hb_hs ! The distance from the bottom over the thickness of the
611  ! water column [nondim].
612  real :: mech_TKE ! The mechanically generated turbulent kinetic energy
613  ! available for mixing over a time step [R Z3 T-2 ~> J m-2].
614  real :: conv_PErel ! The potential energy that has been convectively released
615  ! during this timestep [R Z3 T-2 ~> J m-2]. A portion nstar_FC
616  ! of conv_PErel is available to drive mixing.
617  real :: htot ! The total depth of the layers above an interface [H ~> m or kg m-2].
618  real :: uhtot ! The depth integrated zonal and meridional velocities in the
619  real :: vhtot ! layers above [H L T-1 ~> m2 s-1 or kg m-1 s-1].
620  real :: Idecay_len_TKE ! The inverse of a turbulence decay length scale [H-1 ~> m-1 or m2 kg-1].
621  real :: h_sum ! The total thickness of the water column [H ~> m or kg m-2].
622 
623  real, dimension(SZK_(GV)) :: &
624  dT_to_dColHt, & ! Partial derivative of the total column height with the temperature changes
625  ! within a layer [Z degC-1 ~> m degC-1].
626  ds_to_dcolht, & ! Partial derivative of the total column height with the salinity changes
627  ! within a layer [Z ppt-1 ~> m ppt-1].
628  dt_to_dpe, & ! Partial derivatives of column potential energy with the temperature
629  ! changes within a layer, in [R Z3 T-2 degC-1 ~> J m-2 degC-1].
630  ds_to_dpe, & ! Partial derivatives of column potential energy with the salinity changes
631  ! within a layer, in [R Z3 T-2 ppt-1 ~> J m-2 ppt-1].
632  dt_to_dcolht_a, & ! Partial derivative of the total column height with the temperature changes
633  ! within a layer, including the implicit effects of mixing with layers higher
634  ! in the water column [Z degC-1 ~> m degC-1].
635  ds_to_dcolht_a, & ! Partial derivative of the total column height with the salinity changes
636  ! within a layer, including the implicit effects of mixing with layers higher
637  ! in the water column [Z ppt-1 ~> m ppt-1].
638  dt_to_dpe_a, & ! Partial derivatives of column potential energy with the temperature changes
639  ! within a layer, including the implicit effects of mixing with layers higher
640  ! in the water column [R Z3 T-2 degC-1 ~> J m-2 degC-1].
641  ds_to_dpe_a, & ! Partial derivative of column potential energy with the salinity changes
642  ! within a layer, including the implicit effects of mixing with layers higher
643  ! in the water column [R Z3 T-2 ppt-1 ~> J m-2 ppt-1].
644  c1, & ! c1 is used by the tridiagonal solver [nondim].
645  te, & ! Estimated final values of T in the column [degC].
646  se, & ! Estimated final values of S in the column [ppt].
647  dte, & ! Running (1-way) estimates of temperature change [degC].
648  dse, & ! Running (1-way) estimates of salinity change [ppt].
649  th_a, & ! An effective temperature times a thickness in the layer above, including implicit
650  ! mixing effects with other yet higher layers [degC H ~> degC m or degC kg m-2].
651  sh_a, & ! An effective salinity times a thickness in the layer above, including implicit
652  ! mixing effects with other yet higher layers [ppt H ~> ppt m or ppt kg m-2].
653  th_b, & ! An effective temperature times a thickness in the layer below, including implicit
654  ! mixing effects with other yet lower layers [degC H ~> degC m or degC kg m-2].
655  sh_b ! An effective salinity times a thickness in the layer below, including implicit
656  ! mixing effects with other yet lower layers [ppt H ~> ppt m or ppt kg m-2].
657  real, dimension(SZK_(GV)+1) :: &
658  MixLen_shape, & ! A nondimensional shape factor for the mixing length that
659  ! gives it an appropriate assymptotic value at the bottom of
660  ! the boundary layer.
661  kddt_h ! The diapycnal diffusivity times a timestep divided by the
662  ! average thicknesses around a layer [H ~> m or kg m-2].
663  real :: b1 ! b1 is inverse of the pivot used by the tridiagonal solver [H-1 ~> m-1 or m2 kg-1].
664  real :: hp_a ! An effective pivot thickness of the layer including the effects
665  ! of coupling with layers above [H ~> m or kg m-2]. This is the first term
666  ! in the denominator of b1 in a downward-oriented tridiagonal solver.
667  real :: h_neglect ! A thickness that is so small it is usually lost
668  ! in roundoff and can be neglected [H ~> m or kg m-2].
669  real :: dMass ! The mass per unit area within a layer [Z R ~> kg m-2].
670  real :: dPres ! The hydrostatic pressure change across a layer [R Z2 T-2 ~> Pa = J m-3].
671  real :: dMKE_max ! The maximum amount of mean kinetic energy that could be
672  ! converted to turbulent kinetic energy if the velocity in
673  ! the layer below an interface were homogenized with all of
674  ! the water above the interface [R Z3 T-2 ~> J m-2].
675  real :: MKE2_Hharm ! Twice the inverse of the harmonic mean of the thickness
676  ! of a layer and the thickness of the water above, used in
677  ! the MKE conversion equation [H-1 ~> m-1 or m2 kg-1].
678 
679  real :: dt_h ! The timestep divided by the averages of the thicknesses around
680  ! a layer, times a thickness conversion factor [H T m-2 ~> s m-1 or kg s m-4].
681  real :: h_bot ! The distance from the bottom [H ~> m or kg m-2].
682  real :: h_rsum ! The running sum of h from the top [Z ~> m].
683  real :: I_hs ! The inverse of h_sum [H-1 ~> m-1 or m2 kg-1].
684  real :: I_MLD ! The inverse of the current value of MLD [Z-1 ~> m-1].
685  real :: h_tt ! The distance from the surface or up to the next interface
686  ! that did not exhibit turbulent mixing from this scheme plus
687  ! a surface mixing roughness length given by h_tt_min [H ~> m or kg m-2].
688  real :: h_tt_min ! A surface roughness length [H ~> m or kg m-2].
689 
690  real :: C1_3 ! = 1/3.
691  real :: I_dtrho ! 1.0 / (dt * Rho0) times conversion factors in [m3 Z-3 R-1 T2 s-3 ~> m3 kg-1 s-1].
692  ! This is used convert TKE back into ustar^3.
693  real :: vstar ! An in-situ turbulent velocity [Z T-1 ~> m s-1].
694  real :: mstar_total ! The value of mstar used in ePBL [nondim]
695  real :: mstar_LT ! An addition to mstar due to Langmuir turbulence [nondim] (output for diagnostic)
696  real :: MLD_output ! The mixed layer depth output from this routine [Z ~> m].
697  real :: LA ! The value of the Langmuir number [nondim]
698  real :: LAmod ! The modified Langmuir number by convection [nondim]
699  real :: hbs_here ! The local minimum of hb_hs and MixLen_shape, times a
700  ! conversion factor from H to Z [Z H-1 ~> 1 or m3 kg-1].
701  real :: nstar_FC ! The fraction of conv_PErel that can be converted to mixing [nondim].
702  real :: TKE_reduc ! The fraction by which TKE and other energy fields are
703  ! reduced to support mixing [nondim]. between 0 and 1.
704  real :: tot_TKE ! The total TKE available to support mixing at interface K [R Z3 T-2 ~> J m-2].
705  real :: TKE_here ! The total TKE at this point in the algorithm [R Z3 T-2 ~> J m-2].
706  real :: dT_km1_t2 ! A diffusivity-independent term related to the temperature
707  ! change in the layer above the interface [degC].
708  real :: dS_km1_t2 ! A diffusivity-independent term related to the salinity
709  ! change in the layer above the interface [ppt].
710  real :: dTe_term ! A diffusivity-independent term related to the temperature
711  ! change in the layer below the interface [degC H ~> degC m or degC kg m-2].
712  real :: dSe_term ! A diffusivity-independent term related to the salinity
713  ! change in the layer above the interface [ppt H ~> ppt m or ppt kg m-2].
714  real :: dTe_t2 ! A part of dTe_term [degC H ~> degC m or degC kg m-2].
715  real :: dSe_t2 ! A part of dSe_term [ppt H ~> ppt m or ppt kg m-2].
716  real :: dPE_conv ! The convective change in column potential energy [R Z3 T-2 ~> J m-2].
717  real :: MKE_src ! The mean kinetic energy source of TKE due to Kddt_h(K) [R Z3 T-2 ~> J m-2].
718  real :: dMKE_src_dK ! The partial derivative of MKE_src with Kddt_h(K) [R Z3 T-2 H-1 ~> J m-3 or J kg-1].
719  real :: Kd_guess0 ! A first guess of the diapycnal diffusivity [Z2 T-1 ~> m2 s-1].
720  real :: PE_chg_g0 ! The potential energy change when Kd is Kd_guess0 [R Z3 T-2 ~> J m-2]
721  real :: Kddt_h_g0 ! The first guess diapycnal diffusivity times a timestep divided
722  ! by the average thicknesses around a layer [H ~> m or kg m-2].
723  real :: PE_chg_max ! The maximum PE change for very large values of Kddt_h(K) [R Z3 T-2 ~> J m-2].
724  real :: dPEc_dKd_Kd0 ! The partial derivative of PE change with Kddt_h(K)
725  ! for very small values of Kddt_h(K) [R Z3 T-2 H-1 ~> J m-3 or J kg-1].
726  real :: PE_chg ! The change in potential energy due to mixing at an
727  ! interface [R Z3 T-2 ~> J m-2], positive for the column increasing
728  ! in potential energy (i.e., consuming TKE).
729  real :: TKE_left ! The amount of turbulent kinetic energy left for the most
730  ! recent guess at Kddt_h(K) [R Z3 T-2 ~> J m-2].
731  real :: dPEc_dKd ! The partial derivative of PE_chg with Kddt_h(K) [R Z3 T-2 H-1 ~> J m-3 or J kg-1].
732  real :: TKE_left_min, TKE_left_max ! Maximum and minimum values of TKE_left [R Z3 T-2 ~> J m-2].
733  real :: Kddt_h_max, Kddt_h_min ! Maximum and minimum values of Kddt_h(K) [H ~> m or kg m-2].
734  real :: Kddt_h_guess ! A guess at the value of Kddt_h(K) [H ~> m or kg m-2].
735  real :: Kddt_h_next ! The next guess at the value of Kddt_h(K) [H ~> m or kg m-2].
736  real :: dKddt_h ! The change between guesses at Kddt_h(K) [H ~> m or kg m-2].
737  real :: dKddt_h_Newt ! The change between guesses at Kddt_h(K) with Newton's method [H ~> m or kg m-2].
738  real :: Kddt_h_newt ! The Newton's method next guess for Kddt_h(K) [H ~> m or kg m-2].
739  real :: exp_kh ! The nondimensional decay of TKE across a layer [nondim].
740  real :: vstar_unit_scale ! A unit converion factor for turbulent velocities [Z T-1 s m-1 ~> 1]
741  logical :: use_Newt ! Use Newton's method for the next guess at Kddt_h(K).
742  logical :: convectively_stable ! If true the water column is convectively stable at this interface.
743  logical :: sfc_connected ! If true the ocean is actively turbulent from the present
744  ! interface all the way up to the surface.
745  logical :: sfc_disconnect ! If true, any turbulence has become disconnected
746  ! from the surface.
747 
748 ! The following are only used for diagnostics.
749  real :: dt__diag ! A copy of dt_diag (if present) or dt [T ~> s].
750  real :: I_dtdiag ! = 1.0 / dt__diag [T-1 ~> s-1].
751 
752  !----------------------------------------------------------------------
753  !/BGR added Aug24,2016 for adding iteration to get boundary layer depth
754  ! - needed to compute new mixing length.
755  real :: MLD_guess, MLD_found ! Mixing Layer depth guessed/found for iteration [Z ~> m].
756  real :: min_MLD ! Iteration bounds [Z ~> m], which are adjusted at each step
757  real :: max_MLD ! - These are initialized based on surface/bottom
758  ! 1. The iteration guesses a value (possibly from prev step or neighbor).
759  ! 2. The iteration checks if value is converged, too shallow, or too deep.
760  ! 3. Based on result adjusts the Max/Min and searches through the water column.
761  ! - If using an accurate guess the iteration is very quick (e.g. if MLD doesn't
762  ! change over timestep). Otherwise it takes 5-10 passes, but has a high
763  ! convergence rate. Other iteration may be tried, but this method seems to
764  ! fail very rarely and the added cost is likely not significant.
765  ! Additionally, when it fails to converge it does so in a reasonable
766  ! manner giving a usable guess. When it does fail, it is due to convection
767  ! within the boundary layer. Likely, a new method e.g. surface_disconnect,
768  ! can improve this.
769  real :: dMLD_min ! The change in diagnosed mixed layer depth when the guess is min_MLD [Z ~> m]
770  real :: dMLD_max ! The change in diagnosed mixed layer depth when the guess is max_MLD [Z ~> m]
771  logical :: FIRST_OBL ! Flag for computing "found" Mixing layer depth
772  logical :: OBL_converged ! Flag for convergence of MLD
773  integer :: OBL_it ! Iteration counter
774 
775  real :: Surface_Scale ! Surface decay scale for vstar
776  logical :: calc_dT_expect ! If true calculate the expected changes in temperature and salinity.
777  logical :: calc_Te ! If true calculate the expected final temperature and salinity values.
778  logical :: debug=.false. ! Change this hard-coded value for debugging.
779 
780  ! The following arrays are used only for debugging purposes.
781  real :: dPE_debug, mixing_debug, taux2, tauy2
782  real, dimension(20) :: TKE_left_itt, PE_chg_itt, Kddt_h_itt, dPEa_dKd_itt, MKE_src_itt
783  real, dimension(SZK_(GV)) :: mech_TKE_k, conv_PErel_k, nstar_k
784  integer, dimension(SZK_(GV)) :: num_itts
785 
786  integer :: k, nz, itt, max_itt
787 
788  nz = gv%ke
789 
790  if (.not. associated(cs)) call mom_error(fatal, "energetic_PBL: "//&
791  "Module must be initialized before it is used.")
792 
793  calc_dt_expect = debug ; if (allocated(ecd%dT_expect) .or. allocated(ecd%dS_expect)) calc_dt_expect = .true.
794  calc_te = (calc_dt_expect .or. (.not.cs%orig_PE_calc))
795 
796  h_neglect = gv%H_subroundoff
797 
798  c1_3 = 1.0 / 3.0
799  dt__diag = dt ; if (present(dt_diag)) dt__diag = dt_diag
800  i_dtdiag = 1.0 / dt__diag
801  max_itt = 20
802 
803  h_tt_min = 0.0
804  i_dtrho = 0.0 ; if (dt*gv%Rho0 > 0.0) i_dtrho = (us%Z_to_m**3*us%s_to_T**3) / (dt*gv%Rho0)
805  vstar_unit_scale = us%m_to_Z * us%T_to_s
806 
807  mld_guess = mld_io
808 
809 ! Determine the initial mech_TKE and conv_PErel, including the energy required
810 ! to mix surface heating through the topmost cell, the energy released by mixing
811 ! surface cooling & brine rejection down through the topmost cell, and
812 ! homogenizing the shortwave heating within that cell. This sets the energy
813 ! and ustar and wstar available to drive mixing at the first interior
814 ! interface.
815 
816  do k=1,nz+1 ; kd(k) = 0.0 ; enddo
817 
818  pres_z(1) = 0.0
819  do k=1,nz
820  dmass = gv%H_to_RZ * h(k)
821  dpres = us%L_to_Z**2 * gv%g_Earth * dmass
822  dt_to_dpe(k) = (dmass * (pres_z(k) + 0.5*dpres)) * dsv_dt(k)
823  ds_to_dpe(k) = (dmass * (pres_z(k) + 0.5*dpres)) * dsv_ds(k)
824  dt_to_dcolht(k) = dmass * dsv_dt(k)
825  ds_to_dcolht(k) = dmass * dsv_ds(k)
826 
827  pres_z(k+1) = pres_z(k) + dpres
828  enddo
829 
830  ! Determine the total thickness (h_sum) and the fractional distance from the bottom (hb_hs).
831  h_sum = h_neglect ; do k=1,nz ; h_sum = h_sum + h(k) ; enddo
832  i_hs = 0.0 ; if (h_sum > 0.0) i_hs = 1.0 / h_sum
833  h_bot = 0.0
834  hb_hs(nz+1) = 0.0
835  do k=nz,1,-1
836  h_bot = h_bot + h(k)
837  hb_hs(k) = h_bot * i_hs
838  enddo
839 
840  mld_output = h(1)*gv%H_to_Z
841 
842  !/The following lines are for the iteration over MLD
843  ! max_MLD will initialized as ocean bottom depth
844  max_mld = 0.0 ; do k=1,nz ; max_mld = max_mld + h(k)*gv%H_to_Z ; enddo
845  ! min_MLD will be initialized to 0.
846  min_mld = 0.0
847  ! Set values of the wrong signs to indicate that these changes are not based on valid estimates
848  dmld_min = -1.0*us%m_to_Z ; dmld_max = 1.0*us%m_to_Z
849 
850  ! If no first guess is provided for MLD, try the middle of the water column
851  if (mld_guess <= min_mld) mld_guess = 0.5 * (min_mld + max_mld)
852 
853  ! Iterate to determine a converged EPBL depth.
854  obl_converged = .false.
855  do obl_it=1,cs%Max_MLD_Its
856 
857  if (.not. obl_converged) then
858  ! If not using MLD_Iteration flag loop to only execute once.
859  if (.not.cs%Use_MLD_iteration) obl_converged = .true.
860 
861  if (debug) then ; mech_tke_k(:) = 0.0 ; conv_perel_k(:) = 0.0 ; endif
862 
863  ! Reset ML_depth
864  mld_output = h(1)*gv%H_to_Z
865  sfc_connected = .true.
866 
867  !/ Here we get MStar, which is the ratio of convective TKE driven mixing to UStar**3
868  if (cs%Use_LT) then
869  call get_langmuir_number(la, g, gv, us, abs(mld_guess), u_star_mean, i, j, &
870  h=h, u_h=u, v_h=v, waves=waves)
871  call find_mstar(cs, us, b_flux, u_star, u_star_mean, mld_guess, absf, &
872  mstar_total, langmuir_number=la, convect_langmuir_number=lamod,&
873  mstar_lt=mstar_lt)
874  else
875  call find_mstar(cs, us, b_flux, u_star, u_star_mean, mld_guess, absf, mstar_total)
876  endif
877 
878  !/ Apply MStar to get mech_TKE
879  if ((cs%answers_2018) .and. (cs%mstar_scheme==use_fixed_mstar)) then
880  mech_tke = (dt*mstar_total*gv%Rho0) * u_star**3
881  else
882  mech_tke = mstar_total * (dt*gv%Rho0* u_star**3)
883  endif
884 
885  if (cs%TKE_diagnostics) then
886  ecd%dTKE_conv = 0.0 ; ecd%dTKE_mixing = 0.0
887  ecd%dTKE_MKE = 0.0 ; ecd%dTKE_mech_decay = 0.0 ; ecd%dTKE_conv_decay = 0.0
888 
889  ecd%dTKE_wind = mech_tke * i_dtdiag
890  if (tke_forcing(1) <= 0.0) then
891  ecd%dTKE_forcing = max(-mech_tke, tke_forcing(1)) * i_dtdiag
892  ! eCD%dTKE_unbalanced = min(0.0, TKE_forcing(1) + mech_TKE) * I_dtdiag
893  else
894  ecd%dTKE_forcing = cs%nstar*tke_forcing(1) * i_dtdiag
895  ! eCD%dTKE_unbalanced = 0.0
896  endif
897  endif
898 
899  if (tke_forcing(1) <= 0.0) then
900  mech_tke = mech_tke + tke_forcing(1)
901  if (mech_tke < 0.0) mech_tke = 0.0
902  conv_perel = 0.0
903  else
904  conv_perel = tke_forcing(1)
905  endif
906 
907 
908  ! Store in 1D arrays for output.
909  do k=1,nz+1 ; mixvel(k) = 0.0 ; mixlen(k) = 0.0 ; enddo
910 
911  ! Determine the mixing shape function MixLen_shape.
912  if ((.not.cs%Use_MLD_iteration) .or. &
913  (cs%transLay_scale >= 1.0) .or. (cs%transLay_scale < 0.0) ) then
914  do k=1,nz+1
915  mixlen_shape(k) = 1.0
916  enddo
917  elseif (mld_guess <= 0.0) then
918  if (cs%transLay_scale > 0.0) then ; do k=1,nz+1
919  mixlen_shape(k) = cs%transLay_scale
920  enddo ; else ; do k=1,nz+1
921  mixlen_shape(k) = 1.0
922  enddo ; endif
923  else
924  ! Reduce the mixing length based on MLD, with a quadratic
925  ! expression that follows KPP.
926  i_mld = 1.0 / mld_guess
927  h_rsum = 0.0
928  mixlen_shape(1) = 1.0
929  do k=2,nz+1
930  h_rsum = h_rsum + h(k-1)*gv%H_to_Z
931  if (cs%MixLenExponent==2.0) then
932  mixlen_shape(k) = cs%transLay_scale + (1.0 - cs%transLay_scale) * &
933  (max(0.0, (mld_guess - h_rsum)*i_mld) )**2 ! CS%MixLenExponent
934  else
935  mixlen_shape(k) = cs%transLay_scale + (1.0 - cs%transLay_scale) * &
936  (max(0.0, (mld_guess - h_rsum)*i_mld) )**cs%MixLenExponent
937  endif
938  enddo
939  endif
940 
941  kd(1) = 0.0 ; kddt_h(1) = 0.0
942  hp_a = h(1)
943  dt_to_dpe_a(1) = dt_to_dpe(1) ; dt_to_dcolht_a(1) = dt_to_dcolht(1)
944  ds_to_dpe_a(1) = ds_to_dpe(1) ; ds_to_dcolht_a(1) = ds_to_dcolht(1)
945 
946  htot = h(1) ; uhtot = u(1)*h(1) ; vhtot = v(1)*h(1)
947 
948  if (debug) then
949  mech_tke_k(1) = mech_tke ; conv_perel_k(1) = conv_perel
950  nstar_k(:) = 0.0 ; nstar_k(1) = cs%nstar ; num_itts(:) = -1
951  endif
952 
953  do k=2,nz
954  ! Apply dissipation to the TKE, here applied as an exponential decay
955  ! due to 3-d turbulent energy being lost to inefficient rotational modes.
956 
957  ! There should be several different "flavors" of TKE that decay at
958  ! different rates. The following form is often used for mechanical
959  ! stirring from the surface, perhaps due to breaking surface gravity
960  ! waves and wind-driven turbulence.
961  idecay_len_tke = (cs%TKE_decay * absf / u_star) * gv%H_to_Z
962  exp_kh = 1.0
963  if (idecay_len_tke > 0.0) exp_kh = exp(-h(k-1)*idecay_len_tke)
964  if (cs%TKE_diagnostics) &
965  ecd%dTKE_mech_decay = ecd%dTKE_mech_decay + (exp_kh-1.0) * mech_tke * i_dtdiag
966  mech_tke = mech_tke * exp_kh
967 
968  ! Accumulate any convectively released potential energy to contribute
969  ! to wstar and to drive penetrating convection.
970  if (tke_forcing(k) > 0.0) then
971  conv_perel = conv_perel + tke_forcing(k)
972  if (cs%TKE_diagnostics) &
973  ecd%dTKE_forcing = ecd%dTKE_forcing + cs%nstar*tke_forcing(k) * i_dtdiag
974  endif
975 
976  if (debug) then
977  mech_tke_k(k) = mech_tke ; conv_perel_k(k) = conv_perel
978  endif
979 
980  ! Determine the total energy
981  nstar_fc = cs%nstar
982  if (cs%nstar * conv_perel > 0.0) then
983  ! Here nstar is a function of the natural Rossby number 0.2/(1+0.2/Ro), based
984  ! on a curve fit from the data of Wang (GRL, 2003).
985  ! Note: Ro = 1.0 / sqrt(0.5 * dt * Rho0 * (absf*htot)**3 / conv_PErel)
986  nstar_fc = cs%nstar * conv_perel / (conv_perel + 0.2 * &
987  sqrt(0.5 * dt * gv%Rho0 * (absf*(htot*gv%H_to_Z))**3 * conv_perel))
988  endif
989 
990  if (debug) nstar_k(k) = nstar_fc
991 
992  tot_tke = mech_tke + nstar_fc * conv_perel
993 
994  ! For each interior interface, first discard the TKE to account for
995  ! mixing of shortwave radiation through the next denser cell.
996  if (tke_forcing(k) < 0.0) then
997  if (tke_forcing(k) + tot_tke < 0.0) then
998  ! The shortwave requirements deplete all the energy in this layer.
999  if (cs%TKE_diagnostics) then
1000  ecd%dTKE_mixing = ecd%dTKE_mixing + tot_tke * i_dtdiag
1001  ecd%dTKE_forcing = ecd%dTKE_forcing - tot_tke * i_dtdiag
1002  ! eCD%dTKE_unbalanced = eCD%dTKE_unbalanced + (TKE_forcing(k) + tot_TKE) * I_dtdiag
1003  ecd%dTKE_conv_decay = ecd%dTKE_conv_decay + (cs%nstar-nstar_fc) * conv_perel * i_dtdiag
1004  endif
1005  tot_tke = 0.0 ; mech_tke = 0.0 ; conv_perel = 0.0
1006  else
1007  ! Reduce the mechanical and convective TKE proportionately.
1008  tke_reduc = (tot_tke + tke_forcing(k)) / tot_tke
1009  if (cs%TKE_diagnostics) then
1010  ecd%dTKE_mixing = ecd%dTKE_mixing - tke_forcing(k) * i_dtdiag
1011  ecd%dTKE_forcing = ecd%dTKE_forcing + tke_forcing(k) * i_dtdiag
1012  ecd%dTKE_conv_decay = ecd%dTKE_conv_decay + &
1013  (1.0-tke_reduc)*(cs%nstar-nstar_fc) * conv_perel * i_dtdiag
1014  endif
1015  tot_tke = tke_reduc*tot_tke ! = tot_TKE + TKE_forcing(k)
1016  mech_tke = tke_reduc*mech_tke
1017  conv_perel = tke_reduc*conv_perel
1018  endif
1019  endif
1020 
1021  ! Precalculate some temporary expressions that are independent of Kddt_h(K).
1022  if (cs%orig_PE_calc) then
1023  if (k==2) then
1024  dte_t2 = 0.0 ; dse_t2 = 0.0
1025  else
1026  dte_t2 = kddt_h(k-1) * ((t0(k-2) - t0(k-1)) + dte(k-2))
1027  dse_t2 = kddt_h(k-1) * ((s0(k-2) - s0(k-1)) + dse(k-2))
1028  endif
1029  endif
1030  dt_h = (gv%Z_to_H**2*dt) / max(0.5*(h(k-1)+h(k)), 1e-15*h_sum)
1031 
1032  ! This tests whether the layers above and below this interface are in
1033  ! a convetively stable configuration, without considering any effects of
1034  ! mixing at higher interfaces. It is an approximation to the more
1035  ! complete test dPEc_dKd_Kd0 >= 0.0, that would include the effects of
1036  ! mixing across interface K-1. The dT_to_dColHt here are effectively
1037  ! mass-weigted estimates of dSV_dT.
1038  convectively_stable = ( 0.0 <= &
1039  ( (dt_to_dcolht(k) + dt_to_dcolht(k-1) ) * (t0(k-1)-t0(k)) + &
1040  (ds_to_dcolht(k) + ds_to_dcolht(k-1) ) * (s0(k-1)-s0(k)) ) )
1041 
1042  if ((mech_tke + conv_perel) <= 0.0 .and. convectively_stable) then
1043  ! Energy is already exhausted, so set Kd = 0 and cycle or exit?
1044  tot_tke = 0.0 ; mech_tke = 0.0 ; conv_perel = 0.0
1045  kd(k) = 0.0 ; kddt_h(k) = 0.0
1046  sfc_disconnect = .true.
1047  ! if (.not.debug) exit
1048 
1049  ! The estimated properties for layer k-1 can be calculated, using
1050  ! greatly simplified expressions when Kddt_h = 0. This enables the
1051  ! tridiagonal solver for the whole column to be completed for debugging
1052  ! purposes, and also allows for something akin to convective adjustment
1053  ! in unstable interior regions?
1054  b1 = 1.0 / hp_a
1055  c1(k) = 0.0
1056  if (cs%orig_PE_calc) then
1057  dte(k-1) = b1 * ( dte_t2 )
1058  dse(k-1) = b1 * ( dse_t2 )
1059  endif
1060 
1061  hp_a = h(k)
1062  dt_to_dpe_a(k) = dt_to_dpe(k)
1063  ds_to_dpe_a(k) = ds_to_dpe(k)
1064  dt_to_dcolht_a(k) = dt_to_dcolht(k)
1065  ds_to_dcolht_a(k) = ds_to_dcolht(k)
1066 
1067  else ! tot_TKE > 0.0 or this is a potentially convectively unstable profile.
1068  sfc_disconnect = .false.
1069 
1070  ! Precalculate some more temporary expressions that are independent of
1071  ! Kddt_h(K).
1072  if (cs%orig_PE_calc) then
1073  if (k==2) then
1074  dt_km1_t2 = (t0(k)-t0(k-1))
1075  ds_km1_t2 = (s0(k)-s0(k-1))
1076  else
1077  dt_km1_t2 = (t0(k)-t0(k-1)) - &
1078  (kddt_h(k-1) / hp_a) * ((t0(k-2) - t0(k-1)) + dte(k-2))
1079  ds_km1_t2 = (s0(k)-s0(k-1)) - &
1080  (kddt_h(k-1) / hp_a) * ((s0(k-2) - s0(k-1)) + dse(k-2))
1081  endif
1082  dte_term = dte_t2 + hp_a * (t0(k-1)-t0(k))
1083  dse_term = dse_t2 + hp_a * (s0(k-1)-s0(k))
1084  else
1085  if (k<=2) then
1086  th_a(k-1) = h(k-1) * t0(k-1) ; sh_a(k-1) = h(k-1) * s0(k-1)
1087  else
1088  th_a(k-1) = h(k-1) * t0(k-1) + kddt_h(k-1) * te(k-2)
1089  sh_a(k-1) = h(k-1) * s0(k-1) + kddt_h(k-1) * se(k-2)
1090  endif
1091  th_b(k) = h(k) * t0(k) ; sh_b(k) = h(k) * s0(k)
1092  endif
1093 
1094  ! Using Pr=1 and the diffusivity at the bottom interface (once it is
1095  ! known), determine how much resolved mean kinetic energy (MKE) will be
1096  ! extracted within a timestep and add a fraction CS%MKE_to_TKE_effic of
1097  ! this to the mTKE budget available for mixing in the next layer.
1098 
1099  if ((cs%MKE_to_TKE_effic > 0.0) .and. (htot*h(k) > 0.0)) then
1100  ! This is the energy that would be available from homogenizing the
1101  ! velocities between layer k and the layers above.
1102  dmke_max = (us%L_to_Z**2*gv%H_to_RZ * cs%MKE_to_TKE_effic) * 0.5 * &
1103  (h(k) / ((htot + h(k))*htot)) * &
1104  ((uhtot-u(k)*htot)**2 + (vhtot-v(k)*htot)**2)
1105  ! A fraction (1-exp(Kddt_h*MKE2_Hharm)) of this energy would be
1106  ! extracted by mixing with a finite viscosity.
1107  mke2_hharm = (htot + h(k) + 2.0*h_neglect) / &
1108  ((htot+h_neglect) * (h(k)+h_neglect))
1109  else
1110  dmke_max = 0.0
1111  mke2_hharm = 0.0
1112  endif
1113 
1114  ! At this point, Kddt_h(K) will be unknown because its value may depend
1115  ! on how much energy is available. mech_TKE might be negative due to
1116  ! contributions from TKE_forced.
1117  h_tt = htot + h_tt_min
1118  tke_here = mech_tke + cs%wstar_ustar_coef*conv_perel
1119  if (tke_here > 0.0) then
1120  if (cs%wT_scheme==wt_from_croot_tke) then
1121  vstar = cs%vstar_scale_fac * vstar_unit_scale * (i_dtrho*tke_here)**c1_3
1122  elseif (cs%wT_scheme==wt_from_rh18) then
1123  surface_scale = max(0.05, 1.0 - htot/mld_guess)
1124  vstar = cs%vstar_scale_fac * surface_scale * (cs%vstar_surf_fac*u_star + &
1125  vstar_unit_scale * (cs%wstar_ustar_coef*conv_perel*i_dtrho)**c1_3)
1126  endif
1127  hbs_here = gv%H_to_Z * min(hb_hs(k), mixlen_shape(k))
1128  mixlen(k) = max(cs%min_mix_len, ((h_tt*hbs_here)*vstar) / &
1129  ((cs%Ekman_scale_coef * absf) * (h_tt*hbs_here) + vstar))
1130  !Note setting Kd_guess0 to vstar * CS%vonKar * mixlen(K) here will
1131  ! change the answers. Therefore, skipping that.
1132  if (.not.cs%Use_MLD_iteration) then
1133  kd_guess0 = vstar * cs%vonKar * ((h_tt*hbs_here)*vstar) / &
1134  ((cs%Ekman_scale_coef * absf) * (h_tt*hbs_here) + vstar)
1135  else
1136  kd_guess0 = vstar * cs%vonKar * mixlen(k)
1137  endif
1138  else
1139  vstar = 0.0 ; kd_guess0 = 0.0
1140  endif
1141  mixvel(k) = vstar ! Track vstar
1142  kddt_h_g0 = kd_guess0 * dt_h
1143 
1144  if (cs%orig_PE_calc) then
1145  call find_pe_chg_orig(kddt_h_g0, h(k), hp_a, dte_term, dse_term, &
1146  dt_km1_t2, ds_km1_t2, dt_to_dpe(k), ds_to_dpe(k), &
1147  dt_to_dpe_a(k-1), ds_to_dpe_a(k-1), &
1148  pres_z(k), dt_to_dcolht(k), ds_to_dcolht(k), &
1149  dt_to_dcolht_a(k-1), ds_to_dcolht_a(k-1), &
1150  pe_chg=pe_chg_g0, dpe_max=pe_chg_max, dpec_dkd_0=dpec_dkd_kd0 )
1151  else
1152  call find_pe_chg(0.0, kddt_h_g0, hp_a, h(k), &
1153  th_a(k-1), sh_a(k-1), th_b(k), sh_b(k), &
1154  dt_to_dpe_a(k-1), ds_to_dpe_a(k-1), dt_to_dpe(k), ds_to_dpe(k), &
1155  pres_z(k), dt_to_dcolht_a(k-1), ds_to_dcolht_a(k-1), &
1156  dt_to_dcolht(k), ds_to_dcolht(k), &
1157  pe_chg=pe_chg_g0, dpe_max=pe_chg_max, dpec_dkd_0=dpec_dkd_kd0 )
1158  endif
1159 
1160  mke_src = dmke_max*(1.0 - exp(-kddt_h_g0 * mke2_hharm))
1161 
1162  ! This block checks out different cases to determine Kd at the present interface.
1163  if ((pe_chg_g0 < 0.0) .or. ((vstar == 0.0) .and. (dpec_dkd_kd0 < 0.0))) then
1164  ! This column is convectively unstable.
1165  if (pe_chg_max <= 0.0) then
1166  ! Does MKE_src need to be included in the calculation of vstar here?
1167  tke_here = mech_tke + cs%wstar_ustar_coef*(conv_perel-pe_chg_max)
1168  if (tke_here > 0.0) then
1169  if (cs%wT_scheme==wt_from_croot_tke) then
1170  vstar = cs%vstar_scale_fac * vstar_unit_scale * (i_dtrho*tke_here)**c1_3
1171  elseif (cs%wT_scheme==wt_from_rh18) then
1172  surface_scale = max(0.05, 1. - htot/mld_guess)
1173  vstar = cs%vstar_scale_fac * surface_scale * (cs%vstar_surf_fac*u_star + &
1174  vstar_unit_scale * (cs%wstar_ustar_coef*conv_perel*i_dtrho)**c1_3)
1175  endif
1176  hbs_here = gv%H_to_Z * min(hb_hs(k), mixlen_shape(k))
1177  mixlen(k) = max(cs%min_mix_len, ((h_tt*hbs_here)*vstar) / &
1178  ((cs%Ekman_scale_coef * absf) * (h_tt*hbs_here) + vstar))
1179  if (.not.cs%Use_MLD_iteration) then
1180  ! Note again (as prev) that using mixlen here
1181  ! instead of redoing the computation will change answers...
1182  kd(k) = vstar * cs%vonKar * ((h_tt*hbs_here)*vstar) / &
1183  ((cs%Ekman_scale_coef * absf) * (h_tt*hbs_here) + vstar)
1184  else
1185  kd(k) = vstar * cs%vonKar * mixlen(k)
1186  endif
1187  else
1188  vstar = 0.0 ; kd(k) = 0.0
1189  endif
1190  mixvel(k) = vstar
1191 
1192  if (cs%orig_PE_calc) then
1193  call find_pe_chg_orig(kd(k)*dt_h, h(k), hp_a, dte_term, dse_term, &
1194  dt_km1_t2, ds_km1_t2, dt_to_dpe(k), ds_to_dpe(k), &
1195  dt_to_dpe_a(k-1), ds_to_dpe_a(k-1), &
1196  pres_z(k), dt_to_dcolht(k), ds_to_dcolht(k), &
1197  dt_to_dcolht_a(k-1), ds_to_dcolht_a(k-1), &
1198  pe_chg=dpe_conv)
1199  else
1200  call find_pe_chg(0.0, kd(k)*dt_h, hp_a, h(k), &
1201  th_a(k-1), sh_a(k-1), th_b(k), sh_b(k), &
1202  dt_to_dpe_a(k-1), ds_to_dpe_a(k-1), dt_to_dpe(k), ds_to_dpe(k), &
1203  pres_z(k), dt_to_dcolht_a(k-1), ds_to_dcolht_a(k-1), &
1204  dt_to_dcolht(k), ds_to_dcolht(k), &
1205  pe_chg=dpe_conv)
1206  endif
1207  ! Should this be iterated to convergence for Kd?
1208  if (dpe_conv > 0.0) then
1209  kd(k) = kd_guess0 ; dpe_conv = pe_chg_g0
1210  else
1211  mke_src = dmke_max*(1.0 - exp(-(kd(k)*dt_h) * mke2_hharm))
1212  endif
1213  else
1214  ! The energy change does not vary monotonically with Kddt_h. Find the maximum?
1215  kd(k) = kd_guess0 ; dpe_conv = pe_chg_g0
1216  endif
1217 
1218  conv_perel = conv_perel - dpe_conv
1219  mech_tke = mech_tke + mke_src
1220  if (cs%TKE_diagnostics) then
1221  ecd%dTKE_conv = ecd%dTKE_conv - cs%nstar*dpe_conv * i_dtdiag
1222  ecd%dTKE_MKE = ecd%dTKE_MKE + mke_src * i_dtdiag
1223  endif
1224  if (sfc_connected) then
1225  mld_output = mld_output + gv%H_to_Z * h(k)
1226  endif
1227 
1228  kddt_h(k) = kd(k) * dt_h
1229  elseif (tot_tke + (mke_src - pe_chg_g0) >= 0.0) then
1230  ! This column is convctively stable and there is energy to support the suggested
1231  ! mixing. Keep that estimate.
1232  kd(k) = kd_guess0
1233  kddt_h(k) = kddt_h_g0
1234 
1235  ! Reduce the mechanical and convective TKE proportionately.
1236  tot_tke = tot_tke + mke_src
1237  tke_reduc = 0.0 ! tot_TKE could be 0 if Convectively_stable is false.
1238  if (tot_tke > 0.0) tke_reduc = (tot_tke - pe_chg_g0) / tot_tke
1239  if (cs%TKE_diagnostics) then
1240  ecd%dTKE_mixing = ecd%dTKE_mixing - pe_chg_g0 * i_dtdiag
1241  ecd%dTKE_MKE = ecd%dTKE_MKE + mke_src * i_dtdiag
1242  ecd%dTKE_conv_decay = ecd%dTKE_conv_decay + &
1243  (1.0-tke_reduc)*(cs%nstar-nstar_fc) * conv_perel * i_dtdiag
1244  endif
1245  tot_tke = tke_reduc*tot_tke
1246  mech_tke = tke_reduc*(mech_tke + mke_src)
1247  conv_perel = tke_reduc*conv_perel
1248  if (sfc_connected) then
1249  mld_output = mld_output + gv%H_to_Z * h(k)
1250  endif
1251 
1252  elseif (tot_tke == 0.0) then
1253  ! This can arise if nstar_FC = 0, but it is not common.
1254  kd(k) = 0.0 ; kddt_h(k) = 0.0
1255  tot_tke = 0.0 ; conv_perel = 0.0 ; mech_tke = 0.0
1256  sfc_disconnect = .true.
1257  else
1258  ! There is not enough energy to support the mixing, so reduce the
1259  ! diffusivity to what can be supported.
1260  kddt_h_max = kddt_h_g0 ; kddt_h_min = 0.0
1261  tke_left_max = tot_tke + (mke_src - pe_chg_g0)
1262  tke_left_min = tot_tke
1263 
1264  ! As a starting guess, take the minimum of a false position estimate
1265  ! and a Newton's method estimate starting from Kddt_h = 0.0.
1266  kddt_h_guess = tot_tke * kddt_h_max / max( pe_chg_g0 - mke_src, &
1267  kddt_h_max * (dpec_dkd_kd0 - dmke_max * mke2_hharm) )
1268  ! The above expression is mathematically the same as the following
1269  ! except it is not susceptible to division by zero when
1270  ! dPEc_dKd_Kd0 = dMKE_max = 0 .
1271  ! Kddt_h_guess = tot_TKE * min( Kddt_h_max / (PE_chg_g0 - MKE_src), &
1272  ! 1.0 / (dPEc_dKd_Kd0 - dMKE_max * MKE2_Hharm) )
1273  if (debug) then
1274  tke_left_itt(:) = 0.0 ; dpea_dkd_itt(:) = 0.0 ; pe_chg_itt(:) = 0.0
1275  mke_src_itt(:) = 0.0 ; kddt_h_itt(:) = 0.0
1276  endif
1277  do itt=1,max_itt
1278  if (cs%orig_PE_calc) then
1279  call find_pe_chg_orig(kddt_h_guess, h(k), hp_a, dte_term, dse_term, &
1280  dt_km1_t2, ds_km1_t2, dt_to_dpe(k), ds_to_dpe(k), &
1281  dt_to_dpe_a(k-1), ds_to_dpe_a(k-1), &
1282  pres_z(k), dt_to_dcolht(k), ds_to_dcolht(k), &
1283  dt_to_dcolht_a(k-1), ds_to_dcolht_a(k-1), &
1284  pe_chg=pe_chg, dpec_dkd=dpec_dkd )
1285  else
1286  call find_pe_chg(0.0, kddt_h_guess, hp_a, h(k), &
1287  th_a(k-1), sh_a(k-1), th_b(k), sh_b(k), &
1288  dt_to_dpe_a(k-1), ds_to_dpe_a(k-1), dt_to_dpe(k), ds_to_dpe(k), &
1289  pres_z(k), dt_to_dcolht_a(k-1), ds_to_dcolht_a(k-1), &
1290  dt_to_dcolht(k), ds_to_dcolht(k), &
1291  pe_chg=dpe_conv, dpec_dkd=dpec_dkd)
1292  endif
1293  mke_src = dmke_max * (1.0 - exp(-mke2_hharm * kddt_h_guess))
1294  dmke_src_dk = dmke_max * mke2_hharm * exp(-mke2_hharm * kddt_h_guess)
1295 
1296  tke_left = tot_tke + (mke_src - pe_chg)
1297  if (debug .and. itt<=20) then
1298  kddt_h_itt(itt) = kddt_h_guess ; mke_src_itt(itt) = mke_src
1299  pe_chg_itt(itt) = pe_chg ; dpea_dkd_itt(itt) = dpec_dkd
1300  tke_left_itt(itt) = tke_left
1301  endif
1302  ! Store the new bounding values, bearing in mind that min and max
1303  ! here refer to Kddt_h and dTKE_left/dKddt_h < 0:
1304  if (tke_left >= 0.0) then
1305  kddt_h_min = kddt_h_guess ; tke_left_min = tke_left
1306  else
1307  kddt_h_max = kddt_h_guess ; tke_left_max = tke_left
1308  endif
1309 
1310  ! Try to use Newton's method, but if it would go outside the bracketed
1311  ! values use the false-position method instead.
1312  use_newt = .true.
1313  if (dpec_dkd - dmke_src_dk <= 0.0) then
1314  use_newt = .false.
1315  else
1316  dkddt_h_newt = tke_left / (dpec_dkd - dmke_src_dk)
1317  kddt_h_newt = kddt_h_guess + dkddt_h_newt
1318  if ((kddt_h_newt > kddt_h_max) .or. (kddt_h_newt < kddt_h_min)) &
1319  use_newt = .false.
1320  endif
1321 
1322  if (use_newt) then
1323  kddt_h_next = kddt_h_guess + dkddt_h_newt
1324  dkddt_h = dkddt_h_newt
1325  else
1326  kddt_h_next = (tke_left_max * kddt_h_min - kddt_h_max * tke_left_min) / &
1327  (tke_left_max - tke_left_min)
1328  dkddt_h = kddt_h_next - kddt_h_guess
1329  endif
1330 
1331  if ((abs(dkddt_h) < 1e-9*kddt_h_guess) .or. (itt==max_itt)) then
1332  ! Use the old value so that the energy calculation does not need to be repeated.
1333  if (debug) num_itts(k) = itt
1334  exit
1335  else
1336  kddt_h_guess = kddt_h_next
1337  endif
1338  enddo ! Inner iteration loop on itt.
1339  kd(k) = kddt_h_guess / dt_h ; kddt_h(k) = kd(k) * dt_h
1340 
1341  ! All TKE should have been consumed.
1342  if (cs%TKE_diagnostics) then
1343  ecd%dTKE_mixing = ecd%dTKE_mixing - (tot_tke + mke_src) * i_dtdiag
1344  ecd%dTKE_MKE = ecd%dTKE_MKE + mke_src * i_dtdiag
1345  ecd%dTKE_conv_decay = ecd%dTKE_conv_decay + &
1346  (cs%nstar-nstar_fc) * conv_perel * i_dtdiag
1347  endif
1348 
1349  if (sfc_connected) mld_output = mld_output + &
1350  (pe_chg / (pe_chg_g0)) * gv%H_to_Z * h(k)
1351 
1352  tot_tke = 0.0 ; mech_tke = 0.0 ; conv_perel = 0.0
1353  sfc_disconnect = .true.
1354  endif ! End of convective or forced mixing cases to determine Kd.
1355 
1356  kddt_h(k) = kd(k) * dt_h
1357  ! At this point, the final value of Kddt_h(K) is known, so the
1358  ! estimated properties for layer k-1 can be calculated.
1359  b1 = 1.0 / (hp_a + kddt_h(k))
1360  c1(k) = kddt_h(k) * b1
1361  if (cs%orig_PE_calc) then
1362  dte(k-1) = b1 * ( kddt_h(k)*(t0(k)-t0(k-1)) + dte_t2 )
1363  dse(k-1) = b1 * ( kddt_h(k)*(s0(k)-s0(k-1)) + dse_t2 )
1364  endif
1365 
1366  hp_a = h(k) + (hp_a * b1) * kddt_h(k)
1367  dt_to_dpe_a(k) = dt_to_dpe(k) + c1(k)*dt_to_dpe_a(k-1)
1368  ds_to_dpe_a(k) = ds_to_dpe(k) + c1(k)*ds_to_dpe_a(k-1)
1369  dt_to_dcolht_a(k) = dt_to_dcolht(k) + c1(k)*dt_to_dcolht_a(k-1)
1370  ds_to_dcolht_a(k) = ds_to_dcolht(k) + c1(k)*ds_to_dcolht_a(k-1)
1371 
1372  endif ! tot_TKT > 0.0 branch. Kddt_h(K) has been set.
1373 
1374  ! Store integrated velocities and thicknesses for MKE conversion calculations.
1375  if (sfc_disconnect) then
1376  ! There is no turbulence at this interface, so zero out the running sums.
1377  uhtot = u(k)*h(k)
1378  vhtot = v(k)*h(k)
1379  htot = h(k)
1380  sfc_connected = .false.
1381  else
1382  uhtot = uhtot + u(k)*h(k)
1383  vhtot = vhtot + v(k)*h(k)
1384  htot = htot + h(k)
1385  endif
1386 
1387  if (calc_te) then
1388  if (k==2) then
1389  te(1) = b1*(h(1)*t0(1))
1390  se(1) = b1*(h(1)*s0(1))
1391  else
1392  te(k-1) = b1 * (h(k-1) * t0(k-1) + kddt_h(k-1) * te(k-2))
1393  se(k-1) = b1 * (h(k-1) * s0(k-1) + kddt_h(k-1) * se(k-2))
1394  endif
1395  endif
1396  enddo
1397  kd(nz+1) = 0.0
1398 
1399  if (calc_dt_expect) then
1400  ! Complete the tridiagonal solve for Te.
1401  b1 = 1.0 / hp_a
1402  te(nz) = b1 * (h(nz) * t0(nz) + kddt_h(nz) * te(nz-1))
1403  se(nz) = b1 * (h(nz) * s0(nz) + kddt_h(nz) * se(nz-1))
1404  ecd%dT_expect(nz) = te(nz) - t0(nz) ; ecd%dS_expect(nz) = se(nz) - s0(nz)
1405  do k=nz-1,1,-1
1406  te(k) = te(k) + c1(k+1)*te(k+1)
1407  se(k) = se(k) + c1(k+1)*se(k+1)
1408  ecd%dT_expect(k) = te(k) - t0(k) ; ecd%dS_expect(k) = se(k) - s0(k)
1409  enddo
1410  endif
1411 
1412  if (debug) then
1413  dpe_debug = 0.0
1414  do k=1,nz
1415  dpe_debug = dpe_debug + (dt_to_dpe(k) * (te(k) - t0(k)) + &
1416  ds_to_dpe(k) * (se(k) - s0(k)))
1417  enddo
1418  mixing_debug = dpe_debug * i_dtdiag
1419  endif
1420  k = nz ! This is here to allow a breakpoint to be set.
1421  !/BGR
1422  ! The following lines are used for the iteration
1423  ! note the iteration has been altered to use the value predicted by
1424  ! the TKE threshold (ML_DEPTH). This is because the MSTAR
1425  ! is now dependent on the ML, and therefore the ML needs to be estimated
1426  ! more precisely than the grid spacing.
1427 
1428  !New method uses ML_DEPTH as computed in ePBL routine
1429  mld_found = mld_output
1430  if (mld_found - mld_guess > cs%MLD_tol) then
1431  min_mld = mld_guess ; dmld_min = mld_found - mld_guess
1432  elseif (abs(mld_found - mld_guess) < cs%MLD_tol) then
1433  obl_converged = .true. ! Break convergence loop
1434  else ! We know this guess was too deep
1435  max_mld = mld_guess ; dmld_max = mld_found - mld_guess ! < -CS%MLD_tol
1436  endif
1437 
1438  if (.not.obl_converged) then ; if (cs%MLD_bisection) then
1439  ! For the next pass, guess the average of the minimum and maximum values.
1440  mld_guess = 0.5*(min_mld + max_mld)
1441  else ! Try using the false position method or the returned value instead of simple bisection.
1442  ! Taking the occasional step with MLD_output empirically helps to converge faster.
1443  if ((dmld_min > 0.0) .and. (dmld_max < 0.0) .and. (obl_it > 2) .and. (mod(obl_it-1,4)>0)) then
1444  ! Both bounds have valid change estimates and are probably in the range of possible outputs.
1445  mld_guess = (dmld_min*max_mld - dmld_max*min_mld) / (dmld_min - dmld_max)
1446  elseif ((mld_found > min_mld) .and. (mld_found < max_mld)) then
1447  ! The output MLD_found is an interesting guess, as it likely to bracket the true solution
1448  ! along with the previous value of MLD_guess and to be close to the solution.
1449  mld_guess = mld_found
1450  else ! Bisect if the other guesses would be out-of-bounds. This does not happen much.
1451  mld_guess = 0.5*(min_mld + max_mld)
1452  endif
1453  endif ; endif
1454  endif
1455  if ((obl_converged) .or. (obl_it==cs%Max_MLD_Its)) then
1456  if (report_avg_its) then
1457  cs%sum_its(1) = cs%sum_its(1) + real_to_efp(real(OBL_it))
1458  cs%sum_its(2) = cs%sum_its(2) + real_to_efp(1.0)
1459  endif
1460  exit
1461  endif
1462  enddo ! Iteration loop for converged boundary layer thickness.
1463  if (cs%Use_LT) then
1464  ecd%LA = la ; ecd%LAmod = lamod ; ecd%mstar = mstar_total ; ecd%mstar_LT = mstar_lt
1465  else
1466  ecd%LA = 0.0 ; ecd%LAmod = 0.0 ; ecd%mstar = mstar_total ; ecd%mstar_LT = 0.0
1467  endif
1468 
1469  mld_io = mld_output
1470 
1471 end subroutine epbl_column
1472 
1473 !> This subroutine calculates the change in potential energy and or derivatives
1474 !! for several changes in an interfaces's diapycnal diffusivity times a timestep.
1475 subroutine find_pe_chg(Kddt_h0, dKddt_h, hp_a, hp_b, Th_a, Sh_a, Th_b, Sh_b, &
1476  dT_to_dPE_a, dS_to_dPE_a, dT_to_dPE_b, dS_to_dPE_b, &
1477  pres_Z, dT_to_dColHt_a, dS_to_dColHt_a, dT_to_dColHt_b, dS_to_dColHt_b, &
1478  PE_chg, dPEc_dKd, dPE_max, dPEc_dKd_0, PE_ColHt_cor)
1479  real, intent(in) :: Kddt_h0 !< The previously used diffusivity at an interface times
1480  !! the time step and divided by the average of the
1481  !! thicknesses around the interface [H ~> m or kg m-2].
1482  real, intent(in) :: dKddt_h !< The trial change in the diffusivity at an interface times
1483  !! the time step and divided by the average of the
1484  !! thicknesses around the interface [H ~> m or kg m-2].
1485  real, intent(in) :: hp_a !< The effective pivot thickness of the layer above the
1486  !! interface, given by h_k plus a term that
1487  !! is a fraction (determined from the tridiagonal solver) of
1488  !! Kddt_h for the interface above [H ~> m or kg m-2].
1489  real, intent(in) :: hp_b !< The effective pivot thickness of the layer below the
1490  !! interface, given by h_k plus a term that
1491  !! is a fraction (determined from the tridiagonal solver) of
1492  !! Kddt_h for the interface above [H ~> m or kg m-2].
1493  real, intent(in) :: Th_a !< An effective temperature times a thickness in the layer
1494  !! above, including implicit mixing effects with other
1495  !! yet higher layers [degC H ~> degC m or degC kg m-2].
1496  real, intent(in) :: Sh_a !< An effective salinity times a thickness in the layer
1497  !! above, including implicit mixing effects with other
1498  !! yet higher layers [degC H ~> degC m or degC kg m-2].
1499  real, intent(in) :: Th_b !< An effective temperature times a thickness in the layer
1500  !! below, including implicit mixfing effects with other
1501  !! yet lower layers [degC H ~> degC m or degC kg m-2].
1502  real, intent(in) :: Sh_b !< An effective salinity times a thickness in the layer
1503  !! below, including implicit mixing effects with other
1504  !! yet lower layers [degC H ~> degC m or degC kg m-2].
1505  real, intent(in) :: dT_to_dPE_a !< A factor (pres_lay*mass_lay*dSpec_vol/dT) relating
1506  !! a layer's temperature change to the change in column potential
1507  !! energy, including all implicit diffusive changes in the
1508  !! temperatures of all the layers above [R Z3 T-2 degC-1 ~> J m-2 degC-1].
1509  real, intent(in) :: dS_to_dPE_a !< A factor (pres_lay*mass_lay*dSpec_vol/dS) relating
1510  !! a layer's salinity change to the change in column potential
1511  !! energy, including all implicit diffusive changes in the
1512  !! salinities of all the layers above [R Z3 T-2 ppt-1 ~> J m-2 ppt-1].
1513  real, intent(in) :: dT_to_dPE_b !< A factor (pres_lay*mass_lay*dSpec_vol/dT) relating
1514  !! a layer's temperature change to the change in column potential
1515  !! energy, including all implicit diffusive changes in the
1516  !! temperatures of all the layers below [R Z3 T-2 degC-1 ~> J m-2 degC-1].
1517  real, intent(in) :: dS_to_dPE_b !< A factor (pres_lay*mass_lay*dSpec_vol/dS) relating
1518  !! a layer's salinity change to the change in column potential
1519  !! energy, including all implicit diffusive changes in the
1520  !! salinities of all the layers below [R Z3 T-2 ppt-1 ~> J m-2 ppt-1].
1521  real, intent(in) :: pres_Z !< The rescaled hydrostatic interface pressure, which relates
1522  !! the changes in column thickness to the energy that is radiated
1523  !! as gravity waves and unavailable to drive mixing [R Z2 T-2 ~> J m-3].
1524  real, intent(in) :: dT_to_dColHt_a !< A factor (mass_lay*dSColHtc_vol/dT) relating
1525  !! a layer's temperature change to the change in column
1526  !! height, including all implicit diffusive changes
1527  !! in the temperatures of all the layers above [Z degC-1 ~> m degC-1].
1528  real, intent(in) :: dS_to_dColHt_a !< A factor (mass_lay*dSColHtc_vol/dS) relating
1529  !! a layer's salinity change to the change in column
1530  !! height, including all implicit diffusive changes
1531  !! in the salinities of all the layers above [Z ppt-1 ~> m ppt-1].
1532  real, intent(in) :: dT_to_dColHt_b !< A factor (mass_lay*dSColHtc_vol/dT) relating
1533  !! a layer's temperature change to the change in column
1534  !! height, including all implicit diffusive changes
1535  !! in the temperatures of all the layers below [Z degC-1 ~> m degC-1].
1536  real, intent(in) :: dS_to_dColHt_b !< A factor (mass_lay*dSColHtc_vol/dS) relating
1537  !! a layer's salinity change to the change in column
1538  !! height, including all implicit diffusive changes
1539  !! in the salinities of all the layers below [Z ppt-1 ~> m ppt-1].
1540 
1541  real, optional, intent(out) :: PE_chg !< The change in column potential energy from applying
1542  !! Kddt_h at the present interface [R Z3 T-2 ~> J m-2].
1543  real, optional, intent(out) :: dPEc_dKd !< The partial derivative of PE_chg with Kddt_h
1544  !! [R Z3 T-2 H-1 ~> J m-3 or J kg-1].
1545  real, optional, intent(out) :: dPE_max !< The maximum change in column potential energy that could
1546  !! be realizedd by applying a huge value of Kddt_h at the
1547  !! present interface [R Z3 T-2 ~> J m-2].
1548  real, optional, intent(out) :: dPEc_dKd_0 !< The partial derivative of PE_chg with Kddt_h in the
1549  !! limit where Kddt_h = 0 [R Z3 T-2 H-1 ~> J m-3 or J kg-1].
1550  real, optional, intent(out) :: PE_ColHt_cor !< The correction to PE_chg that is made due to a net
1551  !! change in the column height [R Z3 T-2 ~> J m-2].
1552 
1553  real :: hps ! The sum of the two effective pivot thicknesses [H ~> m or kg m-2].
1554  real :: bdt1 ! A product of the two pivot thicknesses plus a diffusive term [H2 ~> m2 or kg2 m-4].
1555  real :: dT_c ! The core term in the expressions for the temperature changes [degC H2 ~> degC m2 or degC kg2 m-4].
1556  real :: dS_c ! The core term in the expressions for the salinity changes [ppt H2 ~> ppt m2 or ppt kg2 m-4].
1557  real :: PEc_core ! The diffusivity-independent core term in the expressions
1558  ! for the potential energy changes [R Z2 T-2 ~> J m-3].
1559  real :: ColHt_core ! The diffusivity-independent core term in the expressions
1560  ! for the column height changes [H Z ~> m2 or kg m-1].
1561  real :: ColHt_chg ! The change in the column height [H ~> m or kg m-2].
1562  real :: y1_3 ! A local temporary term in [H-3 ~> m-3 or m6 kg-3].
1563  real :: y1_4 ! A local temporary term in [H-4 ~> m-4 or m8 kg-4].
1564 
1565  ! The expression for the change in potential energy used here is derived
1566  ! from the expression for the final estimates of the changes in temperature
1567  ! and salinities, and then extensively manipulated to get it into its most
1568  ! succint form. The derivation is not necessarily obvious, but it demonstrably
1569  ! works by comparison with separate calculations of the energy changes after
1570  ! the tridiagonal solver for the final changes in temperature and salinity are
1571  ! applied.
1572 
1573  hps = hp_a + hp_b
1574  bdt1 = hp_a * hp_b + kddt_h0 * hps
1575  dt_c = hp_a * th_b - hp_b * th_a
1576  ds_c = hp_a * sh_b - hp_b * sh_a
1577  pec_core = hp_b * (dt_to_dpe_a * dt_c + ds_to_dpe_a * ds_c) - &
1578  hp_a * (dt_to_dpe_b * dt_c + ds_to_dpe_b * ds_c)
1579  colht_core = hp_b * (dt_to_dcolht_a * dt_c + ds_to_dcolht_a * ds_c) - &
1580  hp_a * (dt_to_dcolht_b * dt_c + ds_to_dcolht_b * ds_c)
1581 
1582  if (present(pe_chg)) then
1583  ! Find the change in column potential energy due to the change in the
1584  ! diffusivity at this interface by dKddt_h.
1585  y1_3 = dkddt_h / (bdt1 * (bdt1 + dkddt_h * hps))
1586  pe_chg = pec_core * y1_3
1587  colht_chg = colht_core * y1_3
1588  if (colht_chg < 0.0) pe_chg = pe_chg - pres_z * colht_chg
1589  if (present(pe_colht_cor)) pe_colht_cor = -pres_z * min(colht_chg, 0.0)
1590  elseif (present(pe_colht_cor)) then
1591  y1_3 = dkddt_h / (bdt1 * (bdt1 + dkddt_h * hps))
1592  pe_colht_cor = -pres_z * min(colht_core * y1_3, 0.0)
1593  endif
1594 
1595  if (present(dpec_dkd)) then
1596  ! Find the derivative of the potential energy change with dKddt_h.
1597  y1_4 = 1.0 / (bdt1 + dkddt_h * hps)**2
1598  dpec_dkd = pec_core * y1_4
1599  colht_chg = colht_core * y1_4
1600  if (colht_chg < 0.0) dpec_dkd = dpec_dkd - pres_z * colht_chg
1601  endif
1602 
1603  if (present(dpe_max)) then
1604  ! This expression is the limit of PE_chg for infinite dKddt_h.
1605  y1_3 = 1.0 / (bdt1 * hps)
1606  dpe_max = pec_core * y1_3
1607  colht_chg = colht_core * y1_3
1608  if (colht_chg < 0.0) dpe_max = dpe_max - pres_z * colht_chg
1609  endif
1610 
1611  if (present(dpec_dkd_0)) then
1612  ! This expression is the limit of dPEc_dKd for dKddt_h = 0.
1613  y1_4 = 1.0 / bdt1**2
1614  dpec_dkd_0 = pec_core * y1_4
1615  colht_chg = colht_core * y1_4
1616  if (colht_chg < 0.0) dpec_dkd_0 = dpec_dkd_0 - pres_z * colht_chg
1617  endif
1618 
1619 end subroutine find_pe_chg
1620 
1621 !> This subroutine calculates the change in potential energy and or derivatives
1622 !! for several changes in an interfaces's diapycnal diffusivity times a timestep
1623 !! using the original form used in the first version of ePBL.
1624 subroutine find_pe_chg_orig(Kddt_h, h_k, b_den_1, dTe_term, dSe_term, &
1625  dT_km1_t2, dS_km1_t2, dT_to_dPE_k, dS_to_dPE_k, &
1626  dT_to_dPEa, dS_to_dPEa, pres_Z, dT_to_dColHt_k, &
1627  dS_to_dColHt_k, dT_to_dColHta, dS_to_dColHta, &
1628  PE_chg, dPEc_dKd, dPE_max, dPEc_dKd_0)
1629  real, intent(in) :: Kddt_h !< The diffusivity at an interface times the time step and
1630  !! divided by the average of the thicknesses around the
1631  !! interface [H ~> m or kg m-2].
1632  real, intent(in) :: h_k !< The thickness of the layer below the interface [H ~> m or kg m-2].
1633  real, intent(in) :: b_den_1 !< The first term in the denominator of the pivot
1634  !! for the tridiagonal solver, given by h_k plus a term that
1635  !! is a fraction (determined from the tridiagonal solver) of
1636  !! Kddt_h for the interface above [H ~> m or kg m-2].
1637  real, intent(in) :: dTe_term !< A diffusivity-independent term related to the temperature change
1638  !! in the layer below the interface [degC H ~> degC m or degC kg m-2].
1639  real, intent(in) :: dSe_term !< A diffusivity-independent term related to the salinity change
1640  !! in the layer below the interface [ppt H ~> ppt m or ppt kg m-2].
1641  real, intent(in) :: dT_km1_t2 !< A diffusivity-independent term related to the
1642  !! temperature change in the layer above the interface [degC].
1643  real, intent(in) :: dS_km1_t2 !< A diffusivity-independent term related to the
1644  !! salinity change in the layer above the interface [ppt].
1645  real, intent(in) :: pres_Z !< The rescaled hydrostatic interface pressure, which relates
1646  !! the changes in column thickness to the energy that is radiated
1647  !! as gravity waves and unavailable to drive mixing [R Z2 T-2 ~> J m-3].
1648  real, intent(in) :: dT_to_dPE_k !< A factor (pres_lay*mass_lay*dSpec_vol/dT) relating
1649  !! a layer's temperature change to the change in column potential
1650  !! energy, including all implicit diffusive changes in the
1651  !! temperatures of all the layers below [R Z3 T-2 degC-1 ~> J m-2 degC-1].
1652  real, intent(in) :: dS_to_dPE_k !< A factor (pres_lay*mass_lay*dSpec_vol/dS) relating
1653  !! a layer's salinity change to the change in column potential
1654  !! energy, including all implicit diffusive changes in the
1655  !! in the salinities of all the layers below [R Z3 T-2 ppt-1 ~> J m-2 ppt-1].
1656  real, intent(in) :: dT_to_dPEa !< A factor (pres_lay*mass_lay*dSpec_vol/dT) relating
1657  !! a layer's temperature change to the change in column potential
1658  !! energy, including all implicit diffusive changes in the
1659  !! temperatures of all the layers above [R Z3 T-2 degC-1 ~> J m-2 degC-1].
1660  real, intent(in) :: dS_to_dPEa !< A factor (pres_lay*mass_lay*dSpec_vol/dS) relating
1661  !! a layer's salinity change to the change in column potential
1662  !! energy, including all implicit diffusive changes in the
1663  !! salinities of all the layers above [R Z3 T-2 ppt-1 ~> J m-2 ppt-1].
1664  real, intent(in) :: dT_to_dColHt_k !< A factor (mass_lay*dSColHtc_vol/dT) relating
1665  !! a layer's temperature change to the change in column
1666  !! height, including all implicit diffusive changes in the
1667  !! temperatures of all the layers below [Z degC-1 ~> m degC-1].
1668  real, intent(in) :: dS_to_dColHt_k !< A factor (mass_lay*dSColHtc_vol/dS) relating
1669  !! a layer's salinity change to the change in column
1670  !! height, including all implicit diffusive changes
1671  !! in the salinities of all the layers below [Z ppt-1 ~> m ppt-1].
1672  real, intent(in) :: dT_to_dColHta !< A factor (mass_lay*dSColHtc_vol/dT) relating
1673  !! a layer's temperature change to the change in column
1674  !! height, including all implicit diffusive changes
1675  !! in the temperatures of all the layers above [Z degC-1 ~> m degC-1].
1676  real, intent(in) :: dS_to_dColHta !< A factor (mass_lay*dSColHtc_vol/dS) relating
1677  !! a layer's salinity change to the change in column
1678  !! height, including all implicit diffusive changes
1679  !! in the salinities of all the layers above [Z ppt-1 ~> m ppt-1].
1680 
1681  real, optional, intent(out) :: PE_chg !< The change in column potential energy from applying
1682  !! Kddt_h at the present interface [R Z3 T-2 ~> J m-2].
1683  real, optional, intent(out) :: dPEc_dKd !< The partial derivative of PE_chg with Kddt_h
1684  !! [R Z3 T-2 H-1 ~> J m-3 or J kg-1].
1685  real, optional, intent(out) :: dPE_max !< The maximum change in column potential energy that could
1686  !! be realizedd by applying a huge value of Kddt_h at the
1687  !! present interface [R Z3 T-2 ~> J m-2].
1688  real, optional, intent(out) :: dPEc_dKd_0 !< The partial derivative of PE_chg with Kddt_h in the
1689  !! limit where Kddt_h = 0 [R Z3 T-2 H-1 ~> J m-3 or J kg-1].
1690 
1691 ! This subroutine determines the total potential energy change due to mixing
1692 ! at an interface, including all of the implicit effects of the prescribed
1693 ! mixing at interfaces above. Everything here is derived by careful manipulation
1694 ! of the robust tridiagonal solvers used for tracers by MOM6. The results are
1695 ! positive for mixing in a stably stratified environment.
1696 ! The comments describing these arguments are for a downward mixing pass, but
1697 ! this routine can also be used for an upward pass with the sense of direction
1698 ! reversed.
1699 
1700  real :: b1 ! b1 is used by the tridiagonal solver [H-1 ~> m-1 or m2 kg-1].
1701  real :: b1Kd ! Temporary array [nondim]
1702  real :: ColHt_chg ! The change in column thickness [Z ~> m].
1703  real :: dColHt_max ! The change in column thickness for infinite diffusivity [Z ~> m].
1704  real :: dColHt_dKd ! The partial derivative of column thickness with Kddt_h [Z H-1 ~> 1 or m3 kg-2].
1705  real :: dT_k, dT_km1 ! Temporary arrays [degC].
1706  real :: dS_k, dS_km1 ! Temporary arrays [ppt].
1707  real :: I_Kr_denom ! Temporary array [H-2 ~> m-2 or m4 kg-2]
1708  real :: dKr_dKd ! Nondimensional temporary array.
1709  real :: ddT_k_dKd, ddT_km1_dKd ! Temporary arrays [degC H-1 ~> m-1 or m2 kg-1].
1710  real :: ddS_k_dKd, ddS_km1_dKd ! Temporary arrays [ppt H-1 ~> ppt m-1 or ppt m2 kg-1].
1711 
1712  b1 = 1.0 / (b_den_1 + kddt_h)
1713  b1kd = kddt_h*b1
1714 
1715  ! Start with the temperature change in layer k-1 due to the diffusivity at
1716  ! interface K without considering the effects of changes in layer k.
1717 
1718  ! Calculate the change in PE due to the diffusion at interface K
1719  ! if Kddt_h(K+1) = 0.
1720  i_kr_denom = 1.0 / (h_k*b_den_1 + (b_den_1 + h_k)*kddt_h)
1721 
1722  dt_k = (kddt_h*i_kr_denom) * dte_term
1723  ds_k = (kddt_h*i_kr_denom) * dse_term
1724 
1725  if (present(pe_chg)) then
1726  ! Find the change in energy due to diffusion with strength Kddt_h at this interface.
1727  ! Increment the temperature changes in layer k-1 due the changes in layer k.
1728  dt_km1 = b1kd * ( dt_k + dt_km1_t2 )
1729  ds_km1 = b1kd * ( ds_k + ds_km1_t2 )
1730  pe_chg = (dt_to_dpe_k * dt_k + dt_to_dpea * dt_km1) + &
1731  (ds_to_dpe_k * ds_k + ds_to_dpea * ds_km1)
1732  colht_chg = (dt_to_dcolht_k * dt_k + dt_to_dcolhta * dt_km1) + &
1733  (ds_to_dcolht_k * ds_k + ds_to_dcolhta * ds_km1)
1734  if (colht_chg < 0.0) pe_chg = pe_chg - pres_z * colht_chg
1735  endif
1736 
1737  if (present(dpec_dkd)) then
1738  ! Find the derivatives of the temperature and salinity changes with Kddt_h.
1739  dkr_dkd = (h_k*b_den_1) * i_kr_denom**2
1740 
1741  ddt_k_dkd = dkr_dkd * dte_term
1742  dds_k_dkd = dkr_dkd * dse_term
1743  ddt_km1_dkd = (b1**2 * b_den_1) * ( dt_k + dt_km1_t2 ) + b1kd * ddt_k_dkd
1744  dds_km1_dkd = (b1**2 * b_den_1) * ( ds_k + ds_km1_t2 ) + b1kd * dds_k_dkd
1745 
1746  ! Calculate the partial derivative of Pe_chg with Kddt_h.
1747  dpec_dkd = (dt_to_dpe_k * ddt_k_dkd + dt_to_dpea * ddt_km1_dkd) + &
1748  (ds_to_dpe_k * dds_k_dkd + ds_to_dpea * dds_km1_dkd)
1749  dcolht_dkd = (dt_to_dcolht_k * ddt_k_dkd + dt_to_dcolhta * ddt_km1_dkd) + &
1750  (ds_to_dcolht_k * dds_k_dkd + ds_to_dcolhta * dds_km1_dkd)
1751  if (dcolht_dkd < 0.0) dpec_dkd = dpec_dkd - pres_z * dcolht_dkd
1752  endif
1753 
1754  if (present(dpe_max)) then
1755  ! This expression is the limit of PE_chg for infinite Kddt_h.
1756  dpe_max = (dt_to_dpea * dt_km1_t2 + ds_to_dpea * ds_km1_t2) + &
1757  ((dt_to_dpe_k + dt_to_dpea) * dte_term + &
1758  (ds_to_dpe_k + ds_to_dpea) * dse_term) / (b_den_1 + h_k)
1759  dcolht_max = (dt_to_dcolhta * dt_km1_t2 + ds_to_dcolhta * ds_km1_t2) + &
1760  ((dt_to_dcolht_k + dt_to_dcolhta) * dte_term + &
1761  (ds_to_dcolht_k + ds_to_dcolhta) * dse_term) / (b_den_1 + h_k)
1762  if (dcolht_max < 0.0) dpe_max = dpe_max - pres_z*dcolht_max
1763  endif
1764 
1765  if (present(dpec_dkd_0)) then
1766  ! This expression is the limit of dPEc_dKd for Kddt_h = 0.
1767  dpec_dkd_0 = (dt_to_dpea * dt_km1_t2 + ds_to_dpea * ds_km1_t2) / (b_den_1) + &
1768  (dt_to_dpe_k * dte_term + ds_to_dpe_k * dse_term) / (h_k*b_den_1)
1769  dcolht_dkd = (dt_to_dcolhta * dt_km1_t2 + ds_to_dcolhta * ds_km1_t2) / (b_den_1) + &
1770  (dt_to_dcolht_k * dte_term + ds_to_dcolht_k * dse_term) / (h_k*b_den_1)
1771  if (dcolht_dkd < 0.0) dpec_dkd_0 = dpec_dkd_0 - pres_z*dcolht_dkd
1772  endif
1773 
1774 end subroutine find_pe_chg_orig
1775 
1776 !> This subroutine finds the Mstar value for ePBL
1777 subroutine find_mstar(CS, US, Buoyancy_Flux, UStar, UStar_Mean,&
1778  BLD, Abs_Coriolis, MStar, Langmuir_Number,&
1779  MStar_LT, Convect_Langmuir_Number)
1780  type(energetic_PBL_CS), pointer :: CS !< Energetic_PBL control structure.
1781  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1782  real, intent(in) :: UStar !< ustar w/ gustiness [Z T-1 ~> m s-1]
1783  real, intent(in) :: UStar_Mean !< ustar w/o gustiness [Z T-1 ~> m s-1]
1784  real, intent(in) :: Abs_Coriolis !< abolute value of the Coriolis parameter [T-1 ~> s-1]
1785  real, intent(in) :: Buoyancy_Flux !< Buoyancy flux [Z2 T-3 ~> m2 s-3]
1786  real, intent(in) :: BLD !< boundary layer depth [Z ~> m]
1787  real, intent(out) :: Mstar !< Ouput mstar (Mixing/ustar**3) [nondim]
1788  real, optional, intent(in) :: Langmuir_Number !< Langmuir number [nondim]
1789  real, optional, intent(out) :: MStar_LT !< Mstar increase due to Langmuir turbulence [nondim]
1790  real, optional, intent(out) :: Convect_Langmuir_number !< Langmuir number including buoyancy flux [nondim]
1791 
1792  !/ Variables used in computing mstar
1793  real :: MSN_term ! Temporary terms [nondim]
1794  real :: MSCR_term1, MSCR_term2 ! Temporary terms [Z3 T-3 ~> m3 s-3]
1795  real :: MStar_Conv_Red ! Adjustment made to mstar due to convection reducing mechanical mixing [nondim]
1796  real :: MStar_S, MStar_N ! Mstar in (S)tabilizing/(N)ot-stabilizing buoyancy flux [nondim]
1797 
1798  !/ Integer options for how to find mstar
1799 
1800  !/
1801 
1802  if (cs%mstar_scheme == use_fixed_mstar) then
1803  mstar = cs%Fixed_MStar
1804  !/ 1. Get mstar
1805  elseif (cs%mstar_scheme == mstar_from_ekman) then
1806 
1807  if (cs%answers_2018) then
1808  ! The limit for the balance of rotation and stabilizing is f(L_Ekman,L_Obukhov)
1809  mstar_s = cs%MStar_coef*sqrt(max(0.0,buoyancy_flux) / ustar**2 / &
1810  (abs_coriolis + 1.e-10*us%T_to_s) )
1811  ! The limit for rotation (Ekman length) limited mixing
1812  mstar_n = cs%C_Ek * log( max( 1., ustar / (abs_coriolis + 1.e-10*us%T_to_s) / bld ) )
1813  else
1814  ! The limit for the balance of rotation and stabilizing is f(L_Ekman,L_Obukhov)
1815  mstar_s = cs%MSTAR_COEF*sqrt(max(0.0, buoyancy_flux) / (ustar**2 * max(abs_coriolis, 1.e-20*us%T_to_s)))
1816  ! The limit for rotation (Ekman length) limited mixing
1817  mstar_n = 0.0
1818  if (ustar > abs_coriolis * bld) mstar_n = cs%C_EK * log(ustar / (abs_coriolis * bld))
1819  endif
1820 
1821  ! Here 1.25 is about .5/von Karman, which gives the Obukhov limit.
1822  mstar = max(mstar_s, min(1.25, mstar_n))
1823  if (cs%MStar_Cap > 0.0) mstar = min( cs%MStar_Cap,mstar )
1824  elseif ( cs%mstar_scheme == mstar_from_rh18 ) then
1825  if (cs%answers_2018) then
1826  mstar_n = cs%RH18_MStar_cn1 * ( 1.0 - 1.0 / ( 1. + cs%RH18_MStar_cn2 * &
1827  exp( cs%RH18_mstar_CN3 * bld * abs_coriolis / ustar) ) )
1828  else
1829  msn_term = cs%RH18_MStar_cn2 * exp( cs%RH18_mstar_CN3 * bld * abs_coriolis / ustar)
1830  mstar_n = (cs%RH18_MStar_cn1 * msn_term) / ( 1. + msn_term)
1831  endif
1832  mstar_s = cs%RH18_MStar_CS1 * ( max(0.0, buoyancy_flux)**2 * bld / &
1833  ( ustar**5 * max(abs_coriolis,1.e-20*us%T_to_s) ) )**cs%RH18_mstar_cs2
1834  mstar = mstar_n + mstar_s
1835  endif
1836 
1837  !/ 2. Adjust mstar to account for convective turbulence
1838  if (cs%answers_2018) then
1839  mstar_conv_red = 1. - cs%MStar_Convect_coef * (-min(0.0,buoyancy_flux) + 1.e-10*us%T_to_s**3*us%m_to_Z**2) / &
1840  ( (-min(0.0,buoyancy_flux) + 1.e-10*us%T_to_s**3*us%m_to_Z**2) + &
1841  2.0 *mstar * ustar**3 / bld )
1842  else
1843  mscr_term1 = -bld * min(0.0, buoyancy_flux)
1844  mscr_term2 = 2.0*mstar * ustar**3
1845  if ( abs(mscr_term2) > 0.0) then
1846  mstar_conv_red = ((1.-cs%mstar_convect_coef) * mscr_term1 + mscr_term2) / (mscr_term1 + mscr_term2)
1847  else
1848  mstar_conv_red = 1.-cs%mstar_convect_coef
1849  endif
1850  endif
1851 
1852  !/3. Combine various mstar terms to get final value
1853  mstar = mstar * mstar_conv_red
1854 
1855  if (present(langmuir_number)) then
1856  !### In this call, ustar was previously ustar_mean. Is this change deliberate, Brandon? -RWH
1857  call mstar_langmuir(cs, us, abs_coriolis, buoyancy_flux, ustar, bld, langmuir_number, mstar, &
1858  mstar_lt, convect_langmuir_number)
1859  endif
1860 
1861 end subroutine find_mstar
1862 
1863 !> This subroutine modifies the Mstar value if the Langmuir number is present
1864 subroutine mstar_langmuir(CS, US, Abs_Coriolis, Buoyancy_Flux, UStar, BLD, Langmuir_Number, &
1865  Mstar, MStar_LT, Convect_Langmuir_Number)
1866  type(energetic_PBL_CS), pointer :: CS !< Energetic_PBL control structure.
1867  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1868  real, intent(in) :: Abs_Coriolis !< Absolute value of the Coriolis parameter [T-1 ~> s-1]
1869  real, intent(in) :: Buoyancy_Flux !< Buoyancy flux [Z2 T-3 ~> m2 s-3]
1870  real, intent(in) :: UStar !< Surface friction velocity with? gustiness [Z T-1 ~> m s-1]
1871  real, intent(in) :: BLD !< boundary layer depth [Z ~> m]
1872  real, intent(inout) :: Mstar !< Input/output mstar (Mixing/ustar**3) [nondim]
1873  real, intent(in) :: Langmuir_Number !< Langmuir number [nondim]
1874  real, intent(out) :: MStar_LT !< Mstar increase due to Langmuir turbulence [nondim]
1875  real, intent(out) :: Convect_Langmuir_number !< Langmuir number including buoyancy flux [nondim]
1876 
1877  !/
1878  real, parameter :: Max_ratio = 1.0e16 ! The maximum value of a nondimensional ratio.
1879  real :: enhance_mstar ! A multiplicative scaling of mstar due to Langmuir turbulence.
1880  real :: mstar_LT_add ! A value that is added to mstar due to Langmuir turbulence.
1881  real :: iL_Ekman ! Inverse of Ekman length scale [Z-1 ~> m-1].
1882  real :: iL_Obukhov ! Inverse of Obukhov length scale [Z-1 ~> m-1].
1883  real :: I_ustar ! The Adcroft reciprocal of ustar [T Z-1 ~> s m-1]
1884  real :: I_f ! The Adcroft reciprocal of the Coriolis parameter [T ~> s]
1885  real :: MLD_Ekman ! The ratio of the mixed layer depth to the Ekman layer depth [nondim].
1886  real :: Ekman_Obukhov ! The Ekman layer thickness divided by the Obukhov depth [nondim].
1887  real :: MLD_Obukhov ! The mixed layer depth divided by the Obukhov depth [nondim].
1888  real :: MLD_Obukhov_stab ! Ratios of length scales where MLD is boundary layer depth [nondim].
1889  real :: Ekman_Obukhov_stab ! >
1890  real :: MLD_Obukhov_un ! Ratios of length scales where MLD is boundary layer depth
1891  real :: Ekman_Obukhov_un ! >
1892 
1893  ! Set default values for no Langmuir effects.
1894  enhance_mstar = 1.0 ; mstar_lt_add = 0.0
1895 
1896  if (cs%LT_Enhance_Form /= no_langmuir) then
1897  ! a. Get parameters for modified LA
1898  if (cs%answers_2018) then
1899  il_ekman = abs_coriolis / ustar
1900  il_obukhov = buoyancy_flux*cs%vonkar / ustar**3
1901  ekman_obukhov_stab = abs(max(0., il_obukhov / (il_ekman + 1.e-10*us%Z_to_m)))
1902  ekman_obukhov_un = abs(min(0., il_obukhov / (il_ekman + 1.e-10*us%Z_to_m)))
1903  mld_obukhov_stab = abs(max(0., bld*il_obukhov))
1904  mld_obukhov_un = abs(min(0., bld*il_obukhov))
1905  mld_ekman = abs( bld*il_ekman )
1906  else
1907  ekman_obukhov = max_ratio ; mld_obukhov = max_ratio ; mld_ekman = max_ratio
1908  i_f = 0.0 ; if (abs(abs_coriolis) > 0.0) i_f = 1.0 / abs_coriolis
1909  i_ustar = 0.0 ; if (abs(ustar) > 0.0) i_ustar = 1.0 / ustar
1910  if (abs(buoyancy_flux*cs%vonkar) < max_ratio*(abs_coriolis * ustar**2)) &
1911  ekman_obukhov = abs(buoyancy_flux*cs%vonkar) * (i_f * i_ustar**2)
1912  if (abs(bld*buoyancy_flux*cs%vonkar) < max_ratio*ustar**3) &
1913  mld_obukhov = abs(bld*buoyancy_flux*cs%vonkar) * i_ustar**3
1914  if (bld*abs_coriolis < max_ratio*ustar) &
1915  mld_ekman = bld*abs_coriolis * i_ustar
1916 
1917  if (buoyancy_flux > 0.0) then
1918  ekman_obukhov_stab = ekman_obukhov ; ekman_obukhov_un = 0.0
1919  mld_obukhov_stab = mld_obukhov ; mld_obukhov_un = 0.0
1920  else
1921  ekman_obukhov_un = ekman_obukhov ; ekman_obukhov_stab = 0.0
1922  mld_obukhov_un = mld_obukhov ; mld_obukhov_stab = 0.0
1923  endif
1924  endif
1925 
1926  ! b. Adjust LA based on various parameters.
1927  ! Assumes linear factors based on length scale ratios to adjust LA
1928  ! Note when these coefficients are set to 0 recovers simple LA.
1929  convect_langmuir_number = langmuir_number * &
1930  ( (1.0 + max(-0.5, cs%LaC_MLDoEK * mld_ekman)) + &
1931  ((cs%LaC_EKoOB_stab * ekman_obukhov_stab + cs%LaC_EKoOB_un * ekman_obukhov_un) + &
1932  (cs%LaC_MLDoOB_stab * mld_obukhov_stab + cs%LaC_MLDoOB_un * mld_obukhov_un)) )
1933 
1934  if (cs%LT_Enhance_Form == langmuir_rescale) then
1935  ! Enhancement is multiplied (added mst_lt set to 0)
1936  enhance_mstar = min(cs%Max_Enhance_M, &
1937  (1. + cs%LT_ENHANCE_COEF * convect_langmuir_number**cs%LT_ENHANCE_EXP) )
1938  elseif (cs%LT_ENHANCE_Form == langmuir_add) then
1939  ! or Enhancement is additive (multiplied enhance_m set to 1)
1940  mstar_lt_add = cs%LT_ENHANCE_COEF * convect_langmuir_number**cs%LT_ENHANCE_EXP
1941  endif
1942  endif
1943 
1944  mstar_lt = (enhance_mstar - 1.0)*mstar + mstar_lt_add ! Diagnose the full increase in mstar.
1945  mstar = mstar*enhance_mstar + mstar_lt_add
1946 
1947 end subroutine mstar_langmuir
1948 
1949 
1950 !> Copies the ePBL active mixed layer depth into MLD, in units of [Z ~> m] unless other units are specified.
1951 subroutine energetic_pbl_get_mld(CS, MLD, G, US, m_to_MLD_units)
1952  type(energetic_pbl_cs), pointer :: cs !< Control structure for ePBL
1953  type(ocean_grid_type), intent(in) :: g !< Grid structure
1954  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
1955  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: mld !< Depth of ePBL active mixing layer [Z ~> m] or other units
1956  real, optional, intent(in) :: m_to_mld_units !< A conversion factor from meters
1957  !! to the desired units for MLD
1958  ! Local variables
1959  real :: scale ! A dimensional rescaling factor
1960  integer :: i,j
1961 
1962  scale = 1.0 ; if (present(m_to_mld_units)) scale = us%Z_to_m * m_to_mld_units
1963 
1964  do j=g%jsc,g%jec ; do i=g%isc,g%iec
1965  mld(i,j) = scale*cs%ML_Depth(i,j)
1966  enddo ; enddo
1967 
1968 end subroutine energetic_pbl_get_mld
1969 
1970 
1971 !> This subroutine initializes the energetic_PBL module
1972 subroutine energetic_pbl_init(Time, G, GV, US, param_file, diag, CS)
1973  type(time_type), target, intent(in) :: time !< The current model time
1974  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
1975  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure
1976  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
1977  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
1978  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to regulate diagnostic output
1979  type(energetic_pbl_cs), pointer :: cs !< A pointer that is set to point to the control
1980  !! structure for this module
1981  ! Local variables
1982  ! This include declares and sets the variable "version".
1983 # include "version_variable.h"
1984  character(len=40) :: mdl = "MOM_energetic_PBL" ! This module's name.
1985  character(len=20) :: tmpstr
1986  real :: omega_frac_dflt
1987  integer :: isd, ied, jsd, jed
1988  integer :: mstar_mode, lt_enhance, wt_mode
1989  logical :: default_2018_answers
1990  logical :: use_temperature, use_omega
1991  logical :: use_la_windsea
1992  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
1993 
1994  if (associated(cs)) then
1995  call mom_error(warning, "mixedlayer_init called with an associated"//&
1996  "associated control structure.")
1997  return
1998  else ; allocate(cs) ; endif
1999 
2000  cs%diag => diag
2001  cs%Time => time
2002 
2003 ! Set default, read and log parameters
2004  call log_version(param_file, mdl, version, "")
2005 
2006 
2007 !/1. General ePBL settings
2008  call get_param(param_file, mdl, "OMEGA", cs%omega, &
2009  "The rotation rate of the earth.", units="s-1", &
2010  default=7.2921e-5, scale=us%T_to_S)
2011  call get_param(param_file, mdl, "ML_USE_OMEGA", use_omega, &
2012  "If true, use the absolute rotation rate instead of the "//&
2013  "vertical component of rotation when setting the decay "//&
2014  "scale for turbulence.", default=.false., do_not_log=.true.)
2015  omega_frac_dflt = 0.0
2016  if (use_omega) then
2017  call mom_error(warning, "ML_USE_OMEGA is depricated; use ML_OMEGA_FRAC=1.0 instead.")
2018  omega_frac_dflt = 1.0
2019  endif
2020  call get_param(param_file, mdl, "ML_OMEGA_FRAC", cs%omega_frac, &
2021  "When setting the decay scale for turbulence, use this "//&
2022  "fraction of the absolute rotation rate blended with the "//&
2023  "local value of f, as sqrt((1-of)*f^2 + of*4*omega^2).", &
2024  units="nondim", default=omega_frac_dflt)
2025  call get_param(param_file, mdl, "EKMAN_SCALE_COEF", cs%Ekman_scale_coef, &
2026  "A nondimensional scaling factor controlling the inhibition "//&
2027  "of the diffusive length scale by rotation. Making this larger "//&
2028  "decreases the PBL diffusivity.", units="nondim", default=1.0)
2029  call get_param(param_file, mdl, "DEFAULT_2018_ANSWERS", default_2018_answers, &
2030  "This sets the default value for the various _2018_ANSWERS parameters.", &
2031  default=.false.)
2032  call get_param(param_file, mdl, "EPBL_2018_ANSWERS", cs%answers_2018, &
2033  "If true, use the order of arithmetic and expressions that recover the "//&
2034  "answers from the end of 2018. Otherwise, use updated and more robust "//&
2035  "forms of the same expressions.", default=default_2018_answers)
2036 
2037 
2038  call get_param(param_file, mdl, "EPBL_ORIGINAL_PE_CALC", cs%orig_PE_calc, &
2039  "If true, the ePBL code uses the original form of the "//&
2040  "potential energy change code. Otherwise, the newer "//&
2041  "version that can work with successive increments to the "//&
2042  "diffusivity in upward or downward passes is used.", default=.true.)
2043 
2044  call get_param(param_file, mdl, "MKE_TO_TKE_EFFIC", cs%MKE_to_TKE_effic, &
2045  "The efficiency with which mean kinetic energy released "//&
2046  "by mechanically forced entrainment of the mixed layer "//&
2047  "is converted to turbulent kinetic energy.", units="nondim", &
2048  default=0.0)
2049  call get_param(param_file, mdl, "TKE_DECAY", cs%TKE_decay, &
2050  "TKE_DECAY relates the vertical rate of decay of the "//&
2051  "TKE available for mechanical entrainment to the natural "//&
2052  "Ekman depth.", units="nondim", default=2.5)
2053 
2054 
2055 !/2. Options related to setting MSTAR
2056  call get_param(param_file, mdl, "EPBL_MSTAR_SCHEME", tmpstr, &
2057  "EPBL_MSTAR_SCHEME selects the method for setting mstar. Valid values are: \n"//&
2058  "\t CONSTANT - Use a fixed mstar given by MSTAR \n"//&
2059  "\t OM4 - Use L_Ekman/L_Obukhov in the sabilizing limit, as in OM4 \n"//&
2060  "\t REICHL_H18 - Use the scheme documented in Reichl & Hallberg, 2018.", &
2061  default=constant_string, do_not_log=.true.)
2062  call get_param(param_file, mdl, "MSTAR_MODE", mstar_mode, default=-1)
2063  if (mstar_mode == 0) then
2064  tmpstr = constant_string
2065  call mom_error(warning, "Use EPBL_MSTAR_SCHEME = CONSTANT instead of the archaic MSTAR_MODE = 0.")
2066  elseif (mstar_mode == 1) then
2067  call mom_error(fatal, "You are using a legacy mstar mode in ePBL that has been phased out. "//&
2068  "If you need to use this setting please report this error. Also use "//&
2069  "EPBL_MSTAR_SCHEME to specify the scheme for mstar.")
2070  elseif (mstar_mode == 2) then
2071  tmpstr = om4_string
2072  call mom_error(warning, "Use EPBL_MSTAR_SCHEME = OM4 instead of the archaic MSTAR_MODE = 2.")
2073  elseif (mstar_mode == 3) then
2074  tmpstr = rh18_string
2075  call mom_error(warning, "Use EPBL_MSTAR_SCHEME = REICHL_H18 instead of the archaic MSTAR_MODE = 3.")
2076  elseif (mstar_mode > 3) then
2077  call mom_error(fatal, "An unrecognized value of the obsolete parameter MSTAR_MODE was specified.")
2078  endif
2079  call log_param(param_file, mdl, "EPBL_MSTAR_SCHEME", tmpstr, &
2080  "EPBL_MSTAR_SCHEME selects the method for setting mstar. Valid values are: \n"//&
2081  "\t CONSTANT - Use a fixed mstar given by MSTAR \n"//&
2082  "\t OM4 - Use L_Ekman/L_Obukhov in the sabilizing limit, as in OM4 \n"//&
2083  "\t REICHL_H18 - Use the scheme documented in Reichl & Hallberg, 2018.", &
2084  default=constant_string)
2085  tmpstr = uppercase(tmpstr)
2086  select case (tmpstr)
2087  case (constant_string)
2088  cs%mstar_Scheme = use_fixed_mstar
2089  case (om4_string)
2090  cs%mstar_Scheme = mstar_from_ekman
2091  case (rh18_string)
2092  cs%mstar_Scheme = mstar_from_rh18
2093  case default
2094  call mom_mesg('energetic_PBL_init: EPBL_MSTAR_SCHEME ="'//trim(tmpstr)//'"', 0)
2095  call mom_error(fatal, "energetic_PBL_init: Unrecognized setting "// &
2096  "EPBL_MSTAR_SCHEME = "//trim(tmpstr)//" found in input file.")
2097  end select
2098 
2099  call get_param(param_file, mdl, "MSTAR", cs%fixed_mstar, &
2100  "The ratio of the friction velocity cubed to the TKE input to the "//&
2101  "mixed layer. This option is used if EPBL_MSTAR_SCHEME = CONSTANT.", &
2102  units="nondim", default=1.2, do_not_log=(cs%mstar_scheme/=use_fixed_mstar))
2103  call get_param(param_file, mdl, "MSTAR_CAP", cs%mstar_cap, &
2104  "If this value is positive, it sets the maximum value of mstar "//&
2105  "allowed in ePBL. (This is not used if EPBL_MSTAR_SCHEME = CONSTANT).", &
2106  units="nondim", default=-1.0, do_not_log=(cs%mstar_scheme==use_fixed_mstar))
2107  ! mstar_scheme==MStar_from_Ekman options
2108  call get_param(param_file, mdl, "MSTAR2_COEF1", cs%MSTAR_COEF, &
2109  "Coefficient in computing mstar when rotation and stabilizing "//&
2110  "effects are both important (used if EPBL_MSTAR_SCHEME = OM4).", &
2111  units="nondim", default=0.3, do_not_log=(cs%mstar_scheme/=mstar_from_ekman))
2112  call get_param(param_file, mdl, "MSTAR2_COEF2", cs%C_EK, &
2113  "Coefficient in computing mstar when only rotation limits "// &
2114  "the total mixing (used if EPBL_MSTAR_SCHEME = OM4)", &
2115  units="nondim", default=0.085, do_not_log=(cs%mstar_scheme/=mstar_from_ekman))
2116  ! mstar_scheme==MStar_from_RH18 options
2117  call get_param(param_file, mdl, "RH18_MSTAR_CN1", cs%RH18_mstar_cn1,&
2118  "MSTAR_N coefficient 1 (outter-most coefficient for fit). "//&
2119  "The value of 0.275 is given in RH18. Increasing this "//&
2120  "coefficient increases MSTAR for all values of Hf/ust, but more "//&
2121  "effectively at low values (weakly developed OSBLs).", &
2122  units="nondim", default=0.275, do_not_log=(cs%mstar_scheme/=mstar_from_rh18))
2123  call get_param(param_file, mdl, "RH18_MSTAR_CN2", cs%RH18_mstar_cn2,&
2124  "MSTAR_N coefficient 2 (coefficient outside of exponential decay). "//&
2125  "The value of 8.0 is given in RH18. Increasing this coefficient "//&
2126  "increases MSTAR for all values of HF/ust, with a much more even "//&
2127  "effect across a wide range of Hf/ust than CN1.", &
2128  units="nondim", default=8.0, do_not_log=(cs%mstar_scheme/=mstar_from_rh18))
2129  call get_param(param_file, mdl, "RH18_MSTAR_CN3", cs%RH18_mstar_CN3,&
2130  "MSTAR_N coefficient 3 (exponential decay coefficient). "//&
2131  "The value of -5.0 is given in RH18. Increasing this increases how "//&
2132  "quickly the value of MSTAR decreases as Hf/ust increases.", &
2133  units="nondim", default=-5.0, do_not_log=(cs%mstar_scheme/=mstar_from_rh18))
2134  call get_param(param_file, mdl, "RH18_MSTAR_CS1", cs%RH18_mstar_cs1,&
2135  "MSTAR_S coefficient for RH18 in stabilizing limit. "//&
2136  "The value of 0.2 is given in RH18 and increasing it increases "//&
2137  "MSTAR in the presence of a stabilizing surface buoyancy flux.", &
2138  units="nondim", default=0.2, do_not_log=(cs%mstar_scheme/=mstar_from_rh18))
2139  call get_param(param_file, mdl, "RH18_MSTAR_CS2", cs%RH18_mstar_cs2,&
2140  "MSTAR_S exponent for RH18 in stabilizing limit. "//&
2141  "The value of 0.4 is given in RH18 and increasing it increases MSTAR "//&
2142  "exponentially in the presence of a stabilizing surface buoyancy flux.", &
2143  units="nondim", default=0.4, do_not_log=(cs%mstar_scheme/=mstar_from_rh18))
2144 
2145 
2146 !/ Convective turbulence related options
2147  call get_param(param_file, mdl, "NSTAR", cs%nstar, &
2148  "The portion of the buoyant potential energy imparted by "//&
2149  "surface fluxes that is available to drive entrainment "//&
2150  "at the base of mixed layer when that energy is positive.", &
2151  units="nondim", default=0.2)
2152  call get_param(param_file, mdl, "MSTAR_CONV_ADJ", cs%mstar_convect_coef, &
2153  "Coefficient used for reducing mstar during convection "//&
2154  "due to reduction of stable density gradient.", &
2155  units="nondim", default=0.0)
2156 
2157 !/ Mixing Length Options
2158  call get_param(param_file, mdl, "USE_MLD_ITERATION", cs%Use_MLD_iteration, &
2159  "A logical that specifies whether or not to use the "//&
2160  "distance to the bottom of the actively turbulent boundary "//&
2161  "layer to help set the EPBL length scale.", default=.true.)
2162  call get_param(param_file, mdl, "EPBL_TRANSITION_SCALE", cs%transLay_scale, &
2163  "A scale for the mixing length in the transition layer "//&
2164  "at the edge of the boundary layer as a fraction of the "//&
2165  "boundary layer thickness.", units="nondim", default=0.1)
2166  if ( cs%Use_MLD_iteration .and. abs(cs%transLay_scale-0.5) >= 0.5) then
2167  call mom_error(fatal, "If flag USE_MLD_ITERATION is true, then "//&
2168  "EPBL_TRANSITION should be greater than 0 and less than 1.")
2169  endif
2170 
2171  call get_param(param_file, mdl, "MLD_ITERATION_GUESS", cs%MLD_ITERATION_GUESS, &
2172  "If true, use the previous timestep MLD as a first guess in the MLD iteration, "//&
2173  "otherwise use half the ocean depth as the first guess of the boundary layer "//&
2174  "depth. The default is false to facilitate reproducibility.", &
2175  default=.false., do_not_log=.not.cs%Use_MLD_iteration)
2176  call get_param(param_file, mdl, "EPBL_MLD_TOLERANCE", cs%MLD_tol, &
2177  "The tolerance for the iteratively determined mixed "//&
2178  "layer depth. This is only used with USE_MLD_ITERATION.", &
2179  units="meter", default=1.0, scale=us%m_to_Z, do_not_log=.not.cs%Use_MLD_iteration)
2180  call get_param(param_file, mdl, "EPBL_MLD_BISECTION", cs%MLD_bisection, &
2181  "If true, use bisection with the iterative determination of the self-consistent "//&
2182  "mixed layer depth. Otherwise use the false position after a maximum and minimum "//&
2183  "bound have been evaluated and the returned value or bisection before this.", &
2184  default=.true., do_not_log=.not.cs%Use_MLD_iteration) !### The default should become false.
2185  call get_param(param_file, mdl, "EPBL_MLD_MAX_ITS", cs%max_MLD_its, &
2186  "The maximum number of iterations that can be used to find a self-consistent "//&
2187  "mixed layer depth. If EPBL_MLD_BISECTION is true, the maximum number "//&
2188  "iteractions needed is set by Depth/2^MAX_ITS < EPBL_MLD_TOLERANCE.", &
2189  default=20, do_not_log=.not.cs%Use_MLD_iteration)
2190  if (.not.cs%Use_MLD_iteration) cs%Max_MLD_Its = 1
2191  call get_param(param_file, mdl, "EPBL_MIN_MIX_LEN", cs%min_mix_len, &
2192  "The minimum mixing length scale that will be used "//&
2193  "by ePBL. The default (0) does not set a minimum.", &
2194  units="meter", default=0.0, scale=us%m_to_Z)
2195 
2196  call get_param(param_file, mdl, "MIX_LEN_EXPONENT", cs%MixLenExponent, &
2197  "The exponent applied to the ratio of the distance to the MLD "//&
2198  "and the MLD depth which determines the shape of the mixing length. "//&
2199  "This is only used if USE_MLD_ITERATION is True.", &
2200  units="nondim", default=2.0)
2201 
2202 !/ Turbulent velocity scale in mixing coefficient
2203  call get_param(param_file, mdl, "EPBL_VEL_SCALE_SCHEME", tmpstr, &
2204  "Selects the method for translating TKE into turbulent velocities. "//&
2205  "Valid values are: \n"//&
2206  "\t CUBE_ROOT_TKE - A constant times the cube root of remaining TKE. \n"//&
2207  "\t REICHL_H18 - Use the scheme based on a combination of w* and v* as \n"//&
2208  "\t documented in Reichl & Hallberg, 2018.", &
2209  default=root_tke_string, do_not_log=.true.)
2210  call get_param(param_file, mdl, "EPBL_VEL_SCALE_MODE", wt_mode, default=-1)
2211  if (wt_mode == 0) then
2212  tmpstr = root_tke_string
2213  call mom_error(warning, "Use EPBL_VEL_SCALE_SCHEME = CUBE_ROOT_TKE instead of the archaic EPBL_VEL_SCALE_MODE = 0.")
2214  elseif (wt_mode == 1) then
2215  tmpstr = rh18_string
2216  call mom_error(warning, "Use EPBL_VEL_SCALE_SCHEME = REICHL_H18 instead of the archaic EPBL_VEL_SCALE_MODE = 1.")
2217  elseif (wt_mode >= 2) then
2218  call mom_error(fatal, "An unrecognized value of the obsolete parameter EPBL_VEL_SCALE_MODE was specified.")
2219  endif
2220  call log_param(param_file, mdl, "EPBL_VEL_SCALE_SCHEME", tmpstr, &
2221  "Selects the method for translating TKE into turbulent velocities. "//&
2222  "Valid values are: \n"//&
2223  "\t CUBE_ROOT_TKE - A constant times the cube root of remaining TKE. \n"//&
2224  "\t REICHL_H18 - Use the scheme based on a combination of w* and v* as \n"//&
2225  "\t documented in Reichl & Hallberg, 2018.", &
2226  default=root_tke_string)
2227  tmpstr = uppercase(tmpstr)
2228  select case (tmpstr)
2229  case (root_tke_string)
2230  cs%wT_scheme = wt_from_croot_tke
2231  case (rh18_string)
2232  cs%wT_scheme = wt_from_rh18
2233  case default
2234  call mom_mesg('energetic_PBL_init: EPBL_VEL_SCALE_SCHEME ="'//trim(tmpstr)//'"', 0)
2235  call mom_error(fatal, "energetic_PBL_init: Unrecognized setting "// &
2236  "EPBL_VEL_SCALE_SCHEME = "//trim(tmpstr)//" found in input file.")
2237  end select
2238 
2239  call get_param(param_file, mdl, "WSTAR_USTAR_COEF", cs%wstar_ustar_coef, &
2240  "A ratio relating the efficiency with which convectively "//&
2241  "released energy is converted to a turbulent velocity, "//&
2242  "relative to mechanically forced TKE. Making this larger "//&
2243  "increases the BL diffusivity", units="nondim", default=1.0)
2244  call get_param(param_file, mdl, "EPBL_VEL_SCALE_FACTOR", cs%vstar_scale_fac, &
2245  "An overall nondimensional scaling factor for wT. "//&
2246  "Making this larger increases the PBL diffusivity.", &
2247  units="nondim", default=1.0)
2248  call get_param(param_file, mdl, "VSTAR_SURF_FAC", cs%vstar_surf_fac,&
2249  "The proportionality times ustar to set vstar at the surface.", &
2250  units="nondim", default=1.2)
2251 
2252  !/ Options related to Langmuir turbulence
2253  call get_param(param_file, mdl, "USE_LA_LI2016", use_la_windsea, &
2254  "A logical to use the Li et al. 2016 (submitted) formula to "//&
2255  "determine the Langmuir number.", units="nondim", default=.false.)
2256  ! Note this can be activated in other ways, but this preserves the old method.
2257  if (use_la_windsea) then
2258  cs%USE_LT = .true.
2259  else
2260  call get_param(param_file, mdl, "EPBL_LT", cs%USE_LT, &
2261  "A logical to use a LT parameterization.", &
2262  units="nondim", default=.false.)
2263  endif
2264  if (cs%USE_LT) then
2265  call get_param(param_file, mdl, "EPBL_LANGMUIR_SCHEME", tmpstr, &
2266  "EPBL_LANGMUIR_SCHEME selects the method for including Langmuir turbulence. "//&
2267  "Valid values are: \n"//&
2268  "\t NONE - Do not do any extra mixing due to Langmuir turbulence \n"//&
2269  "\t RESCALE - Use a multiplicative rescaling of mstar to account for Langmuir turbulence \n"//&
2270  "\t ADDITIVE - Add a Langmuir turblence contribution to mstar to other contributions", &
2271  default=none_string, do_not_log=.true.)
2272  call get_param(param_file, mdl, "LT_ENHANCE", lt_enhance, default=-1)
2273  if (lt_enhance == 0) then
2274  tmpstr = none_string
2275  call mom_error(warning, "Use EPBL_LANGMUIR_SCHEME = NONE instead of the archaic LT_ENHANCE = 0.")
2276  elseif (lt_enhance == 1) then
2277  call mom_error(fatal, "You are using a legacy LT_ENHANCE mode in ePBL that has been phased out. "//&
2278  "If you need to use this setting please report this error. Also use "//&
2279  "EPBL_LANGMUIR_SCHEME to specify the scheme for mstar.")
2280  elseif (lt_enhance == 2) then
2281  tmpstr = rescaled_string
2282  call mom_error(warning, "Use EPBL_LANGMUIR_SCHEME = RESCALE instead of the archaic LT_ENHANCE = 2.")
2283  elseif (lt_enhance == 3) then
2284  tmpstr = additive_string
2285  call mom_error(warning, "Use EPBL_LANGMUIR_SCHEME = ADDITIVE instead of the archaic LT_ENHANCE = 3.")
2286  elseif (lt_enhance > 3) then
2287  call mom_error(fatal, "An unrecognized value of the obsolete parameter LT_ENHANCE was specified.")
2288  endif
2289  call log_param(param_file, mdl, "EPBL_LANGMUIR_SCHEME", tmpstr, &
2290  "EPBL_LANGMUIR_SCHEME selects the method for including Langmuir turbulence. "//&
2291  "Valid values are: \n"//&
2292  "\t NONE - Do not do any extra mixing due to Langmuir turbulence \n"//&
2293  "\t RESCALE - Use a multiplicative rescaling of mstar to account for Langmuir turbulence \n"//&
2294  "\t ADDITIVE - Add a Langmuir turblence contribution to mstar to other contributions", &
2295  default=none_string)
2296  tmpstr = uppercase(tmpstr)
2297  select case (tmpstr)
2298  case (none_string)
2299  cs%LT_enhance_form = no_langmuir
2300  case (rescaled_string)
2301  cs%LT_enhance_form = langmuir_rescale
2302  case (additive_string)
2303  cs%LT_enhance_form = langmuir_add
2304  case default
2305  call mom_mesg('energetic_PBL_init: EPBL_LANGMUIR_SCHEME ="'//trim(tmpstr)//'"', 0)
2306  call mom_error(fatal, "energetic_PBL_init: Unrecognized setting "// &
2307  "EPBL_LANGMUIR_SCHEME = "//trim(tmpstr)//" found in input file.")
2308  end select
2309 
2310  call get_param(param_file, mdl, "LT_ENHANCE_COEF", cs%LT_ENHANCE_COEF, &
2311  "Coefficient for Langmuir enhancement of mstar", &
2312  units="nondim", default=0.447, do_not_log=(cs%LT_enhance_form==no_langmuir))
2313  call get_param(param_file, mdl, "LT_ENHANCE_EXP", cs%LT_ENHANCE_EXP, &
2314  "Exponent for Langmuir enhancementt of mstar", &
2315  units="nondim", default=-1.33, do_not_log=(cs%LT_enhance_form==no_langmuir))
2316  call get_param(param_file, mdl, "LT_MOD_LAC1", cs%LaC_MLDoEK, &
2317  "Coefficient for modification of Langmuir number due to "//&
2318  "MLD approaching Ekman depth.", &
2319  units="nondim", default=-0.87, do_not_log=(cs%LT_enhance_form==no_langmuir))
2320  call get_param(param_file, mdl, "LT_MOD_LAC2", cs%LaC_MLDoOB_stab, &
2321  "Coefficient for modification of Langmuir number due to "//&
2322  "MLD approaching stable Obukhov depth.", &
2323  units="nondim", default=0.0, do_not_log=(cs%LT_enhance_form==no_langmuir))
2324  call get_param(param_file, mdl, "LT_MOD_LAC3", cs%LaC_MLDoOB_un, &
2325  "Coefficient for modification of Langmuir number due to "//&
2326  "MLD approaching unstable Obukhov depth.", &
2327  units="nondim", default=0.0, do_not_log=(cs%LT_enhance_form==no_langmuir))
2328  call get_param(param_file, mdl, "LT_MOD_LAC4", cs%Lac_EKoOB_stab, &
2329  "Coefficient for modification of Langmuir number due to "//&
2330  "ratio of Ekman to stable Obukhov depth.", &
2331  units="nondim", default=0.95, do_not_log=(cs%LT_enhance_form==no_langmuir))
2332  call get_param(param_file, mdl, "LT_MOD_LAC5", cs%Lac_EKoOB_un, &
2333  "Coefficient for modification of Langmuir number due to "//&
2334  "ratio of Ekman to unstable Obukhov depth.", &
2335  units="nondim", default=0.95, do_not_log=(cs%LT_enhance_form==no_langmuir))
2336  endif
2337 
2338 
2339 !/ Logging parameters
2340  ! This gives a minimum decay scale that is typically much less than Angstrom.
2341  cs%ustar_min = 2e-4*cs%omega*(gv%Angstrom_Z + gv%H_to_Z*gv%H_subroundoff)
2342  call log_param(param_file, mdl, "!EPBL_USTAR_MIN", cs%ustar_min*us%Z_to_m*us%s_to_T, &
2343  "The (tiny) minimum friction velocity used within the "//&
2344  "ePBL code, derived from OMEGA and ANGSTROM.", units="m s-1", &
2345  like_default=.true.)
2346 
2347 
2348 !/ Checking output flags
2349  cs%id_ML_depth = register_diag_field('ocean_model', 'ePBL_h_ML', diag%axesT1, &
2350  time, 'Surface boundary layer depth', 'm', conversion=us%Z_to_m, &
2351  cmor_long_name='Ocean Mixed Layer Thickness Defined by Mixing Scheme')
2352  ! This is an alias for the same variable as ePBL_h_ML
2353  cs%id_hML_depth = register_diag_field('ocean_model', 'h_ML', diag%axesT1, &
2354  time, 'Surface mixed layer depth based on active turbulence', 'm', conversion=us%Z_to_m)
2355  cs%id_TKE_wind = register_diag_field('ocean_model', 'ePBL_TKE_wind', diag%axesT1, &
2356  time, 'Wind-stirring source of mixed layer TKE', 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2357  cs%id_TKE_MKE = register_diag_field('ocean_model', 'ePBL_TKE_MKE', diag%axesT1, &
2358  time, 'Mean kinetic energy source of mixed layer TKE', 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2359  cs%id_TKE_conv = register_diag_field('ocean_model', 'ePBL_TKE_conv', diag%axesT1, &
2360  time, 'Convective source of mixed layer TKE', 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2361  cs%id_TKE_forcing = register_diag_field('ocean_model', 'ePBL_TKE_forcing', diag%axesT1, &
2362  time, 'TKE consumed by mixing surface forcing or penetrative shortwave radation '//&
2363  'through model layers', 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2364  cs%id_TKE_mixing = register_diag_field('ocean_model', 'ePBL_TKE_mixing', diag%axesT1, &
2365  time, 'TKE consumed by mixing that deepens the mixed layer', 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2366  cs%id_TKE_mech_decay = register_diag_field('ocean_model', 'ePBL_TKE_mech_decay', diag%axesT1, &
2367  time, 'Mechanical energy decay sink of mixed layer TKE', 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2368  cs%id_TKE_conv_decay = register_diag_field('ocean_model', 'ePBL_TKE_conv_decay', diag%axesT1, &
2369  time, 'Convective energy decay sink of mixed layer TKE', 'W m-2', conversion=us%RZ3_T3_to_W_m2)
2370  cs%id_Mixing_Length = register_diag_field('ocean_model', 'Mixing_Length', diag%axesTi, &
2371  time, 'Mixing Length that is used', 'm', conversion=us%Z_to_m)
2372  cs%id_Velocity_Scale = register_diag_field('ocean_model', 'Velocity_Scale', diag%axesTi, &
2373  time, 'Velocity Scale that is used.', 'm s-1', conversion=us%Z_to_m*us%s_to_T)
2374  cs%id_MSTAR_mix = register_diag_field('ocean_model', 'MSTAR', diag%axesT1, &
2375  time, 'Total mstar that is used.', 'nondim')
2376 
2377  if (cs%use_LT) then
2378  cs%id_LA = register_diag_field('ocean_model', 'LA', diag%axesT1, &
2379  time, 'Langmuir number.', 'nondim')
2380  cs%id_LA_mod = register_diag_field('ocean_model', 'LA_MOD', diag%axesT1, &
2381  time, 'Modified Langmuir number.', 'nondim')
2382  cs%id_MSTAR_LT = register_diag_field('ocean_model', 'MSTAR_LT', diag%axesT1, &
2383  time, 'Increase in mstar due to Langmuir Turbulence.', 'nondim')
2384  endif
2385 
2386  call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", use_temperature, &
2387  "If true, temperature and salinity are used as state "//&
2388  "variables.", default=.true.)
2389 
2390  if (report_avg_its) then
2391  cs%sum_its(1) = real_to_efp(0.0) ; cs%sum_its(2) = real_to_efp(0.0)
2392  endif
2393 
2394  if (max(cs%id_TKE_wind, cs%id_TKE_MKE, cs%id_TKE_conv, &
2395  cs%id_TKE_mixing, cs%id_TKE_mech_decay, cs%id_TKE_forcing, &
2396  cs%id_TKE_conv_decay) > 0) then
2397  call safe_alloc_alloc(cs%diag_TKE_wind, isd, ied, jsd, jed)
2398  call safe_alloc_alloc(cs%diag_TKE_MKE, isd, ied, jsd, jed)
2399  call safe_alloc_alloc(cs%diag_TKE_conv, isd, ied, jsd, jed)
2400  call safe_alloc_alloc(cs%diag_TKE_forcing, isd, ied, jsd, jed)
2401  call safe_alloc_alloc(cs%diag_TKE_mixing, isd, ied, jsd, jed)
2402  call safe_alloc_alloc(cs%diag_TKE_mech_decay, isd, ied, jsd, jed)
2403  call safe_alloc_alloc(cs%diag_TKE_conv_decay, isd, ied, jsd, jed)
2404 
2405  cs%TKE_diagnostics = .true.
2406  endif
2407  if (cs%id_Velocity_Scale>0) call safe_alloc_alloc(cs%Velocity_Scale, isd, ied, jsd, jed, gv%ke+1)
2408  if (cs%id_Mixing_Length>0) call safe_alloc_alloc(cs%Mixing_Length, isd, ied, jsd, jed, gv%ke+1)
2409 
2410  call safe_alloc_alloc(cs%ML_depth, isd, ied, jsd, jed)
2411  if (max(cs%id_mstar_mix, cs%id_LA, cs%id_LA_mod, cs%id_MSTAR_LT ) >0) then
2412  call safe_alloc_alloc(cs%Mstar_mix, isd, ied, jsd, jed)
2413  call safe_alloc_alloc(cs%LA, isd, ied, jsd, jed)
2414  call safe_alloc_alloc(cs%LA_MOD, isd, ied, jsd, jed)
2415  call safe_alloc_alloc(cs%MSTAR_LT, isd, ied, jsd, jed)
2416  endif
2417 
2418 end subroutine energetic_pbl_init
2419 
2420 !> Clean up and deallocate memory associated with the energetic_PBL module.
2421 subroutine energetic_pbl_end(CS)
2422  type(energetic_pbl_cs), pointer :: cs !< Energetic_PBL control structure that
2423  !! will be deallocated in this subroutine.
2424 
2425  character(len=256) :: mesg
2426  real :: avg_its
2428  if (.not.associated(cs)) return
2429 
2430  if (allocated(cs%ML_depth)) deallocate(cs%ML_depth)
2431  if (allocated(cs%LA)) deallocate(cs%LA)
2432  if (allocated(cs%LA_MOD)) deallocate(cs%LA_MOD)
2433  if (allocated(cs%MSTAR_MIX)) deallocate(cs%MSTAR_MIX)
2434  if (allocated(cs%MSTAR_LT)) deallocate(cs%MSTAR_LT)
2435  if (allocated(cs%diag_TKE_wind)) deallocate(cs%diag_TKE_wind)
2436  if (allocated(cs%diag_TKE_MKE)) deallocate(cs%diag_TKE_MKE)
2437  if (allocated(cs%diag_TKE_conv)) deallocate(cs%diag_TKE_conv)
2438  if (allocated(cs%diag_TKE_forcing)) deallocate(cs%diag_TKE_forcing)
2439  if (allocated(cs%diag_TKE_mixing)) deallocate(cs%diag_TKE_mixing)
2440  if (allocated(cs%diag_TKE_mech_decay)) deallocate(cs%diag_TKE_mech_decay)
2441  if (allocated(cs%diag_TKE_conv_decay)) deallocate(cs%diag_TKE_conv_decay)
2442  if (allocated(cs%Mixing_Length)) deallocate(cs%Mixing_Length)
2443  if (allocated(cs%Velocity_Scale)) deallocate(cs%Velocity_Scale)
2444 
2445  if (report_avg_its) then
2446  call efp_sum_across_pes(cs%sum_its, 2)
2447 
2448  avg_its = efp_to_real(cs%sum_its(1)) / efp_to_real(cs%sum_its(2))
2449  write (mesg,*) "Average ePBL iterations = ", avg_its
2450  call mom_mesg(mesg)
2451  endif
2452 
2453  deallocate(cs)
2454 
2455 end subroutine energetic_pbl_end
2456 
2457 !> \namespace MOM_energetic_PBL
2458 !!
2459 !! By Robert Hallberg, 2015.
2460 !!
2461 !! This file contains the subroutine (energetic_PBL) that uses an
2462 !! integrated boundary layer energy budget (like a bulk- or refined-
2463 !! bulk mixed layer scheme), but instead of homogenizing this model
2464 !! calculates a finite diffusivity and viscosity, which in this
2465 !! regard is conceptually similar to what is done with KPP or various
2466 !! two-equation closures. However, the scheme that is implemented
2467 !! here has the big advantage that is entirely implicit, but is
2468 !! simple enough that it requires only a single vertical pass to
2469 !! determine the diffusivity. The development of bulk mixed layer
2470 !! models stems from the work of various people, as described in the
2471 !! review paper by Niiler and Kraus (1979). The work here draws in
2472 !! with particular on the form for TKE decay proposed by Oberhuber
2473 !! (JPO, 1993, 808-829), with an extension to a refined bulk mixed
2474 !! layer as described in Hallberg (Aha Huliko'a, 2003). The physical
2475 !! processes portrayed in this subroutine include convectively driven
2476 !! mixing and mechanically driven mixing. Unlike boundary-layer
2477 !! mixing, stratified shear mixing is not a one-directional turbulent
2478 !! process, and it is dealt with elsewhere in the MOM6 code within
2479 !! the module MOM_kappa_shear.F90. It is assumed that the heat,
2480 !! mass, and salt fluxes have been applied elsewhere, but that their
2481 !! implications for the integrated TKE budget have been captured in
2482 !! an array that is provided as an argument to this subroutine. This
2483 !! is a full 3-d array due to the effects of penetrating shortwave
2484 !! radiation.
2485 
2486 end module mom_energetic_pbl
This module implements boundary forcing for MOM6.
A type for conveniently passing around ePBL diagnostics for a column.
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Sum a value or 1-d array of values across processors, returning the sums in place.
Definition: MOM_coms.F90:64
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Wraps the MPP cpu clock functions.
This control structure holds parameters for the MOM_energetic_PBL module.
The MOM6 facility to parse input files for runtime parameters.
An overloaded interface to log the values of various types of parameters.
Interfaces to non-domain-oriented communication subroutines, including the MOM6 reproducing sums faci...
Definition: MOM_coms.F90:3
Interface for surface waves.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Routines for error handling and I/O management.
Container for all surface wave related parameters.
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Energetically consistent planetary boundary layer parameterization.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Set up a group of halo updates.
Definition: MOM_domains.F90:84
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Handy functions for manipulating strings.
Provides a transparent vertical ocean grid type and supporting routines.
Provides transparent structures with groups of MOM6 variables and supporting routines.
An overloaded interface to read and log the values of various types of parameters.
The Extended Fixed Point (EFP) type provides a public interface for doing sums and taking differences...
Definition: MOM_coms.F90:74