MOM6
mom_bulk_mixed_layer Module Reference

Detailed Description

Build mixed layer parameterization.

By Robert Hallberg, 1997 - 2005.

This file contains the subroutine (bulkmixedlayer) that implements a Kraus-Turner-like bulk mixed layer, based on the work of various people, as described in the review paper by Niiler and Kraus (1979), with particular attention to the form proposed by Oberhuber (JPO, 1993, 808-829), with an extension to a refied bulk mixed layer as described in Hallberg (Aha Huliko'a, 2003). The physical processes portrayed in this subroutine include convective adjustment and mixed layer entrainment and detrainment. Penetrating shortwave radiation and an exponential decay of TKE fluxes are also supported by this subroutine. Several constants can alternately be set to give a traditional Kraus-Turner mixed layer scheme, although that is not the preferred option. The physical processes and arguments are described in detail below.

Data Types

type  bulkmixedlayer_cs
 The control structure with parameters for the MOM_bulk_mixed_layer module. More...
 

Functions/Subroutines

subroutine, public bulkmixedlayer (h_3d, u_3d, v_3d, tv, fluxes, dt, ea, eb, G, GV, US, CS, optics, Hml, aggregate_FW_forcing, dt_diag, last_call)
 This subroutine partially steps the bulk mixed layer model. The following processes are executed, in the order listed. More...
 
subroutine convective_adjustment (h, u, v, R0, Rcv, T, S, eps, d_eb, dKE_CA, cTKE, j, G, GV, US, CS, nz_conv)
 This subroutine does instantaneous convective entrainment into the buffer layers and mixed layers to remove hydrostatic instabilities. Any water that is lighter than currently in the mixed- or buffer- layer is entrained. More...
 
subroutine mixedlayer_convection (h, d_eb, htot, Ttot, Stot, uhtot, vhtot, R0_tot, Rcv_tot, u, v, T, S, R0, Rcv, eps, dR0_dT, dRcv_dT, dR0_dS, dRcv_dS, netMassInOut, netMassOut, Net_heat, Net_salt, nsw, Pen_SW_bnd, opacity_band, Conv_En, dKE_FC, j, ksort, G, GV, US, CS, tv, fluxes, dt, aggregate_FW_forcing)
 This subroutine causes the mixed layer to entrain to the depth of free convection. The depth of free convection is the shallowest depth at which the fluid is denser than the average of the fluid above. More...
 
subroutine find_starting_tke (htot, h_CA, fluxes, Conv_En, cTKE, dKE_FC, dKE_CA, TKE, TKE_river, Idecay_len_TKE, cMKE, dt, Idt_diag, j, ksort, G, GV, US, CS)
 This subroutine determines the TKE available at the depth of free convection to drive mechanical entrainment. More...
 
subroutine mechanical_entrainment (h, d_eb, htot, Ttot, Stot, uhtot, vhtot, R0_tot, Rcv_tot, u, v, T, S, R0, Rcv, eps, dR0_dT, dRcv_dT, cMKE, Idt_diag, nsw, Pen_SW_bnd, opacity_band, TKE, Idecay_len_TKE, j, ksort, G, GV, US, CS)
 This subroutine calculates mechanically driven entrainment. More...
 
subroutine sort_ml (h, R0, eps, G, GV, CS, ksort)
 This subroutine generates an array of indices that are sorted by layer density. More...
 
subroutine resort_ml (h, T, S, R0, Rcv, RcvTgt, eps, d_ea, d_eb, ksort, G, GV, CS, dR0_dT, dR0_dS, dRcv_dT, dRcv_dS)
 This subroutine actually moves properties between layers to achieve a resorted state, with all of the resorted water either moved into the correct interior layers or in the top nkmb layers. More...
 
subroutine mixedlayer_detrain_2 (h, T, S, R0, Rcv, RcvTgt, dt, dt_diag, d_ea, j, G, GV, US, CS, dR0_dT, dR0_dS, dRcv_dT, dRcv_dS, max_BL_det)
 This subroutine moves any water left in the former mixed layers into the two buffer layers and may also move buffer layer water into the interior isopycnal layers. More...
 
subroutine mixedlayer_detrain_1 (h, T, S, R0, Rcv, RcvTgt, dt, dt_diag, d_ea, d_eb, j, G, GV, US, CS, dRcv_dT, dRcv_dS, max_BL_det)
 This subroutine moves any water left in the former mixed layers into the single buffer layers and may also move buffer layer water into the interior isopycnal layers. More...
 
subroutine, public bulkmixedlayer_init (Time, G, GV, US, param_file, diag, CS)
 This subroutine initializes the MOM bulk mixed layer module. More...
 
real function ef4 (Ht, En, I_L, dR_de)
 This subroutine returns an approximation to the integral R = exp(-L*(H+E)) integral(LH to L(H+E)) L/(1-(1+x)exp(-x)) dx. The approximation to the integrand is good to within -2% at x~.3 and +25% at x~3.5, but the exponential deemphasizes the importance of large x. When L=0, EF4 returns E/((Ht+E)*Ht). More...
 

Function/Subroutine Documentation

◆ bulkmixedlayer()

subroutine, public mom_bulk_mixed_layer::bulkmixedlayer ( real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(inout)  h_3d,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(in)  u_3d,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(in)  v_3d,
type(thermo_var_ptrs), intent(inout)  tv,
type(forcing), intent(inout)  fluxes,
real, intent(in)  dt,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(inout)  ea,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(inout)  eb,
type(ocean_grid_type), intent(inout)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(bulkmixedlayer_cs), pointer  CS,
type(optics_type), pointer  optics,
real, dimension(:,:), pointer  Hml,
logical, intent(in)  aggregate_FW_forcing,
real, intent(in), optional  dt_diag,
logical, intent(in), optional  last_call 
)

This subroutine partially steps the bulk mixed layer model. The following processes are executed, in the order listed.

  1. Undergo convective adjustment into mixed layer.
  2. Apply surface heating and cooling.
  3. Starting from the top, entrain whatever fluid the TKE budget permits. Penetrating shortwave radiation is also applied at this point.
  4. If there is any unentrained fluid that was formerly in the mixed layer, detrain this fluid into the buffer layer. This is equivalent to the mixed layer detraining to the Monin- Obukhov depth.
  5. Divide the fluid in the mixed layer evenly into CSnkml pieces.
  6. Split the buffer layer if appropriate. Layers 1 to nkml are the mixed layer, nkml+1 to nkml+nkbl are the buffer layers. The results of this subroutine are mathematically identical if there are multiple pieces of the mixed layer with the same density or if there is just a single layer. There is no stability limit on the time step.

The key parameters for the mixed layer are found in the control structure. These include mstar, nstar, nstar2, pen_SW_frac, pen_SW_scale, and TKE_decay. For the Oberhuber (1993) mixed layer, the values of these are: pen_SW_frac = 0.42, pen_SW_scale = 15.0 m, mstar = 1.25, nstar = 1, TKE_decay = 2.5, conv_decay = 0.5 TKE_decay is 1/kappa in eq. 28 of Oberhuber (1993), while conv_decay is 1/mu. Conv_decay has been eliminated in favor of the well-calibrated form for the efficiency of penetrating convection from Wang (2003). For a traditional Kraus-Turner mixed layer, the values are: pen_SW_frac = 0.0, pen_SW_scale = 0.0 m, mstar = 1.25, nstar = 0.4, TKE_decay = 0.0, conv_decay = 0.0

Parameters
[in,out]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in,out]h_3dLayer thickness [H ~> m or kg m-2].
[in]u_3dZonal velocities interpolated to h points
[in]v_3dZonal velocities interpolated to h points
[in,out]tvA structure containing pointers to any available thermodynamic fields. Absent fields have NULL ptrs.
[in,out]fluxesA structure containing pointers to any possible forcing fields. Unused fields have NULL ptrs.
[in]dtTime increment [T ~> s].
[in,out]eaThe amount of fluid moved downward into a
[in,out]ebThe amount of fluid moved upward into a
csThe control structure returned by a previous call to mixedlayer_init.
opticsThe structure containing the inverse of the vertical absorption decay scale for penetrating shortwave radiation [m-1].
hmlActive mixed layer depth [Z ~> m].
[in]aggregate_fw_forcingIf true, the net incoming and outgoing surface freshwater fluxes are combined before being applied, instead of being applied separately.
[in]dt_diagThe diagnostic time step, which may be less than dt if there are two callse to mixedlayer [T ~> s].
[in]last_callif true, this is the last call to mixedlayer in the current time step, so diagnostics will be written. The default is .true.

Definition at line 188 of file MOM_bulk_mixed_layer.F90.

190  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
191  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
192  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
193  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
194  intent(inout) :: h_3d !< Layer thickness [H ~> m or kg m-2].
195  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
196  intent(in) :: u_3d !< Zonal velocities interpolated to h points
197  !! [L T-1 ~> m s-1].
198  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
199  intent(in) :: v_3d !< Zonal velocities interpolated to h points
200  !! [L T-1 ~> m s-1].
201  type(thermo_var_ptrs), intent(inout) :: tv !< A structure containing pointers to any
202  !! available thermodynamic fields. Absent
203  !! fields have NULL ptrs.
204  type(forcing), intent(inout) :: fluxes !< A structure containing pointers to any
205  !! possible forcing fields. Unused fields
206  !! have NULL ptrs.
207  real, intent(in) :: dt !< Time increment [T ~> s].
208  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
209  intent(inout) :: ea !< The amount of fluid moved downward into a
210  !! layer; this should be increased due to
211  !! mixed layer detrainment [H ~> m or kg m-2].
212  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
213  intent(inout) :: eb !< The amount of fluid moved upward into a
214  !! layer; this should be increased due to
215  !! mixed layer entrainment [H ~> m or kg m-2].
216  type(bulkmixedlayer_CS), pointer :: CS !< The control structure returned by a
217  !! previous call to mixedlayer_init.
218  type(optics_type), pointer :: optics !< The structure containing the inverse of the
219  !! vertical absorption decay scale for
220  !! penetrating shortwave radiation [m-1].
221  real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [Z ~> m].
222  logical, intent(in) :: aggregate_FW_forcing !< If true, the net incoming and
223  !! outgoing surface freshwater fluxes are
224  !! combined before being applied, instead of
225  !! being applied separately.
226  real, optional, intent(in) :: dt_diag !< The diagnostic time step,
227  !! which may be less than dt if there are
228  !! two callse to mixedlayer [T ~> s].
229  logical, optional, intent(in) :: last_call !< if true, this is the last call
230  !! to mixedlayer in the current time step, so
231  !! diagnostics will be written. The default is
232  !! .true.
233 
234  ! Local variables
235  real, dimension(SZI_(G),SZK_(GV)) :: &
236  eaml, & ! The amount of fluid moved downward into a layer due to mixed
237  ! layer detrainment [H ~> m or kg m-2]. (I.e. entrainment from above.)
238  ebml ! The amount of fluid moved upward into a layer due to mixed
239  ! layer detrainment [H ~> m or kg m-2]. (I.e. entrainment from below.)
240 
241  ! If there is resorting, the vertical coordinate for these variables is the
242  ! new, sorted index space. Here layer 0 is an initially massless layer that
243  ! will be used to hold the new mixed layer properties.
244  real, dimension(SZI_(G),SZK0_(GV)) :: &
245  h, & ! The layer thickness [H ~> m or kg m-2].
246  T, & ! The layer temperatures [degC].
247  S, & ! The layer salinities [ppt].
248  R0, & ! The potential density referenced to the surface [R ~> kg m-3].
249  Rcv ! The coordinate variable potential density [R ~> kg m-3].
250  real, dimension(SZI_(G),SZK_(GV)) :: &
251  u, & ! The zonal velocity [L T-1 ~> m s-1].
252  v, & ! The meridional velocity [L T-1 ~> m s-1].
253  h_orig, & ! The original thickness [H ~> m or kg m-2].
254  d_eb, & ! The downward increase across a layer in the entrainment from
255  ! below [H ~> m or kg m-2]. The sign convention is that positive values of
256  ! d_eb correspond to a gain in mass by a layer by upward motion.
257  d_ea, & ! The upward increase across a layer in the entrainment from
258  ! above [H ~> m or kg m-2]. The sign convention is that positive values of
259  ! d_ea mean a net gain in mass by a layer from downward motion.
260  eps ! The (small) thickness that must remain in a layer [H ~> m or kg m-2].
261  integer, dimension(SZI_(G),SZK_(GV)) :: &
262  ksort ! The sorted k-index that each original layer goes to.
263  real, dimension(SZI_(G),SZJ_(G)) :: &
264  h_miss ! The summed absolute mismatch [Z ~> m].
265  real, dimension(SZI_(G)) :: &
266  TKE, & ! The turbulent kinetic energy available for mixing over a
267  ! time step [Z L2 T-2 ~> m3 s-2].
268  conv_en, & ! The turbulent kinetic energy source due to mixing down to
269  ! the depth of free convection [Z L2 T-2 ~> m3 s-2].
270  htot, & ! The total depth of the layers being considered for
271  ! entrainment [H ~> m or kg m-2].
272  r0_tot, & ! The integrated potential density referenced to the surface
273  ! of the layers which are fully entrained [H R ~> kg m-2 or kg2 m-5].
274  rcv_tot, & ! The integrated coordinate value potential density of the
275  ! layers that are fully entrained [H R ~> kg m-2 or kg2 m-5].
276  ttot, & ! The integrated temperature of layers which are fully
277  ! entrained [degC H ~> degC m or degC kg m-2].
278  stot, & ! The integrated salt of layers which are fully entrained
279  ! [H ppt ~> m ppt or ppt kg m-2].
280  uhtot, & ! The depth integrated zonal and meridional velocities in the
281  vhtot, & ! mixed layer [H L T-1 ~> m2 s-1 or kg m-1 s-1].
282 
283  netmassinout, & ! The net mass flux (if non-Boussinsq) or volume flux (if
284  ! Boussinesq - i.e. the fresh water flux (P+R-E)) into the
285  ! ocean over a time step [H ~> m or kg m-2].
286  netmassout, & ! The mass flux (if non-Boussinesq) or volume flux (if Boussinesq)
287  ! over a time step from evaporating fresh water [H ~> m or kg m-2]
288  net_heat, & ! The net heating at the surface over a time step [degC H ~> degC m or degC kg m-2].
289  ! Any penetrating shortwave radiation is not included in Net_heat.
290  net_salt, & ! The surface salt flux into the ocean over a time step, ppt H.
291  idecay_len_tke, & ! The inverse of a turbulence decay length scale [H-1 ~> m-1 or m2 kg-1].
292  p_ref, & ! Reference pressure for the potential density governing mixed
293  ! layer dynamics, almost always 0 (or 1e5) [R L2 T-2 ~> Pa].
294  p_ref_cv, & ! Reference pressure for the potential density which defines
295  ! the coordinate variable, set to P_Ref [R L2 T-2 ~> Pa].
296  dr0_dt, & ! Partial derivative of the mixed layer potential density with
297  ! temperature [R degC-1 ~> kg m-3 degC-1].
298  drcv_dt, & ! Partial derivative of the coordinate variable potential
299  ! density in the mixed layer with temperature [R degC-1 ~> kg m-3 degC-1].
300  dr0_ds, & ! Partial derivative of the mixed layer potential density with
301  ! salinity [R ppt-1 ~> kg m-3 ppt-1].
302  drcv_ds, & ! Partial derivative of the coordinate variable potential
303  ! density in the mixed layer with salinity [R ppt-1 ~> kg m-3 ppt-1].
304  tke_river ! The source of turbulent kinetic energy available for mixing
305  ! at rivermouths [Z L2 T-3 ~> m3 s-3].
306 
307  real, dimension(max(CS%nsw,1),SZI_(G)) :: &
308  Pen_SW_bnd ! The penetrating fraction of the shortwave heating integrated
309  ! over a time step in each band [degC H ~> degC m or degC kg m-2].
310  real, dimension(max(CS%nsw,1),SZI_(G),SZK_(GV)) :: &
311  opacity_band ! The opacity in each band [H-1 ~> m-1 or m2 kg-1]. The indicies are band, i, k.
312 
313  real :: cMKE(2,SZI_(G)) ! Coefficients of HpE and HpE^2 used in calculating the
314  ! denominator of MKE_rate; the two elements have differing
315  ! units of [H-1 ~> m-1 or m2 kg-1] and [H-2 ~> m-2 or m4 kg-2].
316  real :: Irho0 ! 1.0 / rho_0 [R-1 ~> m3 kg-1]
317  real :: Inkml, Inkmlm1! 1.0 / REAL(nkml) and 1.0 / REAL(nkml-1)
318  real :: Ih ! The inverse of a thickness [H-1 ~> m-1 or m2 kg-1].
319  real :: Idt_diag ! The inverse of the timestep used for diagnostics [T-1 ~> s-1].
320  real :: RmixConst
321 
322  real, dimension(SZI_(G)) :: &
323  dKE_FC, & ! The change in mean kinetic energy due to free convection
324  ! [Z L2 T-2 ~> m3 s-2].
325  h_ca ! The depth to which convective adjustment has gone [H ~> m or kg m-2].
326  real, dimension(SZI_(G),SZK_(GV)) :: &
327  dKE_CA, & ! The change in mean kinetic energy due to convective
328  ! adjustment [Z L2 T-2 ~> m3 s-2].
329  ctke ! The turbulent kinetic energy source due to convective
330  ! adjustment [Z L2 T-2 ~> m3 s-2].
331  real, dimension(SZI_(G),SZJ_(G)) :: &
332  Hsfc_max, & ! The thickness of the surface region (mixed and buffer layers)
333  ! after entrainment but before any buffer layer detrainment [Z ~> m].
334  hsfc_used, & ! The thickness of the surface region after buffer layer
335  ! detrainment [Z ~> m].
336  hsfc_min, & ! The minimum thickness of the surface region based on the
337  ! new mixed layer depth and the previous thickness of the
338  ! neighboring water columns [Z ~> m].
339  h_sum, & ! The total thickness of the water column [H ~> m or kg m-2].
340  hmbl_prev ! The previous thickness of the mixed and buffer layers [H ~> m or kg m-2].
341  real, dimension(SZI_(G)) :: &
342  Hsfc, & ! The thickness of the surface region (mixed and buffer
343  ! layers before detrainment in to the interior [H ~> m or kg m-2].
344  max_bl_det ! If non-negative, the maximum amount of entrainment from
345  ! the buffer layers that will be allowed this time step [H ~> m or kg m-2].
346  real :: dHsfc, dHD ! Local copies of nondimensional parameters.
347  real :: H_nbr ! A minimum thickness based on neighboring thicknesses [H ~> m or kg m-2].
348 
349  real :: absf_x_H ! The absolute value of f times the mixed layer thickness [Z T-1 ~> m s-1].
350  real :: kU_star ! Ustar times the Von Karmen constant [Z T-1 ~> m s-1].
351  real :: dt__diag ! A recaled copy of dt_diag (if present) or dt [T ~> s].
352  logical :: write_diags ! If true, write out diagnostics with this step.
353  logical :: reset_diags ! If true, zero out the accumulated diagnostics.
354  integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
355  integer :: i, j, k, is, ie, js, je, nz, nkmb, n
356  integer :: nsw ! The number of bands of penetrating shortwave radiation.
357 
358  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = gv%ke
359 
360  if (.not. associated(cs)) call mom_error(fatal, "MOM_mixed_layer: "//&
361  "Module must be initialized before it is used.")
362  if (gv%nkml < 1) return
363 
364  if (.not. associated(tv%eqn_of_state)) call mom_error(fatal, &
365  "MOM_mixed_layer: Temperature, salinity and an equation of state "//&
366  "must now be used.")
367  if (.NOT. associated(fluxes%ustar)) call mom_error(fatal, &
368  "MOM_mixed_layer: No surface TKE fluxes (ustar) defined in mixedlayer!")
369 
370  nkmb = cs%nkml+cs%nkbl
371  inkml = 1.0 / real(cs%nkml)
372  if (cs%nkml > 1) inkmlm1 = 1.0 / real(cs%nkml-1)
373 
374  irho0 = 1.0 / (gv%Rho0)
375  dt__diag = dt ; if (present(dt_diag)) dt__diag = dt_diag
376  idt_diag = 1.0 / (dt__diag)
377  write_diags = .true. ; if (present(last_call)) write_diags = last_call
378 
379  p_ref(:) = 0.0 ; p_ref_cv(:) = tv%P_Ref
380 
381  nsw = cs%nsw
382 
383  if (cs%limit_det .or. (cs%id_Hsfc_min > 0)) then
384  !$OMP parallel do default(shared)
385  do j=js-1,je+1 ; do i=is-1,ie+1
386  h_sum(i,j) = 0.0 ; hmbl_prev(i,j) = 0.0
387  enddo ; enddo
388  !$OMP parallel do default(shared)
389  do j=js-1,je+1
390  do k=1,nkmb ; do i=is-1,ie+1
391  h_sum(i,j) = h_sum(i,j) + h_3d(i,j,k)
392  hmbl_prev(i,j) = hmbl_prev(i,j) + h_3d(i,j,k)
393  enddo ; enddo
394  do k=nkmb+1,nz ; do i=is-1,ie+1
395  h_sum(i,j) = h_sum(i,j) + h_3d(i,j,k)
396  enddo ; enddo
397  enddo
398 
399  call cpu_clock_begin(id_clock_pass)
400  call create_group_pass(cs%pass_h_sum_hmbl_prev, h_sum,g%Domain)
401  call create_group_pass(cs%pass_h_sum_hmbl_prev, hmbl_prev,g%Domain)
402  call do_group_pass(cs%pass_h_sum_hmbl_prev, g%Domain)
403  call cpu_clock_end(id_clock_pass)
404  endif
405 
406  ! Determine whether to zero out diagnostics before accumulation.
407  reset_diags = .true.
408  if (present(dt_diag) .and. write_diags .and. (dt__diag > dt)) &
409  reset_diags = .false. ! This is the second call to mixedlayer.
410 
411  if (reset_diags) then
412  if (cs%TKE_diagnostics) then
413  !$OMP parallel do default(shared)
414  do j=js,je ; do i=is,ie
415  cs%diag_TKE_wind(i,j) = 0.0 ; cs%diag_TKE_RiBulk(i,j) = 0.0
416  cs%diag_TKE_conv(i,j) = 0.0 ; cs%diag_TKE_pen_SW(i,j) = 0.0
417  cs%diag_TKE_mixing(i,j) = 0.0 ; cs%diag_TKE_mech_decay(i,j) = 0.0
418  cs%diag_TKE_conv_decay(i,j) = 0.0 ; cs%diag_TKE_conv_s2(i,j) = 0.0
419  enddo ; enddo
420  endif
421  if (allocated(cs%diag_PE_detrain)) then
422  !$OMP parallel do default(shared)
423  do j=js,je ; do i=is,ie
424  cs%diag_PE_detrain(i,j) = 0.0
425  enddo ; enddo
426  endif
427  if (allocated(cs%diag_PE_detrain2)) then
428  !$OMP parallel do default(shared)
429  do j=js,je ; do i=is,ie
430  cs%diag_PE_detrain2(i,j) = 0.0
431  enddo ; enddo
432  endif
433  endif
434 
435  if (cs%ML_resort) then
436  do i=is,ie ; h_ca(i) = 0.0 ; enddo
437  do k=1,nz ; do i=is,ie ; dke_ca(i,k) = 0.0 ; ctke(i,k) = 0.0 ; enddo ; enddo
438  endif
439  max_bl_det(:) = -1
440  eosdom(:) = eos_domain(g%HI)
441 
442  !$OMP parallel default(shared) firstprivate(dKE_CA,cTKE,h_CA,max_BL_det,p_ref,p_ref_cv) &
443  !$OMP private(h,u,v,h_orig,eps,T,S,opacity_band,d_ea,d_eb,R0,Rcv,ksort, &
444  !$OMP dR0_dT,dR0_dS,dRcv_dT,dRcv_dS,htot,Ttot,Stot,TKE,Conv_en, &
445  !$OMP RmixConst,TKE_river,Pen_SW_bnd,netMassInOut,NetMassOut, &
446  !$OMP Net_heat,Net_salt,uhtot,vhtot,R0_tot,Rcv_tot,dKE_FC, &
447  !$OMP Idecay_len_TKE,cMKE,Hsfc,dHsfc,dHD,H_nbr,kU_Star, &
448  !$OMP absf_x_H,ebml,eaml)
449  !$OMP do
450  do j=js,je
451  ! Copy the thicknesses and other fields to 2-d arrays.
452  do k=1,nz ; do i=is,ie
453  h(i,k) = h_3d(i,j,k) ; u(i,k) = u_3d(i,j,k) ; v(i,k) = v_3d(i,j,k)
454  h_orig(i,k) = h_3d(i,j,k)
455  eps(i,k) = 0.0 ; if (k > nkmb) eps(i,k) = gv%Angstrom_H
456  t(i,k) = tv%T(i,j,k) ; s(i,k) = tv%S(i,j,k)
457  enddo ; enddo
458  if (nsw>0) call extract_optics_slice(optics, j, g, gv, opacity=opacity_band, opacity_scale=gv%H_to_m)
459 
460  do k=1,nz ; do i=is,ie
461  d_ea(i,k) = 0.0 ; d_eb(i,k) = 0.0
462  enddo ; enddo
463 
464  if (id_clock_eos>0) call cpu_clock_begin(id_clock_eos)
465  ! Calculate an estimate of the mid-mixed layer pressure [R L2 T-2 ~> Pa]
466  if (associated(tv%p_surf)) then
467  do i=is,ie ; p_ref(i) = tv%p_surf(i,j) ; enddo
468  else
469  do i=is,ie ; p_ref(i) = 0.0 ; enddo
470  endif
471  do k=1,cs%nkml ; do i=is,ie
472  p_ref(i) = p_ref(i) + 0.5*(gv%H_to_RZ*gv%g_Earth)*h(i,k)
473  enddo ; enddo
474  call calculate_density_derivs(t(:,1), s(:,1), p_ref, dr0_dt, dr0_ds, tv%eqn_of_state, eosdom)
475  call calculate_density_derivs(t(:,1), s(:,1), p_ref_cv, drcv_dt, drcv_ds, tv%eqn_of_state, eosdom)
476  do k=1,nz
477  call calculate_density(t(:,k), s(:,k), p_ref, r0(:,k), tv%eqn_of_state, eosdom)
478  call calculate_density(t(:,k), s(:,k), p_ref_cv, rcv(:,k), tv%eqn_of_state, eosdom)
479  enddo
480  if (id_clock_eos>0) call cpu_clock_end(id_clock_eos)
481 
482  if (cs%ML_resort) then
483  if (id_clock_resort>0) call cpu_clock_begin(id_clock_resort)
484  if (cs%ML_presort_nz_conv_adj > 0) &
485  call convective_adjustment(h(:,1:), u, v, r0(:,1:), rcv(:,1:), t(:,1:), &
486  s(:,1:), eps, d_eb, dke_ca, ctke, j, g, gv, us, cs, &
487  cs%ML_presort_nz_conv_adj)
488 
489  call sort_ml(h(:,1:), r0(:,1:), eps, g, gv, cs, ksort)
490  if (id_clock_resort>0) call cpu_clock_end(id_clock_resort)
491  else
492  do k=1,nz ; do i=is,ie ; ksort(i,k) = k ; enddo ; enddo
493 
494  if (id_clock_adjustment>0) call cpu_clock_begin(id_clock_adjustment)
495  ! Undergo instantaneous entrainment into the buffer layers and mixed layers
496  ! to remove hydrostatic instabilities. Any water that is lighter than
497  ! currently in the mixed or buffer layer is entrained.
498  call convective_adjustment(h(:,1:), u, v, r0(:,1:), rcv(:,1:), t(:,1:), &
499  s(:,1:), eps, d_eb, dke_ca, ctke, j, g, gv, us, cs)
500  do i=is,ie ; h_ca(i) = h(i,1) ; enddo
501 
502  if (id_clock_adjustment>0) call cpu_clock_end(id_clock_adjustment)
503  endif
504 
505  if (associated(fluxes%lrunoff) .and. cs%do_rivermix) then
506 
507  ! Here we add an additional source of TKE to the mixed layer where river
508  ! is present to simulate unresolved estuaries. The TKE input is diagnosed
509  ! as follows:
510  ! TKE_river[m3 s-3] = 0.5*rivermix_depth*g*Irho0*drho_ds*
511  ! River*(Samb - Sriver) = CS%mstar*U_star^3
512  ! where River is in units of [m s-1].
513  ! Samb = Ambient salinity at the mouth of the estuary
514  ! rivermix_depth = The prescribed depth over which to mix river inflow
515  ! drho_ds = The gradient of density wrt salt at the ambient surface salinity.
516  ! Sriver = 0 (i.e. rivers are assumed to be pure freshwater)
517  rmixconst = 0.5*cs%rivermix_depth * gv%g_Earth * irho0**2
518  do i=is,ie
519  tke_river(i) = max(0.0, rmixconst*dr0_ds(i)* &
520  (fluxes%lrunoff(i,j) + fluxes%frunoff(i,j)) * s(i,1))
521  enddo
522  else
523  do i=is,ie ; tke_river(i) = 0.0 ; enddo
524  endif
525 
526 
527  if (id_clock_conv>0) call cpu_clock_begin(id_clock_conv)
528 
529  ! The surface forcing is contained in the fluxes type.
530  ! We aggregate the thermodynamic forcing for a time step into the following:
531  ! netMassInOut = water [H ~> m or kg m-2] added/removed via surface fluxes
532  ! netMassOut = water [H ~> m or kg m-2] removed via evaporating surface fluxes
533  ! net_heat = heat via surface fluxes [degC H ~> degC m or degC kg m-2]
534  ! net_salt = salt via surface fluxes [ppt H ~> dppt m or gSalt m-2]
535  ! Pen_SW_bnd = components to penetrative shortwave radiation
536  call extractfluxes1d(g, gv, us, fluxes, optics, nsw, j, dt, &
537  cs%H_limit_fluxes, cs%use_river_heat_content, cs%use_calving_heat_content, &
538  h(:,1:), t(:,1:), netmassinout, netmassout, net_heat, net_salt, pen_sw_bnd,&
539  tv, aggregate_fw_forcing)
540 
541  ! This subroutine causes the mixed layer to entrain to depth of free convection.
542  call mixedlayer_convection(h(:,1:), d_eb, htot, ttot, stot, uhtot, vhtot, &
543  r0_tot, rcv_tot, u, v, t(:,1:), s(:,1:), &
544  r0(:,1:), rcv(:,1:), eps, &
545  dr0_dt, drcv_dt, dr0_ds, drcv_ds, &
546  netmassinout, netmassout, net_heat, net_salt, &
547  nsw, pen_sw_bnd, opacity_band, conv_en, &
548  dke_fc, j, ksort, g, gv, us, cs, tv, fluxes, dt, &
549  aggregate_fw_forcing)
550 
551  if (id_clock_conv>0) call cpu_clock_end(id_clock_conv)
552 
553  ! Now the mixed layer undergoes mechanically forced entrainment.
554  ! The mixed layer may entrain down to the Monin-Obukhov depth if the
555  ! surface is becoming lighter, and is effecti1336vely detraining.
556 
557  ! First the TKE at the depth of free convection that is available
558  ! to drive mixing is calculated.
559  if (id_clock_mech>0) call cpu_clock_begin(id_clock_mech)
560 
561  call find_starting_tke(htot, h_ca, fluxes, conv_en, ctke, dke_fc, dke_ca, &
562  tke, tke_river, idecay_len_tke, cmke, dt, idt_diag, &
563  j, ksort, g, gv, us, cs)
564 
565  ! Here the mechanically driven entrainment occurs.
566  call mechanical_entrainment(h(:,1:), d_eb, htot, ttot, stot, uhtot, vhtot, &
567  r0_tot, rcv_tot, u, v, t(:,1:), s(:,1:), r0(:,1:), rcv(:,1:), eps, dr0_dt, drcv_dt, &
568  cmke, idt_diag, nsw, pen_sw_bnd, opacity_band, tke, &
569  idecay_len_tke, j, ksort, g, gv, us, cs)
570 
571  call absorbremainingsw(g, gv, us, h(:,1:), opacity_band, nsw, optics, j, dt, &
572  cs%H_limit_fluxes, cs%correct_absorption, cs%absorb_all_SW, &
573  t(:,1:), pen_sw_bnd, eps, ksort, htot, ttot)
574 
575  if (cs%TKE_diagnostics) then ; do i=is,ie
576  cs%diag_TKE_mech_decay(i,j) = cs%diag_TKE_mech_decay(i,j) - idt_diag * tke(i)
577  enddo ; endif
578  if (id_clock_mech>0) call cpu_clock_end(id_clock_mech)
579 
580  ! Calculate the homogeneous mixed layer properties and store them in layer 0.
581  do i=is,ie ; if (htot(i) > 0.0) then
582  ih = 1.0 / htot(i)
583  r0(i,0) = r0_tot(i) * ih ; rcv(i,0) = rcv_tot(i) * ih
584  t(i,0) = ttot(i) * ih ; s(i,0) = stot(i) * ih
585  h(i,0) = htot(i)
586  else ! This may not ever be needed?
587  t(i,0) = t(i,1) ; s(i,0) = s(i,1) ; r0(i,0) = r0(i,1) ; rcv(i,0) = rcv(i,1)
588  h(i,0) = htot(i)
589  endif ; enddo
590  if (write_diags .and. allocated(cs%ML_depth)) then ; do i=is,ie
591  cs%ML_depth(i,j) = h(i,0) * gv%H_to_m ! Rescale the diagnostic.
592  enddo ; endif
593  if (associated(hml)) then ; do i=is,ie
594  hml(i,j) = g%mask2dT(i,j) * (h(i,0) * gv%H_to_Z) ! Rescale the diagnostic for output.
595  enddo ; endif
596 
597 ! At this point, return water to the original layers, but constrained to
598 ! still be sorted. After this point, all the water that is in massive
599 ! interior layers will be denser than water remaining in the mixed- and
600 ! buffer-layers. To achieve this, some of these variable density layers
601 ! might be split between two isopycnal layers that are denser than new
602 ! mixed layer or any remaining water from the old mixed- or buffer-layers.
603 ! Alternately, if there are fewer than nkbl of the old buffer or mixed layers
604 ! with any mass, relatively light interior layers might be transferred to
605 ! these unused layers (but not currently in the code).
606 
607  if (cs%ML_resort) then
608  if (id_clock_resort>0) call cpu_clock_begin(id_clock_resort)
609  call resort_ml(h(:,0:), t(:,0:), s(:,0:), r0(:,0:), rcv(:,0:), gv%Rlay(:), eps, &
610  d_ea, d_eb, ksort, g, gv, cs, dr0_dt, dr0_ds, drcv_dt, drcv_ds)
611  if (id_clock_resort>0) call cpu_clock_end(id_clock_resort)
612  endif
613 
614  if (cs%limit_det .or. (cs%id_Hsfc_max > 0) .or. (cs%id_Hsfc_min > 0)) then
615  do i=is,ie ; hsfc(i) = h(i,0) ; enddo
616  do k=1,nkmb ; do i=is,ie ; hsfc(i) = hsfc(i) + h(i,k) ; enddo ; enddo
617 
618  if (cs%limit_det .or. (cs%id_Hsfc_min > 0)) then
619  dhsfc = cs%lim_det_dH_sfc ; dhd = cs%lim_det_dH_bathy
620  do i=is,ie
621  h_nbr = min(dhsfc*max(hmbl_prev(i-1,j), hmbl_prev(i+1,j), &
622  hmbl_prev(i,j-1), hmbl_prev(i,j+1)), &
623  max(hmbl_prev(i-1,j) - dhd*min(h_sum(i,j),h_sum(i-1,j)), &
624  hmbl_prev(i+1,j) - dhd*min(h_sum(i,j),h_sum(i+1,j)), &
625  hmbl_prev(i,j-1) - dhd*min(h_sum(i,j),h_sum(i,j-1)), &
626  hmbl_prev(i,j+1) - dhd*min(h_sum(i,j),h_sum(i,j+1))) )
627 
628  hsfc_min(i,j) = gv%H_to_Z * max(h(i,0), min(hsfc(i), h_nbr))
629 
630  if (cs%limit_det) max_bl_det(i) = max(0.0, hsfc(i)-h_nbr)
631  enddo
632  endif
633 
634  if (cs%id_Hsfc_max > 0) then ; do i=is,ie
635  hsfc_max(i,j) = gv%H_to_Z * hsfc(i)
636  enddo ; endif
637  endif
638 
639 ! Move water left in the former mixed layer into the buffer layer and
640 ! from the buffer layer into the interior. These steps might best be
641 ! treated in conjuction.
642  if (id_clock_detrain>0) call cpu_clock_begin(id_clock_detrain)
643  if (cs%nkbl == 1) then
644  call mixedlayer_detrain_1(h(:,0:), t(:,0:), s(:,0:), r0(:,0:), rcv(:,0:), &
645  gv%Rlay(:), dt, dt__diag, d_ea, d_eb, j, g, gv, us, cs, &
646  drcv_dt, drcv_ds, max_bl_det)
647  elseif (cs%nkbl == 2) then
648  call mixedlayer_detrain_2(h(:,0:), t(:,0:), s(:,0:), r0(:,0:), rcv(:,0:), &
649  gv%Rlay(:), dt, dt__diag, d_ea, j, g, gv, us, cs, &
650  dr0_dt, dr0_ds, drcv_dt, drcv_ds, max_bl_det)
651  else ! CS%nkbl not = 1 or 2
652  ! This code only works with 1 or 2 buffer layers.
653  call mom_error(fatal, "MOM_mixed_layer: CS%nkbl must be 1 or 2 for now.")
654  endif
655  if (id_clock_detrain>0) call cpu_clock_end(id_clock_detrain)
656 
657 
658  if (cs%id_Hsfc_used > 0) then
659  do i=is,ie ; hsfc_used(i,j) = gv%H_to_Z * h(i,0) ; enddo
660  do k=cs%nkml+1,nkmb ; do i=is,ie
661  hsfc_used(i,j) = hsfc_used(i,j) + gv%H_to_Z * h(i,k)
662  enddo ; enddo
663  endif
664 
665 ! Now set the properties of the layers in the mixed layer in the original
666 ! 3-d variables.
667  if (cs%Resolve_Ekman .and. (cs%nkml>1)) then
668  ! The thickness of the topmost piece of the mixed layer is given by
669  ! h_1 = H / (3 + sqrt(|f|*H^2/2*nu_max)), which asymptotes to the Ekman
670  ! layer depth and 1/3 of the mixed layer depth. This curve has been
671  ! determined to maximize the impact of the Ekman transport in the mixed
672  ! layer TKE budget with nkml=2. With nkml=3, this should also be used,
673  ! as the third piece will then optimally describe mixed layer
674  ! restratification. For nkml>=4 the whole strategy should be revisited.
675  do i=is,ie
676  ku_star = 0.41*fluxes%ustar(i,j) ! Maybe could be replaced with u*+w*?
677  if (associated(fluxes%ustar_shelf) .and. &
678  associated(fluxes%frac_shelf_h)) then
679  if (fluxes%frac_shelf_h(i,j) > 0.0) &
680  ku_star = (1.0 - fluxes%frac_shelf_h(i,j)) * ku_star + &
681  fluxes%frac_shelf_h(i,j) * (0.41*fluxes%ustar_shelf(i,j))
682  endif
683  absf_x_h = 0.25 * gv%H_to_Z * h(i,0) * &
684  ((abs(g%CoriolisBu(i,j)) + abs(g%CoriolisBu(i-1,j-1))) + &
685  (abs(g%CoriolisBu(i,j-1)) + abs(g%CoriolisBu(i-1,j))))
686  ! If the mixed layer vertical viscosity specification is changed in
687  ! MOM_vert_friction.F90, this line will have to be modified accordingly.
688  h_3d(i,j,1) = h(i,0) / (3.0 + sqrt(absf_x_h*(absf_x_h + 2.0*ku_star) / ku_star**2))
689  do k=2,cs%nkml
690  ! The other layers are evenly distributed through the mixed layer.
691  h_3d(i,j,k) = (h(i,0)-h_3d(i,j,1)) * inkmlm1
692  d_ea(i,k) = d_ea(i,k) + h_3d(i,j,k)
693  d_ea(i,1) = d_ea(i,1) - h_3d(i,j,k)
694  enddo
695  enddo
696  else
697  do i=is,ie
698  h_3d(i,j,1) = h(i,0) * inkml
699  enddo
700  do k=2,cs%nkml ; do i=is,ie
701  h_3d(i,j,k) = h(i,0) * inkml
702  d_ea(i,k) = d_ea(i,k) + h_3d(i,j,k)
703  d_ea(i,1) = d_ea(i,1) - h_3d(i,j,k)
704  enddo ; enddo
705  endif
706  do i=is,ie ; h(i,0) = 0.0 ; enddo
707  do k=1,cs%nkml ; do i=is,ie
708  tv%T(i,j,k) = t(i,0) ; tv%S(i,j,k) = s(i,0)
709  enddo ; enddo
710 
711  ! These sum needs to be done in the original layer space.
712 
713  ! The treatment of layer 1 is atypical because evaporation shows up as
714  ! negative ea(i,1), and because all precipitation goes straight into layer 1.
715  ! The code is ordered so that any roundoff errors in ea are lost the surface.
716 ! do i=is,ie ; eaml(i,1) = 0.0 ; enddo
717 ! do k=2,nz ; do i=is,ie ; eaml(i,k) = eaml(i,k-1) - d_ea(i,k-1) ; enddo ; enddo
718 ! do i=is,ie ; eaml(i,1) = netMassInOut(i) ; enddo
719 
720 
721  do i=is,ie
722 ! eaml(i,nz) is derived from h(i,nz) - h_orig(i,nz) = eaml(i,nz) - ebml(i,nz-1)
723  ebml(i,nz) = 0.0
724  eaml(i,nz) = (h(i,nz) - h_orig(i,nz)) - d_eb(i,nz)
725  enddo
726  do k=nz-1,1,-1 ; do i=is,ie
727  ebml(i,k) = ebml(i,k+1) - d_eb(i,k+1)
728  eaml(i,k) = eaml(i,k+1) + d_ea(i,k)
729  enddo ; enddo
730  do i=is,ie ; eaml(i,1) = netmassinout(i) ; enddo
731 
732  ! Copy the interior thicknesses and other fields back to the 3-d arrays.
733  do k=cs%nkml+1,nz ; do i=is,ie
734  h_3d(i,j,k) = h(i,k); tv%T(i,j,k) = t(i,k) ; tv%S(i,j,k) = s(i,k)
735  enddo ; enddo
736 
737  do k=1,nz ; do i=is,ie
738  ea(i,j,k) = ea(i,j,k) + eaml(i,k)
739  eb(i,j,k) = eb(i,j,k) + ebml(i,k)
740  enddo ; enddo
741 
742  if (cs%id_h_mismatch > 0) then
743  do i=is,ie
744  h_miss(i,j) = gv%H_to_Z * abs(h_3d(i,j,1) - (h_orig(i,1) + &
745  (eaml(i,1) + (ebml(i,1) - eaml(i,1+1)))))
746  enddo
747  do k=2,nz-1 ; do i=is,ie
748  h_miss(i,j) = h_miss(i,j) + gv%H_to_Z * abs(h_3d(i,j,k) - (h_orig(i,k) + &
749  ((eaml(i,k) - ebml(i,k-1)) + (ebml(i,k) - eaml(i,k+1)))))
750  enddo ; enddo
751  do i=is,ie
752  h_miss(i,j) = h_miss(i,j) + gv%H_to_Z * abs(h_3d(i,j,nz) - (h_orig(i,nz) + &
753  ((eaml(i,nz) - ebml(i,nz-1)) + ebml(i,nz))))
754  enddo
755  endif
756 
757  enddo ! j loop
758  !$OMP end parallel
759 
760  ! Whenever thickness changes let the diag manager know, target grids
761  ! for vertical remapping may need to be regenerated.
762  ! This needs to happen after the H update and before the next post_data.
763  call diag_update_remap_grids(cs%diag)
764 
765 
766  if (write_diags) then
767  if (cs%id_ML_depth > 0) &
768  call post_data(cs%id_ML_depth, cs%ML_depth, cs%diag)
769  if (cs%id_TKE_wind > 0) &
770  call post_data(cs%id_TKE_wind, cs%diag_TKE_wind, cs%diag)
771  if (cs%id_TKE_RiBulk > 0) &
772  call post_data(cs%id_TKE_RiBulk, cs%diag_TKE_RiBulk, cs%diag)
773  if (cs%id_TKE_conv > 0) &
774  call post_data(cs%id_TKE_conv, cs%diag_TKE_conv, cs%diag)
775  if (cs%id_TKE_pen_SW > 0) &
776  call post_data(cs%id_TKE_pen_SW, cs%diag_TKE_pen_SW, cs%diag)
777  if (cs%id_TKE_mixing > 0) &
778  call post_data(cs%id_TKE_mixing, cs%diag_TKE_mixing, cs%diag)
779  if (cs%id_TKE_mech_decay > 0) &
780  call post_data(cs%id_TKE_mech_decay, cs%diag_TKE_mech_decay, cs%diag)
781  if (cs%id_TKE_conv_decay > 0) &
782  call post_data(cs%id_TKE_conv_decay, cs%diag_TKE_conv_decay, cs%diag)
783  if (cs%id_TKE_conv_s2 > 0) &
784  call post_data(cs%id_TKE_conv_s2, cs%diag_TKE_conv_s2, cs%diag)
785  if (cs%id_PE_detrain > 0) &
786  call post_data(cs%id_PE_detrain, cs%diag_PE_detrain, cs%diag)
787  if (cs%id_PE_detrain2 > 0) &
788  call post_data(cs%id_PE_detrain2, cs%diag_PE_detrain2, cs%diag)
789  if (cs%id_h_mismatch > 0) &
790  call post_data(cs%id_h_mismatch, h_miss, cs%diag)
791  if (cs%id_Hsfc_used > 0) &
792  call post_data(cs%id_Hsfc_used, hsfc_used, cs%diag)
793  if (cs%id_Hsfc_max > 0) &
794  call post_data(cs%id_Hsfc_max, hsfc_max, cs%diag)
795  if (cs%id_Hsfc_min > 0) &
796  call post_data(cs%id_Hsfc_min, hsfc_min, cs%diag)
797  endif
798 

◆ bulkmixedlayer_init()

subroutine, public mom_bulk_mixed_layer::bulkmixedlayer_init ( type(time_type), intent(in), target  Time,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(param_file_type), intent(in)  param_file,
type(diag_ctrl), intent(inout), target  diag,
type(bulkmixedlayer_cs), pointer  CS 
)

This subroutine initializes the MOM bulk mixed layer module.

Parameters
[in]timeThe model's clock with the current time.
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in]param_fileA structure to parse for run-time parameters.
[in,out]diagA structure that is used to regulate diagnostic output.
csA pointer that is set to point to the control structure for this module.

Definition at line 3389 of file MOM_bulk_mixed_layer.F90.

3390  type(time_type), target, intent(in) :: Time !< The model's clock with the current time.
3391  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
3392  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
3393  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
3394  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time
3395  !! parameters.
3396  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to regulate diagnostic
3397  !! output.
3398  type(bulkmixedlayer_CS), pointer :: CS !< A pointer that is set to point to the control
3399  !! structure for this module.
3400 ! Arguments: Time - The current model time.
3401 ! (in) G - The ocean's grid structure.
3402 ! (in) GV - The ocean's vertical grid structure.
3403 ! (in) param_file - A structure indicating the open file to parse for
3404 ! model parameter values.
3405 ! (in) diag - A structure that is used to regulate diagnostic output.
3406 ! (in/out) CS - A pointer that is set to point to the control structure
3407 ! for this module
3408 ! This include declares and sets the variable "version".
3409 #include "version_variable.h"
3410  character(len=40) :: mdl = "MOM_mixed_layer" ! This module's name.
3411  real :: BL_detrain_time_dflt ! The default value for BUFFER_LAY_DETRAIN_TIME [s]
3412  real :: omega_frac_dflt, ustar_min_dflt, Hmix_min_m
3413  integer :: isd, ied, jsd, jed
3414  logical :: use_temperature, use_omega
3415  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
3416 
3417  if (associated(cs)) then
3418  call mom_error(warning, "mixedlayer_init called with an associated"// &
3419  "associated control structure.")
3420  return
3421  else ; allocate(cs) ; endif
3422 
3423  cs%diag => diag
3424  cs%Time => time
3425 
3426  if (gv%nkml < 1) return
3427 
3428 ! Set default, read and log parameters
3429  call log_version(param_file, mdl, version, "")
3430 
3431  cs%nkml = gv%nkml
3432  call log_param(param_file, mdl, "NKML", cs%nkml, &
3433  "The number of sublayers within the mixed layer if "//&
3434  "BULKMIXEDLAYER is true.", units="nondim", default=2)
3435  cs%nkbl = gv%nk_rho_varies - gv%nkml
3436  call log_param(param_file, mdl, "NKBL", cs%nkbl, &
3437  "The number of variable density buffer layers if "//&
3438  "BULKMIXEDLAYER is true.", units="nondim", default=2)
3439  call get_param(param_file, mdl, "MSTAR", cs%mstar, &
3440  "The ratio of the friction velocity cubed to the TKE "//&
3441  "input to the mixed layer.", units="nondim", default=1.2)
3442  call get_param(param_file, mdl, "NSTAR", cs%nstar, &
3443  "The portion of the buoyant potential energy imparted by "//&
3444  "surface fluxes that is available to drive entrainment "//&
3445  "at the base of mixed layer when that energy is positive.", &
3446  units="nondim", default=0.15)
3447  call get_param(param_file, mdl, "BULK_RI_ML", cs%bulk_Ri_ML, &
3448  "The efficiency with which mean kinetic energy released "//&
3449  "by mechanically forced entrainment of the mixed layer "//&
3450  "is converted to turbulent kinetic energy.", units="nondim",&
3451  fail_if_missing=.true.)
3452  call get_param(param_file, mdl, "ABSORB_ALL_SW", cs%absorb_all_sw, &
3453  "If true, all shortwave radiation is absorbed by the "//&
3454  "ocean, instead of passing through to the bottom mud.", &
3455  default=.false.)
3456  call get_param(param_file, mdl, "TKE_DECAY", cs%TKE_decay, &
3457  "TKE_DECAY relates the vertical rate of decay of the "//&
3458  "TKE available for mechanical entrainment to the natural "//&
3459  "Ekman depth.", units="nondim", default=2.5)
3460  call get_param(param_file, mdl, "NSTAR2", cs%nstar2, &
3461  "The portion of any potential energy released by "//&
3462  "convective adjustment that is available to drive "//&
3463  "entrainment at the base of mixed layer. By default "//&
3464  "NSTAR2=NSTAR.", units="nondim", default=cs%nstar)
3465  call get_param(param_file, mdl, "BULK_RI_CONVECTIVE", cs%bulk_Ri_convective, &
3466  "The efficiency with which convectively released mean "//&
3467  "kinetic energy is converted to turbulent kinetic "//&
3468  "energy. By default BULK_RI_CONVECTIVE=BULK_RI_ML.", &
3469  units="nondim", default=cs%bulk_Ri_ML)
3470  call get_param(param_file, mdl, "HMIX_MIN", cs%Hmix_min, &
3471  "The minimum mixed layer depth if the mixed layer depth "//&
3472  "is determined dynamically.", units="m", default=0.0, scale=gv%m_to_H, &
3473  unscaled=hmix_min_m)
3474 
3475  call get_param(param_file, mdl, "LIMIT_BUFFER_DETRAIN", cs%limit_det, &
3476  "If true, limit the detrainment from the buffer layers "//&
3477  "to not be too different from the neighbors.", default=.false.)
3478  call get_param(param_file, mdl, "ALLOWED_DETRAIN_TEMP_CHG", cs%Allowed_T_chg, &
3479  "The amount by which temperature is allowed to exceed "//&
3480  "previous values during detrainment.", units="K", default=0.5)
3481  call get_param(param_file, mdl, "ALLOWED_DETRAIN_SALT_CHG", cs%Allowed_S_chg, &
3482  "The amount by which salinity is allowed to exceed "//&
3483  "previous values during detrainment.", units="PSU", default=0.1)
3484  call get_param(param_file, mdl, "ML_DT_DS_WEIGHT", cs%dT_dS_wt, &
3485  "When forced to extrapolate T & S to match the layer "//&
3486  "densities, this factor (in deg C / PSU) is combined "//&
3487  "with the derivatives of density with T & S to determine "//&
3488  "what direction is orthogonal to density contours. It "//&
3489  "should be a typical value of (dR/dS) / (dR/dT) in "//&
3490  "oceanic profiles.", units="degC PSU-1", default=6.0)
3491  call get_param(param_file, mdl, "BUFFER_LAYER_EXTRAP_LIMIT", cs%BL_extrap_lim, &
3492  "A limit on the density range over which extrapolation "//&
3493  "can occur when detraining from the buffer layers, "//&
3494  "relative to the density range within the mixed and "//&
3495  "buffer layers, when the detrainment is going into the "//&
3496  "lightest interior layer, nondimensional, or a negative "//&
3497  "value not to apply this limit.", units="nondim", default = -1.0)
3498  call get_param(param_file, mdl, "BUFFER_LAYER_HMIN_THICK", cs%Hbuffer_min, &
3499  "The minimum buffer layer thickness when the mixed layer is very thick.", &
3500  units="m", default=5.0, scale=gv%m_to_H)
3501  call get_param(param_file, mdl, "BUFFER_LAYER_HMIN_REL", cs%Hbuffer_rel_min, &
3502  "The minimum buffer layer thickness relative to the combined mixed "//&
3503  "land buffer ayer thicknesses when they are thin.", &
3504  units="nondim", default=0.1/cs%nkbl)
3505  bl_detrain_time_dflt = 4.0*3600.0 ; if (cs%nkbl==1) bl_detrain_time_dflt = 86400.0*30.0
3506  call get_param(param_file, mdl, "BUFFER_LAY_DETRAIN_TIME", cs%BL_detrain_time, &
3507  "A timescale that characterizes buffer layer detrainment events.", &
3508  units="s", default=bl_detrain_time_dflt, scale=us%s_to_T)
3509  call get_param(param_file, mdl, "BUFFER_SPLIT_RHO_TOL", cs%BL_split_rho_tol, &
3510  "The fractional tolerance for matching layer target densities when splitting "//&
3511  "layers to deal with massive interior layers that are lighter than one of the "//&
3512  "mixed or buffer layers.", units="nondim", default=0.1)
3513 
3514  call get_param(param_file, mdl, "DEPTH_LIMIT_FLUXES", cs%H_limit_fluxes, &
3515  "The surface fluxes are scaled away when the total ocean "//&
3516  "depth is less than DEPTH_LIMIT_FLUXES.", &
3517  units="m", default=0.1*hmix_min_m, scale=gv%m_to_H)
3518  call get_param(param_file, mdl, "OMEGA", cs%omega, &
3519  "The rotation rate of the earth.", &
3520  default=7.2921e-5, units="s-1", scale=us%T_to_s)
3521  call get_param(param_file, mdl, "ML_USE_OMEGA", use_omega, &
3522  "If true, use the absolute rotation rate instead of the "//&
3523  "vertical component of rotation when setting the decay "//&
3524  "scale for turbulence.", default=.false., do_not_log=.true.)
3525  omega_frac_dflt = 0.0
3526  if (use_omega) then
3527  call mom_error(warning, "ML_USE_OMEGA is depricated; use ML_OMEGA_FRAC=1.0 instead.")
3528  omega_frac_dflt = 1.0
3529  endif
3530  call get_param(param_file, mdl, "ML_OMEGA_FRAC", cs%omega_frac, &
3531  "When setting the decay scale for turbulence, use this "//&
3532  "fraction of the absolute rotation rate blended with the "//&
3533  "local value of f, as sqrt((1-of)*f^2 + of*4*omega^2).", &
3534  units="nondim", default=omega_frac_dflt)
3535  call get_param(param_file, mdl, "ML_RESORT", cs%ML_resort, &
3536  "If true, resort the topmost layers by potential density "//&
3537  "before the mixed layer calculations.", default=.false.)
3538  if (cs%ML_resort) &
3539  call get_param(param_file, mdl, "ML_PRESORT_NK_CONV_ADJ", cs%ML_presort_nz_conv_adj, &
3540  "Convectively mix the first ML_PRESORT_NK_CONV_ADJ "//&
3541  "layers before sorting when ML_RESORT is true.", &
3542  units="nondim", default=0, fail_if_missing=.true.) ! Fail added by AJA.
3543  ! This gives a minimum decay scale that is typically much less than Angstrom.
3544  ustar_min_dflt = 2e-4*us%s_to_T*cs%omega*(gv%Angstrom_m + gv%H_to_m*gv%H_subroundoff)
3545  call get_param(param_file, mdl, "BML_USTAR_MIN", cs%ustar_min, &
3546  "The minimum value of ustar that should be used by the "//&
3547  "bulk mixed layer model in setting vertical TKE decay "//&
3548  "scales. This must be greater than 0.", units="m s-1", &
3549  default=ustar_min_dflt, scale=us%m_to_Z*us%T_to_s)
3550  if (cs%ustar_min<=0.0) call mom_error(fatal, "BML_USTAR_MIN must be positive.")
3551 
3552  call get_param(param_file, mdl, "RESOLVE_EKMAN", cs%Resolve_Ekman, &
3553  "If true, the NKML>1 layers in the mixed layer are "//&
3554  "chosen to optimally represent the impact of the Ekman "//&
3555  "transport on the mixed layer TKE budget. Otherwise, "//&
3556  "the sublayers are distributed uniformly through the "//&
3557  "mixed layer.", default=.false.)
3558  call get_param(param_file, mdl, "CORRECT_ABSORPTION_DEPTH", cs%correct_absorption, &
3559  "If true, the average depth at which penetrating shortwave "//&
3560  "radiation is absorbed is adjusted to match the average "//&
3561  "heating depth of an exponential profile by moving some "//&
3562  "of the heating upward in the water column.", default=.false.)
3563  call get_param(param_file, mdl, "DO_RIVERMIX", cs%do_rivermix, &
3564  "If true, apply additional mixing wherever there is "//&
3565  "runoff, so that it is mixed down to RIVERMIX_DEPTH, "//&
3566  "if the ocean is that deep.", default=.false.)
3567  if (cs%do_rivermix) &
3568  call get_param(param_file, mdl, "RIVERMIX_DEPTH", cs%rivermix_depth, &
3569  "The depth to which rivers are mixed if DO_RIVERMIX is "//&
3570  "defined.", units="m", default=0.0, scale=us%m_to_Z)
3571  call get_param(param_file, mdl, "USE_RIVER_HEAT_CONTENT", cs%use_river_heat_content, &
3572  "If true, use the fluxes%runoff_Hflx field to set the "//&
3573  "heat carried by runoff, instead of using SST*CP*liq_runoff.", &
3574  default=.false.)
3575  call get_param(param_file, mdl, "USE_CALVING_HEAT_CONTENT", cs%use_calving_heat_content, &
3576  "If true, use the fluxes%calving_Hflx field to set the "//&
3577  "heat carried by runoff, instead of using SST*CP*froz_runoff.", &
3578  default=.false.)
3579  call get_param(param_file, mdl, "BULKML_CONV_MOMENTUM_BUG", cs%convect_mom_bug, &
3580  "If true, use code with a bug that causes a loss of momentum conservation "//&
3581  "during mixedlayer convection.", default=.false.)
3582 
3583  call get_param(param_file, mdl, "ALLOW_CLOCKS_IN_OMP_LOOPS", &
3584  cs%allow_clocks_in_omp_loops, &
3585  "If true, clocks can be called from inside loops that can "//&
3586  "be threaded. To run with multiple threads, set to False.", &
3587  default=.true.)
3588 
3589  cs%id_ML_depth = register_diag_field('ocean_model', 'h_ML', diag%axesT1, &
3590  time, 'Surface mixed layer depth', 'm')
3591  cs%id_TKE_wind = register_diag_field('ocean_model', 'TKE_wind', diag%axesT1, &
3592  time, 'Wind-stirring source of mixed layer TKE', &
3593  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3594  cs%id_TKE_RiBulk = register_diag_field('ocean_model', 'TKE_RiBulk', diag%axesT1, &
3595  time, 'Mean kinetic energy source of mixed layer TKE', &
3596  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3597  cs%id_TKE_conv = register_diag_field('ocean_model', 'TKE_conv', diag%axesT1, &
3598  time, 'Convective source of mixed layer TKE', &
3599  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3600  cs%id_TKE_pen_SW = register_diag_field('ocean_model', 'TKE_pen_SW', diag%axesT1, &
3601  time, 'TKE consumed by mixing penetrative shortwave radation through the mixed layer', &
3602  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3603  cs%id_TKE_mixing = register_diag_field('ocean_model', 'TKE_mixing', diag%axesT1, &
3604  time, 'TKE consumed by mixing that deepens the mixed layer', &
3605  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3606  cs%id_TKE_mech_decay = register_diag_field('ocean_model', 'TKE_mech_decay', diag%axesT1, &
3607  time, 'Mechanical energy decay sink of mixed layer TKE', &
3608  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3609  cs%id_TKE_conv_decay = register_diag_field('ocean_model', 'TKE_conv_decay', diag%axesT1, &
3610  time, 'Convective energy decay sink of mixed layer TKE', &
3611  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3612  cs%id_TKE_conv_s2 = register_diag_field('ocean_model', 'TKE_conv_s2', diag%axesT1, &
3613  time, 'Spurious source of mixed layer TKE from sigma2', &
3614  'm3 s-3', conversion=us%Z_to_m*(us%L_to_m**2)*(us%s_to_T**3))
3615  cs%id_PE_detrain = register_diag_field('ocean_model', 'PE_detrain', diag%axesT1, &
3616  time, 'Spurious source of potential energy from mixed layer detrainment', &
3617  'W m-2', conversion=us%RZ3_T3_to_W_m2*us%L_to_Z**2)
3618  cs%id_PE_detrain2 = register_diag_field('ocean_model', 'PE_detrain2', diag%axesT1, &
3619  time, 'Spurious source of potential energy from mixed layer only detrainment', &
3620  'W m-2', conversion=us%RZ3_T3_to_W_m2*us%L_to_Z**2)
3621  cs%id_h_mismatch = register_diag_field('ocean_model', 'h_miss_ML', diag%axesT1, &
3622  time, 'Summed absolute mismatch in entrainment terms', 'm', conversion=us%Z_to_m)
3623  cs%id_Hsfc_used = register_diag_field('ocean_model', 'Hs_used', diag%axesT1, &
3624  time, 'Surface region thickness that is used', 'm', conversion=us%Z_to_m)
3625  cs%id_Hsfc_max = register_diag_field('ocean_model', 'Hs_max', diag%axesT1, &
3626  time, 'Maximum surface region thickness', 'm', conversion=us%Z_to_m)
3627  cs%id_Hsfc_min = register_diag_field('ocean_model', 'Hs_min', diag%axesT1, &
3628  time, 'Minimum surface region thickness', 'm', conversion=us%Z_to_m)
3629  !CS%lim_det_dH_sfc = 0.5 ; CS%lim_det_dH_bathy = 0.2 ! Technically these should not get used if limit_det is false?
3630  if (cs%limit_det .or. (cs%id_Hsfc_min > 0)) then
3631  call get_param(param_file, mdl, "LIMIT_BUFFER_DET_DH_SFC", cs%lim_det_dH_sfc, &
3632  "The fractional limit in the change between grid points "//&
3633  "of the surface region (mixed & buffer layer) thickness.", &
3634  units="nondim", default=0.5)
3635  call get_param(param_file, mdl, "LIMIT_BUFFER_DET_DH_BATHY", cs%lim_det_dH_bathy, &
3636  "The fraction of the total depth by which the thickness "//&
3637  "of the surface region (mixed & buffer layer) is allowed "//&
3638  "to change between grid points.", units="nondim", default=0.2)
3639  endif
3640 
3641  call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", use_temperature, &
3642  "If true, temperature and salinity are used as state "//&
3643  "variables.", default=.true.)
3644  cs%nsw = 0
3645  if (use_temperature) then
3646  call get_param(param_file, mdl, "PEN_SW_NBANDS", cs%nsw, default=1)
3647  endif
3648 
3649 
3650  if (max(cs%id_TKE_wind, cs%id_TKE_RiBulk, cs%id_TKE_conv, cs%id_TKE_mixing, &
3651  cs%id_TKE_pen_SW, cs%id_TKE_mech_decay, cs%id_TKE_conv_decay) > 0) then
3652  call safe_alloc_alloc(cs%diag_TKE_wind, isd, ied, jsd, jed)
3653  call safe_alloc_alloc(cs%diag_TKE_RiBulk, isd, ied, jsd, jed)
3654  call safe_alloc_alloc(cs%diag_TKE_conv, isd, ied, jsd, jed)
3655  call safe_alloc_alloc(cs%diag_TKE_pen_SW, isd, ied, jsd, jed)
3656  call safe_alloc_alloc(cs%diag_TKE_mixing, isd, ied, jsd, jed)
3657  call safe_alloc_alloc(cs%diag_TKE_mech_decay, isd, ied, jsd, jed)
3658  call safe_alloc_alloc(cs%diag_TKE_conv_decay, isd, ied, jsd, jed)
3659  call safe_alloc_alloc(cs%diag_TKE_conv_s2, isd, ied, jsd, jed)
3660 
3661  cs%TKE_diagnostics = .true.
3662  endif
3663  if (cs%id_PE_detrain > 0) call safe_alloc_alloc(cs%diag_PE_detrain, isd, ied, jsd, jed)
3664  if (cs%id_PE_detrain2 > 0) call safe_alloc_alloc(cs%diag_PE_detrain2, isd, ied, jsd, jed)
3665  if (cs%id_ML_depth > 0) call safe_alloc_alloc(cs%ML_depth, isd, ied, jsd, jed)
3666 
3667  if (cs%allow_clocks_in_omp_loops) then
3668  id_clock_detrain = cpu_clock_id('(Ocean mixed layer detrain)', grain=clock_routine)
3669  id_clock_mech = cpu_clock_id('(Ocean mixed layer mechanical entrainment)', grain=clock_routine)
3670  id_clock_conv = cpu_clock_id('(Ocean mixed layer convection)', grain=clock_routine)
3671  if (cs%ML_resort) then
3672  id_clock_resort = cpu_clock_id('(Ocean mixed layer resorting)', grain=clock_routine)
3673  else
3674  id_clock_adjustment = cpu_clock_id('(Ocean mixed layer convective adjustment)', grain=clock_routine)
3675  endif
3676  id_clock_eos = cpu_clock_id('(Ocean mixed layer EOS)', grain=clock_routine)
3677  endif
3678 
3679  if (cs%limit_det .or. (cs%id_Hsfc_min > 0)) &
3680  id_clock_pass = cpu_clock_id('(Ocean mixed layer halo updates)', grain=clock_routine)
3681 
3682 
3683 ! if (CS%limit_det) then
3684 ! endif
3685 

◆ convective_adjustment()

subroutine mom_bulk_mixed_layer::convective_adjustment ( real, dimension( g %isd: g %ied, gv %ke), intent(inout)  h,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  u,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  v,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  R0,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  Rcv,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  T,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  S,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  eps,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  d_eb,
real, dimension( g %isd: g %ied, gv %ke), intent(out)  dKE_CA,
real, dimension( g %isd: g %ied, gv %ke), intent(out)  cTKE,
integer, intent(in)  j,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(bulkmixedlayer_cs), pointer  CS,
integer, intent(in), optional  nz_conv 
)
private

This subroutine does instantaneous convective entrainment into the buffer layers and mixed layers to remove hydrostatic instabilities. Any water that is lighter than currently in the mixed- or buffer- layer is entrained.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in,out]hLayer thickness [H ~> m or kg m-2]. The units of h are referred to as H below.
[in,out]uZonal velocities interpolated to h points [L T-1 ~> m s-1].
[in,out]vZonal velocities interpolated to h points [L T-1 ~> m s-1].
[in,out]tLayer temperatures [degC].
[in,out]sLayer salinities [ppt].
[in,out]r0Potential density referenced to surface pressure [R ~> kg m-3].
[in,out]rcvThe coordinate defining potential density [R ~> kg m-3].
[in,out]d_ebThe downward increase across a layer in the entrainment from below [H ~> m or kg m-2]. Positive values go with mass gain by a layer.
[in]epsThe negligibly small amount of water that will be left in each layer [H ~> m or kg m-2].
[out]dke_caThe vertically integrated change in kinetic energy due to convective adjustment [Z L2 T-2 ~> m3 s-2].
[out]ctkeThe buoyant turbulent kinetic energy source due to convective adjustment [Z L2 T-2 ~> m3 s-2].
[in]jThe j-index to work on.
[in]usA dimensional unit scaling type
csThe control structure for this module.
[in]nz_convIf present, the number of layers over which to do convective adjustment (perhaps CSnkml).

Definition at line 804 of file MOM_bulk_mixed_layer.F90.

806  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
807  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
808  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: h !< Layer thickness [H ~> m or kg m-2].
809  !! The units of h are referred to as H below.
810  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: u !< Zonal velocities interpolated to h
811  !! points [L T-1 ~> m s-1].
812  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: v !< Zonal velocities interpolated to h
813  !! points [L T-1 ~> m s-1].
814  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: T !< Layer temperatures [degC].
815  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: S !< Layer salinities [ppt].
816  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: R0 !< Potential density referenced to
817  !! surface pressure [R ~> kg m-3].
818  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: Rcv !< The coordinate defining potential
819  !! density [R ~> kg m-3].
820  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: d_eb !< The downward increase across a layer
821  !! in the entrainment from below [H ~> m or kg m-2].
822  !! Positive values go with mass gain by
823  !! a layer.
824  real, dimension(SZI_(G),SZK_(GV)), intent(in) :: eps !< The negligibly small amount of water
825  !! that will be left in each layer [H ~> m or kg m-2].
826  real, dimension(SZI_(G),SZK_(GV)), intent(out) :: dKE_CA !< The vertically integrated change in
827  !! kinetic energy due to convective
828  !! adjustment [Z L2 T-2 ~> m3 s-2].
829  real, dimension(SZI_(G),SZK_(GV)), intent(out) :: cTKE !< The buoyant turbulent kinetic energy
830  !! source due to convective adjustment
831  !! [Z L2 T-2 ~> m3 s-2].
832  integer, intent(in) :: j !< The j-index to work on.
833  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
834  type(bulkmixedlayer_CS), pointer :: CS !< The control structure for this module.
835  integer, optional, intent(in) :: nz_conv !< If present, the number of layers
836  !! over which to do convective adjustment
837  !! (perhaps CS%nkml).
838 
839 ! This subroutine does instantaneous convective entrainment into the buffer
840 ! layers and mixed layers to remove hydrostatic instabilities. Any water that
841 ! is lighter than currently in the mixed- or buffer- layer is entrained.
842 
843  ! Local variables
844  real, dimension(SZI_(G)) :: &
845  htot, & ! The total depth of the layers being considered for
846  ! entrainment [H ~> m or kg m-2].
847  r0_tot, & ! The integrated potential density referenced to the surface
848  ! of the layers which are fully entrained [H R ~> kg m-2 or kg2 m-5].
849  rcv_tot, & ! The integrated coordinate value potential density of the
850  ! layers that are fully entrained [H R ~> kg m-2 or kg2 m-5].
851  ttot, & ! The integrated temperature of layers which are fully
852  ! entrained [degC H ~> degC m or degC kg m-2].
853  stot, & ! The integrated salt of layers which are fully entrained
854  ! [H ppt ~> m ppt or ppt kg m-2].
855  uhtot, & ! The depth integrated zonal and meridional velocities in
856  vhtot, & ! the mixed layer [H L T-1 ~> m2 s-1 or kg m-1 s-1].
857  ke_orig, & ! The total mean kinetic energy in the mixed layer before
858  ! convection, [H L2 T-2 ~> H m2 s-2].
859  h_orig_k1 ! The depth of layer k1 before convective adjustment [H ~> m or kg m-2].
860  real :: h_ent ! The thickness from a layer that is entrained [H ~> m or kg m-2].
861  real :: Ih ! The inverse of a thickness [H-1 ~> m-1 or m2 kg-1].
862  real :: g_H2_2Rho0 ! Half the gravitational acceleration times the square of
863  ! the conversion from H to Z divided by the mean density,
864  ! in [L2 Z T-3 H-2 R-1 ~> m4 s-3 kg-1 or m10 s-3 kg-3].
865  integer :: is, ie, nz, i, k, k1, nzc, nkmb
866 
867  is = g%isc ; ie = g%iec ; nz = gv%ke
868  g_h2_2rho0 = (gv%g_Earth * gv%H_to_Z**2) / (2.0 * gv%Rho0)
869  nzc = nz ; if (present(nz_conv)) nzc = nz_conv
870  nkmb = cs%nkml+cs%nkbl
871 
872 ! Undergo instantaneous entrainment into the buffer layers and mixed layers
873 ! to remove hydrostatic instabilities. Any water that is lighter than currently
874 ! in the layer is entrained.
875  do k1=min(nzc-1,nkmb),1,-1
876  do i=is,ie
877  h_orig_k1(i) = h(i,k1)
878  ke_orig(i) = 0.5*h(i,k1)*(u(i,k1)**2 + v(i,k1)**2)
879  uhtot(i) = h(i,k1)*u(i,k1) ; vhtot(i) = h(i,k1)*v(i,k1)
880  r0_tot(i) = r0(i,k1) * h(i,k1)
881  ctke(i,k1) = 0.0 ; dke_ca(i,k1) = 0.0
882 
883  rcv_tot(i) = rcv(i,k1) * h(i,k1)
884  ttot(i) = t(i,k1) * h(i,k1) ; stot(i) = s(i,k1) * h(i,k1)
885  enddo
886  do k=k1+1,nzc
887  do i=is,ie
888  if ((h(i,k) > eps(i,k)) .and. (r0_tot(i) > h(i,k1)*r0(i,k))) then
889  h_ent = h(i,k)-eps(i,k)
890  ctke(i,k1) = ctke(i,k1) + h_ent * g_h2_2rho0 * &
891  (r0_tot(i) - h(i,k1)*r0(i,k)) * cs%nstar2
892  if (k < nkmb) then
893  ctke(i,k1) = ctke(i,k1) + ctke(i,k)
894  dke_ca(i,k1) = dke_ca(i,k1) + dke_ca(i,k)
895  endif
896  r0_tot(i) = r0_tot(i) + h_ent * r0(i,k)
897  ke_orig(i) = ke_orig(i) + 0.5*h_ent* &
898  (u(i,k)*u(i,k) + v(i,k)*v(i,k))
899  uhtot(i) = uhtot(i) + h_ent*u(i,k)
900  vhtot(i) = vhtot(i) + h_ent*v(i,k)
901 
902  rcv_tot(i) = rcv_tot(i) + h_ent * rcv(i,k)
903  ttot(i) = ttot(i) + h_ent * t(i,k)
904  stot(i) = stot(i) + h_ent * s(i,k)
905  h(i,k1) = h(i,k1) + h_ent ; h(i,k) = eps(i,k)
906 
907  d_eb(i,k) = d_eb(i,k) - h_ent
908  d_eb(i,k1) = d_eb(i,k1) + h_ent
909  endif
910  enddo
911  enddo
912 ! Determine the temperature, salinity, and velocities of the mixed or buffer
913 ! layer in question, if it has entrained.
914  do i=is,ie ; if (h(i,k1) > h_orig_k1(i)) then
915  ih = 1.0 / h(i,k1)
916  r0(i,k1) = r0_tot(i) * ih
917  u(i,k1) = uhtot(i) * ih ; v(i,k1) = vhtot(i) * ih
918  dke_ca(i,k1) = dke_ca(i,k1) + gv%H_to_Z * (cs%bulk_Ri_convective * &
919  (ke_orig(i) - 0.5*h(i,k1)*(u(i,k1)**2 + v(i,k1)**2)))
920  rcv(i,k1) = rcv_tot(i) * ih
921  t(i,k1) = ttot(i) * ih ; s(i,k1) = stot(i) * ih
922  endif ; enddo
923  enddo
924 ! If lower mixed or buffer layers are massless, give them the properties of the
925 ! layer above.
926  do k=2,min(nzc,nkmb) ; do i=is,ie ; if (h(i,k) == 0.0) then
927  r0(i,k) = r0(i,k-1)
928  rcv(i,k) = rcv(i,k-1) ; t(i,k) = t(i,k-1) ; s(i,k) = s(i,k-1)
929  endif ; enddo ; enddo
930 

◆ ef4()

real function mom_bulk_mixed_layer::ef4 ( real, intent(in)  Ht,
real, intent(in)  En,
real, intent(in)  I_L,
real, intent(inout), optional  dR_de 
)
private

This subroutine returns an approximation to the integral R = exp(-L*(H+E)) integral(LH to L(H+E)) L/(1-(1+x)exp(-x)) dx. The approximation to the integrand is good to within -2% at x~.3 and +25% at x~3.5, but the exponential deemphasizes the importance of large x. When L=0, EF4 returns E/((Ht+E)*Ht).

Parameters
[in]htTotal thickness [H ~> m or kg m-2].
[in]enEntrainment [H ~> m or kg m-2].
[in]i_lThe e-folding scale [H-1 ~> m-1 or m2 kg-1]
[in,out]dr_deThe partial derivative of the result R with E [H-2 ~> m-2 or m4 kg-2].
Returns
The integral [H-1 ~> m-1 or m2 kg-1].

Definition at line 3693 of file MOM_bulk_mixed_layer.F90.

3694  real, intent(in) :: Ht !< Total thickness [H ~> m or kg m-2].
3695  real, intent(in) :: En !< Entrainment [H ~> m or kg m-2].
3696  real, intent(in) :: I_L !< The e-folding scale [H-1 ~> m-1 or m2 kg-1]
3697  real, optional, intent(inout) :: dR_de !< The partial derivative of the result R with E [H-2 ~> m-2 or m4 kg-2].
3698  real :: EF4 !< The integral [H-1 ~> m-1 or m2 kg-1].
3699 
3700  ! Local variables
3701  real :: exp_LHpE ! A nondimensional exponential decay.
3702  real :: I_HpE ! An inverse thickness plus entrainment [H-1 ~> m-1 or m2 kg-1].
3703  real :: Res ! The result of the integral above [H-1 ~> m-1 or m2 kg-1].
3704 
3705  exp_lhpe = exp(-i_l*(en+ht))
3706  i_hpe = 1.0/(ht+en)
3707  res = exp_lhpe * (en*i_hpe/ht - 0.5*i_l*log(ht*i_hpe) + 0.5*i_l*i_l*en)
3708  if (PRESENT(dr_de)) &
3709  dr_de = -i_l*res + exp_lhpe*(i_hpe*i_hpe + 0.5*i_l*i_hpe + 0.5*i_l*i_l)
3710  ef4 = res
3711 

◆ find_starting_tke()

subroutine mom_bulk_mixed_layer::find_starting_tke ( real, dimension(szi_(g)), intent(in)  htot,
real, dimension(szi_(g)), intent(in)  h_CA,
type(forcing), intent(in)  fluxes,
real, dimension(szi_(g)), intent(inout)  Conv_En,
real, dimension(szi_(g),szk_(gv)), intent(in)  cTKE,
real, dimension(szi_(g)), intent(in)  dKE_FC,
real, dimension(szi_(g),szk_(gv)), intent(in)  dKE_CA,
real, dimension(szi_(g)), intent(out)  TKE,
real, dimension(szi_(g)), intent(in)  TKE_river,
real, dimension(szi_(g)), intent(out)  Idecay_len_TKE,
real, dimension(2,szi_(g)), intent(out)  cMKE,
real, intent(in)  dt,
real, intent(in)  Idt_diag,
integer, intent(in)  j,
integer, dimension(szi_(g),szk_(gv)), intent(in)  ksort,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(bulkmixedlayer_cs), pointer  CS 
)
private

This subroutine determines the TKE available at the depth of free convection to drive mechanical entrainment.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in]htotThe accumulated mixed layer thickness [H ~> m or kg m-2]
[in]h_caThe mixed layer depth after convective adjustment [H ~> m or kg m-2].
[in]fluxesA structure containing pointers to any possible forcing fields. Unused fields have NULL ptrs.
[in,out]conv_enThe buoyant turbulent kinetic energy source due to free convection [Z L2 T-2 ~> m3 s-2].
[in]dke_fcThe vertically integrated change in kinetic energy due to free convection [Z L2 T-2 ~> m3 s-2].
[in]ctkeThe buoyant turbulent kinetic energy
[in]dke_caThe vertically integrated change in
[out]tkeThe turbulent kinetic energy available for mixing over a time step [Z m2 T-2 ~> m3 s-2].
[out]idecay_len_tkeThe inverse of the vertical decay scale for TKE [H-1 ~> m-1 or m2 kg-1].
[in]tke_riverThe source of turbulent kinetic energy available for driving mixing at river mouths [Z L2 T-3 ~> m3 s-3].
[out]cmkeCoefficients of HpE and HpE^2 in calculating the denominator of MKE_rate, [H-1 ~> m-1 or m2 kg-1] and [H-2 ~> m-2 or m4 kg-2].
[in]dtThe time step [T ~> s].
[in]idt_diagThe inverse of the accumulated diagnostic time interval [T-1 ~> s-1].
[in]jThe j-index to work on.
[in]ksortThe density-sorted k-indicies.
csThe control structure for this module.

Definition at line 1313 of file MOM_bulk_mixed_layer.F90.

1316  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1317  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1318  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1319  real, dimension(SZI_(G)), intent(in) :: htot !< The accumulated mixed layer thickness
1320  !! [H ~> m or kg m-2]
1321  real, dimension(SZI_(G)), intent(in) :: h_CA !< The mixed layer depth after convective
1322  !! adjustment [H ~> m or kg m-2].
1323  type(forcing), intent(in) :: fluxes !< A structure containing pointers to any
1324  !! possible forcing fields. Unused fields
1325  !! have NULL ptrs.
1326  real, dimension(SZI_(G)), intent(inout) :: Conv_En !< The buoyant turbulent kinetic energy source
1327  !! due to free convection [Z L2 T-2 ~> m3 s-2].
1328  real, dimension(SZI_(G)), intent(in) :: dKE_FC !< The vertically integrated change in
1329  !! kinetic energy due to free convection
1330  !! [Z L2 T-2 ~> m3 s-2].
1331  real, dimension(SZI_(G),SZK_(GV)), &
1332  intent(in) :: cTKE !< The buoyant turbulent kinetic energy
1333  !! source due to convective adjustment
1334  !! [Z L2 T-2 ~> m3 s-2].
1335  real, dimension(SZI_(G),SZK_(GV)), &
1336  intent(in) :: dKE_CA !< The vertically integrated change in
1337  !! kinetic energy due to convective
1338  !! adjustment [Z L2 T-2 ~> m3 s-2].
1339  real, dimension(SZI_(G)), intent(out) :: TKE !< The turbulent kinetic energy available for
1340  !! mixing over a time step [Z m2 T-2 ~> m3 s-2].
1341  real, dimension(SZI_(G)), intent(out) :: Idecay_len_TKE !< The inverse of the vertical decay
1342  !! scale for TKE [H-1 ~> m-1 or m2 kg-1].
1343  real, dimension(SZI_(G)), intent(in) :: TKE_river !< The source of turbulent kinetic energy
1344  !! available for driving mixing at river mouths
1345  !! [Z L2 T-3 ~> m3 s-3].
1346  real, dimension(2,SZI_(G)), intent(out) :: cMKE !< Coefficients of HpE and HpE^2 in
1347  !! calculating the denominator of MKE_rate,
1348  !! [H-1 ~> m-1 or m2 kg-1] and [H-2 ~> m-2 or m4 kg-2].
1349  real, intent(in) :: dt !< The time step [T ~> s].
1350  real, intent(in) :: Idt_diag !< The inverse of the accumulated diagnostic
1351  !! time interval [T-1 ~> s-1].
1352  integer, intent(in) :: j !< The j-index to work on.
1353  integer, dimension(SZI_(G),SZK_(GV)), &
1354  intent(in) :: ksort !< The density-sorted k-indicies.
1355  type(bulkmixedlayer_CS), pointer :: CS !< The control structure for this module.
1356 
1357 ! This subroutine determines the TKE available at the depth of free
1358 ! convection to drive mechanical entrainment.
1359 
1360  ! Local variables
1361  real :: dKE_conv ! The change in mean kinetic energy due to all convection [Z L2 T-2 ~> m3 s-2].
1362  real :: nstar_FC ! The effective efficiency with which the energy released by
1363  ! free convection is converted to TKE, often ~0.2 [nondim].
1364  real :: nstar_CA ! The effective efficiency with which the energy released by
1365  ! convective adjustment is converted to TKE, often ~0.2 [nondim].
1366  real :: TKE_CA ! The potential energy released by convective adjustment if
1367  ! that release is positive [Z L2 T-2 ~> m3 s-2].
1368  real :: MKE_rate_CA ! MKE_rate for convective adjustment [nondim], 0 to 1.
1369  real :: MKE_rate_FC ! MKE_rate for free convection [nondim], 0 to 1.
1370  real :: totEn_Z ! The total potential energy released by convection, [Z3 T-2 ~> m3 s-2].
1371  real :: Ih ! The inverse of a thickness [H-1 ~> m-1 or m2 kg-1].
1372  real :: exp_kh ! The nondimensional decay of TKE across a layer [nondim].
1373  real :: absf ! The absolute value of f averaged to thickness points [T-1 ~> s-1].
1374  real :: U_star ! The friction velocity [Z T-1 ~> m s-1].
1375  real :: absf_Ustar ! The absolute value of f divided by U_star [Z-1 ~> m-1].
1376  real :: wind_TKE_src ! The surface wind source of TKE [Z L2 T-3 ~> m3 s-3].
1377  real :: diag_wt ! The ratio of the current timestep to the diagnostic
1378  ! timestep (which may include 2 calls) [nondim].
1379  integer :: is, ie, nz, i
1380 
1381  is = g%isc ; ie = g%iec ; nz = gv%ke
1382  diag_wt = dt * idt_diag
1383 
1384  if (cs%omega_frac >= 1.0) absf = 2.0*cs%omega
1385  do i=is,ie
1386  u_star = fluxes%ustar(i,j)
1387  if (associated(fluxes%ustar_shelf) .and. associated(fluxes%frac_shelf_h)) then
1388  if (fluxes%frac_shelf_h(i,j) > 0.0) &
1389  u_star = (1.0 - fluxes%frac_shelf_h(i,j)) * u_star + &
1390  fluxes%frac_shelf_h(i,j) * fluxes%ustar_shelf(i,j)
1391  endif
1392 
1393  if (u_star < cs%ustar_min) u_star = cs%ustar_min
1394  if (cs%omega_frac < 1.0) then
1395  absf = 0.25*((abs(g%CoriolisBu(i,j)) + abs(g%CoriolisBu(i-1,j-1))) + &
1396  (abs(g%CoriolisBu(i,j-1)) + abs(g%CoriolisBu(i-1,j))))
1397  if (cs%omega_frac > 0.0) &
1398  absf = sqrt(cs%omega_frac*4.0*cs%omega**2 + (1.0-cs%omega_frac)*absf**2)
1399  endif
1400  absf_ustar = absf / u_star
1401  idecay_len_tke(i) = (absf_ustar * cs%TKE_decay) * gv%H_to_Z
1402 
1403 ! The first number in the denominator could be anywhere up to 16. The
1404 ! value of 3 was chosen to minimize the time-step dependence of the amount
1405 ! of shear-driven mixing in 10 days of a 1-degree global model, emphasizing
1406 ! the equatorial areas. Although it is not cast as a parameter, it should
1407 ! be considered an empirical parameter, and it might depend strongly on the
1408 ! number of sublayers in the mixed layer and their locations.
1409 ! The 0.41 is VonKarman's constant. This equation assumes that small & large
1410 ! scales contribute to mixed layer deepening at similar rates, even though
1411 ! small scales are dissipated more rapidly (implying they are less efficient).
1412 ! Ih = 1.0/(16.0*0.41*U_star*dt)
1413  ih = gv%H_to_Z/(3.0*0.41*u_star*dt)
1414  cmke(1,i) = 4.0 * ih ; cmke(2,i) = (absf_ustar*gv%H_to_Z) * ih
1415 
1416  if (idecay_len_tke(i) > 0.0) then
1417  exp_kh = exp(-htot(i)*idecay_len_tke(i))
1418  else
1419  exp_kh = 1.0
1420  endif
1421 
1422 ! Here nstar is a function of the natural Rossby number 0.2/(1+0.2/Ro), based
1423 ! on a curve fit from the data of Wang (GRL, 2003).
1424 ! Note: Ro = 1.0/sqrt(0.5 * dt * (absf*htot(i))**3 / totEn)
1425  if (conv_en(i) < 0.0) conv_en(i) = 0.0
1426  if (ctke(i,1) > 0.0) then ; tke_ca = ctke(i,1) ; else ; tke_ca = 0.0 ; endif
1427  if ((htot(i) >= h_ca(i)) .or. (tke_ca == 0.0)) then
1428  toten_z = us%L_to_Z**2 * (conv_en(i) + tke_ca)
1429 
1430  if (toten_z > 0.0) then
1431  nstar_fc = cs%nstar * toten_z / (toten_z + 0.2 * &
1432  sqrt(0.5 * dt * (absf*(htot(i)*gv%H_to_Z))**3 * toten_z))
1433  else
1434  nstar_fc = cs%nstar
1435  endif
1436  nstar_ca = nstar_fc
1437  else
1438  ! This reconstructs the Buoyancy flux within the topmost htot of water.
1439  if (conv_en(i) > 0.0) then
1440  toten_z = us%L_to_Z**2 * (conv_en(i) + tke_ca * (htot(i) / h_ca(i)) )
1441  nstar_fc = cs%nstar * toten_z / (toten_z + 0.2 * &
1442  sqrt(0.5 * dt * (absf*(htot(i)*gv%H_to_Z))**3 * toten_z))
1443  else
1444  nstar_fc = cs%nstar
1445  endif
1446 
1447  toten_z = us%L_to_Z**2 * (conv_en(i) + tke_ca)
1448  if (tke_ca > 0.0) then
1449  nstar_ca = cs%nstar * toten_z / (toten_z + 0.2 * &
1450  sqrt(0.5 * dt * (absf*(h_ca(i)*gv%H_to_Z))**3 * toten_z))
1451  else
1452  nstar_ca = cs%nstar
1453  endif
1454  endif
1455 
1456  if (dke_fc(i) + dke_ca(i,1) > 0.0) then
1457  if (htot(i) >= h_ca(i)) then
1458  mke_rate_fc = 1.0 / (1.0 + htot(i)*(cmke(1,i) + cmke(2,i)*htot(i)) )
1459  mke_rate_ca = mke_rate_fc
1460  else
1461  mke_rate_fc = 1.0 / (1.0 + htot(i)*(cmke(1,i) + cmke(2,i)*htot(i)) )
1462  mke_rate_ca = 1.0 / (1.0 + h_ca(i)*(cmke(1,i) + cmke(2,i)*h_ca(i)) )
1463  endif
1464  else
1465  ! This branch just saves unnecessary calculations.
1466  mke_rate_fc = 1.0 ; mke_rate_ca = 1.0
1467  endif
1468 
1469  dke_conv = dke_ca(i,1) * mke_rate_ca + dke_fc(i) * mke_rate_fc
1470 ! At this point, it is assumed that cTKE is positive and stored in TKE_CA!
1471 ! Note: Removed factor of 2 in u*^3 terms.
1472  tke(i) = (dt*cs%mstar)*((us%Z_to_L**2*(u_star*u_star*u_star))*exp_kh) + &
1473  (exp_kh * dke_conv + nstar_fc*conv_en(i) + nstar_ca * tke_ca)
1474 
1475  if (cs%do_rivermix) then ! Add additional TKE at river mouths
1476  tke(i) = tke(i) + tke_river(i)*dt*exp_kh
1477  endif
1478 
1479  if (cs%TKE_diagnostics) then
1480  wind_tke_src = cs%mstar*(us%Z_to_L**2*u_star*u_star*u_star) * diag_wt
1481  cs%diag_TKE_wind(i,j) = cs%diag_TKE_wind(i,j) + &
1482  ( wind_tke_src + tke_river(i) * diag_wt )
1483  cs%diag_TKE_RiBulk(i,j) = cs%diag_TKE_RiBulk(i,j) + dke_conv*idt_diag
1484  cs%diag_TKE_mech_decay(i,j) = cs%diag_TKE_mech_decay(i,j) + &
1485  (exp_kh-1.0)*(wind_tke_src + dke_conv*idt_diag)
1486  cs%diag_TKE_conv(i,j) = cs%diag_TKE_conv(i,j) + &
1487  idt_diag * (nstar_fc*conv_en(i) + nstar_ca*tke_ca)
1488  cs%diag_TKE_conv_decay(i,j) = cs%diag_TKE_conv_decay(i,j) + &
1489  idt_diag * ((cs%nstar-nstar_fc)*conv_en(i) + (cs%nstar-nstar_ca)*tke_ca)
1490  cs%diag_TKE_conv_s2(i,j) = cs%diag_TKE_conv_s2(i,j) + &
1491  idt_diag * (ctke(i,1)-tke_ca)
1492  endif
1493  enddo
1494 

◆ mechanical_entrainment()

subroutine mom_bulk_mixed_layer::mechanical_entrainment ( real, dimension( g %isd: g %ied, gv %ke), intent(inout)  h,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  d_eb,
real, dimension( g %isd: g %ied), intent(inout)  htot,
real, dimension( g %isd: g %ied), intent(inout)  Ttot,
real, dimension( g %isd: g %ied), intent(inout)  Stot,
real, dimension( g %isd: g %ied), intent(inout)  uhtot,
real, dimension( g %isd: g %ied), intent(inout)  vhtot,
real, dimension( g %isd: g %ied), intent(inout)  R0_tot,
real, dimension( g %isd: g %ied), intent(inout)  Rcv_tot,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  u,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  v,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  T,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  S,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  R0,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  Rcv,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  eps,
real, dimension( g %isd: g %ied), intent(in)  dR0_dT,
real, dimension( g %isd: g %ied), intent(in)  dRcv_dT,
real, dimension(2, g %isd: g %ied), intent(in)  cMKE,
real, intent(in)  Idt_diag,
integer, intent(in)  nsw,
real, dimension(max(nsw,1), g %isd: g %ied), intent(inout)  Pen_SW_bnd,
real, dimension(max(nsw,1), g %isd: g %ied, gv %ke), intent(in)  opacity_band,
real, dimension( g %isd: g %ied), intent(inout)  TKE,
real, dimension( g %isd: g %ied), intent(inout)  Idecay_len_TKE,
integer, intent(in)  j,
integer, dimension( g %isd: g %ied, gv %ke), intent(in)  ksort,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(bulkmixedlayer_cs), pointer  CS 
)
private

This subroutine calculates mechanically driven entrainment.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]usA dimensional unit scaling type
[in,out]hLayer thickness [H ~> m or kg m-2].
[in,out]d_ebThe downward increase across a layer in the
[in,out]htotThe accumlated mixed layer thickness [H ~> m or kg m-2].
[in,out]ttotThe depth integrated mixed layer temperature [degC H ~> degC m or degC kg m-2].
[in,out]stotThe depth integrated mixed layer salinity [ppt H ~> ppt m or ppt kg m-2].
[in,out]uhtotThe depth integrated mixed layer zonal velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
[in,out]vhtotThe integrated mixed layer meridional velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
[in,out]r0_totThe integrated mixed layer potential density referenced to 0 pressure [H R ~> kg m-2 or kg2 m-5].
[in,out]rcv_totThe integrated mixed layer coordinate variable potential density [H R ~> kg m-2 or kg2 m-5].
[in]uZonal velocities interpolated to h points [L T-1 ~> m s-1].
[in]vZonal velocities interpolated to h points [L T-1 ~> m s-1].
[in]tLayer temperatures [degC].
[in]sLayer salinities [ppt].
[in]r0Potential density referenced to
[in]rcvThe coordinate defining potential
[in]epsThe negligibly small amount of water
[in]dr0_dtThe partial derivative of R0 with respect to temperature [R degC-1 ~> kg m-3 degC-1].
[in]drcv_dtThe partial derivative of Rcv with respect to temperature [R degC-1 ~> kg m-3 degC-1].
[in]cmkeCoefficients of HpE and HpE^2 used in calculating the denominator of MKE_rate; the two elements have differing units of [H-1 ~> m-1 or m2 kg-1] and [H-2 ~> m-2 or m4 kg-2].
[in]idt_diagThe inverse of the accumulated diagnostic time interval [T-1 ~> s-1].
[in]nswThe number of bands of penetrating shortwave radiation.
[in,out]pen_sw_bndThe penetrating shortwave heating at the sea surface in each penetrating band [degC H ~> degC m or degC kg m-2].
[in]opacity_bandThe opacity in each band of penetrating shortwave radiation [H-1 ~> m-1 or m2 kg-1].
[in,out]tkeThe turbulent kinetic energy available for mixing over a time step [Z m2 T-2 ~> m3 s-2].
[in,out]idecay_len_tkeThe vertical TKE decay rate [H-1 ~> m-1 or m2 kg-1].
[in]jThe j-index to work on.
[in]ksortThe density-sorted k-indicies.
csThe control structure for this module.

Definition at line 1498 of file MOM_bulk_mixed_layer.F90.

1503  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1504  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1505  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1506  real, dimension(SZI_(G),SZK_(GV)), &
1507  intent(inout) :: h !< Layer thickness [H ~> m or kg m-2].
1508  real, dimension(SZI_(G),SZK_(GV)), &
1509  intent(inout) :: d_eb !< The downward increase across a layer in the
1510  !! layer in the entrainment from below [H ~> m or kg m-2].
1511  !! Positive values go with mass gain by a layer.
1512  real, dimension(SZI_(G)), intent(inout) :: htot !< The accumlated mixed layer thickness [H ~> m or kg m-2].
1513  real, dimension(SZI_(G)), intent(inout) :: Ttot !< The depth integrated mixed layer temperature
1514  !! [degC H ~> degC m or degC kg m-2].
1515  real, dimension(SZI_(G)), intent(inout) :: Stot !< The depth integrated mixed layer salinity
1516  !! [ppt H ~> ppt m or ppt kg m-2].
1517  real, dimension(SZI_(G)), intent(inout) :: uhtot !< The depth integrated mixed layer zonal
1518  !! velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
1519  real, dimension(SZI_(G)), intent(inout) :: vhtot !< The integrated mixed layer meridional
1520  !! velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
1521  real, dimension(SZI_(G)), intent(inout) :: R0_tot !< The integrated mixed layer potential density
1522  !! referenced to 0 pressure [H R ~> kg m-2 or kg2 m-5].
1523  real, dimension(SZI_(G)), intent(inout) :: Rcv_tot !< The integrated mixed layer coordinate variable
1524  !! potential density [H R ~> kg m-2 or kg2 m-5].
1525  real, dimension(SZI_(G),SZK_(GV)), &
1526  intent(in) :: u !< Zonal velocities interpolated to h points [L T-1 ~> m s-1].
1527  real, dimension(SZI_(G),SZK_(GV)), &
1528  intent(in) :: v !< Zonal velocities interpolated to h points [L T-1 ~> m s-1].
1529  real, dimension(SZI_(G),SZK_(GV)), &
1530  intent(in) :: T !< Layer temperatures [degC].
1531  real, dimension(SZI_(G),SZK_(GV)), &
1532  intent(in) :: S !< Layer salinities [ppt].
1533  real, dimension(SZI_(G),SZK_(GV)), &
1534  intent(in) :: R0 !< Potential density referenced to
1535  !! surface pressure [R ~> kg m-3].
1536  real, dimension(SZI_(G),SZK_(GV)), &
1537  intent(in) :: Rcv !< The coordinate defining potential
1538  !! density [R ~> kg m-3].
1539  real, dimension(SZI_(G),SZK_(GV)), &
1540  intent(in) :: eps !< The negligibly small amount of water
1541  !! that will be left in each layer [H ~> m or kg m-2].
1542  real, dimension(SZI_(G)), intent(in) :: dR0_dT !< The partial derivative of R0 with respect to
1543  !! temperature [R degC-1 ~> kg m-3 degC-1].
1544  real, dimension(SZI_(G)), intent(in) :: dRcv_dT !< The partial derivative of Rcv with respect to
1545  !! temperature [R degC-1 ~> kg m-3 degC-1].
1546  real, dimension(2,SZI_(G)), intent(in) :: cMKE !< Coefficients of HpE and HpE^2 used in calculating the
1547  !! denominator of MKE_rate; the two elements have differing
1548  !! units of [H-1 ~> m-1 or m2 kg-1] and [H-2 ~> m-2 or m4 kg-2].
1549  real, intent(in) :: Idt_diag !< The inverse of the accumulated diagnostic
1550  !! time interval [T-1 ~> s-1].
1551  integer, intent(in) :: nsw !< The number of bands of penetrating
1552  !! shortwave radiation.
1553  real, dimension(max(nsw,1),SZI_(G)), intent(inout) :: Pen_SW_bnd !< The penetrating shortwave
1554  !! heating at the sea surface in each penetrating
1555  !! band [degC H ~> degC m or degC kg m-2].
1556  real, dimension(max(nsw,1),SZI_(G),SZK_(GV)), intent(in) :: opacity_band !< The opacity in each band of
1557  !! penetrating shortwave radiation [H-1 ~> m-1 or m2 kg-1].
1558  real, dimension(SZI_(G)), intent(inout) :: TKE !< The turbulent kinetic energy
1559  !! available for mixing over a time
1560  !! step [Z m2 T-2 ~> m3 s-2].
1561  real, dimension(SZI_(G)), intent(inout) :: Idecay_len_TKE !< The vertical TKE decay rate [H-1 ~> m-1 or m2 kg-1].
1562  integer, intent(in) :: j !< The j-index to work on.
1563  integer, dimension(SZI_(G),SZK_(GV)), &
1564  intent(in) :: ksort !< The density-sorted k-indicies.
1565  type(bulkmixedlayer_CS), pointer :: CS !< The control structure for this module.
1566 
1567 ! This subroutine calculates mechanically driven entrainment.
1568 
1569  ! Local variables
1570  real :: SW_trans ! The fraction of shortwave radiation that is not
1571  ! absorbed in a layer, nondimensional.
1572  real :: Pen_absorbed ! The amount of penetrative shortwave radiation
1573  ! that is absorbed in a layer [degC H ~> degC m or degC kg m-2].
1574  real :: h_avail ! The thickness in a layer available for entrainment [H ~> m or kg m-2].
1575  real :: h_ent ! The thickness from a layer that is entrained [H ~> m or kg m-2].
1576  real :: h_min, h_max ! Limits on the solution for h_ent [H ~> m or kg m-2].
1577  real :: dh_Newt ! The Newton's method estimate of the change in
1578  ! h_ent between iterations [H ~> m or kg m-2].
1579  real :: MKE_rate ! The fraction of the energy in resolved shears
1580  ! within the mixed layer that will be eliminated
1581  ! within a timestep, nondim, 0 to 1.
1582  real :: HpE ! The current thickness plus entrainment [H ~> m or kg m-2].
1583  real :: g_H_2Rho0 ! Half the gravitational acceleration times the
1584  ! conversion from H to m divided by the mean density,
1585  ! in [L2 T-2 H-1 R-1 ~> m4 s-2 kg-1 or m7 s-2 kg-2].
1586  real :: TKE_full_ent ! The TKE remaining if a layer is fully entrained
1587  ! [Z L2 T-2 ~> m3 s-2].
1588  real :: dRL ! Work required to mix water from the next layer
1589  ! across the mixed layer [L2 T-2 ~> L2 s-2].
1590  real :: Pen_En_Contrib ! Penetrating SW contributions to the changes in
1591  ! TKE, divided by layer thickness in m [L2 T2 ~> m2 s-2].
1592  real :: Cpen1 ! A temporary variable [L2 T-2 ~> m2 s-2].
1593  real :: dMKE ! A temporary variable related to the release of mean
1594  ! kinetic energy [H Z L2 T-2 ~> m4 s-2 or kg m s-2]
1595  real :: TKE_ent ! The TKE that remains if h_ent were entrained [Z L2 T-2 ~> m3 s-2].
1596  real :: TKE_ent1 ! The TKE that would remain, without considering the
1597  ! release of mean kinetic energy [Z L2 T-2 ~> m3 s-2].
1598  real :: dTKE_dh ! The partial derivative of TKE with h_ent [Z L2 T-2 H-1 ~> m2 s-2 or m5 s-2 kg-1].
1599  real :: Pen_dTKE_dh_Contrib ! The penetrating shortwave contribution to
1600  ! dTKE_dh [L2 T-2 ~> m2 s-2].
1601  real :: EF4_val ! The result of EF4() (see later) [H-1 ~> m-1 or m2 kg-1].
1602  real :: h_neglect ! A thickness that is so small it is usually lost
1603  ! in roundoff and can be neglected [H ~> m or kg m-2].
1604  real :: dEF4_dh ! The partial derivative of EF4 with h [H-2 ~> m-2 or m4 kg-2].
1605  real :: Pen_En1 ! A nondimensional temporary variable.
1606  real :: kh, exp_kh ! Nondimensional temporary variables related to the
1607  real :: f1_kh ! fractional decay of TKE across a layer.
1608  real :: x1, e_x1 ! Nondimensional temporary variables related to
1609  real :: f1_x1, f2_x1 ! the relative decay of TKE and SW radiation across
1610  real :: f3_x1 ! a layer, and exponential-related functions of x1.
1611  real :: E_HxHpE ! Entrainment divided by the product of the new and old
1612  ! thicknesses [H-1 ~> m-1 or m2 kg-1].
1613  real :: Hmix_min ! The minimum mixed layer depth [H ~> m or kg m-2].
1614  real :: opacity
1615  real :: C1_3, C1_6, C1_24 ! 1/3, 1/6, and 1/24.
1616  integer :: is, ie, nz, i, k, ks, itt, n
1617 
1618  c1_3 = 1.0/3.0 ; c1_6 = 1.0/6.0 ; c1_24 = 1.0/24.0
1619  g_h_2rho0 = (gv%g_Earth * gv%H_to_Z) / (2.0 * gv%Rho0)
1620  hmix_min = cs%Hmix_min
1621  h_neglect = gv%H_subroundoff
1622  is = g%isc ; ie = g%iec ; nz = gv%ke
1623 
1624  do ks=1,nz
1625 
1626  do i=is,ie ; if (ksort(i,ks) > 0) then
1627  k = ksort(i,ks)
1628 
1629  h_avail = h(i,k) - eps(i,k)
1630  if ((h_avail > 0.) .and. ((tke(i) > 0.) .or. (htot(i) < hmix_min))) then
1631  drl = g_h_2rho0 * (r0(i,k)*htot(i) - r0_tot(i) )
1632  dmke = (gv%H_to_Z * cs%bulk_Ri_ML) * 0.5 * &
1633  ((uhtot(i)-u(i,k)*htot(i))**2 + (vhtot(i)-v(i,k)*htot(i))**2)
1634 
1635 ! Find the TKE that would remain if the entire layer were entrained.
1636  kh = idecay_len_tke(i)*h_avail ; exp_kh = exp(-kh)
1637  if (kh >= 2.0e-5) then ; f1_kh = (1.0-exp_kh) / kh
1638  else ; f1_kh = (1.0 - kh*(0.5 - c1_6*kh)) ; endif
1639 
1640  pen_en_contrib = 0.0
1641  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
1642  opacity = opacity_band(n,i,k)
1643 ! Two different forms are used here to make sure that only negative
1644 ! values are taken into exponentials to avoid excessively large
1645 ! numbers. They are, of course, mathematically identical.
1646  if (idecay_len_tke(i) > opacity) then
1647  x1 = (idecay_len_tke(i) - opacity) * h_avail
1648  if (x1 >= 2.0e-5) then
1649  e_x1 = exp(-x1) ; f1_x1 = ((1.0-e_x1)/(x1))
1650  f3_x1 = ((e_x1-(1.0-x1))/(x1*x1))
1651  else
1652  f1_x1 = (1.0 - x1*(0.5 - c1_6*x1))
1653  f3_x1 = (0.5 - x1*(c1_6 - c1_24*x1))
1654  endif
1655 
1656  pen_en1 = exp(-opacity*h_avail) * &
1657  ((1.0+opacity*htot(i))*f1_x1 + opacity*h_avail*f3_x1)
1658  else
1659  x1 = (opacity - idecay_len_tke(i)) * h_avail
1660  if (x1 >= 2.0e-5) then
1661  e_x1 = exp(-x1) ; f1_x1 = ((1.0-e_x1)/(x1))
1662  f2_x1 = ((1.0-(1.0+x1)*e_x1)/(x1*x1))
1663  else
1664  f1_x1 = (1.0 - x1*(0.5 - c1_6*x1))
1665  f2_x1 = (0.5 - x1*(c1_3 - 0.125*x1))
1666  endif
1667 
1668  pen_en1 = exp_kh * ((1.0+opacity*htot(i))*f1_x1 + &
1669  opacity*h_avail*f2_x1)
1670  endif
1671  pen_en_contrib = pen_en_contrib + &
1672  (g_h_2rho0*dr0_dt(i)*pen_sw_bnd(n,i)) * (pen_en1 - f1_kh)
1673  endif ; enddo
1674 
1675  hpe = htot(i)+h_avail
1676  mke_rate = 1.0/(1.0 + (cmke(1,i)*hpe + cmke(2,i)*hpe**2))
1677  ef4_val = ef4(htot(i)+h_neglect,h_avail,idecay_len_tke(i))
1678  tke_full_ent = (exp_kh*tke(i) - (h_avail*gv%H_to_Z)*(drl*f1_kh + pen_en_contrib)) + &
1679  mke_rate*dmke*ef4_val
1680  if ((tke_full_ent >= 0.0) .or. (h_avail+htot(i) <= hmix_min)) then
1681  ! The layer will be fully entrained.
1682  h_ent = h_avail
1683 
1684  if (cs%TKE_diagnostics) then
1685  e_hxhpe = h_ent / ((htot(i)+h_neglect)*(htot(i)+h_ent+h_neglect))
1686  cs%diag_TKE_mech_decay(i,j) = cs%diag_TKE_mech_decay(i,j) + &
1687  idt_diag * ((exp_kh-1.0)* tke(i) + (h_ent*gv%H_to_Z)*drl*(1.0-f1_kh) + &
1688  mke_rate*dmke*(ef4_val-e_hxhpe))
1689  cs%diag_TKE_mixing(i,j) = cs%diag_TKE_mixing(i,j) - &
1690  idt_diag*(gv%H_to_Z*h_ent)*drl
1691  cs%diag_TKE_pen_SW(i,j) = cs%diag_TKE_pen_SW(i,j) - &
1692  idt_diag*(gv%H_to_Z*h_ent)*pen_en_contrib
1693  cs%diag_TKE_RiBulk(i,j) = cs%diag_TKE_RiBulk(i,j) + &
1694  idt_diag*mke_rate*dmke*e_hxhpe
1695  endif
1696 
1697  tke(i) = tke_full_ent
1698  !### The minimum TKE value in this line may be problematically small.
1699  if (tke(i) <= 0.0) tke(i) = 1.0e-150*us%m_to_Z*us%m_s_to_L_T**2
1700  else
1701 ! The layer is only partially entrained. The amount that will be
1702 ! entrained is determined iteratively. No further layers will be
1703 ! entrained.
1704  h_min = 0.0 ; h_max = h_avail
1705  if (tke(i) <= 0.0) then
1706  h_ent = 0.0
1707  else
1708  h_ent = h_avail * tke(i) / (tke(i) - tke_full_ent)
1709 
1710  do itt=1,15
1711  ! Evaluate the TKE that would remain if h_ent were entrained.
1712 
1713  kh = idecay_len_tke(i)*h_ent ; exp_kh = exp(-kh)
1714  if (kh >= 2.0e-5) then
1715  f1_kh = (1.0-exp_kh) / kh
1716  else
1717  f1_kh = (1.0 - kh*(0.5 - c1_6*kh))
1718  endif
1719 
1720 
1721  pen_en_contrib = 0.0 ; pen_dtke_dh_contrib = 0.0
1722  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
1723  ! Two different forms are used here to make sure that only negative
1724  ! values are taken into exponentials to avoid excessively large
1725  ! numbers. They are, of course, mathematically identical.
1726  opacity = opacity_band(n,i,k)
1727  sw_trans = exp(-h_ent*opacity)
1728  if (idecay_len_tke(i) > opacity) then
1729  x1 = (idecay_len_tke(i) - opacity) * h_ent
1730  if (x1 >= 2.0e-5) then
1731  e_x1 = exp(-x1) ; f1_x1 = ((1.0-e_x1)/(x1))
1732  f3_x1 = ((e_x1-(1.0-x1))/(x1*x1))
1733  else
1734  f1_x1 = (1.0 - x1*(0.5 - c1_6*x1))
1735  f3_x1 = (0.5 - x1*(c1_6 - c1_24*x1))
1736  endif
1737  pen_en1 = sw_trans * ((1.0+opacity*htot(i))*f1_x1 + &
1738  opacity*h_ent*f3_x1)
1739  else
1740  x1 = (opacity - idecay_len_tke(i)) * h_ent
1741  if (x1 >= 2.0e-5) then
1742  e_x1 = exp(-x1) ; f1_x1 = ((1.0-e_x1)/(x1))
1743  f2_x1 = ((1.0-(1.0+x1)*e_x1)/(x1*x1))
1744  else
1745  f1_x1 = (1.0 - x1*(0.5 - c1_6*x1))
1746  f2_x1 = (0.5 - x1*(c1_3 - 0.125*x1))
1747  endif
1748 
1749  pen_en1 = exp_kh * ((1.0+opacity*htot(i))*f1_x1 + &
1750  opacity*h_ent*f2_x1)
1751  endif
1752  cpen1 = g_h_2rho0*dr0_dt(i)*pen_sw_bnd(n,i)
1753  pen_en_contrib = pen_en_contrib + cpen1*(pen_en1 - f1_kh)
1754  pen_dtke_dh_contrib = pen_dtke_dh_contrib + &
1755  cpen1*((1.0-sw_trans) - opacity*(htot(i) + h_ent)*sw_trans)
1756  endif ; enddo ! (Pen_SW_bnd(n,i) > 0.0)
1757 
1758  tke_ent1 = exp_kh* tke(i) - (h_ent*gv%H_to_Z)*(drl*f1_kh + pen_en_contrib)
1759  ef4_val = ef4(htot(i)+h_neglect,h_ent,idecay_len_tke(i),def4_dh)
1760  hpe = htot(i)+h_ent
1761  mke_rate = 1.0/(1.0 + (cmke(1,i)*hpe + cmke(2,i)*hpe**2))
1762  tke_ent = tke_ent1 + dmke*ef4_val*mke_rate
1763  ! TKE_ent is the TKE that would remain if h_ent were entrained.
1764 
1765  dtke_dh = ((-idecay_len_tke(i)*tke_ent1 - drl*gv%H_to_Z) + &
1766  pen_dtke_dh_contrib*gv%H_to_Z) + dmke * mke_rate* &
1767  (def4_dh - ef4_val*mke_rate*(cmke(1,i)+2.0*cmke(2,i)*hpe))
1768  ! dh_Newt = -TKE_ent / dTKE_dh
1769  ! Bisect if the Newton's method prediction is outside of the bounded range.
1770  if (tke_ent > 0.0) then
1771  if ((h_max-h_ent)*(-dtke_dh) > tke_ent) then
1772  dh_newt = -tke_ent / dtke_dh
1773  else
1774  dh_newt = 0.5*(h_max-h_ent)
1775  endif
1776  h_min = h_ent
1777  else
1778  if ((h_min-h_ent)*(-dtke_dh) < tke_ent) then
1779  dh_newt = -tke_ent / dtke_dh
1780  else
1781  dh_newt = 0.5*(h_min-h_ent)
1782  endif
1783  h_max = h_ent
1784  endif
1785  h_ent = h_ent + dh_newt
1786 
1787  if (abs(dh_newt) < 0.2*gv%Angstrom_H) exit
1788  enddo
1789  endif
1790 
1791  if (h_ent < hmix_min-htot(i)) h_ent = hmix_min - htot(i)
1792 
1793  if (cs%TKE_diagnostics) then
1794  hpe = htot(i)+h_ent
1795  mke_rate = 1.0/(1.0 + cmke(1,i)*hpe + cmke(2,i)*hpe**2)
1796  ef4_val = ef4(htot(i)+h_neglect,h_ent,idecay_len_tke(i))
1797 
1798  e_hxhpe = h_ent / ((htot(i)+h_neglect)*(hpe+h_neglect))
1799  cs%diag_TKE_mech_decay(i,j) = cs%diag_TKE_mech_decay(i,j) + &
1800  idt_diag * ((exp_kh-1.0)* tke(i) + (h_ent*gv%H_to_Z)*drl*(1.0-f1_kh) + &
1801  dmke*mke_rate*(ef4_val-e_hxhpe))
1802  cs%diag_TKE_mixing(i,j) = cs%diag_TKE_mixing(i,j) - &
1803  idt_diag*(h_ent*gv%H_to_Z)*drl
1804  cs%diag_TKE_pen_SW(i,j) = cs%diag_TKE_pen_SW(i,j) - &
1805  idt_diag*(h_ent*gv%H_to_Z)*pen_en_contrib
1806  cs%diag_TKE_RiBulk(i,j) = cs%diag_TKE_RiBulk(i,j) + &
1807  idt_diag*dmke*mke_rate*e_hxhpe
1808  endif
1809 
1810  tke(i) = 0.0
1811  endif ! TKE_full_ent > 0.0
1812 
1813  pen_absorbed = 0.0
1814  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
1815  sw_trans = exp(-h_ent*opacity_band(n,i,k))
1816  pen_absorbed = pen_absorbed + pen_sw_bnd(n,i) * (1.0 - sw_trans)
1817  pen_sw_bnd(n,i) = pen_sw_bnd(n,i) * sw_trans
1818  endif ; enddo
1819 
1820  htot(i) = htot(i) + h_ent
1821  r0_tot(i) = r0_tot(i) + (h_ent * r0(i,k) + pen_absorbed*dr0_dt(i))
1822  h(i,k) = h(i,k) - h_ent
1823  d_eb(i,k) = d_eb(i,k) - h_ent
1824 
1825  stot(i) = stot(i) + h_ent * s(i,k)
1826  ttot(i) = ttot(i) + (h_ent * t(i,k) + pen_absorbed)
1827  rcv_tot(i) = rcv_tot(i) + (h_ent*rcv(i,k) + pen_absorbed*drcv_dt(i))
1828 
1829  uhtot(i) = uhtot(i) + u(i,k)*h_ent
1830  vhtot(i) = vhtot(i) + v(i,k)*h_ent
1831  endif ! h_avail > 0.0 .AND TKE(i) > 0.0
1832 
1833  endif ; enddo ! i loop
1834  enddo ! k loop
1835 

◆ mixedlayer_convection()

subroutine mom_bulk_mixed_layer::mixedlayer_convection ( real, dimension( g %isd: g %ied, gv %ke), intent(inout)  h,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  d_eb,
real, dimension( g %isd: g %ied), intent(out)  htot,
real, dimension( g %isd: g %ied), intent(out)  Ttot,
real, dimension( g %isd: g %ied), intent(out)  Stot,
real, dimension( g %isd: g %ied), intent(out)  uhtot,
real, dimension( g %isd: g %ied), intent(out)  vhtot,
real, dimension( g %isd: g %ied), intent(out)  R0_tot,
real, dimension( g %isd: g %ied), intent(out)  Rcv_tot,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  u,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  v,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  T,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  S,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  R0,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  Rcv,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  eps,
real, dimension( g %isd: g %ied), intent(in)  dR0_dT,
real, dimension( g %isd: g %ied), intent(in)  dRcv_dT,
real, dimension( g %isd: g %ied), intent(in)  dR0_dS,
real, dimension( g %isd: g %ied), intent(in)  dRcv_dS,
real, dimension( g %isd: g %ied), intent(in)  netMassInOut,
real, dimension( g %isd: g %ied), intent(in)  netMassOut,
real, dimension( g %isd: g %ied), intent(in)  Net_heat,
real, dimension( g %isd: g %ied), intent(in)  Net_salt,
integer, intent(in)  nsw,
real, dimension(max(nsw,1), g %isd: g %ied), intent(inout)  Pen_SW_bnd,
real, dimension(max(nsw,1), g %isd: g %ied, gv %ke), intent(in)  opacity_band,
real, dimension( g %isd: g %ied), intent(out)  Conv_En,
real, dimension( g %isd: g %ied), intent(out)  dKE_FC,
integer, intent(in)  j,
integer, dimension( g %isd: g %ied, gv %ke), intent(in)  ksort,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(bulkmixedlayer_cs), pointer  CS,
type(thermo_var_ptrs), intent(inout)  tv,
type(forcing), intent(inout)  fluxes,
real, intent(in)  dt,
logical, intent(in)  aggregate_FW_forcing 
)
private

This subroutine causes the mixed layer to entrain to the depth of free convection. The depth of free convection is the shallowest depth at which the fluid is denser than the average of the fluid above.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in,out]hLayer thickness [H ~> m or kg m-2].
[in,out]d_ebThe downward increase across a layer in the
[out]htotThe accumulated mixed layer thickness [H ~> m or kg m-2].
[out]ttotThe depth integrated mixed layer temperature [degC H ~> degC m or degC kg m-2].
[out]stotThe depth integrated mixed layer salinity [ppt H ~> ppt m or ppt kg m-2].
[out]uhtotThe depth integrated mixed layer zonal velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
[out]vhtotThe integrated mixed layer meridional velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
[out]r0_totThe integrated mixed layer potential density referenced to 0 pressure [H R ~> kg m-2 or kg2 m-5].
[out]rcv_totThe integrated mixed layer coordinate variable potential density [H R ~> kg m-2 or kg2 m-5].
[in]uZonal velocities interpolated to h points [L T-1 ~> m s-1].
[in]vZonal velocities interpolated to h points [L T-1 ~> m s-1].
[in]tLayer temperatures [degC].
[in]sLayer salinities [ppt].
[in]r0Potential density referenced to
[in]rcvThe coordinate defining potential
[in]epsThe negligibly small amount of water
[in]dr0_dtThe partial derivative of R0 with respect to temperature [R degC-1 ~> kg m-3 degC-1].
[in]drcv_dtThe partial derivative of Rcv with respect to temperature [R degC-1 ~> kg m-3 degC-1].
[in]dr0_dsThe partial derivative of R0 with respect to salinity [R ppt-1 ~> kg m-3 ppt-1].
[in]drcv_dsThe partial derivative of Rcv with respect to salinity [R ppt-1 ~> kg m-3 ppt-1].
[in]netmassinoutThe net mass flux (if non-Boussinesq) or volume flux (if Boussinesq) into the ocean within a time step [H ~> m or kg m-2]. (I.e. P+R-E.)
[in]netmassoutThe mass or volume flux out of the ocean within a time step [H ~> m or kg m-2].
[in]net_heatThe net heating at the surface over a time step [degC H ~> degC m or degC kg m-2]. Any penetrating shortwave radiation is not included in Net_heat.
[in]net_saltThe net surface salt flux into the ocean over a time step [ppt H ~> ppt m or ppt kg m-2].
[in]nswThe number of bands of penetrating shortwave radiation.
[in,out]pen_sw_bndThe penetrating shortwave heating at the sea surface in each penetrating band [degC H ~> degC m or degC kg m-2].
[in]opacity_bandThe opacity in each band of penetrating shortwave radiation [H-1 ~> m-1 or m2 kg-1].
[out]conv_enThe buoyant turbulent kinetic energy source due to free convection [Z L2 T-2 ~> m3 s-2].
[out]dke_fcThe vertically integrated change in kinetic energy due to free convection [Z L2 T-2 ~> m3 s-2].
[in]jThe j-index to work on.
[in]ksortThe density-sorted k-indices.
[in]usA dimensional unit scaling type
csThe control structure for this module.
[in,out]tvA structure containing pointers to any available thermodynamic fields. Absent fields have NULL ptrs.
[in,out]fluxesA structure containing pointers to any possible forcing fields. Unused fields have NULL ptrs.
[in]dtTime increment [T ~> s].
[in]aggregate_fw_forcingIf true, the net incoming and outgoing surface freshwater fluxes are combined before being applied, instead of being applied separately.

Definition at line 936 of file MOM_bulk_mixed_layer.F90.

943  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
944  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
945  real, dimension(SZI_(G),SZK_(GV)), &
946  intent(inout) :: h !< Layer thickness [H ~> m or kg m-2].
947  !! The units of h are referred to as H below.
948  real, dimension(SZI_(G),SZK_(GV)), &
949  intent(inout) :: d_eb !< The downward increase across a layer in the
950  !! layer in the entrainment from below [H ~> m or kg m-2].
951  !! Positive values go with mass gain by a layer.
952  real, dimension(SZI_(G)), intent(out) :: htot !< The accumulated mixed layer thickness [H ~> m or kg m-2].
953  real, dimension(SZI_(G)), intent(out) :: Ttot !< The depth integrated mixed layer temperature
954  !! [degC H ~> degC m or degC kg m-2].
955  real, dimension(SZI_(G)), intent(out) :: Stot !< The depth integrated mixed layer salinity
956  !! [ppt H ~> ppt m or ppt kg m-2].
957  real, dimension(SZI_(G)), intent(out) :: uhtot !< The depth integrated mixed layer zonal
958  !! velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
959  real, dimension(SZI_(G)), intent(out) :: vhtot !< The integrated mixed layer meridional
960  !! velocity [H L T-1 ~> m2 s-1 or kg m-1 s-1].
961  real, dimension(SZI_(G)), intent(out) :: R0_tot !< The integrated mixed layer potential density referenced
962  !! to 0 pressure [H R ~> kg m-2 or kg2 m-5].
963  real, dimension(SZI_(G)), intent(out) :: Rcv_tot !< The integrated mixed layer coordinate
964  !! variable potential density [H R ~> kg m-2 or kg2 m-5].
965  real, dimension(SZI_(G),SZK_(GV)), &
966  intent(in) :: u !< Zonal velocities interpolated to h points [L T-1 ~> m s-1].
967  real, dimension(SZI_(G),SZK_(GV)), &
968  intent(in) :: v !< Zonal velocities interpolated to h points [L T-1 ~> m s-1].
969  real, dimension(SZI_(G),SZK_(GV)), &
970  intent(in) :: T !< Layer temperatures [degC].
971  real, dimension(SZI_(G),SZK_(GV)), &
972  intent(in) :: S !< Layer salinities [ppt].
973  real, dimension(SZI_(G),SZK_(GV)), &
974  intent(in) :: R0 !< Potential density referenced to
975  !! surface pressure [R ~> kg m-3].
976  real, dimension(SZI_(G),SZK_(GV)), &
977  intent(in) :: Rcv !< The coordinate defining potential
978  !! density [R ~> kg m-3].
979  real, dimension(SZI_(G),SZK_(GV)), &
980  intent(in) :: eps !< The negligibly small amount of water
981  !! that will be left in each layer [H ~> m or kg m-2].
982  real, dimension(SZI_(G)), intent(in) :: dR0_dT !< The partial derivative of R0 with respect to
983  !! temperature [R degC-1 ~> kg m-3 degC-1].
984  real, dimension(SZI_(G)), intent(in) :: dRcv_dT !< The partial derivative of Rcv with respect to
985  !! temperature [R degC-1 ~> kg m-3 degC-1].
986  real, dimension(SZI_(G)), intent(in) :: dR0_dS !< The partial derivative of R0 with respect to
987  !! salinity [R ppt-1 ~> kg m-3 ppt-1].
988  real, dimension(SZI_(G)), intent(in) :: dRcv_dS !< The partial derivative of Rcv with respect to
989  !! salinity [R ppt-1 ~> kg m-3 ppt-1].
990  real, dimension(SZI_(G)), intent(in) :: netMassInOut !< The net mass flux (if non-Boussinesq)
991  !! or volume flux (if Boussinesq) into the ocean
992  !! within a time step [H ~> m or kg m-2]. (I.e. P+R-E.)
993  real, dimension(SZI_(G)), intent(in) :: netMassOut !< The mass or volume flux out of the ocean
994  !! within a time step [H ~> m or kg m-2].
995  real, dimension(SZI_(G)), intent(in) :: Net_heat !< The net heating at the surface over a time
996  !! step [degC H ~> degC m or degC kg m-2]. Any penetrating
997  !! shortwave radiation is not included in Net_heat.
998  real, dimension(SZI_(G)), intent(in) :: Net_salt !< The net surface salt flux into the ocean
999  !! over a time step [ppt H ~> ppt m or ppt kg m-2].
1000  integer, intent(in) :: nsw !< The number of bands of penetrating
1001  !! shortwave radiation.
1002  real, dimension(max(nsw,1),SZI_(G)), intent(inout) :: Pen_SW_bnd !< The penetrating shortwave
1003  !! heating at the sea surface in each penetrating
1004  !! band [degC H ~> degC m or degC kg m-2].
1005  real, dimension(max(nsw,1),SZI_(G),SZK_(GV)), intent(in) :: opacity_band !< The opacity in each band of
1006  !! penetrating shortwave radiation [H-1 ~> m-1 or m2 kg-1].
1007  real, dimension(SZI_(G)), intent(out) :: Conv_En !< The buoyant turbulent kinetic energy source
1008  !! due to free convection [Z L2 T-2 ~> m3 s-2].
1009  real, dimension(SZI_(G)), intent(out) :: dKE_FC !< The vertically integrated change in kinetic
1010  !! energy due to free convection [Z L2 T-2 ~> m3 s-2].
1011  integer, intent(in) :: j !< The j-index to work on.
1012  integer, dimension(SZI_(G),SZK_(GV)), &
1013  intent(in) :: ksort !< The density-sorted k-indices.
1014  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1015  type(bulkmixedlayer_CS), pointer :: CS !< The control structure for this module.
1016  type(thermo_var_ptrs), intent(inout) :: tv !< A structure containing pointers to any
1017  !! available thermodynamic fields. Absent
1018  !! fields have NULL ptrs.
1019  type(forcing), intent(inout) :: fluxes !< A structure containing pointers to any
1020  !! possible forcing fields. Unused fields
1021  !! have NULL ptrs.
1022  real, intent(in) :: dt !< Time increment [T ~> s].
1023  logical, intent(in) :: aggregate_FW_forcing !< If true, the net incoming and
1024  !! outgoing surface freshwater fluxes are
1025  !! combined before being applied, instead of
1026  !! being applied separately.
1027 
1028 ! This subroutine causes the mixed layer to entrain to the depth of free
1029 ! convection. The depth of free convection is the shallowest depth at which the
1030 ! fluid is denser than the average of the fluid above.
1031 
1032  ! Local variables
1033  real, dimension(SZI_(G)) :: &
1034  massOutRem, & ! Evaporation that remains to be supplied [H ~> m or kg m-2].
1035  netMassIn ! mass entering through ocean surface [H ~> m or kg m-2]
1036  real :: SW_trans ! The fraction of shortwave radiation
1037  ! that is not absorbed in a layer [nondim].
1038  real :: Pen_absorbed ! The amount of penetrative shortwave radiation
1039  ! that is absorbed in a layer [degC H ~> degC m or degC kg m-2].
1040  real :: h_avail ! The thickness in a layer available for
1041  ! entrainment [H ~> m or kg m-2].
1042  real :: h_ent ! The thickness from a layer that is entrained [H ~> m or kg m-2].
1043  real :: T_precip ! The temperature of the precipitation [degC].
1044  real :: C1_3, C1_6 ! 1/3 and 1/6.
1045  real :: En_fn, Frac, x1 ! Nondimensional temporary variables.
1046  real :: dr, dr0 ! Temporary variables [R H ~> kg m-2 or kg2 m-5].
1047  real :: dr_ent, dr_comp ! Temporary variables [R H ~> kg m-2 or kg2 m-5].
1048  real :: dr_dh ! The partial derivative of dr_ent with h_ent [R ~> kg m-3].
1049  real :: h_min, h_max ! The minimum, maximum, and previous estimates for
1050  real :: h_prev ! h_ent [H ~> m or kg m-2].
1051  real :: h_evap ! The thickness that is evaporated [H ~> m or kg m-2].
1052  real :: dh_Newt ! The Newton's method estimate of the change in
1053  ! h_ent between iterations [H ~> m or kg m-2].
1054  real :: g_H2_2Rho0 ! Half the gravitational acceleration times the square of
1055  ! the conversion from H to Z divided by the mean density,
1056  ! [L2 Z T-3 H-2 R-1 ~> m4 s-3 kg-1 or m10 s-3 kg-3].
1057  real :: Angstrom ! The minimum layer thickness [H ~> m or kg m-2].
1058  real :: opacity ! The opacity converted to inverse thickness units [H-1 ~> m-1 or m2 kg-1]
1059  real :: sum_Pen_En ! The potential energy change due to penetrating
1060  ! shortwave radiation, integrated over a layer
1061  ! [H R ~> kg m-2 or kg2 m-5].
1062  real :: Idt ! 1.0/dt [T-1 ~> s-1]
1063  real :: netHeatOut ! accumulated heat content of mass leaving ocean
1064  integer :: is, ie, nz, i, k, ks, itt, n
1065  real, dimension(max(nsw,1)) :: &
1066  C2, & ! Temporary variable R H-1 ~> kg m-4 or m-1].
1067  r_SW_top ! Temporary variables [H R ~> kg m-2 or kg2 m-5].
1068 
1069  angstrom = gv%Angstrom_H
1070  c1_3 = 1.0/3.0 ; c1_6 = 1.0/6.0
1071  g_h2_2rho0 = (gv%g_Earth * gv%H_to_Z**2) / (2.0 * gv%Rho0)
1072  idt = 1.0 / dt
1073  is = g%isc ; ie = g%iec ; nz = gv%ke
1074 
1075  do i=is,ie ; if (ksort(i,1) > 0) then
1076  k = ksort(i,1)
1077 
1078  if (aggregate_fw_forcing) then
1079  massoutrem(i) = 0.0
1080  if (netmassinout(i) < 0.0) massoutrem(i) = -netmassinout(i)
1081  netmassin(i) = netmassinout(i) + massoutrem(i)
1082  else
1083  massoutrem(i) = -netmassout(i)
1084  netmassin(i) = netmassinout(i) - netmassout(i)
1085  endif
1086 
1087  ! htot is an Angstrom (taken from layer 1) plus any net precipitation.
1088  h_ent = max(min(angstrom,h(i,k)-eps(i,k)),0.0)
1089  htot(i) = h_ent + netmassin(i)
1090  h(i,k) = h(i,k) - h_ent
1091  d_eb(i,k) = d_eb(i,k) - h_ent
1092 
1093  pen_absorbed = 0.0
1094  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
1095  sw_trans = exp(-htot(i)*opacity_band(n,i,k))
1096  pen_absorbed = pen_absorbed + pen_sw_bnd(n,i) * (1.0-sw_trans)
1097  pen_sw_bnd(n,i) = pen_sw_bnd(n,i) * sw_trans
1098  endif ; enddo
1099 
1100  ! Precipitation is assumed to have the same temperature and velocity
1101  ! as layer 1. Because layer 1 might not be the topmost layer, this
1102  ! involves multiple terms.
1103  t_precip = t(i,1)
1104  ttot(i) = (net_heat(i) + (netmassin(i) * t_precip + h_ent * t(i,k))) + &
1105  pen_absorbed
1106  ! Net_heat contains both heat fluxes and the heat content of mass fluxes.
1107  !! Ttot(i) = netMassIn(i) * T_precip + h_ent * T(i,k)
1108  !! Ttot(i) = Net_heat(i) + Ttot(i)
1109  !! Ttot(i) = Ttot(i) + Pen_absorbed
1110  ! smg:
1111  ! Ttot(i) = (Net_heat(i) + (h_ent * T(i,k))) + Pen_absorbed
1112  stot(i) = h_ent*s(i,k) + net_salt(i)
1113  uhtot(i) = u(i,1)*netmassin(i) + u(i,k)*h_ent
1114  vhtot(i) = v(i,1)*netmassin(i) + v(i,k)*h_ent
1115  r0_tot(i) = (h_ent*r0(i,k) + netmassin(i)*r0(i,1)) + &
1116 ! dR0_dT(i)*netMassIn(i)*(T_precip - T(i,1)) + &
1117  (dr0_dt(i)*(net_heat(i) + pen_absorbed) - &
1118  dr0_ds(i) * (netmassin(i) * s(i,1) - net_salt(i)))
1119  rcv_tot(i) = (h_ent*rcv(i,k) + netmassin(i)*rcv(i,1)) + &
1120 ! dRcv_dT(i)*netMassIn(i)*(T_precip - T(i,1)) + &
1121  (drcv_dt(i)*(net_heat(i) + pen_absorbed) - &
1122  drcv_ds(i) * (netmassin(i) * s(i,1) - net_salt(i)))
1123  conv_en(i) = 0.0 ; dke_fc(i) = 0.0
1124  if (associated(fluxes%heat_content_massin)) &
1125  fluxes%heat_content_massin(i,j) = fluxes%heat_content_massin(i,j) + &
1126  t_precip * netmassin(i) * gv%H_to_RZ * fluxes%C_p * idt
1127  if (associated(tv%TempxPmE)) tv%TempxPmE(i,j) = tv%TempxPmE(i,j) + &
1128  t_precip * netmassin(i) * gv%H_to_RZ
1129  else ! This is a massless column, but zero out the summed variables anyway for safety.
1130  htot(i) = 0.0 ; ttot(i) = 0.0 ; stot(i) = 0.0 ; r0_tot(i) = 0.0 ; rcv_tot = 0.0
1131  uhtot(i) = 0.0 ; vhtot(i) = 0.0 ; conv_en(i) = 0.0 ; dke_fc(i) = 0.0
1132  endif ; enddo
1133 
1134  ! Now do netMassOut case in this block.
1135  ! At this point htot contains an Angstrom of fluid from layer 0 plus netMassIn.
1136  do ks=1,nz
1137  do i=is,ie ; if (ksort(i,ks) > 0) then
1138  k = ksort(i,ks)
1139 
1140  if ((htot(i) < angstrom) .and. (h(i,k) > eps(i,k))) then
1141  ! If less than an Angstrom was available from the layers above plus
1142  ! any precipitation, add more fluid from this layer.
1143  h_ent = min(angstrom-htot(i), h(i,k)-eps(i,k))
1144  htot(i) = htot(i) + h_ent
1145  h(i,k) = h(i,k) - h_ent
1146  d_eb(i,k) = d_eb(i,k) - h_ent
1147 
1148  r0_tot(i) = r0_tot(i) + h_ent*r0(i,k)
1149  uhtot(i) = uhtot(i) + h_ent*u(i,k)
1150  vhtot(i) = vhtot(i) + h_ent*v(i,k)
1151 
1152  rcv_tot(i) = rcv_tot(i) + h_ent*rcv(i,k)
1153  ttot(i) = ttot(i) + h_ent*t(i,k)
1154  stot(i) = stot(i) + h_ent*s(i,k)
1155  endif
1156 
1157  ! Water is removed from the topmost layers with any mass.
1158  ! We may lose layers if they are thin enough.
1159  ! The salt that is left behind goes into Stot.
1160  if ((massoutrem(i) > 0.0) .and. (h(i,k) > eps(i,k))) then
1161  if (massoutrem(i) > (h(i,k) - eps(i,k))) then
1162  h_evap = h(i,k) - eps(i,k)
1163  h(i,k) = eps(i,k)
1164  massoutrem(i) = massoutrem(i) - h_evap
1165  else
1166  h_evap = massoutrem(i)
1167  h(i,k) = h(i,k) - h_evap
1168  massoutrem(i) = 0.0
1169  endif
1170 
1171  stot(i) = stot(i) + h_evap*s(i,k)
1172  r0_tot(i) = r0_tot(i) + dr0_ds(i)*h_evap*s(i,k)
1173  rcv_tot(i) = rcv_tot(i) + drcv_ds(i)*h_evap*s(i,k)
1174  d_eb(i,k) = d_eb(i,k) - h_evap
1175 
1176  ! smg: when resolve the A=B code, we will set
1177  ! heat_content_massout = heat_content_massout - T(i,k)*h_evap*GV%H_to_RZ*fluxes%C_p*Idt
1178  ! by uncommenting the lines here.
1179  ! we will also then completely remove TempXpme from the model.
1180  if (associated(fluxes%heat_content_massout)) &
1181  fluxes%heat_content_massout(i,j) = fluxes%heat_content_massout(i,j) - &
1182  t(i,k)*h_evap*gv%H_to_RZ * fluxes%C_p * idt
1183  if (associated(tv%TempxPmE)) tv%TempxPmE(i,j) = tv%TempxPmE(i,j) - &
1184  t(i,k)*h_evap*gv%H_to_RZ
1185 
1186  endif
1187 
1188  ! The following section calculates how much fluid will be entrained.
1189  h_avail = h(i,k) - eps(i,k)
1190  if (h_avail > 0.0) then
1191  dr = r0_tot(i) - htot(i)*r0(i,k)
1192  h_ent = 0.0
1193 
1194  dr0 = dr
1195  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
1196  dr0 = dr0 - (dr0_dt(i)*pen_sw_bnd(n,i)) * &
1197  opacity_band(n,i,k)*htot(i)
1198  endif ; enddo
1199 
1200  ! Some entrainment will occur from this layer.
1201  if (dr0 > 0.0) then
1202  dr_comp = dr
1203  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
1204  ! Compare the density at the bottom of a layer with the
1205  ! density averaged over the mixed layer and that layer.
1206  opacity = opacity_band(n,i,k)
1207  sw_trans = exp(-h_avail*opacity)
1208  dr_comp = dr_comp + (dr0_dt(i)*pen_sw_bnd(n,i)) * &
1209  ((1.0 - sw_trans) - opacity*(htot(i)+h_avail)*sw_trans)
1210  endif ; enddo
1211  if (dr_comp >= 0.0) then
1212  ! The entire layer is entrained.
1213  h_ent = h_avail
1214  else
1215  ! The layer is partially entrained. Iterate to determine how much
1216  ! entrainment occurs. Solve for the h_ent at which dr_ent = 0.
1217 
1218  ! Instead of assuming that the curve is linear between the two end
1219  ! points, assume that the change is concentrated near small values
1220  ! of entrainment. On average, this saves about 1 iteration.
1221  frac = dr0 / (dr0 - dr_comp)
1222  h_ent = h_avail * frac*frac
1223  h_min = 0.0 ; h_max = h_avail
1224 
1225  do n=1,nsw
1226  r_sw_top(n) = dr0_dt(i) * pen_sw_bnd(n,i)
1227  c2(n) = r_sw_top(n) * opacity_band(n,i,k)**2
1228  enddo
1229  do itt=1,10
1230  dr_ent = dr ; dr_dh = 0.0
1231  do n=1,nsw
1232  opacity = opacity_band(n,i,k)
1233  sw_trans = exp(-h_ent*opacity)
1234  dr_ent = dr_ent + r_sw_top(n) * ((1.0 - sw_trans) - &
1235  opacity*(htot(i)+h_ent)*sw_trans)
1236  dr_dh = dr_dh + c2(n) * (htot(i)+h_ent) * sw_trans
1237  enddo
1238 
1239  if (dr_ent > 0.0) then
1240  h_min = h_ent
1241  else
1242  h_max = h_ent
1243  endif
1244 
1245  dh_newt = -dr_ent / dr_dh
1246  h_prev = h_ent ; h_ent = h_prev+dh_newt
1247  if (h_ent > h_max) then
1248  h_ent = 0.5*(h_prev+h_max)
1249  elseif (h_ent < h_min) then
1250  h_ent = 0.5*(h_prev+h_min)
1251  endif
1252 
1253  if (abs(dh_newt) < 0.2*angstrom) exit
1254  enddo
1255 
1256  endif
1257 
1258  ! Now that the amount of entrainment (h_ent) has been determined,
1259  ! calculate changes in various terms.
1260  sum_pen_en = 0.0 ; pen_absorbed = 0.0
1261  do n=1,nsw ; if (pen_sw_bnd(n,i) > 0.0) then
1262  opacity = opacity_band(n,i,k)
1263  sw_trans = exp(-h_ent*opacity)
1264 
1265  x1 = h_ent*opacity
1266  if (x1 < 2.0e-5) then
1267  en_fn = (opacity*htot(i)*(1.0 - 0.5*(x1 - c1_3*x1)) + &
1268  x1*x1*c1_6)
1269  else
1270  en_fn = ((opacity*htot(i) + 2.0) * &
1271  ((1.0-sw_trans) / x1) - 1.0 + sw_trans)
1272  endif
1273  sum_pen_en = sum_pen_en - (dr0_dt(i)*pen_sw_bnd(n,i)) * en_fn
1274 
1275  pen_absorbed = pen_absorbed + pen_sw_bnd(n,i) * (1.0 - sw_trans)
1276  pen_sw_bnd(n,i) = pen_sw_bnd(n,i) * sw_trans
1277  endif ; enddo
1278 
1279  conv_en(i) = conv_en(i) + g_h2_2rho0 * h_ent * &
1280  ( (r0_tot(i) - r0(i,k)*htot(i)) + sum_pen_en )
1281 
1282  r0_tot(i) = r0_tot(i) + (h_ent * r0(i,k) + pen_absorbed*dr0_dt(i))
1283  stot(i) = stot(i) + h_ent * s(i,k)
1284  ttot(i) = ttot(i) + (h_ent * t(i,k) + pen_absorbed)
1285  rcv_tot(i) = rcv_tot(i) + (h_ent * rcv(i,k) + pen_absorbed*drcv_dt(i))
1286  endif ! dr0 > 0.0
1287 
1288  if (h_ent > 0.0) then
1289  if (htot(i) > 0.0) &
1290  dke_fc(i) = dke_fc(i) + cs%bulk_Ri_convective * 0.5 * &
1291  ((gv%H_to_Z*h_ent) / (htot(i)*(h_ent+htot(i)))) * &
1292  ((uhtot(i)-u(i,k)*htot(i))**2 + (vhtot(i)-v(i,k)*htot(i))**2)
1293 
1294  htot(i) = htot(i) + h_ent
1295  h(i,k) = h(i,k) - h_ent
1296  d_eb(i,k) = d_eb(i,k) - h_ent
1297  if (cs%convect_mom_bug) then
1298  uhtot(i) = u(i,k)*h_ent ; vhtot(i) = v(i,k)*h_ent
1299  else
1300  uhtot(i) = uhtot(i) + h_ent*u(i,k) ; vhtot(i) = vhtot(i) + h_ent*v(i,k)
1301  endif
1302  endif
1303 
1304 
1305  endif ! h_avail>0
1306  endif ; enddo ! i loop
1307  enddo ! k loop
1308 

◆ mixedlayer_detrain_1()

subroutine mom_bulk_mixed_layer::mixedlayer_detrain_1 ( real, dimension(szi_(g),szk0_(gv)), intent(inout)  h,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  T,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  S,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  R0,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  Rcv,
real, dimension(szk_(gv)), intent(in)  RcvTgt,
real, intent(in)  dt,
real, intent(in)  dt_diag,
real, dimension(szi_(g),szk_(gv)), intent(inout)  d_ea,
real, dimension(szi_(g),szk_(gv)), intent(inout)  d_eb,
integer, intent(in)  j,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(bulkmixedlayer_cs), pointer  CS,
real, dimension(szi_(g)), intent(in)  dRcv_dT,
real, dimension(szi_(g)), intent(in)  dRcv_dS,
real, dimension(szi_(g)), intent(in)  max_BL_det 
)
private

This subroutine moves any water left in the former mixed layers into the single buffer layers and may also move buffer layer water into the interior isopycnal layers.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in,out]hLayer thickness [H ~> m or kg m-2]. Layer 0 is the new mixed layer.
[in,out]tPotential temperature [degC].
[in,out]sSalinity [ppt].
[in,out]r0Potential density referenced to surface pressure [R ~> kg m-3].
[in,out]rcvThe coordinate defining potential density [R ~> kg m-3].
[in]rcvtgtThe target value of Rcv for each layer [R ~> kg m-3].
[in]dtTime increment [T ~> s].
[in]dt_diagThe accumulated time interval for diagnostics [T ~> s].
[in,out]d_eaThe upward increase across a layer in the entrainment from above [H ~> m or kg m-2]. Positive d_ea goes with layer thickness increases.
[in,out]d_ebThe downward increase across a layer in the entrainment from below [H ~> m or kg m-2]. Positive values go with mass gain by a layer.
[in]jThe meridional row to work on.
[in]usA dimensional unit scaling type
csThe control structure returned by a previous call to mixedlayer_init.
[in]drcv_dtThe partial derivative of coordinate defining potential density with potential temperature [R degC-1 ~> kg m-3 degC-1].
[in]drcv_dsThe partial derivative of coordinate defining potential density with salinity [R ppt-1 ~> kg m-3 ppt-1].
[in]max_bl_detIf non-negative, the maximum detrainment permitted from the buffer layers [H ~> m or kg m-2].

Definition at line 3103 of file MOM_bulk_mixed_layer.F90.

3105  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
3106  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
3107  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: h !< Layer thickness [H ~> m or kg m-2].
3108  !! Layer 0 is the new mixed layer.
3109  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: T !< Potential temperature [degC].
3110  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: S !< Salinity [ppt].
3111  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: R0 !< Potential density referenced to
3112  !! surface pressure [R ~> kg m-3].
3113  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: Rcv !< The coordinate defining potential
3114  !! density [R ~> kg m-3].
3115  real, dimension(SZK_(GV)), intent(in) :: RcvTgt !< The target value of Rcv for each
3116  !! layer [R ~> kg m-3].
3117  real, intent(in) :: dt !< Time increment [T ~> s].
3118  real, intent(in) :: dt_diag !< The accumulated time interval for
3119  !! diagnostics [T ~> s].
3120  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: d_ea !< The upward increase across a layer in
3121  !! the entrainment from above
3122  !! [H ~> m or kg m-2]. Positive d_ea
3123  !! goes with layer thickness increases.
3124  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: d_eb !< The downward increase across a layer
3125  !! in the entrainment from below [H ~> m or kg m-2].
3126  !! Positive values go with mass gain by
3127  !! a layer.
3128  integer, intent(in) :: j !< The meridional row to work on.
3129  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
3130  type(bulkmixedlayer_CS), pointer :: CS !< The control structure returned by a
3131  !! previous call to mixedlayer_init.
3132  real, dimension(SZI_(G)), intent(in) :: dRcv_dT !< The partial derivative of
3133  !! coordinate defining potential density
3134  !! with potential temperature
3135  !! [R degC-1 ~> kg m-3 degC-1].
3136  real, dimension(SZI_(G)), intent(in) :: dRcv_dS !< The partial derivative of
3137  !! coordinate defining potential density
3138  !! with salinity [R ppt-1 ~> kg m-3 ppt-1].
3139  real, dimension(SZI_(G)), intent(in) :: max_BL_det !< If non-negative, the maximum
3140  !! detrainment permitted from the buffer
3141  !! layers [H ~> m or kg m-2].
3142 
3143  ! Local variables
3144  real :: Ih ! The inverse of a thickness [H-1 ~> m-1 or m2 kg-1].
3145  real :: h_ent ! The thickness from a layer that is
3146  ! entrained [H ~> m or kg m-2].
3147  real :: max_det_rem(SZI_(G)) ! Remaining permitted detrainment [H ~> m or kg m-2].
3148  real :: detrain(SZI_(G)) ! The thickness of fluid to detrain
3149  ! from the mixed layer [H ~> m or kg m-2].
3150  real :: dT_dR, dS_dR, dRml, dR0_dRcv, dT_dS_wt2
3151  real :: I_denom ! A work variable [ppt2 R-2 ~> ppt2 m6 kg-2].
3152  real :: Sdown, Tdown
3153  real :: dt_Time ! The timestep divided by the detrainment timescale [nondim].
3154  real :: g_H2_2Rho0dt ! Half the gravitational acceleration times the square of the
3155  ! conversion from H to m divided by the mean density times the time
3156  ! step [L2 Z T-3 H-2 R-1 ~> m4 s-3 kg-1 or m10 s-3 kg-3].
3157  real :: g_H2_2dt ! Half the gravitational acceleration times the square of the
3158  ! conversion from H to Z divided by the diagnostic time step
3159  ! [L2 Z H-2 T-3 ~> m s-3 or m7 kg-2 s-3].
3160 
3161  logical :: splittable_BL(SZI_(G)), orthogonal_extrap
3162  real :: x1
3163 
3164  integer :: i, is, ie, k, k1, nkmb, nz
3165  is = g%isc ; ie = g%iec ; nz = gv%ke
3166  nkmb = cs%nkml+cs%nkbl
3167  if (cs%nkbl /= 1) call mom_error(fatal,"MOM_mixed_layer: "// &
3168  "CS%nkbl must be 1 in mixedlayer_detrain_1.")
3169 
3170  dt_time = dt / cs%BL_detrain_time
3171  g_h2_2rho0dt = (gv%g_Earth * gv%H_to_Z**2) / (2.0 * gv%Rho0 * dt_diag)
3172  g_h2_2dt = (gv%g_Earth * gv%H_to_Z**2) / (2.0 * dt_diag)
3173 
3174  ! Move detrained water into the buffer layer.
3175  do k=1,cs%nkml
3176  do i=is,ie ; if (h(i,k) > 0.0) then
3177  ih = 1.0 / (h(i,nkmb) + h(i,k))
3178  if (cs%TKE_diagnostics) &
3179  cs%diag_TKE_conv_s2(i,j) = cs%diag_TKE_conv_s2(i,j) + &
3180  g_h2_2rho0dt * h(i,k) * h(i,nkmb) * (r0(i,nkmb) - r0(i,k))
3181  if (allocated(cs%diag_PE_detrain)) &
3182  cs%diag_PE_detrain(i,j) = cs%diag_PE_detrain(i,j) + &
3183  g_h2_2dt * h(i,k) * h(i,nkmb) * (r0(i,nkmb) - r0(i,k))
3184  if (allocated(cs%diag_PE_detrain2)) &
3185  cs%diag_PE_detrain2(i,j) = cs%diag_PE_detrain2(i,j) + &
3186  g_h2_2dt * h(i,k) * h(i,nkmb) * (r0(i,nkmb) - r0(i,k))
3187 
3188  r0(i,nkmb) = (r0(i,nkmb)*h(i,nkmb) + r0(i,k)*h(i,k)) * ih
3189  rcv(i,nkmb) = (rcv(i,nkmb)*h(i,nkmb) + rcv(i,k)*h(i,k)) * ih
3190  t(i,nkmb) = (t(i,nkmb)*h(i,nkmb) + t(i,k)*h(i,k)) * ih
3191  s(i,nkmb) = (s(i,nkmb)*h(i,nkmb) + s(i,k)*h(i,k)) * ih
3192 
3193  d_ea(i,k) = d_ea(i,k) - h(i,k)
3194  d_ea(i,nkmb) = d_ea(i,nkmb) + h(i,k)
3195  h(i,nkmb) = h(i,nkmb) + h(i,k)
3196  h(i,k) = 0.0
3197  endif ; enddo
3198  enddo
3199 
3200  do i=is,ie
3201  max_det_rem(i) = 10.0 * h(i,nkmb)
3202  if (max_bl_det(i) >= 0.0) max_det_rem(i) = max_bl_det(i)
3203  enddo
3204 
3205 ! If the mixed layer was denser than the densest interior layer,
3206 ! but is now lighter than this layer, leaving a buffer layer that
3207 ! is denser than this layer, there are problems. This should prob-
3208 ! ably be considered a case of an inadequate choice of resolution in
3209 ! density space and should be avoided. To make the model run sens-
3210 ! ibly in this case, it will make the mixed layer denser while making
3211 ! the buffer layer the density of the densest interior layer (pro-
3212 ! vided that the this will not make the mixed layer denser than the
3213 ! interior layer). Otherwise, make the mixed layer the same density
3214 ! as the densest interior layer and lighten the buffer layer with
3215 ! the released buoyancy. With multiple buffer layers, much more
3216 ! graceful options are available.
3217  do i=is,ie ; if (h(i,nkmb) > 0.0) then
3218  if ((r0(i,0)<r0(i,nz)) .and. (r0(i,nz)<r0(i,nkmb))) then
3219  if ((r0(i,nz)-r0(i,0))*h(i,0) > &
3220  (r0(i,nkmb)-r0(i,nz))*h(i,nkmb)) then
3221  detrain(i) = (r0(i,nkmb)-r0(i,nz))*h(i,nkmb) / (r0(i,nkmb)-r0(i,0))
3222  else
3223  detrain(i) = (r0(i,nz)-r0(i,0))*h(i,0) / (r0(i,nkmb)-r0(i,0))
3224  endif
3225 
3226  d_eb(i,cs%nkml) = d_eb(i,cs%nkml) + detrain(i)
3227  d_ea(i,cs%nkml) = d_ea(i,cs%nkml) - detrain(i)
3228  d_eb(i,nkmb) = d_eb(i,nkmb) - detrain(i)
3229  d_ea(i,nkmb) = d_ea(i,nkmb) + detrain(i)
3230 
3231  if (allocated(cs%diag_PE_detrain)) cs%diag_PE_detrain(i,j) = &
3232  cs%diag_PE_detrain(i,j) + g_h2_2dt * detrain(i)* &
3233  (h(i,0) + h(i,nkmb)) * (r0(i,nkmb) - r0(i,0))
3234  x1 = r0(i,0)
3235  r0(i,0) = r0(i,0) - detrain(i)*(r0(i,0)-r0(i,nkmb)) / h(i,0)
3236  r0(i,nkmb) = r0(i,nkmb) - detrain(i)*(r0(i,nkmb)-x1) / h(i,nkmb)
3237  x1 = rcv(i,0)
3238  rcv(i,0) = rcv(i,0) - detrain(i)*(rcv(i,0)-rcv(i,nkmb)) / h(i,0)
3239  rcv(i,nkmb) = rcv(i,nkmb) - detrain(i)*(rcv(i,nkmb)-x1) / h(i,nkmb)
3240  x1 = t(i,0)
3241  t(i,0) = t(i,0) - detrain(i)*(t(i,0)-t(i,nkmb)) / h(i,0)
3242  t(i,nkmb) = t(i,nkmb) - detrain(i)*(t(i,nkmb)-x1) / h(i,nkmb)
3243  x1 = s(i,0)
3244  s(i,0) = s(i,0) - detrain(i)*(s(i,0)-s(i,nkmb)) / h(i,0)
3245  s(i,nkmb) = s(i,nkmb) - detrain(i)*(s(i,nkmb)-x1) / h(i,nkmb)
3246 
3247  endif
3248  endif ; enddo
3249 
3250  ! Move water out of the buffer layer, if convenient.
3251 ! Split the buffer layer if possible, and replace the buffer layer
3252 ! with a small amount of fluid from the mixed layer.
3253 ! This is the exponential-in-time splitting, circa 2005.
3254  do i=is,ie
3255  if (h(i,nkmb) > 0.0) then ; splittable_bl(i) = .true.
3256  else ; splittable_bl(i) = .false. ; endif
3257  enddo
3258 
3259  dt_ds_wt2 = cs%dT_dS_wt**2
3260 
3261  do k=nz-1,nkmb+1,-1 ; do i=is,ie
3262  if (splittable_bl(i)) then
3263  if (rcvtgt(k)<=rcv(i,nkmb)) then
3264 ! Estimate dR/drho, dTheta/dR, and dS/dR, where R is the coordinate variable
3265 ! and rho is in-situ (or surface) potential density.
3266 ! There is no "right" way to do this, so this keeps things reasonable, if
3267 ! slightly arbitrary.
3268  splittable_bl(i) = .false.
3269 
3270  k1 = k+1 ; orthogonal_extrap = .false.
3271  ! Here we try to find a massive layer to use for interpolating the
3272  ! temperature and salinity. If none is available a pseudo-orthogonal
3273  ! extrapolation is used. The 10.0 and 0.9 in the following are
3274  ! arbitrary but probably about right.
3275  if ((h(i,k+1) < 10.0*gv%Angstrom_H) .or. &
3276  ((rcvtgt(k+1)-rcv(i,nkmb)) >= 0.9*(rcv(i,k1) - rcv(i,0)))) then
3277  if (k>=nz-1) then ; orthogonal_extrap = .true.
3278  elseif ((h(i,k+2) <= 10.0*gv%Angstrom_H) .and. &
3279  ((rcvtgt(k+1)-rcv(i,nkmb)) < 0.9*(rcv(i,k+2)-rcv(i,0)))) then
3280  k1 = k+2
3281  else ; orthogonal_extrap = .true. ; endif
3282  endif
3283 
3284  if ((r0(i,0) >= r0(i,k1)) .or. (rcv(i,0) >= rcv(i,nkmb))) cycle
3285  ! In this case there is an inversion of in-situ density relative to
3286  ! the coordinate variable. Do not detrain from the buffer layer.
3287 
3288  if (orthogonal_extrap) then
3289  ! 36 here is a typical oceanic value of (dR/dS) / (dR/dT) - it says
3290  ! that the relative weights of T & S changes is a plausible 6:1.
3291  ! Also, this was coded on Athena's 6th birthday!
3292  i_denom = 1.0 / (drcv_ds(i)**2 + dt_ds_wt2*drcv_dt(i)**2)
3293  dt_dr = dt_ds_wt2*drcv_dt(i) * i_denom
3294  ds_dr = drcv_ds(i) * i_denom
3295  else
3296  dt_dr = (t(i,0) - t(i,k1)) / (rcv(i,0) - rcv(i,k1))
3297  ds_dr = (s(i,0) - s(i,k1)) / (rcv(i,0) - rcv(i,k1))
3298  endif
3299  drml = dt_time * (r0(i,nkmb) - r0(i,0)) * &
3300  (rcv(i,0) - rcv(i,k1)) / (r0(i,0) - r0(i,k1))
3301  ! Once again, there is an apparent density inversion in Rcv.
3302  if (drml < 0.0) cycle
3303  dr0_drcv = (r0(i,0) - r0(i,k1)) / (rcv(i,0) - rcv(i,k1))
3304 
3305  if ((rcv(i,nkmb) - drml < rcvtgt(k)) .and. (max_det_rem(i) > h(i,nkmb))) then
3306  ! In this case, the buffer layer is split into two isopycnal layers.
3307  detrain(i) = h(i,nkmb)*(rcv(i,nkmb) - rcvtgt(k)) / &
3308  (rcvtgt(k+1) - rcvtgt(k))
3309 
3310  if (allocated(cs%diag_PE_detrain)) cs%diag_PE_detrain(i,j) = &
3311  cs%diag_PE_detrain(i,j) - g_h2_2dt * detrain(i) * &
3312  (h(i,nkmb)-detrain(i)) * (rcvtgt(k+1) - rcvtgt(k)) * dr0_drcv
3313 
3314  tdown = detrain(i) * (t(i,nkmb) + dt_dr*(rcvtgt(k+1)-rcv(i,nkmb)))
3315  t(i,k) = (h(i,k) * t(i,k) + &
3316  (h(i,nkmb) * t(i,nkmb) - tdown)) / &
3317  (h(i,k) + (h(i,nkmb) - detrain(i)))
3318  t(i,k+1) = (h(i,k+1) * t(i,k+1) + tdown)/ &
3319  (h(i,k+1) + detrain(i))
3320  t(i,nkmb) = t(i,0)
3321  sdown = detrain(i) * (s(i,nkmb) + ds_dr*(rcvtgt(k+1)-rcv(i,nkmb)))
3322  s(i,k) = (h(i,k) * s(i,k) + &
3323  (h(i,nkmb) * s(i,nkmb) - sdown)) / &
3324  (h(i,k) + (h(i,nkmb) - detrain(i)))
3325  s(i,k+1) = (h(i,k+1) * s(i,k+1) + sdown)/ &
3326  (h(i,k+1) + detrain(i))
3327  s(i,nkmb) = s(i,0)
3328  rcv(i,nkmb) = rcv(i,0)
3329 
3330  d_ea(i,k+1) = d_ea(i,k+1) + detrain(i)
3331  d_ea(i,k) = d_ea(i,k) + (h(i,nkmb) - detrain(i))
3332  d_ea(i,nkmb) = d_ea(i,nkmb) - h(i,nkmb)
3333 
3334  h(i,k+1) = h(i,k+1) + detrain(i)
3335  h(i,k) = h(i,k) + h(i,nkmb) - detrain(i)
3336  h(i,nkmb) = 0.0
3337  else
3338  ! Here only part of the buffer layer is moved into the interior.
3339  detrain(i) = h(i,nkmb) * drml / (rcvtgt(k+1) - rcv(i,nkmb) + drml)
3340  if (detrain(i) > max_det_rem(i)) detrain(i) = max_det_rem(i)
3341  ih = 1.0 / (h(i,k+1) + detrain(i))
3342 
3343  tdown = (t(i,nkmb) + dt_dr*(rcvtgt(k+1)-rcv(i,nkmb)))
3344  t(i,nkmb) = t(i,nkmb) - dt_dr * drml
3345  t(i,k+1) = (h(i,k+1) * t(i,k+1) + detrain(i) * tdown) * ih
3346  sdown = (s(i,nkmb) + ds_dr*(rcvtgt(k+1)-rcv(i,nkmb)))
3347 ! The following two expressions updating S(nkmb) are mathematically identical.
3348 ! S(i,nkmb) = (h(i,nkmb) * S(i,nkmb) - detrain(i) * Sdown) / &
3349 ! (h(i,nkmb) - detrain(i))
3350  s(i,nkmb) = s(i,nkmb) - ds_dr * drml
3351  s(i,k+1) = (h(i,k+1) * s(i,k+1) + detrain(i) * sdown) * ih
3352 
3353  d_ea(i,k+1) = d_ea(i,k+1) + detrain(i)
3354  d_ea(i,nkmb) = d_ea(i,nkmb) - detrain(i)
3355 
3356  h(i,k+1) = h(i,k+1) + detrain(i)
3357  h(i,nkmb) = h(i,nkmb) - detrain(i)
3358 
3359  if (allocated(cs%diag_PE_detrain)) cs%diag_PE_detrain(i,j) = &
3360  cs%diag_PE_detrain(i,j) - g_h2_2dt * detrain(i) * dr0_drcv * &
3361  (h(i,nkmb)-detrain(i)) * (rcvtgt(k+1) - rcv(i,nkmb) + drml)
3362  endif
3363  endif ! RcvTgt(k)<=Rcv(i,nkmb)
3364  endif ! splittable_BL
3365  enddo ; enddo ! i & k loops
3366 
3367 ! The numerical behavior of the buffer layer is dramatically improved
3368 ! if it is always at least a small fraction (say 10%) of the thickness
3369 ! of the mixed layer. As the physical distinction between the mixed
3370 ! and buffer layers is vague anyway, this seems hard to argue against.
3371  do i=is,ie
3372  if (h(i,nkmb) < 0.1*h(i,0)) then
3373  h_ent = 0.1*h(i,0) - h(i,nkmb)
3374  ih = 10.0/h(i,0)
3375  t(i,nkmb) = (h(i,nkmb)*t(i,nkmb) + h_ent*t(i,0)) * ih
3376  s(i,nkmb) = (h(i,nkmb)*s(i,nkmb) + h_ent*s(i,0)) * ih
3377 
3378  d_ea(i,1) = d_ea(i,1) - h_ent
3379  d_ea(i,nkmb) = d_ea(i,nkmb) + h_ent
3380 
3381  h(i,0) = h(i,0) - h_ent
3382  h(i,nkmb) = h(i,nkmb) + h_ent
3383  endif
3384  enddo
3385 

◆ mixedlayer_detrain_2()

subroutine mom_bulk_mixed_layer::mixedlayer_detrain_2 ( real, dimension(szi_(g),szk0_(gv)), intent(inout)  h,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  T,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  S,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  R0,
real, dimension(szi_(g),szk0_(gv)), intent(inout)  Rcv,
real, dimension(szk_(gv)), intent(in)  RcvTgt,
real, intent(in)  dt,
real, intent(in)  dt_diag,
real, dimension(szi_(g),szk_(gv)), intent(inout)  d_ea,
integer, intent(in)  j,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(unit_scale_type), intent(in)  US,
type(bulkmixedlayer_cs), pointer  CS,
real, dimension(szi_(g)), intent(in)  dR0_dT,
real, dimension(szi_(g)), intent(in)  dR0_dS,
real, dimension(szi_(g)), intent(in)  dRcv_dT,
real, dimension(szi_(g)), intent(in)  dRcv_dS,
real, dimension(szi_(g)), intent(in)  max_BL_det 
)
private

This subroutine moves any water left in the former mixed layers into the two buffer layers and may also move buffer layer water into the interior isopycnal layers.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in,out]hLayer thickness [H ~> m or kg m-2]. Layer 0 is the new mixed layer.
[in,out]tPotential temperature [degC].
[in,out]sSalinity [ppt].
[in,out]r0Potential density referenced to surface pressure [R ~> kg m-3].
[in,out]rcvThe coordinate defining potential density [R ~> kg m-3].
[in]rcvtgtThe target value of Rcv for each layer [R ~> kg m-3].
[in]dtTime increment [T ~> s].
[in]dt_diagThe diagnostic time step [T ~> s].
[in,out]d_eaThe upward increase across a layer in the entrainment from above [H ~> m or kg m-2]. Positive d_ea goes with layer thickness increases.
[in]jThe meridional row to work on.
[in]usA dimensional unit scaling type
csThe control structure returned by a previous call to mixedlayer_init.
[in]dr0_dtThe partial derivative of potential density referenced to the surface with potential temperature, [R degC-1 ~> kg m-3 degC-1].
[in]dr0_dsThe partial derivative of cpotential density referenced to the surface with salinity [R ppt-1 ~> kg m-3 ppt-1].
[in]drcv_dtThe partial derivative of coordinate defining potential density with potential temperature, [R degC-1 ~> kg m-3 degC-1].
[in]drcv_dsThe partial derivative of coordinate defining potential density with salinity [R ppt-1 ~> kg m-3 ppt-1].
[in]max_bl_detIf non-negative, the maximum detrainment permitted from the buffer layers [H ~> m or kg m-2].

Definition at line 2212 of file MOM_bulk_mixed_layer.F90.

2214  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
2215  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
2216  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: h !< Layer thickness [H ~> m or kg m-2].
2217  !! Layer 0 is the new mixed layer.
2218  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: T !< Potential temperature [degC].
2219  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: S !< Salinity [ppt].
2220  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: R0 !< Potential density referenced to
2221  !! surface pressure [R ~> kg m-3].
2222  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: Rcv !< The coordinate defining potential
2223  !! density [R ~> kg m-3].
2224  real, dimension(SZK_(GV)), intent(in) :: RcvTgt !< The target value of Rcv for each
2225  !! layer [R ~> kg m-3].
2226  real, intent(in) :: dt !< Time increment [T ~> s].
2227  real, intent(in) :: dt_diag !< The diagnostic time step [T ~> s].
2228  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: d_ea !< The upward increase across a layer in
2229  !! the entrainment from above
2230  !! [H ~> m or kg m-2]. Positive d_ea
2231  !! goes with layer thickness increases.
2232  integer, intent(in) :: j !< The meridional row to work on.
2233  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2234  type(bulkmixedlayer_CS), pointer :: CS !< The control structure returned by a
2235  !! previous call to mixedlayer_init.
2236  real, dimension(SZI_(G)), intent(in) :: dR0_dT !< The partial derivative of
2237  !! potential density referenced to the
2238  !! surface with potential temperature,
2239  !! [R degC-1 ~> kg m-3 degC-1].
2240  real, dimension(SZI_(G)), intent(in) :: dR0_dS !< The partial derivative of
2241  !! cpotential density referenced to the
2242  !! surface with salinity
2243  !! [R ppt-1 ~> kg m-3 ppt-1].
2244  real, dimension(SZI_(G)), intent(in) :: dRcv_dT !< The partial derivative of
2245  !! coordinate defining potential density
2246  !! with potential temperature,
2247  !! [R degC-1 ~> kg m-3 degC-1].
2248  real, dimension(SZI_(G)), intent(in) :: dRcv_dS !< The partial derivative of
2249  !! coordinate defining potential density
2250  !! with salinity [R ppt-1 ~> kg m-3 ppt-1].
2251  real, dimension(SZI_(G)), intent(in) :: max_BL_det !< If non-negative, the maximum
2252  !! detrainment permitted from the buffer
2253  !! layers [H ~> m or kg m-2].
2254 
2255 ! This subroutine moves any water left in the former mixed layers into the
2256 ! two buffer layers and may also move buffer layer water into the interior
2257 ! isopycnal layers.
2258 
2259  ! Local variables
2260  real :: h_to_bl ! The total thickness detrained to the buffer
2261  ! layers [H ~> m or kg m-2].
2262  real :: R0_to_bl ! The depth integrated amount of R0 that is detrained to the
2263  ! buffer layer [H R ~> kg m-2 or kg2 m-5]
2264  real :: Rcv_to_bl ! The depth integrated amount of Rcv that is detrained to the
2265  ! buffer layer [H R ~> kg m-2 or kg2 m-5]
2266  real :: T_to_bl ! The depth integrated amount of T that is detrained to the
2267  ! buffer layer [degC H ~> degC m or degC kg m-2]
2268  real :: S_to_bl ! The depth integrated amount of S that is detrained to the
2269  ! buffer layer [ppt H ~> ppt m or ppt kg m-2]
2270  real :: h_min_bl ! The minimum buffer layer thickness [H ~> m or kg m-2].
2271 
2272  real :: h1, h2 ! Scalar variables holding the values of
2273  ! h(i,CS%nkml+1) and h(i,CS%nkml+2) [H ~> m or kg m-2].
2274  real :: h1_avail ! The thickness of the upper buffer layer
2275  ! available to move into the lower buffer
2276  ! layer [H ~> m or kg m-2].
2277  real :: stays ! stays is the thickness of the upper buffer
2278  ! layer that remains there [H ~> m or kg m-2].
2279  real :: stays_min, stays_max ! The minimum and maximum permitted values of
2280  ! stays [H ~> m or kg m-2].
2281 
2282  logical :: mergeable_bl ! If true, it is an option to combine the two
2283  ! buffer layers and create water that matches
2284  ! the target density of an interior layer.
2285  real :: stays_merge ! If the two buffer layers can be combined
2286  ! stays_merge is the thickness of the upper
2287  ! layer that remains [H ~> m or kg m-2].
2288  real :: stays_min_merge ! The minimum allowed value of stays_merge [H ~> m or kg m-2].
2289 
2290  real :: dR0_2dz, dRcv_2dz ! Half the vertical gradients of R0 and Rcv [R H-1 ~> kg m-4 or m-1]
2291 ! real :: dT_2dz, dS_2dz ! Half the vertical gradients of T and S, in degC H-1, and ppt H-1.
2292  real :: scale_slope ! A nondimensional number < 1 used to scale down
2293  ! the slope within the upper buffer layer when
2294  ! water MUST be detrained to the lower layer.
2295 
2296  real :: dPE_extrap ! The potential energy change due to dispersive
2297  ! advection or mixing layers, divided by
2298  ! rho_0*g [H2 ~> m2 or kg2 m-4].
2299  real :: dPE_det, dPE_merge ! The energy required to mix the detrained water
2300  ! into the buffer layer or the merge the two
2301  ! buffer layers [R H2 L2 Z-1 T-2 ~> J m-2 or J kg2 m-8].
2302 
2303  real :: h_from_ml ! The amount of additional water that must be
2304  ! drawn from the mixed layer [H ~> m or kg m-2].
2305  real :: h_det_h2 ! The amount of detrained water and mixed layer
2306  ! water that will go directly into the lower
2307  ! buffer layer [H ~> m or kg m-2].
2308  real :: h_det_to_h2, h_ml_to_h2 ! All of the variables hA_to_hB are the thickness fluxes
2309  real :: h_det_to_h1, h_ml_to_h1 ! from one layer to another [H ~> m or kg m-2],
2310  real :: h1_to_h2, h1_to_k0 ! with h_det the detrained water, h_ml
2311  real :: h2_to_k1, h2_to_k1_rem ! the actively mixed layer, h1 and h2 the upper
2312  ! and lower buffer layers, and k0 and k1 the
2313  ! interior layers that are just lighter and
2314  ! just denser than the lower buffer layer.
2315 
2316  real :: R0_det, T_det, S_det ! Detrained values of R0 [R ~> kg m-3], T [degC], and S [ppt].
2317  real :: Rcv_stays, R0_stays ! Values of Rcv and R0 that stay in a layer.
2318  real :: T_stays, S_stays ! Values of T and S that stay in a layer.
2319  real :: dSpice_det, dSpice_stays! The spiciness difference between an original
2320  ! buffer layer and the water that moves into
2321  ! an interior layer or that stays in that
2322  ! layer [R ~> kg m-3].
2323  real :: dSpice_lim, dSpice_lim2 ! Limits to the spiciness difference between
2324  ! the lower buffer layer and the water that
2325  ! moves into an interior layer [R ~> kg m-3].
2326  real :: dSpice_2dz ! The vertical gradient of spiciness used for
2327  ! advection [R H-1 ~> kg m-4 or m-1].
2328 
2329  real :: dPE_ratio ! Multiplier of dPE_det at which merging is
2330  ! permitted - here (detrainment_per_day/dt)*30
2331  ! days?
2332  real :: num_events ! The number of detrainment events over which
2333  ! to prefer merging the buffer layers.
2334  real :: dPE_time_ratio ! Larger of 1 and the detrainment timescale over dt [nondim].
2335  real :: dT_dS_gauge, dS_dT_gauge ! The relative scales of temperature and
2336  ! salinity changes in defining spiciness, in
2337  ! [degC ppt-1] and [ppt degC-1].
2338  real :: I_denom ! A work variable with units of [ppt2 R-2 ~> ppt2 m6 kg-2].
2339 
2340  real :: g_2 ! 1/2 g_Earth [L2 Z-1 T-2 ~> m s-2].
2341  real :: Rho0xG ! Rho0 times G_Earth [R L2 Z-1 T-2 ~> kg m-2 s-2].
2342  real :: I2Rho0 ! 1 / (2 Rho0) [R-1 ~> m3 kg-1].
2343  real :: Idt_H2 ! The square of the conversion from thickness to Z
2344  ! divided by the time step [Z2 H-2 T-1 ~> s-1 or m6 kg-2 s-1].
2345  logical :: stable_Rcv ! If true, the buffer layers are stable with
2346  ! respect to the coordinate potential density.
2347  real :: h_neglect ! A thickness that is so small it is usually lost
2348  ! in roundoff and can be neglected [H ~> m or kg m-2].
2349 
2350  real :: s1en ! A work variable [H2 L2 kg m-1 T-3 ~> kg m3 s-3 or kg3 m-3 s-3].
2351  real :: s1, s2, bh0 ! Work variables [H ~> m or kg m-2].
2352  real :: s3sq ! A work variable [H2 ~> m2 or kg2 m-4].
2353  real :: I_ya, b1 ! Nondimensional work variables.
2354  real :: Ih, Ihdet, Ih1f, Ih2f ! Assorted inverse thickness work variables,
2355  real :: Ihk0, Ihk1, Ih12 ! all in [H-1 ~> m-1 or m2 kg-1].
2356  real :: dR1, dR2, dR2b, dRk1 ! Assorted density difference work variables,
2357  real :: dR0, dR21, dRcv ! all in [R ~> kg m-3].
2358  real :: dRcv_stays, dRcv_det, dRcv_lim
2359  real :: Angstrom ! The minumum layer thickness [H ~> m or kg m-2].
2360 
2361  real :: h2_to_k1_lim, T_new, S_new, T_max, T_min, S_max, S_min
2362  character(len=200) :: mesg
2363 
2364  integer :: i, k, k0, k1, is, ie, nz, kb1, kb2, nkmb
2365  is = g%isc ; ie = g%iec ; nz = gv%ke
2366  kb1 = cs%nkml+1; kb2 = cs%nkml+2
2367  nkmb = cs%nkml+cs%nkbl
2368  h_neglect = gv%H_subroundoff
2369  g_2 = 0.5 * gv%g_Earth
2370  rho0xg = gv%Rho0 * gv%g_Earth
2371  idt_h2 = gv%H_to_Z**2 / dt_diag
2372  i2rho0 = 0.5 / (gv%Rho0)
2373  angstrom = gv%Angstrom_H
2374 
2375  ! This is hard coding of arbitrary and dimensional numbers.
2376  dt_ds_gauge = cs%dT_dS_wt ; ds_dt_gauge = 1.0 / dt_ds_gauge
2377  num_events = 10.0
2378 
2379  if (cs%nkbl /= 2) call mom_error(fatal, "MOM_mixed_layer"// &
2380  "CS%nkbl must be 2 in mixedlayer_detrain_2.")
2381 
2382  if (dt < cs%BL_detrain_time) then ; dpe_time_ratio = cs%BL_detrain_time / (dt)
2383  else ; dpe_time_ratio = 1.0 ; endif
2384 
2385  do i=is,ie
2386 
2387  ! Determine all of the properties being detrained from the mixed layer.
2388 
2389  ! As coded this has the k and i loop orders switched, but k is CS%nkml is
2390  ! often just 1 or 2, so this seems like it should not be a problem, especially
2391  ! since it means that a number of variables can now be scalars, not arrays.
2392  h_to_bl = 0.0 ; r0_to_bl = 0.0
2393  rcv_to_bl = 0.0 ; t_to_bl = 0.0 ; s_to_bl = 0.0
2394 
2395  do k=1,cs%nkml ; if (h(i,k) > 0.0) then
2396  h_to_bl = h_to_bl + h(i,k)
2397  r0_to_bl = r0_to_bl + r0(i,k)*h(i,k)
2398 
2399  rcv_to_bl = rcv_to_bl + rcv(i,k)*h(i,k)
2400  t_to_bl = t_to_bl + t(i,k)*h(i,k)
2401  s_to_bl = s_to_bl + s(i,k)*h(i,k)
2402 
2403  d_ea(i,k) = d_ea(i,k) - h(i,k)
2404  h(i,k) = 0.0
2405  endif ; enddo
2406  if (h_to_bl > 0.0) then ; r0_det = r0_to_bl / h_to_bl
2407  else ; r0_det = r0(i,0) ; endif
2408 
2409  ! This code does both downward detrainment from both the mixed layer and the
2410  ! buffer layers.
2411  ! Several considerations apply in detraining water into the interior:
2412  ! (1) Water only moves into the interior from the deeper buffer layer,
2413  ! so the deeper buffer layer must have some mass.
2414  ! (2) The upper buffer layer must have some mass so the extrapolation of
2415  ! density is meaningful (i.e. there is not detrainment from the buffer
2416  ! layers when there is strong mixed layer entrainment).
2417  ! (3) The lower buffer layer density extrapolated to its base with a
2418  ! linear fit between the two layers must exceed the density of the
2419  ! next denser interior layer.
2420  ! (4) The average extroplated coordinate density that is moved into the
2421  ! isopycnal interior matches the target value for that layer.
2422  ! (5) The potential energy change is calculated and might be used later
2423  ! to allow the upper buffer layer to mix more into the lower buffer
2424  ! layer.
2425 
2426  ! Determine whether more must be detrained from the mixed layer to keep a
2427  ! minimal amount of mass in the buffer layers. In this case the 5% of the
2428  ! mixed layer thickness is hard-coded, but probably shouldn't be!
2429  h_min_bl = min(cs%Hbuffer_min, cs%Hbuffer_rel_min*h(i,0))
2430 
2431  stable_rcv = .true.
2432  if (((r0(i,kb2)-r0(i,kb1)) * (rcv(i,kb2)-rcv(i,kb1)) <= 0.0)) &
2433  stable_rcv = .false.
2434 
2435  h1 = h(i,kb1) ; h2 = h(i,kb2)
2436 
2437  h2_to_k1_rem = (h1 + h2) + h_to_bl
2438  if ((max_bl_det(i) >= 0.0) .and. (h2_to_k1_rem > max_bl_det(i))) &
2439  h2_to_k1_rem = max_bl_det(i)
2440 
2441 
2442  if ((h2 == 0.0) .and. (h1 > 0.0)) then
2443  ! The lower buffer layer has been eliminated either by convective
2444  ! adjustment or entrainment from the interior, and its current properties
2445  ! are not meaningful, but may later be used to determine the properties of
2446  ! waters moving into the lower buffer layer. So the properties of the
2447  ! lower buffer layer are set to be between those of the upper buffer layer
2448  ! and the next denser interior layer, measured by R0. This probably does
2449  ! not happen very often, so I am not too worried about the inefficiency of
2450  ! the following loop.
2451  do k1=kb2+1,nz ; if (h(i,k1) > 2.0*angstrom) exit ; enddo
2452 
2453  r0(i,kb2) = r0(i,kb1)
2454 
2455  rcv(i,kb2)=rcv(i,kb1) ; t(i,kb2)=t(i,kb1) ; s(i,kb2)=s(i,kb1)
2456 
2457 
2458  if (k1 <= nz) then ; if (r0(i,k1) >= r0(i,kb1)) then
2459  r0(i,kb2) = 0.5*(r0(i,kb1)+r0(i,k1))
2460 
2461  rcv(i,kb2) = 0.5*(rcv(i,kb1)+rcv(i,k1))
2462  t(i,kb2) = 0.5*(t(i,kb1)+t(i,k1))
2463  s(i,kb2) = 0.5*(s(i,kb1)+s(i,k1))
2464  endif ; endif
2465  endif ! (h2 = 0 && h1 > 0)
2466 
2467  dpe_extrap = 0.0 ; dpe_merge = 0.0
2468  mergeable_bl = .false.
2469  if ((h1 > 0.0) .and. (h2 > 0.0) .and. (h_to_bl > 0.0) .and. &
2470  (stable_rcv)) then
2471  ! Check whether it is permissible for the buffer layers to detrain
2472  ! into the interior isopycnal layers.
2473 
2474  ! Determine the layer that has the lightest target density that is
2475  ! denser than the lowermost buffer layer.
2476  do k1=kb2+1,nz ; if (rcvtgt(k1) >= rcv(i,kb2)) exit ; enddo ; k0 = k1-1
2477  dr1 = rcvtgt(k0)-rcv(i,kb1) ; dr2 = rcv(i,kb2)-rcvtgt(k0)
2478 
2479  ! Use an energy-balanced combination of downwind advection into the next
2480  ! denser interior layer and upwind advection from the upper buffer layer
2481  ! into the lower one, each with an energy change that equals that required
2482  ! to mix the detrained water with the upper buffer layer.
2483  h1_avail = h1 - max(0.0,h_min_bl-h_to_bl)
2484  if ((k1<=nz) .and. (h2 > h_min_bl) .and. (h1_avail > 0.0) .and. &
2485  (r0(i,kb1) < r0(i,kb2)) .and. (h_to_bl*r0(i,kb1) > r0_to_bl)) then
2486  drk1 = (rcvtgt(k1) - rcv(i,kb2)) * (r0(i,kb2) - r0(i,kb1)) / &
2487  (rcv(i,kb2) - rcv(i,kb1))
2488  b1 = drk1 / (r0(i,kb2) - r0(i,kb1))
2489  ! b1 = RcvTgt(k1) - Rcv(i,kb2)) / (Rcv(i,kb2) - Rcv(i,kb1))
2490 
2491  ! Apply several limits to the detrainment.
2492  ! Entrain less than the mass in h2, and keep the base of the buffer
2493  ! layers from becoming shallower than any neighbors.
2494  h2_to_k1 = min(h2 - h_min_bl, h2_to_k1_rem)
2495  ! Balance downwind advection of density into the layer below the
2496  ! buffer layers with upwind advection from the layer above.
2497  if (h2_to_k1*(h1_avail + b1*(h1_avail + h2)) > h2*h1_avail) &
2498  h2_to_k1 = (h2*h1_avail) / (h1_avail + b1*(h1_avail + h2))
2499  if (h2_to_k1*(drk1 * h2) > (h_to_bl*r0(i,kb1) - r0_to_bl) * h1) &
2500  h2_to_k1 = (h_to_bl*r0(i,kb1) - r0_to_bl) * h1 / (drk1 * h2)
2501 
2502  if ((k1==kb2+1) .and. (cs%BL_extrap_lim > 0.)) then
2503  ! Simply do not detrain very light water into the lightest isopycnal
2504  ! coordinate layers if the density jump is too large.
2505  drcv_lim = rcv(i,kb2)-rcv(i,0)
2506  do k=1,kb2 ; drcv_lim = max(drcv_lim, rcv(i,kb2)-rcv(i,k)) ; enddo
2507  drcv_lim = cs%BL_extrap_lim*drcv_lim
2508  if ((rcvtgt(k1) - rcv(i,kb2)) >= drcv_lim) then
2509  h2_to_k1 = 0.0
2510  elseif ((rcvtgt(k1) - rcv(i,kb2)) > 0.5*drcv_lim) then
2511  h2_to_k1 = h2_to_k1 * (2.0 - 2.0*((rcvtgt(k1) - rcv(i,kb2)) / drcv_lim))
2512  endif
2513  endif
2514 
2515  drcv = (rcvtgt(k1) - rcv(i,kb2))
2516 
2517  ! Use 2nd order upwind advection of spiciness, limited by the values
2518  ! in deeper thick layers to determine the detrained temperature and
2519  ! salinity.
2520  dspice_det = (ds_dt_gauge*drcv_ds(i)*(t(i,kb2)-t(i,kb1)) - &
2521  dt_ds_gauge*drcv_dt(i)*(s(i,kb2)-s(i,kb1))) * &
2522  (h2 - h2_to_k1) / (h1 + h2)
2523  dspice_lim = 0.0
2524  if (h(i,k1) > 10.0*angstrom) then
2525  dspice_lim = ds_dt_gauge*drcv_ds(i)*(t(i,k1)-t(i,kb2)) - &
2526  dt_ds_gauge*drcv_dt(i)*(s(i,k1)-s(i,kb2))
2527  if (dspice_det*dspice_lim <= 0.0) dspice_lim = 0.0
2528  endif
2529  if (k1<nz) then ; if (h(i,k1+1) > 10.0*angstrom) then
2530  dspice_lim2 = ds_dt_gauge*drcv_ds(i)*(t(i,k1+1)-t(i,kb2)) - &
2531  dt_ds_gauge*drcv_dt(i)*(s(i,k1+1)-s(i,kb2))
2532  if ((dspice_det*dspice_lim2 > 0.0) .and. &
2533  (abs(dspice_lim2) > abs(dspice_lim))) dspice_lim = dspice_lim2
2534  endif ; endif
2535  if (abs(dspice_det) > abs(dspice_lim)) dspice_det = dspice_lim
2536 
2537  i_denom = 1.0 / (drcv_ds(i)**2 + (dt_ds_gauge*drcv_dt(i))**2)
2538  t_det = t(i,kb2) + dt_ds_gauge * i_denom * &
2539  (dt_ds_gauge * drcv_dt(i) * drcv + drcv_ds(i) * dspice_det)
2540  s_det = s(i,kb2) + i_denom * &
2541  (drcv_ds(i) * drcv - dt_ds_gauge * drcv_dt(i) * dspice_det)
2542  ! The detrained values of R0 are based on changes in T and S.
2543  r0_det = r0(i,kb2) + (t_det-t(i,kb2)) * dr0_dt(i) + &
2544  (s_det-s(i,kb2)) * dr0_ds(i)
2545 
2546  if (cs%BL_extrap_lim >= 0.) then
2547  ! Only do this detrainment if the new layer's temperature and salinity
2548  ! are not too far outside of the range of previous values.
2549  if (h(i,k1) > 10.0*angstrom) then
2550  t_min = min(t(i,kb1), t(i,kb2), t(i,k1)) - cs%Allowed_T_chg
2551  t_max = max(t(i,kb1), t(i,kb2), t(i,k1)) + cs%Allowed_T_chg
2552  s_min = min(s(i,kb1), s(i,kb2), s(i,k1)) - cs%Allowed_S_chg
2553  s_max = max(s(i,kb1), s(i,kb2), s(i,k1)) + cs%Allowed_S_chg
2554  else
2555  t_min = min(t(i,kb1), t(i,kb2)) - cs%Allowed_T_chg
2556  t_max = max(t(i,kb1), t(i,kb2)) + cs%Allowed_T_chg
2557  s_min = min(s(i,kb1), s(i,kb2)) - cs%Allowed_S_chg
2558  s_max = max(s(i,kb1), s(i,kb2)) + cs%Allowed_S_chg
2559  endif
2560  ihk1 = 1.0 / (h(i,k1) + h2_to_k1)
2561  t_new = (h(i,k1)*t(i,k1) + h2_to_k1*t_det) * ihk1
2562  s_new = (h(i,k1)*s(i,k1) + h2_to_k1*s_det) * ihk1
2563  ! A less restrictive limit might be used here.
2564  if ((t_new < t_min) .or. (t_new > t_max) .or. &
2565  (s_new < s_min) .or. (s_new > s_max)) &
2566  h2_to_k1 = 0.0
2567  endif
2568 
2569  h1_to_h2 = b1*h2*h2_to_k1 / (h2 - (1.0+b1)*h2_to_k1)
2570 
2571  ihk1 = 1.0 / (h(i,k1) + h_neglect + h2_to_k1)
2572  ih2f = 1.0 / ((h(i,kb2) - h2_to_k1) + h1_to_h2)
2573 
2574  rcv(i,kb2) = ((h(i,kb2)*rcv(i,kb2) - h2_to_k1*rcvtgt(k1)) + &
2575  h1_to_h2*rcv(i,kb1))*ih2f
2576  rcv(i,k1) = ((h(i,k1)+h_neglect)*rcv(i,k1) + h2_to_k1*rcvtgt(k1)) * ihk1
2577 
2578  t(i,kb2) = ((h(i,kb2)*t(i,kb2) - h2_to_k1*t_det) + &
2579  h1_to_h2*t(i,kb1)) * ih2f
2580  t(i,k1) = ((h(i,k1)+h_neglect)*t(i,k1) + h2_to_k1*t_det) * ihk1
2581 
2582  s(i,kb2) = ((h(i,kb2)*s(i,kb2) - h2_to_k1*s_det) + &
2583  h1_to_h2*s(i,kb1)) * ih2f
2584  s(i,k1) = ((h(i,k1)+h_neglect)*s(i,k1) + h2_to_k1*s_det) * ihk1
2585 
2586  ! Changes in R0 are based on changes in T and S.
2587  r0(i,kb2) = ((h(i,kb2)*r0(i,kb2) - h2_to_k1*r0_det) + &
2588  h1_to_h2*r0(i,kb1)) * ih2f
2589  r0(i,k1) = ((h(i,k1)+h_neglect)*r0(i,k1) + h2_to_k1*r0_det) * ihk1
2590 
2591  h(i,kb1) = h(i,kb1) - h1_to_h2 ; h1 = h(i,kb1)
2592  h(i,kb2) = (h(i,kb2) - h2_to_k1) + h1_to_h2 ; h2 = h(i,kb2)
2593  h(i,k1) = h(i,k1) + h2_to_k1
2594 
2595  d_ea(i,kb1) = d_ea(i,kb1) - h1_to_h2
2596  d_ea(i,kb2) = (d_ea(i,kb2) - h2_to_k1) + h1_to_h2
2597  d_ea(i,k1) = d_ea(i,k1) + h2_to_k1
2598  h2_to_k1_rem = max(h2_to_k1_rem - h2_to_k1, 0.0)
2599 
2600  ! The lower buffer layer has become lighter - it may be necessary to
2601  ! adjust k1 lighter.
2602  if ((k1>kb2+1) .and. (rcvtgt(k1-1) >= rcv(i,kb2))) then
2603  do k1=k1,kb2+1,-1 ; if (rcvtgt(k1-1) < rcv(i,kb2)) exit ; enddo
2604  endif
2605  endif
2606 
2607  k0 = k1-1
2608  dr1 = rcvtgt(k0)-rcv(i,kb1) ; dr2 = rcv(i,kb2)-rcvtgt(k0)
2609 
2610  if ((k0>kb2) .and. (dr1 > 0.0) .and. (h1 > h_min_bl) .and. &
2611  (h2*dr2 < h1*dr1) .and. (r0(i,kb2) > r0(i,kb1))) then
2612  ! An interior isopycnal layer (k0) is intermediate in density between
2613  ! the two buffer layers, and there can be detrainment. The entire
2614  ! lower buffer layer is combined with a portion of the upper buffer
2615  ! layer to match the target density of layer k0.
2616  stays_merge = 2.0*(h1+h2)*(h1*dr1 - h2*dr2) / &
2617  ((dr1+dr2)*h1 + dr1*(h1+h2) + &
2618  sqrt((dr2*h1-dr1*h2)**2 + 4*(h1+h2)*h2*(dr1+dr2)*dr2))
2619 
2620  stays_min_merge = max(h_min_bl, 2.0*h_min_bl - h_to_bl, &
2621  h1 - (h1+h2)*(r0(i,kb1) - r0_det) / (r0(i,kb2) - r0(i,kb1)))
2622  if ((stays_merge > stays_min_merge) .and. &
2623  (stays_merge + h2_to_k1_rem >= h1 + h2)) then
2624  mergeable_bl = .true.
2625  dpe_merge = g_2*(r0(i,kb2)-r0(i,kb1))*(h1-stays_merge)*(h2-stays_merge)
2626  endif
2627  endif
2628 
2629  if ((k1<=nz).and.(.not.mergeable_bl)) then
2630  ! Check whether linear extrapolation of density (i.e. 2nd order upwind
2631  ! advection) will allow some of the lower buffer layer to detrain into
2632  ! the next denser interior layer (k1).
2633  dr2b = rcvtgt(k1)-rcv(i,kb2) ; dr21 = rcv(i,kb2) - rcv(i,kb1)
2634  if (dr2b*(h1+h2) < h2*dr21) then
2635  ! Some of layer kb2 is denser than k1.
2636  h2_to_k1 = min(h2 - (h1+h2) * dr2b / dr21, h2_to_k1_rem)
2637 
2638  if (h2 > h2_to_k1) then
2639  drcv = (rcvtgt(k1) - rcv(i,kb2))
2640 
2641  ! Use 2nd order upwind advection of spiciness, limited by the values
2642  ! in deeper thick layers to determine the detrained temperature and
2643  ! salinity.
2644  dspice_det = (ds_dt_gauge*drcv_ds(i)*(t(i,kb2)-t(i,kb1)) - &
2645  dt_ds_gauge*drcv_dt(i)*(s(i,kb2)-s(i,kb1))) * &
2646  (h2 - h2_to_k1) / (h1 + h2)
2647  dspice_lim = 0.0
2648  if (h(i,k1) > 10.0*angstrom) then
2649  dspice_lim = ds_dt_gauge*drcv_ds(i)*(t(i,k1)-t(i,kb2)) - &
2650  dt_ds_gauge*drcv_dt(i)*(s(i,k1)-s(i,kb2))
2651  if (dspice_det*dspice_lim <= 0.0) dspice_lim = 0.0
2652  endif
2653  if (k1<nz) then; if (h(i,k1+1) > 10.0*angstrom) then
2654  dspice_lim2 = ds_dt_gauge*drcv_ds(i)*(t(i,k1+1)-t(i,kb2)) - &
2655  dt_ds_gauge*drcv_dt(i)*(s(i,k1+1)-s(i,kb2))
2656  if ((dspice_det*dspice_lim2 > 0.0) .and. &
2657  (abs(dspice_lim2) > abs(dspice_lim))) dspice_lim = dspice_lim2
2658  endif; endif
2659  if (abs(dspice_det) > abs(dspice_lim)) dspice_det = dspice_lim
2660 
2661  i_denom = 1.0 / (drcv_ds(i)**2 + (dt_ds_gauge*drcv_dt(i))**2)
2662  t_det = t(i,kb2) + dt_ds_gauge * i_denom * &
2663  (dt_ds_gauge * drcv_dt(i) * drcv + drcv_ds(i) * dspice_det)
2664  s_det = s(i,kb2) + i_denom * &
2665  (drcv_ds(i) * drcv - dt_ds_gauge * drcv_dt(i) * dspice_det)
2666  ! The detrained values of R0 are based on changes in T and S.
2667  r0_det = r0(i,kb2) + (t_det-t(i,kb2)) * dr0_dt(i) + &
2668  (s_det-s(i,kb2)) * dr0_ds(i)
2669 
2670  ! Now that the properties of the detrained water are known,
2671  ! potentially limit the amount of water that is detrained to
2672  ! avoid creating unphysical properties in the remaining water.
2673  ih2f = 1.0 / (h2 - h2_to_k1)
2674 
2675  t_min = min(t(i,kb2), t(i,kb1)) - cs%Allowed_T_chg
2676  t_max = max(t(i,kb2), t(i,kb1)) + cs%Allowed_T_chg
2677  t_new = (h2*t(i,kb2) - h2_to_k1*t_det)*ih2f
2678  if (t_new < t_min) then
2679  h2_to_k1_lim = h2 * (t(i,kb2) - t_min) / (t_det - t_min)
2680 ! write(mesg,'("Low temperature limits det to ", &
2681 ! & 1pe12.5, " from ", 1pe12.5, " at ", 1pg11.4,"E, ",1pg11.4,"N. T=", &
2682 ! & 5(1pe12.5))') &
2683 ! h2_to_k1_lim, h2_to_k1, G%geoLonT(i,j), G%geoLatT(i,j), &
2684 ! T_new, T(i,kb2), T(i,kb1), T_det, T_new-T_min
2685 ! call MOM_error(WARNING, mesg)
2686  h2_to_k1 = h2_to_k1_lim
2687  ih2f = 1.0 / (h2 - h2_to_k1)
2688  elseif (t_new > t_max) then
2689  h2_to_k1_lim = h2 * (t(i,kb2) - t_max) / (t_det - t_max)
2690 ! write(mesg,'("High temperature limits det to ", &
2691 ! & 1pe12.5, " from ", 1pe12.5, " at ", 1pg11.4,"E, ",1pg11.4,"N. T=", &
2692 ! & 5(1pe12.5))') &
2693 ! h2_to_k1_lim, h2_to_k1, G%geoLonT(i,j), G%geoLatT(i,j), &
2694 ! T_new, T(i,kb2), T(i,kb1), T_det, T_new-T_max
2695 ! call MOM_error(WARNING, mesg)
2696  h2_to_k1 = h2_to_k1_lim
2697  ih2f = 1.0 / (h2 - h2_to_k1)
2698  endif
2699  s_min = max(min(s(i,kb2), s(i,kb1)) - cs%Allowed_S_chg, 0.0)
2700  s_max = max(s(i,kb2), s(i,kb1)) + cs%Allowed_S_chg
2701  s_new = (h2*s(i,kb2) - h2_to_k1*s_det)*ih2f
2702  if (s_new < s_min) then
2703  h2_to_k1_lim = h2 * (s(i,kb2) - s_min) / (s_det - s_min)
2704 ! write(mesg,'("Low salinity limits det to ", &
2705 ! & 1pe12.5, " from ", 1pe12.5, " at ", 1pg11.4,"E, ",1pg11.4,"N. S=", &
2706 ! & 5(1pe12.5))') &
2707 ! h2_to_k1_lim, h2_to_k1, G%geoLonT(i,j), G%geoLatT(i,j), &
2708 ! S_new, S(i,kb2), S(i,kb1), S_det, S_new-S_min
2709 ! call MOM_error(WARNING, mesg)
2710  h2_to_k1 = h2_to_k1_lim
2711  ih2f = 1.0 / (h2 - h2_to_k1)
2712  elseif (s_new > s_max) then
2713  h2_to_k1_lim = h2 * (s(i,kb2) - s_max) / (s_det - s_max)
2714 ! write(mesg,'("High salinity limits det to ", &
2715 ! & 1pe12.5, " from ", 1pe12.5, " at ", 1pg11.4,"E, ",1pg11.4,"N. S=", &
2716 ! & 5(1pe12.5))') &
2717 ! h2_to_k1_lim, h2_to_k1, G%geoLonT(i,j), G%geoLatT(i,j), &
2718 ! S_new, S(i,kb2), S(i,kb1), S_det, S_new-S_max
2719 ! call MOM_error(WARNING, mesg)
2720  h2_to_k1 = h2_to_k1_lim
2721  ih2f = 1.0 / (h2 - h2_to_k1)
2722  endif
2723 
2724  ihk1 = 1.0 / (h(i,k1) + h_neglect + h2_to_k1)
2725  rcv(i,k1) = ((h(i,k1)+h_neglect)*rcv(i,k1) + h2_to_k1*rcvtgt(k1)) * ihk1
2726  rcv(i,kb2) = rcv(i,kb2) - h2_to_k1*drcv*ih2f
2727 
2728  t(i,kb2) = (h2*t(i,kb2) - h2_to_k1*t_det)*ih2f
2729  t(i,k1) = ((h(i,k1)+h_neglect)*t(i,k1) + h2_to_k1*t_det) * ihk1
2730 
2731  s(i,kb2) = (h2*s(i,kb2) - h2_to_k1*s_det) * ih2f
2732  s(i,k1) = ((h(i,k1)+h_neglect)*s(i,k1) + h2_to_k1*s_det) * ihk1
2733 
2734  ! Changes in R0 are based on changes in T and S.
2735  r0(i,kb2) = (h2*r0(i,kb2) - h2_to_k1*r0_det) * ih2f
2736  r0(i,k1) = ((h(i,k1)+h_neglect)*r0(i,k1) + h2_to_k1*r0_det) * ihk1
2737  else
2738  ! h2==h2_to_k1 can happen if dR2b = 0 exactly, but this is very
2739  ! unlikely. In this case the entirety of layer kb2 is detrained.
2740  h2_to_k1 = h2 ! These 2 lines are probably unnecessary.
2741  ihk1 = 1.0 / (h(i,k1) + h2)
2742 
2743  rcv(i,k1) = (h(i,k1)*rcv(i,k1) + h2*rcv(i,kb2)) * ihk1
2744  t(i,k1) = (h(i,k1)*t(i,k1) + h2*t(i,kb2)) * ihk1
2745  s(i,k1) = (h(i,k1)*s(i,k1) + h2*s(i,kb2)) * ihk1
2746  r0(i,k1) = (h(i,k1)*r0(i,k1) + h2*r0(i,kb2)) * ihk1
2747  endif
2748 
2749  h(i,k1) = h(i,k1) + h2_to_k1
2750  h(i,kb2) = h(i,kb2) - h2_to_k1 ; h2 = h(i,kb2)
2751  ! dPE_extrap should be positive here.
2752  dpe_extrap = i2rho0*(r0_det-r0(i,kb2))*h2_to_k1*h2
2753 
2754  d_ea(i,kb2) = d_ea(i,kb2) - h2_to_k1
2755  d_ea(i,k1) = d_ea(i,k1) + h2_to_k1
2756  h2_to_k1_rem = max(h2_to_k1_rem - h2_to_k1, 0.0)
2757  endif
2758  endif ! Detrainment by extrapolation.
2759 
2760  endif ! Detrainment to the interior at all.
2761 
2762  ! Does some of the detrained water go into the lower buffer layer?
2763  h_det_h2 = max(h_min_bl-(h1+h2), 0.0)
2764  if (h_det_h2 > 0.0) then
2765  ! Detrained water will go into both upper and lower buffer layers.
2766  ! h(kb2) will be h_min_bl, but h(kb1) may be larger if there was already
2767  ! ample detrainment; all water in layer kb1 moves into layer kb2.
2768 
2769  ! Determine the fluxes between the various layers.
2770  h_det_to_h2 = min(h_to_bl, h_det_h2)
2771  h_ml_to_h2 = h_det_h2 - h_det_to_h2
2772  h_det_to_h1 = h_to_bl - h_det_to_h2
2773  h_ml_to_h1 = max(h_min_bl-h_det_to_h1,0.0)
2774 
2775  ih = 1.0/h_min_bl
2776  ihdet = 0.0 ; if (h_to_bl > 0.0) ihdet = 1.0 / h_to_bl
2777  ih1f = 1.0 / (h_det_to_h1 + h_ml_to_h1)
2778 
2779  r0(i,kb2) = ((h2*r0(i,kb2) + h1*r0(i,kb1)) + &
2780  (h_det_to_h2*r0_to_bl*ihdet + h_ml_to_h2*r0(i,0))) * ih
2781  r0(i,kb1) = (h_det_to_h1*r0_to_bl*ihdet + h_ml_to_h1*r0(i,0)) * ih1f
2782 
2783  rcv(i,kb2) = ((h2*rcv(i,kb2) + h1*rcv(i,kb1)) + &
2784  (h_det_to_h2*rcv_to_bl*ihdet + h_ml_to_h2*rcv(i,0))) * ih
2785  rcv(i,kb1) = (h_det_to_h1*rcv_to_bl*ihdet + h_ml_to_h1*rcv(i,0)) * ih1f
2786 
2787  t(i,kb2) = ((h2*t(i,kb2) + h1*t(i,kb1)) + &
2788  (h_det_to_h2*t_to_bl*ihdet + h_ml_to_h2*t(i,0))) * ih
2789  t(i,kb1) = (h_det_to_h1*t_to_bl*ihdet + h_ml_to_h1*t(i,0)) * ih1f
2790 
2791  s(i,kb2) = ((h2*s(i,kb2) + h1*s(i,kb1)) + &
2792  (h_det_to_h2*s_to_bl*ihdet + h_ml_to_h2*s(i,0))) * ih
2793  s(i,kb1) = (h_det_to_h1*s_to_bl*ihdet + h_ml_to_h1*s(i,0)) * ih1f
2794 
2795  ! Recall that h1 = h(i,kb1) & h2 = h(i,kb2).
2796  d_ea(i,1) = d_ea(i,1) - (h_ml_to_h1 + h_ml_to_h2)
2797  d_ea(i,kb1) = d_ea(i,kb1) + ((h_det_to_h1 + h_ml_to_h1) - h1)
2798  d_ea(i,kb2) = d_ea(i,kb2) + (h_min_bl - h2)
2799 
2800  h(i,kb1) = h_det_to_h1 + h_ml_to_h1 ; h(i,kb2) = h_min_bl
2801  h(i,0) = h(i,0) - (h_ml_to_h1 + h_ml_to_h2)
2802 
2803 
2804  if (allocated(cs%diag_PE_detrain) .or. allocated(cs%diag_PE_detrain2)) then
2805  r0_det = r0_to_bl*ihdet
2806  s1en = g_2 * idt_h2 * ( ((r0(i,kb2)-r0(i,kb1))*h1*h2 + &
2807  h_det_to_h2*( (r0(i,kb1)-r0_det)*h1 + (r0(i,kb2)-r0_det)*h2 ) + &
2808  h_ml_to_h2*( (r0(i,kb2)-r0(i,0))*h2 + (r0(i,kb1)-r0(i,0))*h1 + &
2809  (r0_det-r0(i,0))*h_det_to_h2 ) + &
2810  h_det_to_h1*h_ml_to_h1*(r0_det-r0(i,0))) - 2.0*gv%Rho0*dpe_extrap )
2811 
2812  if (allocated(cs%diag_PE_detrain)) &
2813  cs%diag_PE_detrain(i,j) = cs%diag_PE_detrain(i,j) + s1en
2814 
2815  if (allocated(cs%diag_PE_detrain2)) cs%diag_PE_detrain2(i,j) = &
2816  cs%diag_PE_detrain2(i,j) + s1en + idt_h2*rho0xg*dpe_extrap
2817  endif
2818 
2819  elseif ((h_to_bl > 0.0) .or. (h1 < h_min_bl) .or. (h2 < h_min_bl)) then
2820  ! Determine how much of the upper buffer layer will be moved into
2821  ! the lower buffer layer and the properties with which it is moving.
2822  ! This implementation assumes a 2nd-order upwind advection of density
2823  ! from the uppermost buffer layer into the next one down.
2824  h_from_ml = h_min_bl + max(h_min_bl-h2,0.0) - h1 - h_to_bl
2825  if (h_from_ml > 0.0) then
2826  ! Some water needs to be moved from the mixed layer so that the upper
2827  ! (and perhaps lower) buffer layers exceed their minimum thicknesses.
2828  dpe_extrap = dpe_extrap - i2rho0*h_from_ml*(r0_to_bl - r0(i,0)*h_to_bl)
2829  r0_to_bl = r0_to_bl + h_from_ml*r0(i,0)
2830  rcv_to_bl = rcv_to_bl + h_from_ml*rcv(i,0)
2831  t_to_bl = t_to_bl + h_from_ml*t(i,0)
2832  s_to_bl = s_to_bl + h_from_ml*s(i,0)
2833 
2834  h_to_bl = h_to_bl + h_from_ml
2835  h(i,0) = h(i,0) - h_from_ml
2836  d_ea(i,1) = d_ea(i,1) - h_from_ml
2837  endif
2838 
2839  ! The absolute value should be unnecessary and 1e9 is just a large number.
2840  b1 = 1.0e9
2841  if (r0(i,kb2) - r0(i,kb1) > 1.0e-9*abs(r0(i,kb1) - r0_det)) &
2842  b1 = abs(r0(i,kb1) - r0_det) / (r0(i,kb2) - r0(i,kb1))
2843  stays_min = max((1.0-b1)*h1 - b1*h2, 0.0, h_min_bl - h_to_bl)
2844  stays_max = h1 - max(h_min_bl-h2,0.0)
2845 
2846  scale_slope = 1.0
2847  if (stays_max <= stays_min) then
2848  stays = stays_max
2849  mergeable_bl = .false.
2850  if (stays_max < h1) scale_slope = (h1 - stays_min) / (h1 - stays_max)
2851  else
2852  ! There are numerous temporary variables used here that should not be
2853  ! used outside of this "else" branch: s1, s2, s3sq, I_ya, bh0
2854  bh0 = b1*h_to_bl
2855  i_ya = (h1 + h2) / ((h1 + h2) + h_to_bl)
2856  ! s1 is the amount staying that minimizes the PE increase.
2857  s1 = 0.5*(h1 + (h2 - bh0) * i_ya) ; s2 = h1 - s1
2858 
2859  if (s2 < 0.0) then
2860  ! The energy released by detrainment from the lower buffer layer can be
2861  ! used to mix water from the upper buffer layer into the lower one.
2862  s3sq = i_ya*max(bh0*h1-dpe_extrap, 0.0)
2863  else
2864  s3sq = i_ya*(bh0*h1-min(dpe_extrap,0.0))
2865  endif
2866 
2867  if (s3sq == 0.0) then
2868  ! There is a simple, exact solution to the quadratic equation, namely:
2869  stays = h1 ! This will revert to stays_max later.
2870  elseif (s2*s2 <= s3sq) then
2871  ! There is no solution with 0 PE change - use the minimum energy input.
2872  stays = s1
2873  else
2874  ! The following choose the solutions that are continuous with all water
2875  ! staying in the upper buffer layer when there is no detrainment,
2876  ! namely the + root when s2>0 and the - root otherwise. They also
2877  ! carefully avoid differencing large numbers, using s2 = (h1-s).
2878  if (bh0 <= 0.0) then ; stays = h1
2879  elseif (s2 > 0.0) then
2880  ! stays = s + sqrt(s2*s2 - s3sq) ! Note that s2 = h1-s
2881  if (s1 >= stays_max) then ; stays = stays_max
2882  elseif (s1 >= 0.0) then ; stays = s1 + sqrt(s2*s2 - s3sq)
2883  else ; stays = (h1*(s2-s1) - s3sq) / (-s1 + sqrt(s2*s2 - s3sq))
2884  endif
2885  else
2886  ! stays = s - sqrt(s2*s2 - s3sq) ! Note that s2 = h1-s & stays_min >= 0
2887  if (s1 <= stays_min) then ; stays = stays_min
2888  else ; stays = (h1*(s1-s2) + s3sq) / (s1 + sqrt(s2*s2 - s3sq))
2889  endif
2890  endif
2891  endif
2892 
2893  ! Limit the amount that stays so that the motion of water is from the
2894  ! upper buffer layer into the lower, but no more than is in the upper
2895  ! layer, and the water left in the upper layer is no lighter than the
2896  ! detrained water.
2897  if (stays >= stays_max) then ; stays = stays_max
2898  elseif (stays < stays_min) then ; stays = stays_min
2899  endif
2900  endif
2901 
2902  dpe_det = g_2*((r0(i,kb1)*h_to_bl - r0_to_bl)*stays + &
2903  (r0(i,kb2)-r0(i,kb1)) * (h1-stays) * &
2904  (h2 - scale_slope*stays*((h1+h2)+h_to_bl)/(h1+h2)) ) - &
2905  rho0xg*dpe_extrap
2906 
2907  if (dpe_time_ratio*h_to_bl > h_to_bl+h(i,0)) then
2908  dpe_ratio = (h_to_bl+h(i,0)) / h_to_bl
2909  else
2910  dpe_ratio = dpe_time_ratio
2911  endif
2912 
2913  if ((mergeable_bl) .and. (num_events*dpe_ratio*dpe_det > dpe_merge)) then
2914  ! It is energetically preferable to merge the two buffer layers, detrain
2915  ! them into interior layer (k0), move the remaining upper buffer layer
2916  ! water into the lower buffer layer, and detrain undiluted into the
2917  ! upper buffer layer.
2918  h1_to_k0 = (h1-stays_merge)
2919  stays = max(h_min_bl-h_to_bl,0.0)
2920  h1_to_h2 = stays_merge - stays
2921 
2922  ihk0 = 1.0 / ((h1_to_k0 + h2) + h(i,k0))
2923  ih1f = 1.0 / (h_to_bl + stays); ih2f = 1.0 / h1_to_h2
2924  ih12 = 1.0 / (h1 + h2)
2925 
2926  drcv_2dz = (rcv(i,kb1) - rcv(i,kb2)) * ih12
2927  drcv_stays = drcv_2dz*(h1_to_k0 + h1_to_h2)
2928  drcv_det = - drcv_2dz*(stays + h1_to_h2)
2929  rcv(i,k0) = ((h1_to_k0*(rcv(i,kb1) + drcv_det) + &
2930  h2*rcv(i,kb2)) + h(i,k0)*rcv(i,k0)) * ihk0
2931  rcv(i,kb2) = rcv(i,kb1) + drcv_2dz*(h1_to_k0-stays)
2932  rcv(i,kb1) = (rcv_to_bl + stays*(rcv(i,kb1) + drcv_stays)) * ih1f
2933 
2934  ! Use 2nd order upwind advection of spiciness, limited by the value in
2935  ! the water from the mixed layer to determine the temperature and
2936  ! salinity of the water that stays in the buffer layers.
2937  i_denom = 1.0 / (drcv_ds(i)**2 + (dt_ds_gauge*drcv_dt(i))**2)
2938  dspice_2dz = (ds_dt_gauge*drcv_ds(i)*(t(i,kb1)-t(i,kb2)) - &
2939  dt_ds_gauge*drcv_dt(i)*(s(i,kb1)-s(i,kb2))) * ih12
2940  dspice_lim = (ds_dt_gauge*dr0_ds(i)*(t_to_bl-t(i,kb1)*h_to_bl) - &
2941  dt_ds_gauge*dr0_dt(i)*(s_to_bl-s(i,kb1)*h_to_bl)) / h_to_bl
2942  if (dspice_lim * dspice_2dz <= 0.0) dspice_2dz = 0.0
2943 
2944  if (stays > 0.0) then
2945  ! Limit the spiciness of the water that stays in the upper buffer layer.
2946  if (abs(dspice_lim) < abs(dspice_2dz*(h1_to_k0 + h1_to_h2))) &
2947  dspice_2dz = dspice_lim/(h1_to_k0 + h1_to_h2)
2948 
2949  dspice_stays = dspice_2dz*(h1_to_k0 + h1_to_h2)
2950  t_stays = t(i,kb1) + dt_ds_gauge * i_denom * &
2951  (dt_ds_gauge * drcv_dt(i) * drcv_stays + drcv_ds(i) * dspice_stays)
2952  s_stays = s(i,kb1) + i_denom * &
2953  (drcv_ds(i) * drcv_stays - dt_ds_gauge * drcv_dt(i) * dspice_stays)
2954  ! The values of R0 are based on changes in T and S.
2955  r0_stays = r0(i,kb1) + (t_stays-t(i,kb1)) * dr0_dt(i) + &
2956  (s_stays-s(i,kb1)) * dr0_ds(i)
2957  else
2958  ! Limit the spiciness of the water that moves into the lower buffer layer.
2959  if (abs(dspice_lim) < abs(dspice_2dz*h1_to_k0)) &
2960  dspice_2dz = dspice_lim/h1_to_k0
2961  ! These will be multiplied by 0 later.
2962  t_stays = 0.0 ; s_stays = 0.0 ; r0_stays = 0.0
2963  endif
2964 
2965  dspice_det = - dspice_2dz*(stays + h1_to_h2)
2966  t_det = t(i,kb1) + dt_ds_gauge * i_denom * &
2967  (dt_ds_gauge * drcv_dt(i) * drcv_det + drcv_ds(i) * dspice_det)
2968  s_det = s(i,kb1) + i_denom * &
2969  (drcv_ds(i) * drcv_det - dt_ds_gauge * drcv_dt(i) * dspice_det)
2970  ! The values of R0 are based on changes in T and S.
2971  r0_det = r0(i,kb1) + (t_det-t(i,kb1)) * dr0_dt(i) + &
2972  (s_det-s(i,kb1)) * dr0_ds(i)
2973 
2974  t(i,k0) = ((h1_to_k0*t_det + h2*t(i,kb2)) + h(i,k0)*t(i,k0)) * ihk0
2975  t(i,kb2) = (h1*t(i,kb1) - stays*t_stays - h1_to_k0*t_det) * ih2f
2976  t(i,kb1) = (t_to_bl + stays*t_stays) * ih1f
2977 
2978  s(i,k0) = ((h1_to_k0*s_det + h2*s(i,kb2)) + h(i,k0)*s(i,k0)) * ihk0
2979  s(i,kb2) = (h1*s(i,kb1) - stays*s_stays - h1_to_k0*s_det) * ih2f
2980  s(i,kb1) = (s_to_bl + stays*s_stays) * ih1f
2981 
2982  r0(i,k0) = ((h1_to_k0*r0_det + h2*r0(i,kb2)) + h(i,k0)*r0(i,k0)) * ihk0
2983  r0(i,kb2) = (h1*r0(i,kb1) - stays*r0_stays - h1_to_k0*r0_det) * ih2f
2984  r0(i,kb1) = (r0_to_bl + stays*r0_stays) * ih1f
2985 
2986 ! ! The following is 2nd-order upwind advection without limiters.
2987 ! dT_2dz = (T(i,kb1) - T(i,kb2)) * Ih12
2988 ! T(i,k0) = (h1_to_k0*(T(i,kb1) - dT_2dz*(stays+h1_to_h2)) + &
2989 ! h2*T(i,kb2) + h(i,k0)*T(i,k0)) * Ihk0
2990 ! T(i,kb2) = T(i,kb1) + dT_2dz*(h1_to_k0-stays)
2991 ! T(i,kb1) = (T_to_bl + stays*(T(i,kb1) + &
2992 ! dT_2dz*(h1_to_k0 + h1_to_h2))) * Ih1f
2993 ! dS_2dz = (S(i,kb1) - S(i,kb2)) * Ih12
2994 ! S(i,k0) = (h1_to_k0*(S(i,kb1) - dS_2dz*(stays+h1_to_h2)) + &
2995 ! h2*S(i,kb2) + h(i,k0)*S(i,k0)) * Ihk0
2996 ! S(i,kb2) = S(i,kb1) + dS_2dz*(h1_to_k0-stays)
2997 ! S(i,kb1) = (S_to_bl + stays*(S(i,kb1) + &
2998 ! dS_2dz*(h1_to_k0 + h1_to_h2))) * Ih1f
2999 ! dR0_2dz = (R0(i,kb1) - R0(i,kb2)) * Ih12
3000 ! R0(i,k0) = (h1_to_k0*(R0(i,kb1) - dR0_2dz*(stays+h1_to_h2)) + &
3001 ! h2*R0(i,kb2) + h(i,k0)*R0(i,k0)) * Ihk0
3002 ! R0(i,kb2) = R0(i,kb1) + dR0_2dz*(h1_to_k0-stays)
3003 ! R0(i,kb1) = (R0_to_bl + stays*(R0(i,kb1) + &
3004 ! dR0_2dz*(h1_to_k0 + h1_to_h2))) * Ih1f
3005 
3006  d_ea(i,kb1) = (d_ea(i,kb1) + h_to_bl) + (stays - h1)
3007  d_ea(i,kb2) = d_ea(i,kb2) + (h1_to_h2 - h2)
3008  d_ea(i,k0) = d_ea(i,k0) + (h1_to_k0 + h2)
3009 
3010  h(i,kb1) = stays + h_to_bl
3011  h(i,kb2) = h1_to_h2
3012  h(i,k0) = h(i,k0) + (h1_to_k0 + h2)
3013  if (allocated(cs%diag_PE_detrain)) &
3014  cs%diag_PE_detrain(i,j) = cs%diag_PE_detrain(i,j) + idt_h2*dpe_merge
3015  if (allocated(cs%diag_PE_detrain2)) cs%diag_PE_detrain2(i,j) = &
3016  cs%diag_PE_detrain2(i,j) + idt_h2*(dpe_det + rho0xg*dpe_extrap)
3017  else ! Not mergeable_bl.
3018  ! There is no further detrainment from the buffer layers, and the
3019  ! upper buffer layer water is distributed optimally between the
3020  ! upper and lower buffer layer.
3021  h1_to_h2 = h1 - stays
3022  ih1f = 1.0 / (h_to_bl + stays) ; ih2f = 1.0 / (h2 + h1_to_h2)
3023  ih = 1.0 / (h1 + h2)
3024  dr0_2dz = (r0(i,kb1) - r0(i,kb2)) * ih
3025  r0(i,kb2) = (h2*r0(i,kb2) + h1_to_h2*(r0(i,kb1) - &
3026  scale_slope*dr0_2dz*stays)) * ih2f
3027  r0(i,kb1) = (r0_to_bl + stays*(r0(i,kb1) + &
3028  scale_slope*dr0_2dz*h1_to_h2)) * ih1f
3029 
3030  ! Use 2nd order upwind advection of spiciness, limited by the value
3031  ! in the detrained water to determine the detrained temperature and
3032  ! salinity.
3033  dr0 = scale_slope*dr0_2dz*h1_to_h2
3034  dspice_stays = (ds_dt_gauge*dr0_ds(i)*(t(i,kb1)-t(i,kb2)) - &
3035  dt_ds_gauge*dr0_dt(i)*(s(i,kb1)-s(i,kb2))) * &
3036  scale_slope*h1_to_h2 * ih
3037  if (h_to_bl > 0.0) then
3038  dspice_lim = (ds_dt_gauge*dr0_ds(i)*(t_to_bl-t(i,kb1)*h_to_bl) - &
3039  dt_ds_gauge*dr0_dt(i)*(s_to_bl-s(i,kb1)*h_to_bl)) /&
3040  h_to_bl
3041  else
3042  dspice_lim = ds_dt_gauge*dr0_ds(i)*(t(i,0)-t(i,kb1)) - &
3043  dt_ds_gauge*dr0_dt(i)*(s(i,0)-s(i,kb1))
3044  endif
3045  if (dspice_stays*dspice_lim <= 0.0) then
3046  dspice_stays = 0.0
3047  elseif (abs(dspice_stays) > abs(dspice_lim)) then
3048  dspice_stays = dspice_lim
3049  endif
3050  i_denom = 1.0 / (dr0_ds(i)**2 + (dt_ds_gauge*dr0_dt(i))**2)
3051  t_stays = t(i,kb1) + dt_ds_gauge * i_denom * &
3052  (dt_ds_gauge * dr0_dt(i) * dr0 + dr0_ds(i) * dspice_stays)
3053  s_stays = s(i,kb1) + i_denom * &
3054  (dr0_ds(i) * dr0 - dt_ds_gauge * dr0_dt(i) * dspice_stays)
3055  ! The detrained values of Rcv are based on changes in T and S.
3056  rcv_stays = rcv(i,kb1) + (t_stays-t(i,kb1)) * drcv_dt(i) + &
3057  (s_stays-s(i,kb1)) * drcv_ds(i)
3058 
3059  t(i,kb2) = (h2*t(i,kb2) + h1*t(i,kb1) - t_stays*stays) * ih2f
3060  t(i,kb1) = (t_to_bl + stays*t_stays) * ih1f
3061  s(i,kb2) = (h2*s(i,kb2) + h1*s(i,kb1) - s_stays*stays) * ih2f
3062  s(i,kb1) = (s_to_bl + stays*s_stays) * ih1f
3063  rcv(i,kb2) = (h2*rcv(i,kb2) + h1*rcv(i,kb1) - rcv_stays*stays) * ih2f
3064  rcv(i,kb1) = (rcv_to_bl + stays*rcv_stays) * ih1f
3065 
3066 ! ! The following is 2nd-order upwind advection without limiters.
3067 ! dRcv_2dz = (Rcv(i,kb1) - Rcv(i,kb2)) * Ih
3068 ! dRcv = scale_slope*dRcv_2dz*h1_to_h2
3069 ! Rcv(i,kb2) = (h2*Rcv(i,kb2) + h1_to_h2*(Rcv(i,kb1) - &
3070 ! scale_slope*dRcv_2dz*stays)) * Ih2f
3071 ! Rcv(i,kb1) = (Rcv_to_bl + stays*(Rcv(i,kb1) + dRcv)) * Ih1f
3072 ! dT_2dz = (T(i,kb1) - T(i,kb2)) * Ih
3073 ! T(i,kb2) = (h2*T(i,kb2) + h1_to_h2*(T(i,kb1) - &
3074 ! scale_slope*dT_2dz*stays)) * Ih2f
3075 ! T(i,kb1) = (T_to_bl + stays*(T(i,kb1) + &
3076 ! scale_slope*dT_2dz*h1_to_h2)) * Ih1f
3077 ! dS_2dz = (S(i,kb1) - S(i,kb2)) * Ih
3078 ! S(i,kb2) = (h2*S(i,kb2) + h1_to_h2*(S(i,kb1) - &
3079 ! scale_slope*dS_2dz*stays)) * Ih2f
3080 ! S(i,kb1) = (S_to_bl + stays*(S(i,kb1) + &
3081 ! scale_slope*dS_2dz*h1_to_h2)) * Ih1f
3082 
3083  d_ea(i,kb1) = d_ea(i,kb1) + ((stays - h1) + h_to_bl)
3084  d_ea(i,kb2) = d_ea(i,kb2) + h1_to_h2
3085 
3086  h(i,kb1) = stays + h_to_bl
3087  h(i,kb2) = h(i,kb2) + h1_to_h2
3088 
3089  if (allocated(cs%diag_PE_detrain)) &
3090  cs%diag_PE_detrain(i,j) = cs%diag_PE_detrain(i,j) + idt_h2*dpe_det
3091  if (allocated(cs%diag_PE_detrain2)) cs%diag_PE_detrain2(i,j) = &
3092  cs%diag_PE_detrain2(i,j) + idt_h2*(dpe_det + rho0xg*dpe_extrap)
3093  endif
3094  endif ! End of detrainment...
3095 
3096  enddo ! i loop
3097 

◆ resort_ml()

subroutine mom_bulk_mixed_layer::resort_ml ( real, dimension( g %isd: g %ied,0: gv %ke), intent(inout)  h,
real, dimension( g %isd: g %ied,0: gv %ke), intent(inout)  T,
real, dimension( g %isd: g %ied,0: gv %ke), intent(inout)  S,
real, dimension( g %isd: g %ied,0: gv %ke), intent(inout)  R0,
real, dimension( g %isd: g %ied,0: gv %ke), intent(inout)  Rcv,
real, dimension( gv %ke), intent(in)  RcvTgt,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  eps,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  d_ea,
real, dimension( g %isd: g %ied, gv %ke), intent(inout)  d_eb,
integer, dimension( g %isd: g %ied, gv %ke), intent(in)  ksort,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(bulkmixedlayer_cs), pointer  CS,
real, dimension( g %isd: g %ied), intent(in)  dR0_dT,
real, dimension( g %isd: g %ied), intent(in)  dR0_dS,
real, dimension( g %isd: g %ied), intent(in)  dRcv_dT,
real, dimension( g %isd: g %ied), intent(in)  dRcv_dS 
)
private

This subroutine actually moves properties between layers to achieve a resorted state, with all of the resorted water either moved into the correct interior layers or in the top nkmb layers.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in,out]hLayer thickness [H ~> m or kg m-2]. Layer 0 is the new mixed layer.
[in,out]tLayer temperatures [degC].
[in,out]sLayer salinities [ppt].
[in,out]r0Potential density referenced to surface pressure [R ~> kg m-3].
[in,out]rcvThe coordinate defining potential density [R ~> kg m-3].
[in]rcvtgtThe target value of Rcv for each layer [R ~> kg m-3].
[in,out]epsThe (small) thickness that must remain in each layer [H ~> m or kg m-2].
[in,out]d_eaThe upward increase across a layer in the entrainment from above [H ~> m or kg m-2]. Positive d_ea goes with layer thickness increases.
[in,out]d_ebThe downward increase across a layer in the entrainment from below [H ~> m or kg m-2]. Positive values go with mass gain by a layer.
[in]ksortThe density-sorted k-indicies.
csThe control structure for this module.
[in]dr0_dtThe partial derivative of potential density referenced to the surface with potential temperature [R degC-1 ~> kg m-3 degC-1].
[in]dr0_dsThe partial derivative of cpotential density referenced to the surface with salinity, [R ppt-1 ~> kg m-3 ppt-1].
[in]drcv_dtThe partial derivative of coordinate defining potential density with potential temperature [R degC-1 ~> kg m-3 degC-1].
[in]drcv_dsThe partial derivative of coordinate defining potential density with salinity, [R ppt-1 ~> kg m-3 ppt-1].

Definition at line 1891 of file MOM_bulk_mixed_layer.F90.

1893  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1894  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid
1895  !! structure.
1896  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: h !< Layer thickness [H ~> m or kg m-2].
1897  !! Layer 0 is the new mixed layer.
1898  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: T !< Layer temperatures [degC].
1899  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: S !< Layer salinities [ppt].
1900  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: R0 !< Potential density referenced to
1901  !! surface pressure [R ~> kg m-3].
1902  real, dimension(SZI_(G),SZK0_(GV)), intent(inout) :: Rcv !< The coordinate defining
1903  !! potential density [R ~> kg m-3].
1904  real, dimension(SZK_(GV)), intent(in) :: RcvTgt !< The target value of Rcv for each
1905  !! layer [R ~> kg m-3].
1906  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: eps !< The (small) thickness that must
1907  !! remain in each layer [H ~> m or kg m-2].
1908  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: d_ea !< The upward increase across a
1909  !! layer in the entrainment from
1910  !! above [H ~> m or kg m-2].
1911  !! Positive d_ea goes with layer
1912  !! thickness increases.
1913  real, dimension(SZI_(G),SZK_(GV)), intent(inout) :: d_eb !< The downward increase across a
1914  !! layer in the entrainment from
1915  !! below [H ~> m or kg m-2]. Positive values go
1916  !! with mass gain by a layer.
1917  integer, dimension(SZI_(G),SZK_(GV)), intent(in) :: ksort !< The density-sorted k-indicies.
1918  type(bulkmixedlayer_CS), pointer :: CS !< The control structure for this
1919  !! module.
1920  real, dimension(SZI_(G)), intent(in) :: dR0_dT !< The partial derivative of
1921  !! potential density referenced
1922  !! to the surface with potential
1923  !! temperature [R degC-1 ~> kg m-3 degC-1].
1924  real, dimension(SZI_(G)), intent(in) :: dR0_dS !< The partial derivative of
1925  !! cpotential density referenced
1926  !! to the surface with salinity,
1927  !! [R ppt-1 ~> kg m-3 ppt-1].
1928  real, dimension(SZI_(G)), intent(in) :: dRcv_dT !< The partial derivative of
1929  !! coordinate defining potential
1930  !! density with potential
1931  !! temperature [R degC-1 ~> kg m-3 degC-1].
1932  real, dimension(SZI_(G)), intent(in) :: dRcv_dS !< The partial derivative of
1933  !! coordinate defining potential
1934  !! density with salinity,
1935  !! [R ppt-1 ~> kg m-3 ppt-1].
1936 
1937 ! If there are no massive light layers above the deepest of the mixed- and
1938 ! buffer layers, do nothing (except perhaps to reshuffle these layers).
1939 ! If there are nkbl or fewer layers above the deepest mixed- or buffer-
1940 ! layers, move them (in sorted order) into the buffer layers, even if they
1941 ! were previously interior layers.
1942 ! If there are interior layers that are intermediate in density (both in-situ
1943 ! and the coordinate density (sigma-2)) between the newly forming mixed layer
1944 ! and a residual buffer- or mixed layer, and the number of massive layers above
1945 ! the deepest massive buffer or mixed layer is greater than nkbl, then split
1946 ! those buffer layers into peices that match the target density of the two
1947 ! nearest interior layers.
1948 ! Otherwise, if there are more than nkbl+1 remaining massive layers
1949 
1950  ! Local variables
1951  real :: h_move, h_tgt_old, I_hnew
1952  real :: dT_dS_wt2, dT_dR, dS_dR, I_denom
1953  real :: Rcv_int
1954  real :: T_up, S_up, R0_up, I_hup, h_to_up
1955  real :: T_dn, S_dn, R0_dn, I_hdn, h_to_dn
1956  real :: wt_dn
1957  real :: dR1, dR2
1958  real :: dPE, hmin, min_dPE, min_hmin
1959  real, dimension(SZK_(GV)) :: &
1960  h_tmp, R0_tmp, T_tmp, S_tmp, Rcv_tmp
1961  integer :: ks_min
1962  logical :: sorted, leave_in_layer
1963  integer :: ks_deep(SZI_(G)), k_count(SZI_(G)), ks2_reverse(SZI_(G), SZK_(GV))
1964  integer :: ks2(SZK_(GV))
1965  integer :: i, k, ks, is, ie, nz, k1, k2, k_tgt, k_src, k_int_top
1966  integer :: nks, nkmb, num_interior, top_interior_ks
1967 
1968  is = g%isc ; ie = g%iec ; nz = gv%ke
1969  nkmb = cs%nkml+cs%nkbl
1970 
1971  dt_ds_wt2 = cs%dT_dS_wt**2
1972 
1973 ! Find out how many massive layers are above the deepest buffer or mixed layer.
1974  do i=is,ie ; ks_deep(i) = -1 ; k_count(i) = 0 ; enddo
1975  do ks=nz,1,-1 ; do i=is,ie ; if (ksort(i,ks) > 0) then
1976  k = ksort(i,ks)
1977 
1978  if (h(i,k) > eps(i,k)) then
1979  if (ks_deep(i) == -1) then
1980  if (k <= nkmb) then
1981  ks_deep(i) = ks ; k_count(i) = k_count(i) + 1
1982  ks2_reverse(i,k_count(i)) = k
1983  endif
1984  else
1985  k_count(i) = k_count(i) + 1
1986  ks2_reverse(i,k_count(i)) = k
1987  endif
1988  endif
1989  endif ; enddo ; enddo
1990 
1991  do i=is,ie ; if (k_count(i) > 1) then
1992  ! This column might need to be reshuffled.
1993  nks = k_count(i)
1994 
1995  ! Put ks2 in the right order and check whether reshuffling is needed.
1996  sorted = .true.
1997  ks2(nks) = ks2_reverse(i,1)
1998  do ks=nks-1,1,-1
1999  ks2(ks) = ks2_reverse(i,1+nks-ks)
2000  if (ks2(ks) > ks2(ks+1)) sorted = .false.
2001  enddo
2002 
2003  ! Go to the next column of no reshuffling is needed.
2004  if (sorted) cycle
2005 
2006  ! Find out how many interior layers are being reshuffled. If none,
2007  ! then this is a simple swapping procedure.
2008  num_interior = 0 ; top_interior_ks = 0
2009  do ks=nks,1,-1 ; if (ks2(ks) > nkmb) then
2010  num_interior = num_interior+1 ; top_interior_ks = ks
2011  endif ; enddo
2012 
2013  if (num_interior >= 1) then
2014  ! Find the lightest interior layer with a target coordinate density
2015  ! greater than the newly forming mixed layer.
2016  do k=nkmb+1,nz ; if (rcv(i,0) < rcvtgt(k)) exit ; enddo
2017  k_int_top = k ; rcv_int = rcvtgt(k)
2018 
2019  i_denom = 1.0 / (drcv_ds(i)**2 + dt_ds_wt2*drcv_dt(i)**2)
2020  dt_dr = dt_ds_wt2*drcv_dt(i) * i_denom
2021  ds_dr = drcv_ds(i) * i_denom
2022 
2023 
2024  ! Examine whether layers can be split out of existence. Stop when there
2025  ! is a layer that cannot be handled this way, or when the topmost formerly
2026  ! interior layer has been dealt with.
2027  do ks = nks,top_interior_ks,-1
2028  k = ks2(ks)
2029  leave_in_layer = .false.
2030  if ((k > nkmb) .and. (rcv(i,k) <= rcvtgt(k))) then
2031  if (rcvtgt(k)-rcv(i,k) < cs%BL_split_rho_tol*(rcvtgt(k) - rcvtgt(k-1))) &
2032  leave_in_layer = .true.
2033  elseif (k > nkmb) then
2034  if (rcv(i,k)-rcvtgt(k) < cs%BL_split_rho_tol*(rcvtgt(k+1) - rcvtgt(k))) &
2035  leave_in_layer = .true.
2036  endif
2037 
2038  if (leave_in_layer) then
2039  ! Just drop this layer from the sorted list.
2040  nks = nks-1
2041  elseif (rcv(i,k) < rcv_int) then
2042  ! There is no interior layer with a target density that is intermediate
2043  ! between this layer and the mixed layer.
2044  exit
2045  else
2046  ! Try splitting the layer between two interior isopycnal layers.
2047  ! Find the target densities that bracket this layer.
2048  do k2=k_int_top+1,nz ; if (rcv(i,k) < rcvtgt(k2)) exit ; enddo
2049  if (k2>nz) exit
2050 
2051  ! This layer is bracketed in density between layers k2-1 and k2.
2052 
2053  dr1 = (rcvtgt(k2-1) - rcv(i,k)) ; dr2 = (rcvtgt(k2) - rcv(i,k))
2054  t_up = t(i,k) + dt_dr * dr1
2055  s_up = s(i,k) + ds_dr * dr1
2056  t_dn = t(i,k) + dt_dr * dr2
2057  s_dn = s(i,k) + ds_dr * dr2
2058 
2059  r0_up = r0(i,k) + (dt_dr*dr0_dt(i) + ds_dr*dr0_ds(i)) * dr1
2060  r0_dn = r0(i,k) + (dt_dr*dr0_dt(i) + ds_dr*dr0_ds(i)) * dr2
2061 
2062  ! Make sure the new properties are acceptable.
2063  if ((r0_up > r0(i,0)) .or. (r0_dn > r0(i,0))) &
2064  ! Avoid creating obviously unstable profiles.
2065  exit
2066 
2067  wt_dn = (rcv(i,k) - rcvtgt(k2-1)) / (rcvtgt(k2) - rcvtgt(k2-1))
2068  h_to_up = (h(i,k)-eps(i,k)) * (1.0 - wt_dn)
2069  h_to_dn = (h(i,k)-eps(i,k)) * wt_dn
2070 
2071  i_hup = 1.0 / (h(i,k2-1) + h_to_up)
2072  i_hdn = 1.0 / (h(i,k2) + h_to_dn)
2073  r0(i,k2-1) = (r0(i,k2)*h(i,k2-1) + r0_up*h_to_up) * i_hup
2074  r0(i,k2) = (r0(i,k2)*h(i,k2) + r0_dn*h_to_dn) * i_hdn
2075 
2076  t(i,k2-1) = (t(i,k2)*h(i,k2-1) + t_up*h_to_up) * i_hup
2077  t(i,k2) = (t(i,k2)*h(i,k2) + t_dn*h_to_dn) * i_hdn
2078  s(i,k2-1) = (s(i,k2)*h(i,k2-1) + s_up*h_to_up) * i_hup
2079  s(i,k2) = (s(i,k2)*h(i,k2) + s_dn*h_to_dn) * i_hdn
2080  rcv(i,k2-1) = (rcv(i,k2)*h(i,k2-1) + rcvtgt(k2-1)*h_to_up) * i_hup
2081  rcv(i,k2) = (rcv(i,k2)*h(i,k2) + rcvtgt(k2)*h_to_dn) * i_hdn
2082 
2083  h(i,k) = eps(i,k)
2084  h(i,k2) = h(i,k2) + h_to_dn
2085  h(i,k2-1) = h(i,k2-1) + h_to_up
2086 
2087  if (k > k2-1) then
2088  d_eb(i,k) = d_eb(i,k) - h_to_up
2089  d_eb(i,k2-1) = d_eb(i,k2-1) + h_to_up
2090  elseif (k < k2-1) then
2091  d_ea(i,k) = d_ea(i,k) - h_to_up
2092  d_ea(i,k2-1) = d_ea(i,k2-1) + h_to_up
2093  endif
2094  if (k > k2) then
2095  d_eb(i,k) = d_eb(i,k) - h_to_dn
2096  d_eb(i,k2) = d_eb(i,k2) + h_to_dn
2097  elseif (k < k2) then
2098  d_ea(i,k) = d_ea(i,k) - h_to_dn
2099  d_ea(i,k2) = d_ea(i,k2) + h_to_dn
2100  endif
2101  nks = nks-1
2102  endif
2103  enddo
2104  endif
2105 
2106  do while (nks > nkmb)
2107  ! Having already tried to move surface layers into the interior, there
2108  ! are still too many layers, and layers must be merged until nks=nkmb.
2109  ! Examine every merger of a layer with its neighbors, and merge the ones
2110  ! that increase the potential energy the least. If there are layers
2111  ! with (apparently?) negative potential energy change, choose the one
2112  ! with the smallest total thickness. Repeat until nkmb layers remain.
2113  ! Choose the smaller value for the remaining index for convenience.
2114 
2115  ks_min = -1 ; min_dpe = 1.0 ; min_hmin = 0.0
2116  do ks=1,nks-1
2117  k1 = ks2(ks) ; k2 = ks2(ks+1)
2118  dpe = max(0.0, (r0(i,k2)-r0(i,k1)) * h(i,k1) * h(i,k2))
2119  hmin = min(h(i,k1)-eps(i,k1), h(i,k2)-eps(i,k2))
2120  if ((ks_min < 0) .or. (dpe < min_dpe) .or. &
2121  ((dpe <= 0.0) .and. (hmin < min_hmin))) then
2122  ks_min = ks ; min_dpe = dpe ; min_hmin = hmin
2123  endif
2124  enddo
2125 
2126  ! Now merge the two layers that do the least damage.
2127  k1 = ks2(ks_min) ; k2 = ks2(ks_min+1)
2128  if (k1 < k2) then ; k_tgt = k1 ; k_src = k2
2129  else ; k_tgt = k2 ; k_src = k1 ; ks2(ks_min) = k2 ; endif
2130 
2131  h_tgt_old = h(i,k_tgt)
2132  h_move = h(i,k_src)-eps(i,k_src)
2133  h(i,k_src) = eps(i,k_src)
2134  h(i,k_tgt) = h(i,k_tgt) + h_move
2135  i_hnew = 1.0 / (h(i,k_tgt))
2136  r0(i,k_tgt) = (r0(i,k_tgt)*h_tgt_old + r0(i,k_src)*h_move) * i_hnew
2137 
2138  t(i,k_tgt) = (t(i,k_tgt)*h_tgt_old + t(i,k_src)*h_move) * i_hnew
2139  s(i,k_tgt) = (s(i,k_tgt)*h_tgt_old + s(i,k_src)*h_move) * i_hnew
2140  rcv(i,k_tgt) = (rcv(i,k_tgt)*h_tgt_old + rcv(i,k_src)*h_move) * i_hnew
2141 
2142  d_eb(i,k_src) = d_eb(i,k_src) - h_move
2143  d_eb(i,k_tgt) = d_eb(i,k_tgt) + h_move
2144 
2145  ! Remove the newly missing layer from the sorted list.
2146  do ks=ks_min+1,nks ; ks2(ks) = ks2(ks+1) ; enddo
2147  nks = nks-1
2148  enddo
2149 
2150  ! Check again whether the layers are sorted, and go on to the next column
2151  ! if they are.
2152  sorted = .true.
2153  do ks=1,nks-1 ; if (ks2(ks) > ks2(ks+1)) sorted = .false. ; enddo
2154  if (sorted) cycle
2155 
2156  if (nks > 1) then
2157  ! At this point, actually swap the properties of the layers, and place
2158  ! the remaining layers in order starting with nkmb.
2159 
2160  ! Save all the properties of the nkmb layers that might be replaced.
2161  do k=1,nkmb
2162  h_tmp(k) = h(i,k) ; r0_tmp(k) = r0(i,k)
2163  t_tmp(k) = t(i,k) ; s_tmp(k) = s(i,k) ; rcv_tmp(k) = rcv(i,k)
2164 
2165  h(i,k) = 0.0
2166  enddo
2167 
2168  do ks=nks,1,-1
2169  k_tgt = nkmb - nks + ks ; k_src = ks2(ks)
2170  if (k_tgt == k_src) then
2171  h(i,k_tgt) = h_tmp(k_tgt) ! This layer doesn't move, so put the water back.
2172  cycle
2173  endif
2174 
2175  ! Note below that eps=0 for k<=nkmb.
2176  if (k_src > nkmb) then
2177  h_move = h(i,k_src)-eps(i,k_src)
2178  h(i,k_src) = eps(i,k_src)
2179  h(i,k_tgt) = h_move
2180  r0(i,k_tgt) = r0(i,k_src)
2181 
2182  t(i,k_tgt) = t(i,k_src) ; s(i,k_tgt) = s(i,k_src)
2183  rcv(i,k_tgt) = rcv(i,k_src)
2184 
2185  d_eb(i,k_src) = d_eb(i,k_src) - h_move
2186  d_eb(i,k_tgt) = d_eb(i,k_tgt) + h_move
2187  else
2188  h(i,k_tgt) = h_tmp(k_src)
2189  r0(i,k_tgt) = r0_tmp(k_src)
2190 
2191  t(i,k_tgt) = t_tmp(k_src) ; s(i,k_tgt) = s_tmp(k_src)
2192  rcv(i,k_tgt) = rcv_tmp(k_src)
2193 
2194  if (k_src > k_tgt) then
2195  d_eb(i,k_src) = d_eb(i,k_src) - h_tmp(k_src)
2196  d_eb(i,k_tgt) = d_eb(i,k_tgt) + h_tmp(k_src)
2197  else
2198  d_ea(i,k_src) = d_ea(i,k_src) - h_tmp(k_src)
2199  d_ea(i,k_tgt) = d_ea(i,k_tgt) + h_tmp(k_src)
2200  endif
2201  endif
2202  enddo
2203  endif
2204 
2205  endif ; enddo
2206 

◆ sort_ml()

subroutine mom_bulk_mixed_layer::sort_ml ( real, dimension( g %isd: g %ied, gv %ke), intent(in)  h,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  R0,
real, dimension( g %isd: g %ied, gv %ke), intent(in)  eps,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(bulkmixedlayer_cs), pointer  CS,
integer, dimension( g %isd: g %ied, gv %ke), intent(out)  ksort 
)
private

This subroutine generates an array of indices that are sorted by layer density.

Parameters
[in]gThe ocean's grid structure.
[in]gvThe ocean's vertical grid structure.
[in]hLayer thickness [H ~> m or kg m-2].
[in]r0The potential density used to sort the layers [R ~> kg m-3].
[in]epsThe (small) thickness that must remain in each layer [H ~> m or kg m-2].
csThe control structure returned by a previous call to mixedlayer_init.
[out]ksortThe k-index to use in the sort.

Definition at line 1840 of file MOM_bulk_mixed_layer.F90.

1841  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure.
1842  type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
1843  real, dimension(SZI_(G),SZK_(GV)), intent(in) :: h !< Layer thickness [H ~> m or kg m-2].
1844  real, dimension(SZI_(G),SZK_(GV)), intent(in) :: R0 !< The potential density used to sort
1845  !! the layers [R ~> kg m-3].
1846  real, dimension(SZI_(G),SZK_(GV)), intent(in) :: eps !< The (small) thickness that must
1847  !! remain in each layer [H ~> m or kg m-2].
1848  type(bulkmixedlayer_CS), pointer :: CS !< The control structure returned by a
1849  !! previous call to mixedlayer_init.
1850  integer, dimension(SZI_(G),SZK_(GV)), intent(out) :: ksort !< The k-index to use in the sort.
1851 
1852  ! Local variables
1853  real :: R0sort(SZI_(G),SZK_(GV))
1854  integer :: nsort(SZI_(G))
1855  logical :: done_sorting(SZI_(G))
1856  integer :: i, k, ks, is, ie, nz, nkmb
1857 
1858  is = g%isc ; ie = g%iec ; nz = gv%ke
1859  nkmb = cs%nkml+cs%nkbl
1860 
1861  ! Come up with a sorted index list of layers with increasing R0.
1862  ! Assume that the layers below nkmb are already stably stratified.
1863  ! Only layers that are thicker than eps are in the list. Extra elements
1864  ! have an index of -1.
1865 
1866  ! This is coded using straight insertion, on the assumption that the
1867  ! layers are usually in the right order (or massless) anyway.
1868 
1869  do k=1,nz ; do i=is,ie ; ksort(i,k) = -1 ; enddo ; enddo
1870 
1871  do i=is,ie ; nsort(i) = 0 ; done_sorting(i) = .false. ; enddo
1872  do k=1,nz ; do i=is,ie ; if (h(i,k) > eps(i,k)) then
1873  if (done_sorting(i)) then ; ks = nsort(i) ; else
1874  do ks=nsort(i),1,-1
1875  if (r0(i,k) >= r0sort(i,ks)) exit
1876  r0sort(i,ks+1) = r0sort(i,ks) ; ksort(i,ks+1) = ksort(i,ks)
1877  enddo
1878  if ((k > nkmb) .and. (ks == nsort(i))) done_sorting(i) = .true.
1879  endif
1880 
1881  ksort(i,ks+1) = k
1882  r0sort(i,ks+1) = r0(i,k)
1883  nsort(i) = nsort(i) + 1
1884  endif ; enddo ; enddo
1885