MOM6
MOM_diabatic_driver.F90
Go to the documentation of this file.
1 !> This routine drives the diabatic/dianeutral physics for MOM
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 
8 use mom_debugging, only : hchksum
10 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
11 use mom_cpu_clock, only : clock_module_driver, clock_module, clock_routine
18 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
28 use mom_domains, only : pass_var, to_west, to_south, to_all, omit_corners
29 use mom_domains, only : create_group_pass, do_group_pass, group_pass_type
39 use mom_error_handler, only : mom_error, fatal, warning, calltree_showquery,mom_mesg
45 use mom_grid, only : ocean_grid_type
63 use mom_time_manager, only : time_type, real_to_time, operator(-), operator(<=)
70 use mom_wave_speed, only : wave_speeds
72 
73 
74 implicit none ; private
75 
76 #include <MOM_memory.h>
77 
78 public diabatic
82 public adiabatic
84 ! public legacy_diabatic
85 
86 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
87 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
88 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
89 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
90 
91 !> Control structure for this module
92 type, public:: diabatic_cs; private
93 
94  logical :: use_legacy_diabatic !< If true (default), use the a legacy version of the diabatic
95  !! algorithm. This is temporary and is needed to avoid change
96  !! in answers.
97  logical :: bulkmixedlayer !< If true, a refined bulk mixed layer is used with
98  !! nkml sublayers (and additional buffer layers).
99  logical :: use_energetic_pbl !< If true, use the implicit energetics planetary
100  !! boundary layer scheme to determine the diffusivity
101  !! in the surface boundary layer.
102  logical :: use_kpp !< If true, use CVMix/KPP boundary layer scheme to determine the
103  !! OBLD and the diffusivities within this layer.
104  logical :: use_kappa_shear !< If true, use the kappa_shear module to find the
105  !! shear-driven diapycnal diffusivity.
106  logical :: use_cvmix_shear !< If true, use the CVMix module to find the
107  !! shear-driven diapycnal diffusivity.
108  logical :: use_cvmix_ddiff !< If true, use the CVMix double diffusion module.
109  logical :: use_tidal_mixing !< If true, activate tidal mixing diffusivity.
110  logical :: use_cvmix_conv !< If true, use the CVMix module to get enhanced
111  !! mixing due to convection.
112  logical :: use_sponge !< If true, sponges may be applied anywhere in the
113  !! domain. The exact location and properties of
114  !! those sponges are set by calls to
115  !! initialize_sponge and set_up_sponge_field.
116  logical :: use_geothermal !< If true, apply geothermal heating.
117  logical :: use_int_tides !< If true, use the code that advances a separate set
118  !! of equations for the internal tide energy density.
119  logical :: epbl_is_additive !< If true, the diffusivity from ePBL is added to all
120  !! other diffusivities. Otherwise, the larger of kappa-
121  !! shear and ePBL diffusivities are used.
122  integer :: nmode = 1 !< Number of baroclinic modes to consider
123  real :: uniform_test_cg !< Uniform group velocity of internal tide
124  !! for testing internal tides [L T-1 ~> m s-1]
125  logical :: usealealgorithm !< If true, use the ALE algorithm rather than layered
126  !! isopycnal/stacked shallow water mode. This logical
127  !! passed by argument to diabatic_driver_init.
128  logical :: aggregate_fw_forcing !< Determines whether net incoming/outgoing surface
129  !! FW fluxes are applied separately or combined before
130  !! being applied.
131  real :: ml_mix_first !< The nondimensional fraction of the mixed layer
132  !! algorithm that is applied before diffusive mixing.
133  !! The default is 0, while 0.5 gives Strang splitting
134  !! and 1 is a sensible value too. Note that if there
135  !! are convective instabilities in the initial state,
136  !! the first call may do much more than the second.
137  integer :: nkbl !< The number of buffer layers (if bulk_mixed_layer)
138  logical :: massless_match_targets !< If true (the default), keep the T & S
139  !! consistent with the target values.
140  logical :: mix_boundary_tracers !< If true, mix the passive tracers in massless
141  !! layers at the bottom into the interior as though
142  !! a diffusivity of Kd_min_tr (see below) were
143  !! operating.
144  real :: kd_bbl_tr !< A bottom boundary layer tracer diffusivity that
145  !! will allow for explicitly specified bottom fluxes
146  !! [Z2 T-1 ~> m2 s-1]. The entrainment at the bottom is at
147  !! least sqrt(Kd_BBL_tr*dt) over the same distance.
148  real :: kd_min_tr !< A minimal diffusivity that should always be
149  !! applied to tracers, especially in massless layers
150  !! near the bottom [Z2 T-1 ~> m2 s-1].
151  real :: minimum_forcing_depth !< The smallest depth over which heat and freshwater
152  !! fluxes are applied [H ~> m or kg m-2].
153  real :: evap_cfl_limit = 0.8 !< The largest fraction of a layer that can be
154  !! evaporated in one time-step [nondim].
155  integer :: halo_ts_diff = 0 !< The temperature, salinity and thickness halo size that
156  !! must be valid for the diffusivity calculations.
157  logical :: usekpp = .false. !< use CVMix/KPP diffusivities and non-local transport
158  logical :: salt_reject_below_ml !< If true, add salt below mixed layer (layer mode only)
159  logical :: kppispassive !< If true, KPP is in passive mode, not changing answers.
160  logical :: debug !< If true, write verbose checksums for debugging purposes.
161  logical :: debugconservation !< If true, monitor conservation and extrema.
162  logical :: tracer_tridiag !< If true, use tracer_vertdiff instead of tridiagTS for
163  !< vertical diffusion of T and S
164  logical :: debug_energy_req !< If true, test the mixing energy requirement code.
165  type(diag_ctrl), pointer :: diag !< structure used to regulate timing of diagnostic output
166  real :: mlddensitydifference !< Density difference used to determine MLD_user [R ~> kg m-3]
167  real :: dz_subml_n2 !< The distance over which to calculate a diagnostic of the
168  !! average stratification at the base of the mixed layer [Z ~> m].
169 
170  !>@{ Diagnostic IDs
171  integer :: id_cg1 = -1 ! diag handle for mode-1 speed (BDM)
172  integer, allocatable, dimension(:) :: id_cn ! diag handle for all mode speeds (BDM)
173  integer :: id_wd = -1, id_ea = -1, id_eb = -1 ! used by layer diabatic
174  integer :: id_dudt_dia = -1, id_dvdt_dia = -1, id_ea_s = -1, id_eb_s = -1
175  integer :: id_ea_t = -1, id_eb_t = -1
176  integer :: id_kd_heat = -1, id_kd_salt = -1, id_kd_interface = -1, id_kd_epbl = -1
177  integer :: id_tdif = -1, id_tadv = -1, id_sdif = -1, id_sadv = -1
178  integer :: id_mld_003 = -1, id_mld_0125 = -1, id_mld_user = -1, id_mlotstsq = -1
179  integer :: id_submln2 = -1, id_brine_lay = -1
180 
181  ! diagnostic for fields prior to applying diapycnal physics
182  integer :: id_u_predia = -1, id_v_predia = -1, id_h_predia = -1
183  integer :: id_t_predia = -1, id_s_predia = -1, id_e_predia = -1
184 
185  integer :: id_diabatic_diff_temp_tend = -1
186  integer :: id_diabatic_diff_saln_tend = -1
187  integer :: id_diabatic_diff_heat_tend = -1
188  integer :: id_diabatic_diff_salt_tend = -1
189  integer :: id_diabatic_diff_heat_tend_2d = -1
190  integer :: id_diabatic_diff_salt_tend_2d = -1
191  integer :: id_diabatic_diff_h= -1
192 
193  integer :: id_boundary_forcing_h = -1
194  integer :: id_boundary_forcing_h_tendency = -1
195  integer :: id_boundary_forcing_temp_tend = -1
196  integer :: id_boundary_forcing_saln_tend = -1
197  integer :: id_boundary_forcing_heat_tend = -1
198  integer :: id_boundary_forcing_salt_tend = -1
199  integer :: id_boundary_forcing_heat_tend_2d = -1
200  integer :: id_boundary_forcing_salt_tend_2d = -1
201 
202  integer :: id_frazil_h = -1
203  integer :: id_frazil_temp_tend = -1
204  integer :: id_frazil_heat_tend = -1
205  integer :: id_frazil_heat_tend_2d = -1
206  !!@}
207 
208  logical :: diabatic_diff_tendency_diag = .false. !< If true calculate diffusive tendency diagnostics
209  logical :: boundary_forcing_tendency_diag = .false. !< If true calculate frazil diagnostics
210  logical :: frazil_tendency_diag = .false. !< If true calculate frazil tendency diagnostics
211  real, allocatable, dimension(:,:,:) :: frazil_heat_diag !< diagnose 3d heat tendency from frazil
212  real, allocatable, dimension(:,:,:) :: frazil_temp_diag !< diagnose 3d temp tendency from frazil
213 
214  type(diabatic_aux_cs), pointer :: diabatic_aux_csp => null() !< Control structure for a child module
215  type(entrain_diffusive_cs), pointer :: entrain_diffusive_csp => null() !< Control structure for a child module
216  type(bulkmixedlayer_cs), pointer :: bulkmixedlayer_csp => null() !< Control structure for a child module
217  type(energetic_pbl_cs), pointer :: energetic_pbl_csp => null() !< Control structure for a child module
218  type(regularize_layers_cs), pointer :: regularize_layers_csp => null() !< Control structure for a child module
219  type(geothermal_cs), pointer :: geothermal_csp => null() !< Control structure for a child module
220  type(int_tide_cs), pointer :: int_tide_csp => null() !< Control structure for a child module
221  type(int_tide_input_cs), pointer :: int_tide_input_csp => null() !< Control structure for a child module
222  type(int_tide_input_type), pointer :: int_tide_input => null() !< Control structure for a child module
223  type(opacity_cs), pointer :: opacity_csp => null() !< Control structure for a child module
224  type(set_diffusivity_cs), pointer :: set_diff_csp => null() !< Control structure for a child module
225  type(sponge_cs), pointer :: sponge_csp => null() !< Control structure for a child module
226  type(ale_sponge_cs), pointer :: ale_sponge_csp => null() !< Control structure for a child module
227  type(tracer_flow_control_cs), pointer :: tracer_flow_csp => null() !< Control structure for a child module
228  type(optics_type), pointer :: optics => null() !< Control structure for a child module
229  type(kpp_cs), pointer :: kpp_csp => null() !< Control structure for a child module
230  type(tidal_mixing_cs), pointer :: tidal_mixing_csp => null() !< Control structure for a child module
231  type(cvmix_conv_cs), pointer :: cvmix_conv_csp => null() !< Control structure for a child module
232  type(diapyc_energy_req_cs), pointer :: diapyc_en_rec_csp => null() !< Control structure for a child module
233 
234  type(group_pass_type) :: pass_hold_eb_ea !< For group halo pass
235  type(group_pass_type) :: pass_kv !< For group halo pass
236  type(diag_grid_storage) :: diag_grids_prev!< Stores diagnostic grids at some previous point in the algorithm
237  ! Data arrays for communicating between components
238  real, allocatable, dimension(:,:,:) :: kpp_nltheat !< KPP non-local transport for heat [m s-1]
239  real, allocatable, dimension(:,:,:) :: kpp_nltscalar !< KPP non-local transport for scalars [m s-1]
240  real, allocatable, dimension(:,:,:) :: kpp_buoy_flux !< KPP forcing buoyancy flux [L2 T-3 ~> m2 s-3]
241  real, allocatable, dimension(:,:) :: kpp_temp_flux !< KPP effective temperature flux [degC m s-1]
242  real, allocatable, dimension(:,:) :: kpp_salt_flux !< KPP effective salt flux [ppt m s-1]
243 
244  type(time_type), pointer :: time !< Pointer to model time (needed for sponges)
245 end type diabatic_cs
246 
247 ! clock ids
251 integer :: id_clock_kpp
252 
253 contains
254 
255 !> This subroutine imposes the diapycnal mass fluxes and the
256 !! accompanying diapycnal advection of momentum and tracers.
257 subroutine diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, &
258  G, GV, US, CS, WAVES)
259  type(ocean_grid_type), intent(inout) :: g !< ocean grid structure
260  type(verticalgrid_type), intent(in) :: gv !< ocean vertical grid structure
261  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
262  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
263  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
264  type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
265  !! unused have NULL ptrs
266  real, dimension(:,:), pointer :: hml !< Active mixed layer depth [m]
267  type(forcing), intent(inout) :: fluxes !< points to forcing fields
268  !! unused fields have NULL ptrs
269  type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and
270  type(accel_diag_ptrs), intent(inout) :: adp !< related points to accelerations in momentum
271  !! equations, to enable the later derived
272  !! diagnostics, like energy budgets
273  type(cont_diag_ptrs), intent(inout) :: cdp !< points to terms in continuity equations
274  real, intent(in) :: dt !< time increment [T ~> s]
275  type(time_type), intent(in) :: time_end !< Time at the end of the interval
276  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
277  type(diabatic_cs), pointer :: cs !< module control structure
278  type(wave_parameters_cs), optional, pointer :: waves !< Surface gravity waves
279 
280  ! local variables
281  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1) :: &
282  eta ! Interface heights before diapycnal mixing [m].
283  real, dimension(SZI_(G),SZJ_(G),CS%nMode) :: &
284  cn_igw ! baroclinic internal gravity wave speeds
285  real, dimension(SZI_(G),SZJ_(G),G%ke) :: temp_diag ! diagnostic array for temp
286  integer :: i, j, k, m, is, ie, js, je, nz
287  logical :: showcalltree ! If true, show the call tree
288 
289  if (g%ke == 1) return
290 
291  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
292 
293  if (.not. associated(cs)) call mom_error(fatal, "MOM_diabatic_driver: "// &
294  "Module must be initialized before it is used.")
295  if (dt == 0.0) call mom_error(fatal, "MOM_diabatic_driver: "// &
296  "diabatic was called with a zero length timestep.")
297  if (dt < 0.0) call mom_error(fatal, "MOM_diabatic_driver: "// &
298  "diabatic was called with a negative timestep.")
299 
300  showcalltree = calltree_showquery()
301 
302  ! Offer diagnostics of various state varables at the start of diabatic
303  ! these are mostly for debugging purposes.
304  if (cs%id_u_predia > 0) call post_data(cs%id_u_predia, u, cs%diag)
305  if (cs%id_v_predia > 0) call post_data(cs%id_v_predia, v, cs%diag)
306  if (cs%id_h_predia > 0) call post_data(cs%id_h_predia, h, cs%diag)
307  if (cs%id_T_predia > 0) call post_data(cs%id_T_predia, tv%T, cs%diag)
308  if (cs%id_S_predia > 0) call post_data(cs%id_S_predia, tv%S, cs%diag)
309  if (cs%id_e_predia > 0) then
310  call find_eta(h, tv, g, gv, us, eta, eta_to_m=1.0)
311  call post_data(cs%id_e_predia, eta, cs%diag)
312  endif
313 
314  if (cs%debug) then
315  call mom_state_chksum("Start of diabatic ", u, v, h, g, gv, us, haloshift=0)
316  call mom_forcing_chksum("Start of diabatic", fluxes, g, us, haloshift=0)
317  endif
318  if (cs%debugConservation) call mom_state_stats('Start of diabatic', u, v, h, tv%T, tv%S, g, gv, us)
319 
320  if (cs%debug_energy_req) &
321  call diapyc_energy_req_test(h, dt, tv, g, gv, us, cs%diapyc_en_rec_CSp)
322 
323  call cpu_clock_begin(id_clock_set_diffusivity)
324  call set_bbl_tke(u, v, h, fluxes, visc, g, gv, us, cs%set_diff_CSp)
325  call cpu_clock_end(id_clock_set_diffusivity)
326 
327  ! Frazil formation keeps the temperature above the freezing point.
328  ! make_frazil is deliberately called at both the beginning and at
329  ! the end of the diabatic processes.
330  if (associated(tv%T) .AND. associated(tv%frazil)) then
331  ! For frazil diagnostic, the first call covers the first half of the time step
332  call enable_averages(0.5*dt, time_end - real_to_time(0.5*us%T_to_s*dt), cs%diag)
333  if (cs%frazil_tendency_diag) then
334  do k=1,nz ; do j=js,je ; do i=is,ie
335  temp_diag(i,j,k) = tv%T(i,j,k)
336  enddo ; enddo ; enddo
337  endif
338 
339  if (associated(fluxes%p_surf_full)) then
340  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp, fluxes%p_surf_full, halo=cs%halo_TS_diff)
341  else
342  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp, halo=cs%halo_TS_diff)
343  endif
344  if (showcalltree) call calltree_waypoint("done with 1st make_frazil (diabatic)")
345 
346  if (cs%frazil_tendency_diag) then
347  call diagnose_frazil_tendency(tv, h, temp_diag, 0.5*dt, g, gv, cs)
348  if (cs%id_frazil_h > 0) call post_data(cs%id_frazil_h, h, cs%diag)
349  endif
350  call disable_averaging(cs%diag)
351  endif ! associated(tv%T) .AND. associated(tv%frazil)
352  if (cs%debugConservation) call mom_state_stats('1st make_frazil', u, v, h, tv%T, tv%S, g, gv, us)
353 
354 
355  if (cs%use_int_tides) then
356  ! This block provides an interface for the unresolved low-mode internal tide module (BDM).
357  call set_int_tide_input(u, v, h, tv, fluxes, cs%int_tide_input, dt, g, gv, us, &
358  cs%int_tide_input_CSp)
359  cn_igw(:,:,:) = 0.0
360  if (cs%uniform_test_cg > 0.0) then
361  do m=1,cs%nMode ; cn_igw(:,:,m) = cs%uniform_test_cg ; enddo
362  else
363  call wave_speeds(h, tv, g, gv, us, cs%nMode, cn_igw, full_halos=.true.)
364  endif
365 
366  call propagate_int_tide(h, tv, cn_igw, cs%int_tide_input%TKE_itidal_input, cs%int_tide_input%tideamp, &
367  cs%int_tide_input%Nb, dt, g, gv, us, cs%int_tide_CSp)
368  if (showcalltree) call calltree_waypoint("done with propagate_int_tide (diabatic)")
369  endif ! end CS%use_int_tides
370 
371  if (cs%useALEalgorithm .and. cs%use_legacy_diabatic) then
372  call diabatic_ale_legacy(u, v, h, tv, hml, fluxes, visc, adp, cdp, dt, time_end, &
373  g, gv, us, cs, waves)
374  elseif (cs%useALEalgorithm) then
375  call diabatic_ale(u, v, h, tv, hml, fluxes, visc, adp, cdp, dt, time_end, &
376  g, gv, us, cs, waves)
377  else
378  call layered_diabatic(u, v, h, tv, hml, fluxes, visc, adp, cdp, dt, time_end, &
379  g, gv, us, cs, waves)
380  endif
381 
382 
383  call cpu_clock_begin(id_clock_pass)
384  if (associated(visc%Kv_shear)) &
385  call pass_var(visc%Kv_shear, g%Domain, to_all+omit_corners, halo=1)
386  call cpu_clock_end(id_clock_pass)
387 
388  call disable_averaging(cs%diag)
389  ! Frazil formation keeps temperature above the freezing point.
390  ! make_frazil is deliberately called at both the beginning and at
391  ! the end of the diabatic processes.
392  if (associated(tv%T) .AND. associated(tv%frazil)) then
393  call enable_averages(0.5*dt, time_end, cs%diag)
394  if (cs%frazil_tendency_diag) then
395  do k=1,nz ; do j=js,je ; do i=is,ie
396  temp_diag(i,j,k) = tv%T(i,j,k)
397  enddo ; enddo ; enddo
398  endif
399 
400  if (associated(fluxes%p_surf_full)) then
401  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp, fluxes%p_surf_full)
402  else
403  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp)
404  endif
405 
406  if (cs%frazil_tendency_diag) then
407  call diagnose_frazil_tendency(tv, h, temp_diag, 0.5*dt, g, gv, cs)
408  if (cs%id_frazil_h > 0 ) call post_data(cs%id_frazil_h, h, cs%diag)
409  endif
410 
411  if (showcalltree) call calltree_waypoint("done with 2nd make_frazil (diabatic)")
412  if (cs%debugConservation) call mom_state_stats('2nd make_frazil', u, v, h, tv%T, tv%S, g, gv, us)
413  call disable_averaging(cs%diag)
414 
415  endif ! endif for frazil
416 
417 
418  ! Diagnose mixed layer depths.
419  call enable_averages(dt, time_end, cs%diag)
420  if (cs%id_MLD_003 > 0 .or. cs%id_subMLN2 > 0 .or. cs%id_mlotstsq > 0) then
421  call diagnosemldbydensitydifference(cs%id_MLD_003, h, tv, 0.03*us%kg_m3_to_R, g, gv, us, cs%diag, &
422  id_n2subml=cs%id_subMLN2, id_mldsq=cs%id_mlotstsq, dz_subml=cs%dz_subML_N2)
423  endif
424  if (cs%id_MLD_0125 > 0) then
425  call diagnosemldbydensitydifference(cs%id_MLD_0125, h, tv, 0.125*us%kg_m3_to_R, g, gv, us, cs%diag)
426  endif
427  if (cs%id_MLD_user > 0) then
428  call diagnosemldbydensitydifference(cs%id_MLD_user, h, tv, cs%MLDdensityDifference, g, gv, us, cs%diag)
429  endif
430  if (cs%use_int_tides) then
431  if (cs%id_cg1 > 0) call post_data(cs%id_cg1, cn_igw(:,:,1),cs%diag)
432  do m=1,cs%nMode ; if (cs%id_cn(m) > 0) call post_data(cs%id_cn(m), cn_igw(:,:,m), cs%diag) ; enddo
433  endif
434  call disable_averaging(cs%diag)
435 
436  if (cs%debugConservation) call mom_state_stats('leaving diabatic', u, v, h, tv%T, tv%S, g, gv, us)
437 
438 end subroutine diabatic
439 
440 
441 
442 !> Applies diabatic forcing and diapycnal mixing of temperature, salinity and other tracers for use
443 !! with an ALE algorithm. This version uses an older set of algorithms compared with diabatic_ALE.
444 subroutine diabatic_ale_legacy(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, &
445  G, GV, US, CS, WAVES)
446  type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
447  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
448  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
449  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
450  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
451  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
452  type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
453  !! unused have NULL ptrs
454  real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [m]
455  type(forcing), intent(inout) :: fluxes !< points to forcing fields
456  !! unused fields have NULL ptrs
457  type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and
458  type(accel_diag_ptrs), intent(inout) :: ADp !< related points to accelerations in momentum
459  !! equations, to enable the later derived
460  !! diagnostics, like energy budgets
461  type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
462  real, intent(in) :: dt !< time increment [T ~> s]
463  type(time_type), intent(in) :: Time_end !< Time at the end of the interval
464  type(diabatic_cs), pointer :: CS !< module control structure
465  type(wave_parameters_cs), optional, pointer :: Waves !< Surface gravity waves
466 
467  ! local variables
468  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
469  ea_s, & ! amount of fluid entrained from the layer above within
470  ! one time step [H ~> m or kg m-2]
471  eb_s, & ! amount of fluid entrained from the layer below within
472  ! one time step [H ~> m or kg m-2]
473  ea_t, & ! amount of fluid entrained from the layer above within
474  ! one time step [H ~> m or kg m-2]
475  eb_t, & ! amount of fluid entrained from the layer below within
476  ! one time step [H ~> m or kg m-2]
477  kd_lay, & ! diapycnal diffusivity of layers [Z2 T-1 ~> m2 s-1]
478  h_orig, & ! initial layer thicknesses [H ~> m or kg m-2]
479  h_prebound, & ! initial layer thicknesses [H ~> m or kg m-2]
480  hold, & ! layer thickness before diapycnal entrainment, and later
481  ! the initial layer thicknesses (if a mixed layer is used),
482  ! [H ~> m or kg m-2]
483  dsv_dt, & ! The partial derivative of specific volume with temperature [R-1 degC-1 ~> m3 kg-1 degC-1]
484  dsv_ds, & ! The partial derivative of specific volume with salinity [R-1 ppt-1 ~> m3 kg-1 ppt-1].
485  ctke, & ! convective TKE requirements for each layer [R Z3 T-2 ~> J m-2].
486  u_h, & ! zonal and meridional velocities at thickness points after
487  v_h ! entrainment [L T-1 ~> m s-1]
488  real, dimension(SZI_(G),SZJ_(G)) :: &
489  Rcv_ml, & ! coordinate density of mixed layer, used for applying sponges
490  SkinBuoyFlux! 2d surface buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL
491  real, dimension(SZI_(G),SZJ_(G),G%ke) :: h_diag ! diagnostic array for thickness
492  real, dimension(SZI_(G),SZJ_(G),G%ke) :: temp_diag ! diagnostic array for temp
493  real, dimension(SZI_(G),SZJ_(G),G%ke) :: saln_diag ! diagnostic array for salinity
494  real, dimension(SZI_(G),SZJ_(G)) :: tendency_2d ! depth integrated content tendency for diagn
495 
496  real :: net_ent ! The net of ea-eb at an interface.
497 
498  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
499  eatr, & ! The equivalent of ea and eb for tracers, which differ from ea and
500  ebtr ! eb in that they tend to homogenize tracers in massless layers
501  ! near the boundaries [H ~> m or kg m-2] (for Bous or non-Bouss)
502 
503  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), target :: &
504  Kd_int, & ! diapycnal diffusivity of interfaces [Z2 T-1 ~> m2 s-1]
505  Kd_heat, & ! diapycnal diffusivity of heat [Z2 T-1 ~> m2 s-1]
506  Kd_salt, & ! diapycnal diffusivity of salt and passive tracers [Z2 T-1 ~> m2 s-1]
507  Kd_ePBL, & ! test array of diapycnal diffusivities at interfaces [Z2 T-1 ~> m2 s-1]
508  Tdif_flx, & ! diffusive diapycnal heat flux across interfaces [degC H T-1 ~> degC m s-1 or degC kg m-2 s-1]
509  Tadv_flx, & ! advective diapycnal heat flux across interfaces [degC H T-1 ~> degC m s-1 or degC kg m-2 s-1]
510  Sdif_flx, & ! diffusive diapycnal salt flux across interfaces [ppt H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
511  Sadv_flx ! advective diapycnal salt flux across interfaces [ppt H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
512 
513  logical :: in_boundary(SZI_(G)) ! True if there are no massive layers below,
514  ! where massive is defined as sufficiently thick that
515  ! the no-flux boundary conditions have not restricted
516  ! the entrainment - usually sqrt(Kd*dt).
517 
518  real :: b_denom_1 ! The first term in the denominator of b1
519  ! [H ~> m or kg m-2]
520  real :: h_neglect ! A thickness that is so small it is usually lost
521  ! in roundoff and can be neglected
522  ! [H ~> m or kg m-2]
523  real :: h_neglect2 ! h_neglect^2 [H2 ~> m2 or kg2 m-4]
524  real :: add_ent ! Entrainment that needs to be added when mixing tracers
525  ! [H ~> m or kg m-2]
526  real :: eaval ! eaval is 2*ea at velocity grid points [H ~> m or kg m-2]
527  real :: hval ! hval is 2*h at velocity grid points [H ~> m or kg m-2]
528  real :: h_tr ! h_tr is h at tracer points with a tiny thickness
529  ! added to ensure positive definiteness [H ~> m or kg m-2]
530  real :: Tr_ea_BBL ! The diffusive tracer thickness in the BBL that is
531  ! coupled to the bottom within a timestep [H ~> m or kg m-2]
532 
533  real :: htot(SZIB_(G)) ! The summed thickness from the bottom [H ~> m or kg m-2].
534  real :: b1(SZIB_(G)), d1(SZIB_(G)) ! b1, c1, and d1 are variables used by the
535  real :: c1(SZIB_(G),SZK_(G)) ! tridiagonal solver.
536 
537  real :: Ent_int ! The diffusive entrainment rate at an interface [H ~> m or kg m-2]
538  real :: Idt ! The inverse time step [T-1 ~> s-1]
539 
540  integer :: dir_flag ! An integer encoding the directions in which to do halo updates.
541  logical :: showCallTree ! If true, show the call tree
542  integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb, m, halo
543 
544  integer :: ig, jg ! global indices for testing testing itide point source (BDM)
545  real :: Kd_add_here ! An added diffusivity [Z2 T-1 ~> m2 s-1].
546 
547  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
548  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
549  nkmb = gv%nk_rho_varies
550  h_neglect = gv%H_subroundoff ; h_neglect2 = h_neglect*h_neglect
551  kd_heat(:,:,:) = 0.0 ; kd_salt(:,:,:) = 0.0
552 
553  showcalltree = calltree_showquery()
554  if (showcalltree) call calltree_enter("diabatic_ALE_legacy(), MOM_diabatic_driver.F90")
555 ! if (showCallTree) call callTree_enter("diabatic_ALE(), MOM_diabatic_driver.F90")
556 
557  ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep
558  call enable_averages(dt, time_end, cs%diag)
559 
560  if (cs%use_geothermal) then
561  halo = cs%halo_TS_diff
562  !$OMP parallel do default(shared)
563  do k=1,nz ; do j=js-halo,je+halo ; do i=is-halo,ie+halo
564  h_orig(i,j,k) = h(i,j,k) ; eatr(i,j,k) = 0.0 ; ebtr(i,j,k) = 0.0
565  enddo ; enddo ; enddo
566  endif
567 
568  if (cs%use_geothermal) then
569  call cpu_clock_begin(id_clock_geothermal)
570  call geothermal(h, tv, dt, eatr, ebtr, g, gv, us, cs%geothermal_CSp, halo=cs%halo_TS_diff)
571  call cpu_clock_end(id_clock_geothermal)
572  if (showcalltree) call calltree_waypoint("geothermal (diabatic)")
573  if (cs%debugConservation) call mom_state_stats('geothermal', u, v, h, tv%T, tv%S, g, gv, us)
574  endif
575 
576  ! Whenever thickness changes let the diag manager know, target grids
577  ! for vertical remapping may need to be regenerated.
578  call diag_update_remap_grids(cs%diag)
579 
580  ! Set_pen_shortwave estimates the optical properties of the water column.
581  ! It will need to be modified later to include information about the
582  ! biological properties and layer thicknesses.
583  if (associated(cs%optics)) &
584  call set_pen_shortwave(cs%optics, fluxes, g, gv, cs%diabatic_aux_CSp, cs%opacity_CSp, cs%tracer_flow_CSp)
585 
586  if (cs%debug) call mom_state_chksum("before find_uv_at_h", u, v, h, g, gv, us, haloshift=0)
587 
588  if (cs%use_kappa_shear .or. cs%use_CVMix_shear) then
589  if (cs%use_geothermal) then
590  call find_uv_at_h(u, v, h_orig, u_h, v_h, g, gv, us, eatr, ebtr)
591  if (cs%debug) then
592  call hchksum(eatr, "after find_uv_at_h eatr",g%HI, scale=gv%H_to_m)
593  call hchksum(ebtr, "after find_uv_at_h ebtr",g%HI, scale=gv%H_to_m)
594  endif
595  else
596  call find_uv_at_h(u, v, h, u_h, v_h, g, gv, us)
597  endif
598  if (showcalltree) call calltree_waypoint("done with find_uv_at_h (diabatic)")
599  endif
600 
601  call cpu_clock_begin(id_clock_set_diffusivity)
602  ! Sets: Kd_lay, Kd_int, visc%Kd_extra_T, visc%Kd_extra_S and visc%TKE_turb
603  ! Also changes: visc%Kd_shear, visc%Kv_shear and visc%Kv_slow
604  call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, cs%optics, &
605  visc, dt, g, gv, us, cs%set_diff_CSp, kd_lay, kd_int)
606  call cpu_clock_end(id_clock_set_diffusivity)
607  if (showcalltree) call calltree_waypoint("done with set_diffusivity (diabatic)")
608 
609  ! Set diffusivities for heat and salt separately
610 
611  if (.not.cs%use_legacy_diabatic .or. cs%useKPP) then
612  !$OMP parallel do default(shared)
613  do k=1,nz+1 ; do j=js,je ; do i=is,ie
614  kd_salt(i,j,k) = kd_int(i,j,k)
615  kd_heat(i,j,k) = kd_int(i,j,k)
616  enddo ; enddo ; enddo
617  ! Add contribution from double diffusion
618  if (associated(visc%Kd_extra_S)) then
619  !$OMP parallel do default(shared)
620  do k=1,nz+1 ; do j=js,je ; do i=is,ie
621  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
622  enddo ; enddo ; enddo
623  endif
624  if (associated(visc%Kd_extra_T)) then
625  !$OMP parallel do default(shared)
626  do k=1,nz+1 ; do j=js,je ; do i=is,ie
627  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
628  enddo ; enddo ; enddo
629  endif
630  endif
631 
632  if (cs%debug) then
633  call mom_state_chksum("after set_diffusivity ", u, v, h, g, gv, us, haloshift=0)
634  call mom_forcing_chksum("after set_diffusivity ", fluxes, g, us, haloshift=0)
635  call mom_thermovar_chksum("after set_diffusivity ", tv, g)
636  call hchksum(kd_int, "after set_diffusivity Kd_Int", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
637  call hchksum(kd_heat, "after set_diffusivity Kd_heat", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
638  call hchksum(kd_salt, "after set_diffusivity Kd_salt", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
639  endif
640 
641  if (cs%useKPP) then
642  call cpu_clock_begin(id_clock_kpp)
643  ! total vertical viscosity in the interior is represented via visc%Kv_shear
644  if (.not.cs%use_legacy_diabatic) then
645  do k=1,nz+1 ; do j=js,je ; do i=is,ie
646  visc%Kv_shear(i,j,k) = visc%Kv_shear(i,j,k) + visc%Kv_slow(i,j,k)
647  enddo ; enddo ; enddo
648  endif
649 
650  ! KPP needs the surface buoyancy flux but does not update state variables.
651  ! We could make this call higher up to avoid a repeat unpacking of the surface fluxes.
652  ! Sets: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux
653  ! NOTE: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux are returned as rates (i.e. stuff per second)
654  ! unlike other instances where the fluxes are integrated in time over a time-step.
655  call calculatebuoyancyflux2d(g, gv, us, fluxes, cs%optics, h, tv%T, tv%S, tv, &
656  cs%KPP_buoy_flux, cs%KPP_temp_flux, cs%KPP_salt_flux)
657  ! The KPP scheme calculates boundary layer diffusivities and non-local transport.
658 
659  call kpp_compute_bld(cs%KPP_CSp, g, gv, us, h, tv%T, tv%S, u, v, tv%eqn_of_state, &
660  fluxes%ustar, cs%KPP_buoy_flux, waves=waves)
661 
662  call kpp_calculate(cs%KPP_CSp, g, gv, us, h, fluxes%ustar, cs%KPP_buoy_flux, kd_heat, &
663  kd_salt, visc%Kv_shear, cs%KPP_NLTheat, cs%KPP_NLTscalar, waves=waves)
664 
665  if (associated(hml)) then
666  !$OMP parallel default(shared)
667  call kpp_get_bld(cs%KPP_CSp, hml(:,:), g)
668  !$OMP end parallel
669  call pass_var(hml, g%domain, halo=1)
670  ! If visc%MLD exists, copy KPP's BLD into it
671  if (associated(visc%MLD)) visc%MLD(:,:) = hml(:,:)
672  endif
673 
674  if (cs%use_legacy_diabatic .and. .not.cs%KPPisPassive) then
675  !$OMP parallel do default(shared)
676  do k=1,nz+1 ; do j=js,je ; do i=is,ie
677  kd_int(i,j,k) = min( kd_salt(i,j,k), kd_heat(i,j,k) )
678  enddo ; enddo ; enddo
679  if (associated(visc%Kd_extra_S)) then
680  !$OMP parallel do default(shared)
681  do k=1,nz+1 ; do j=js,je ; do i=is,ie
682  visc%Kd_extra_S(i,j,k) = (kd_salt(i,j,k) - kd_int(i,j,k))
683  enddo ; enddo ; enddo
684  endif
685  if (associated(visc%Kd_extra_T)) then
686  !$OMP parallel do default(shared)
687  do k=1,nz+1 ; do j=js,je ; do i=is,ie
688  visc%Kd_extra_T(i,j,k) = (kd_heat(i,j,k) - kd_int(i,j,k))
689  enddo ; enddo ; enddo
690  endif
691  endif ! not passive
692 
693  call cpu_clock_end(id_clock_kpp)
694  if (showcalltree) call calltree_waypoint("done with KPP_calculate (diabatic)")
695  if (cs%debug) then
696  call mom_state_chksum("after KPP", u, v, h, g, gv, us, haloshift=0)
697  call mom_forcing_chksum("after KPP", fluxes, g, us, haloshift=0)
698  call mom_thermovar_chksum("after KPP", tv, g)
699  call hchksum(kd_heat, "after KPP Kd_heat", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
700  call hchksum(kd_salt, "after KPP Kd_salt", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
701  endif
702 
703  endif ! endif for KPP
704 
705 
706  if (cs%useKPP) then
707  call cpu_clock_begin(id_clock_kpp)
708  if (cs%debug) then
709  call hchksum(cs%KPP_temp_flux, "before KPP_applyNLT netHeat", g%HI, haloshift=0, scale=gv%H_to_m)
710  call hchksum(cs%KPP_salt_flux, "before KPP_applyNLT netSalt", g%HI, haloshift=0, scale=gv%H_to_m)
711  call hchksum(cs%KPP_NLTheat, "before KPP_applyNLT NLTheat", g%HI, haloshift=0)
712  call hchksum(cs%KPP_NLTscalar, "before KPP_applyNLT NLTscalar", g%HI, haloshift=0)
713  endif
714  ! Apply non-local transport of heat and salt
715  ! Changes: tv%T, tv%S
716  call kpp_nonlocaltransport_temp(cs%KPP_CSp, g, gv, h, cs%KPP_NLTheat, cs%KPP_temp_flux, &
717  us%T_to_s*dt, tv%T, tv%C_p)
718  call kpp_nonlocaltransport_saln(cs%KPP_CSp, g, gv, h, cs%KPP_NLTscalar, cs%KPP_salt_flux, &
719  us%T_to_s*dt, tv%S)
720  call cpu_clock_end(id_clock_kpp)
721  if (showcalltree) call calltree_waypoint("done with KPP_applyNonLocalTransport (diabatic)")
722  if (cs%debugConservation) call mom_state_stats('KPP_applyNonLocalTransport', u, v, h, tv%T, tv%S, g, gv, us)
723 
724  if (cs%debug) then
725  call mom_state_chksum("after KPP_applyNLT ", u, v, h, g, gv, us, haloshift=0)
726  call mom_forcing_chksum("after KPP_applyNLT ", fluxes, g, us, haloshift=0)
727  call mom_thermovar_chksum("after KPP_applyNLT ", tv, g)
728  endif
729  endif ! endif for KPP
730 
731  ! This is the "old" method for applying differential diffusion.
732  ! Changes: tv%T, tv%S
733  if (associated(visc%Kd_extra_T) .and. associated(visc%Kd_extra_S) .and. associated(tv%T) .and. &
734  (cs%use_legacy_diabatic .or. .not.cs%use_CVMix_ddiff)) then
735 
736  call cpu_clock_begin(id_clock_differential_diff)
737  call differential_diffuse_t_s(h, tv, visc, dt, g, gv)
738  call cpu_clock_end(id_clock_differential_diff)
739 
740  if (showcalltree) call calltree_waypoint("done with differential_diffuse_T_S (diabatic)")
741  if (cs%debugConservation) call mom_state_stats('differential_diffuse_T_S', u, v, h, tv%T, tv%S, g, gv, us)
742 
743  ! increment heat and salt diffusivity.
744  ! CS%useKPP==.true. already has extra_T and extra_S included
745  if (.not. cs%useKPP) then
746  !$OMP parallel do default(shared)
747  do k=2,nz ; do j=js,je ; do i=is,ie
748  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
749  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
750  enddo ; enddo ; enddo
751  endif
752 
753  endif
754 
755  ! Calculate vertical mixing due to convection (computed via CVMix)
756  if (cs%use_CVMix_conv) then
757  call calculate_cvmix_conv(h, tv, g, gv, us, cs%CVMix_conv_csp, hml)
758  ! Increment vertical diffusion and viscosity due to convection
759  if (cs%use_legacy_diabatic) then
760  !$OMP parallel do default(shared)
761  do k=1,nz+1 ; do j=js,je ; do i=is,ie
762  kd_int(i,j,k) = kd_int(i,j,k) + cs%CVMix_conv_csp%kd_conv(i,j,k)
763  visc%Kv_slow(i,j,k) = visc%Kv_slow(i,j,k) + cs%CVMix_conv_csp%kv_conv(i,j,k)
764  enddo ; enddo ; enddo
765  else
766  !$OMP parallel do default(shared)
767  do k=1,nz+1 ; do j=js,je ; do i=is,ie
768  kd_heat(i,j,k) = kd_heat(i,j,k) + cs%CVMix_conv_csp%kd_conv(i,j,k)
769  kd_salt(i,j,k) = kd_salt(i,j,k) + cs%CVMix_conv_csp%kd_conv(i,j,k)
770  if (cs%useKPP) then
771  visc%Kv_shear(i,j,k) = visc%Kv_shear(i,j,k) + cs%CVMix_conv_csp%kv_conv(i,j,k)
772  else
773  visc%Kv_slow(i,j,k) = visc%Kv_slow(i,j,k) + cs%CVMix_conv_csp%kv_conv(i,j,k)
774  endif
775  enddo ; enddo ; enddo
776  endif
777  endif
778 
779  ! This block sets ea, eb from h and Kd_int.
780  if (cs%use_legacy_diabatic) then
781  do j=js,je ; do i=is,ie
782  ea_s(i,j,1) = 0.0
783  enddo ; enddo
784  !$OMP parallel do default(shared) private(hval)
785  do k=2,nz ; do j=js,je ; do i=is,ie
786  hval=1.0/(h_neglect + 0.5*(h(i,j,k-1) + h(i,j,k)))
787  ea_s(i,j,k) = (gv%Z_to_H**2) * dt * hval * kd_int(i,j,k)
788  eb_s(i,j,k-1) = ea_s(i,j,k)
789  ea_t(i,j,k-1) = ea_s(i,j,k-1) ; eb_t(i,j,k-1) = eb_s(i,j,k-1)
790  enddo ; enddo ; enddo
791  do j=js,je ; do i=is,ie
792  eb_s(i,j,nz) = 0.0
793  ea_t(i,j,nz) = ea_s(i,j,nz) ; eb_t(i,j,nz) = eb_s(i,j,nz)
794  enddo ; enddo
795  if (showcalltree) call calltree_waypoint("done setting ea,eb from Kd_int (diabatic)")
796  endif
797 
798  if (cs%debug) then
799  call mom_forcing_chksum("after calc_entrain ", fluxes, g, us, haloshift=0)
800  call mom_thermovar_chksum("after calc_entrain ", tv, g)
801  call mom_state_chksum("after calc_entrain ", u, v, h, g, gv, us, haloshift=0)
802  call hchksum(ea_s, "after calc_entrain ea_s", g%HI, haloshift=0, scale=gv%H_to_m)
803  call hchksum(eb_s, "after calc_entrain eb_s", g%HI, haloshift=0, scale=gv%H_to_m)
804  endif
805 
806  ! Save fields before boundary forcing is applied for tendency diagnostics
807  if (cs%boundary_forcing_tendency_diag) then
808  do k=1,nz ; do j=js,je ; do i=is,ie
809  h_diag(i,j,k) = h(i,j,k)
810  temp_diag(i,j,k) = tv%T(i,j,k)
811  saln_diag(i,j,k) = tv%S(i,j,k)
812  enddo ; enddo ; enddo
813  endif
814 
815  ! Apply forcing
816  call cpu_clock_begin(id_clock_remap)
817 
818  ! Changes made to following fields: h, tv%T and tv%S.
819  do k=1,nz ; do j=js,je ; do i=is,ie
820  h_prebound(i,j,k) = h(i,j,k)
821  enddo ; enddo ; enddo
822  if (cs%use_energetic_PBL) then
823 
824  skinbuoyflux(:,:) = 0.0
825  call applyboundaryfluxesinout(cs%diabatic_aux_CSp, g, gv, us, dt, fluxes, cs%optics, &
826  optics_nbands(cs%optics), h, tv, cs%aggregate_FW_forcing, cs%evap_CFL_limit, &
827  cs%minimum_forcing_depth, ctke, dsv_dt, dsv_ds, skinbuoyflux=skinbuoyflux)
828 
829  if (cs%debug) then
830  call hchksum(ea_t, "after applyBoundaryFluxes ea_t",g%HI,haloshift=0, scale=gv%H_to_m)
831  call hchksum(eb_t, "after applyBoundaryFluxes eb_t",g%HI,haloshift=0, scale=gv%H_to_m)
832  call hchksum(ea_s, "after applyBoundaryFluxes ea_s",g%HI,haloshift=0, scale=gv%H_to_m)
833  call hchksum(eb_s, "after applyBoundaryFluxes eb_s",g%HI,haloshift=0, scale=gv%H_to_m)
834  call hchksum(ctke, "after applyBoundaryFluxes cTKE", g%HI, haloshift=0, &
835  scale=us%R_to_kg_m3*us%Z_to_m**3*us%s_to_T**2)
836  call hchksum(dsv_dt, "after applyBoundaryFluxes dSV_dT", g%HI, haloshift=0, scale=us%kg_m3_to_R)
837  call hchksum(dsv_ds, "after applyBoundaryFluxes dSV_dS", g%HI, haloshift=0, scale=us%kg_m3_to_R)
838  endif
839 
840  call find_uv_at_h(u, v, h, u_h, v_h, g, gv, us)
841  call energetic_pbl(h, u_h, v_h, tv, fluxes, dt, kd_epbl, g, gv, us, &
842  cs%energetic_PBL_CSp, dsv_dt, dsv_ds, ctke, skinbuoyflux, waves=waves)
843 
844  if (associated(hml)) then
845  call energetic_pbl_get_mld(cs%energetic_PBL_CSp, hml(:,:), g, us)
846  call pass_var(hml, g%domain, halo=1)
847  ! If visc%MLD exists, copy ePBL's MLD into it
848  if (associated(visc%MLD)) visc%MLD(:,:) = hml(:,:)
849  elseif (associated(visc%MLD)) then
850  call energetic_pbl_get_mld(cs%energetic_PBL_CSp, visc%MLD, g, us)
851  call pass_var(visc%MLD, g%domain, halo=1)
852  endif
853 
854  ! Augment the diffusivities and viscosity due to those diagnosed in energetic_PBL.
855  do k=2,nz ; do j=js,je ; do i=is,ie
856  !### These expressions assume a Prandtl number of 1.
857  if (cs%ePBL_is_additive) then
858  kd_add_here = kd_epbl(i,j,k)
859  visc%Kv_shear(i,j,k) = visc%Kv_shear(i,j,k) + kd_epbl(i,j,k)
860  else
861  kd_add_here = max(kd_epbl(i,j,k) - visc%Kd_shear(i,j,k), 0.0)
862  visc%Kv_shear(i,j,k) = max(visc%Kv_shear(i,j,k), kd_epbl(i,j,k))
863  endif
864 
865  if (cs%use_legacy_diabatic) then
866  ent_int = kd_add_here * (gv%Z_to_H**2 * dt) / &
867  (0.5*(h(i,j,k-1) + h(i,j,k)) + h_neglect)
868  eb_s(i,j,k-1) = eb_s(i,j,k-1) + ent_int
869  ea_s(i,j,k) = ea_s(i,j,k) + ent_int
870  kd_int(i,j,k) = kd_int(i,j,k) + kd_add_here
871 
872  ! for diagnostics
873  kd_heat(i,j,k) = kd_heat(i,j,k) + kd_int(i,j,k)
874  kd_salt(i,j,k) = kd_salt(i,j,k) + kd_int(i,j,k)
875  else
876  kd_heat(i,j,k) = kd_heat(i,j,k) + kd_add_here
877  kd_salt(i,j,k) = kd_salt(i,j,k) + kd_add_here
878  endif
879 
880  enddo ; enddo ; enddo
881 
882  if (cs%debug) then
883  call hchksum(ea_t, "after ePBL ea_t",g%HI,haloshift=0, scale=gv%H_to_m)
884  call hchksum(eb_t, "after ePBL eb_t",g%HI,haloshift=0, scale=gv%H_to_m)
885  call hchksum(ea_s, "after ePBL ea_s",g%HI,haloshift=0, scale=gv%H_to_m)
886  call hchksum(eb_s, "after ePBL eb_s",g%HI,haloshift=0, scale=gv%H_to_m)
887  call hchksum(kd_epbl, "after ePBL Kd_ePBL", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
888  endif
889 
890  else
891  call applyboundaryfluxesinout(cs%diabatic_aux_CSp, g, gv, us, dt, fluxes, cs%optics, &
892  optics_nbands(cs%optics), h, tv, cs%aggregate_FW_forcing, &
893  cs%evap_CFL_limit, cs%minimum_forcing_depth)
894 
895  endif ! endif for CS%use_energetic_PBL
896 
897  ! diagnose the tendencies due to boundary forcing
898  ! At this point, the diagnostic grids have not been updated since the call to the boundary layer scheme
899  ! so all tendency diagnostics need to be posted on h_diag, and grids rebuilt afterwards
900  if (cs%boundary_forcing_tendency_diag) then
901  call diagnose_boundary_forcing_tendency(tv, h, temp_diag, saln_diag, h_diag, dt, g, gv, cs)
902  if (cs%id_boundary_forcing_h > 0) call post_data(cs%id_boundary_forcing_h, h, cs%diag, alt_h = h_diag)
903  endif
904  ! Boundary fluxes may have changed T, S, and h
905  call diag_update_remap_grids(cs%diag)
906  call cpu_clock_end(id_clock_remap)
907  if (cs%debug) then
908  call mom_forcing_chksum("after applyBoundaryFluxes ", fluxes, g, us, haloshift=0)
909  call mom_thermovar_chksum("after applyBoundaryFluxes ", tv, g)
910  call mom_state_chksum("after applyBoundaryFluxes ", u, v, h, g, gv, us, haloshift=0)
911  endif
912  if (showcalltree) call calltree_waypoint("done with applyBoundaryFluxes (diabatic)")
913  if (cs%debugConservation) call mom_state_stats('applyBoundaryFluxes', u, v, h, tv%T, tv%S, g, gv, us)
914 
915  ! Update h according to divergence of the difference between
916  ! ea and eb. We keep a record of the original h in hold.
917  ! In the following, the checks for negative values are to guard against
918  ! instances where entrainment drives a layer to negative thickness.
919  !### This code may be unnecessary, but the negative-thickness checks do appear to change
920  ! answers slightly in some cases.
921  if (cs%use_legacy_diabatic) then
922  !$OMP parallel do default(shared)
923  do j=js,je
924  do i=is,ie
925  hold(i,j,1) = h(i,j,1)
926  ! Does nothing with ALE: h(i,j,1) = h(i,j,1) + (eb_s(i,j,1) - ea_s(i,j,2))
927  hold(i,j,nz) = h(i,j,nz)
928  ! Does nothing with ALE: h(i,j,nz) = h(i,j,nz) + (ea_s(i,j,nz) - eb_s(i,j,nz-1))
929  if (h(i,j,1) <= 0.0) h(i,j,1) = gv%Angstrom_H
930  if (h(i,j,nz) <= 0.0) h(i,j,nz) = gv%Angstrom_H
931  enddo
932  do k=2,nz-1 ; do i=is,ie
933  hold(i,j,k) = h(i,j,k)
934  ! Does nothing with ALE: h(i,j,k) = h(i,j,k) + ((ea_s(i,j,k) - eb_s(i,j,k-1)) + &
935  ! (eb_s(i,j,k) - ea_s(i,j,k+1)))
936  if (h(i,j,k) <= 0.0) h(i,j,k) = gv%Angstrom_H
937  enddo ; enddo
938  enddo
939  ! Checks for negative thickness may have changed layer thicknesses
940  call diag_update_remap_grids(cs%diag)
941  endif
942 
943  if (cs%debug) then
944  call mom_state_chksum("after negative check ", u, v, h, g, gv, us, haloshift=0)
945  call mom_forcing_chksum("after negative check ", fluxes, g, us, haloshift=0)
946  call mom_thermovar_chksum("after negative check ", tv, g)
947  endif
948  if (showcalltree) call calltree_waypoint("done with h=ea-eb (diabatic)")
949  if (cs%debugConservation) call mom_state_stats('h=ea-eb', u, v, h, tv%T, tv%S, g, gv, us)
950 
951  ! calculate change in temperature & salinity due to dia-coordinate surface diffusion
952  if (associated(tv%T)) then
953 
954  if (cs%debug) then
955  call hchksum(ea_t, "before triDiagTS ea_t ",g%HI,haloshift=0, scale=gv%H_to_m)
956  call hchksum(eb_t, "before triDiagTS eb_t ",g%HI,haloshift=0, scale=gv%H_to_m)
957  call hchksum(ea_s, "before triDiagTS ea_s ",g%HI,haloshift=0, scale=gv%H_to_m)
958  call hchksum(eb_s, "before triDiagTS eb_s ",g%HI,haloshift=0, scale=gv%H_to_m)
959  endif
960 
961  call cpu_clock_begin(id_clock_tridiag)
962  ! Keep salinity from falling below a small but positive threshold.
963  ! This constraint is needed for SIS1 ice model, which can extract
964  ! more salt than is present in the ocean. SIS2 does not suffer
965  ! from this limitation, in which case we can let salinity=0 and still
966  ! have salt conserved with SIS2 ice. So for SIS2, we can run with
967  ! BOUND_SALINITY=False in MOM.F90.
968  if (associated(tv%S) .and. associated(tv%salt_deficit)) &
969  call adjust_salt(h, tv, g, gv, cs%diabatic_aux_CSp)
970 
971  if (cs%diabatic_diff_tendency_diag) then
972  do k=1,nz ; do j=js,je ; do i=is,ie
973  temp_diag(i,j,k) = tv%T(i,j,k)
974  saln_diag(i,j,k) = tv%S(i,j,k)
975  enddo ; enddo ; enddo
976  endif
977 
978  if (cs%use_legacy_diabatic) then
979  ! Changes T and S via the tridiagonal solver; no change to h
980  do k=1,nz ; do j=js,je ; do i=is,ie
981  ea_t(i,j,k) = ea_s(i,j,k) ; eb_t(i,j,k) = eb_s(i,j,k)
982  enddo ; enddo ; enddo
983  if (cs%tracer_tridiag) then
984  call tracer_vertdiff(hold, ea_t, eb_t, dt, tv%T, g, gv)
985  call tracer_vertdiff(hold, ea_s, eb_s, dt, tv%S, g, gv)
986  else
987  call tridiagts(g, gv, is, ie, js, je, hold, ea_s, eb_s, tv%T, tv%S)
988  endif
989 
990  ! diagnose temperature, salinity, heat, and salt tendencies
991  ! Note: hold here refers to the thicknesses from before the dual-entraintment when using
992  ! the bulk mixed layer scheme. Otherwise in ALE-mode, layer thicknesses will (not?) have changed
993  ! In either case, tendencies should be posted on hold
994  if (cs%diabatic_diff_tendency_diag) then
995  call diagnose_diabatic_diff_tendency(tv, hold, temp_diag, saln_diag, dt, g, gv, cs)
996  if (cs%id_diabatic_diff_h > 0) call post_data(cs%id_diabatic_diff_h, hold, cs%diag, alt_h = hold)
997  endif
998  else
999  ! Set ea_t=eb_t based on Kd_heat and ea_s=eb_s based on Kd_salt on interfaces for use in the tri-diagonal solver.
1000 
1001  do j=js,je ; do i=is,ie
1002  ea_t(i,j,1) = 0.; ea_s(i,j,1) = 0.
1003  enddo ; enddo
1004 
1005  !$OMP parallel do default(shared) private(hval)
1006  do k=2,nz ; do j=js,je ; do i=is,ie
1007  hval = 1.0 / (h_neglect + 0.5*(h(i,j,k-1) + h(i,j,k)))
1008  ea_t(i,j,k) = (gv%Z_to_H**2) * dt * hval * kd_heat(i,j,k)
1009  eb_t(i,j,k-1) = ea_t(i,j,k)
1010  ea_s(i,j,k) = (gv%Z_to_H**2) * dt * hval * kd_salt(i,j,k)
1011  eb_s(i,j,k-1) = ea_s(i,j,k)
1012  enddo ; enddo ; enddo
1013  do j=js,je ; do i=is,ie
1014  eb_t(i,j,nz) = 0. ; eb_s(i,j,nz) = 0.
1015  enddo ; enddo
1016  if (showcalltree) call calltree_waypoint("done setting ea_t,ea_s,eb_t,eb_s from Kd_heat" //&
1017  "and Kd_salt (diabatic)")
1018 
1019  ! Changes T and S via the tridiagonal solver; no change to h
1020  call tracer_vertdiff(h, ea_t, eb_t, dt, tv%T, g, gv)
1021  call tracer_vertdiff(h, ea_s, eb_s, dt, tv%S, g, gv)
1022 
1023  ! In ALE-mode, layer thicknesses do not change. Therefore, we can use h below
1024  if (cs%diabatic_diff_tendency_diag) &
1025  call diagnose_diabatic_diff_tendency(tv, h, temp_diag, saln_diag, dt, g, gv, cs)
1026  endif
1027 
1028  call cpu_clock_end(id_clock_tridiag)
1029 
1030  if (showcalltree) call calltree_waypoint("done with triDiagTS (diabatic)")
1031 
1032  endif ! endif corresponding to if (associated(tv%T))
1033 
1034  if (cs%debugConservation) call mom_state_stats('triDiagTS', u, v, h, tv%T, tv%S, g, gv, us)
1035 
1036  if (cs%debug) then
1037  call mom_state_chksum("after mixed layer ", u, v, h, g, gv, us, haloshift=0)
1038  call mom_thermovar_chksum("after mixed layer ", tv, g)
1039  endif
1040 
1041  ! Whenever thickness changes let the diag manager know, as the
1042  ! target grids for vertical remapping may need to be regenerated.
1043  if (cs%id_dudt_dia > 0 .or. cs%id_dvdt_dia > 0) &
1044  ! Remapped d[uv]dt_dia require east/north halo updates of h
1045  call pass_var(h, g%domain, to_west+to_south+omit_corners, halo=1)
1046  call diag_update_remap_grids(cs%diag)
1047 
1048  ! diagnostics
1049  idt = 1.0 / dt
1050  if ((cs%id_Tdif > 0) .or. (cs%id_Tadv > 0)) then
1051  do j=js,je ; do i=is,ie
1052  tdif_flx(i,j,1) = 0.0 ; tdif_flx(i,j,nz+1) = 0.0
1053  tadv_flx(i,j,1) = 0.0 ; tadv_flx(i,j,nz+1) = 0.0
1054  enddo ; enddo
1055  !$OMP parallel do default(shared)
1056  do k=2,nz ; do j=js,je ; do i=is,ie
1057  tdif_flx(i,j,k) = (idt * 0.5*(ea_t(i,j,k) + eb_t(i,j,k-1))) * &
1058  (tv%T(i,j,k-1) - tv%T(i,j,k))
1059  tadv_flx(i,j,k) = (idt * (ea_t(i,j,k) - eb_t(i,j,k-1))) * &
1060  0.5*(tv%T(i,j,k-1) + tv%T(i,j,k))
1061  enddo ; enddo ; enddo
1062  endif
1063  if ((cs%id_Sdif > 0) .or. (cs%id_Sadv > 0)) then
1064  do j=js,je ; do i=is,ie
1065  sdif_flx(i,j,1) = 0.0 ; sdif_flx(i,j,nz+1) = 0.0
1066  sadv_flx(i,j,1) = 0.0 ; sadv_flx(i,j,nz+1) = 0.0
1067  enddo ; enddo
1068  !$OMP parallel do default(shared)
1069  do k=2,nz ; do j=js,je ; do i=is,ie
1070  sdif_flx(i,j,k) = (idt * 0.5*(ea_s(i,j,k) + eb_s(i,j,k-1))) * &
1071  (tv%S(i,j,k-1) - tv%S(i,j,k))
1072  sadv_flx(i,j,k) = (idt * (ea_s(i,j,k) - eb_s(i,j,k-1))) * &
1073  0.5*(tv%S(i,j,k-1) + tv%S(i,j,k))
1074  enddo ; enddo ; enddo
1075  endif
1076 
1077  ! mixing of passive tracers from massless boundary layers to interior
1078  call cpu_clock_begin(id_clock_tracers)
1079 
1080  if (cs%mix_boundary_tracers) then
1081  tr_ea_bbl = gv%Z_to_H * sqrt(dt*cs%Kd_BBL_tr)
1082  !$OMP parallel do default(shared) private(htot,in_boundary,add_ent)
1083  do j=js,je
1084  do i=is,ie
1085  ebtr(i,j,nz) = eb_s(i,j,nz)
1086  htot(i) = 0.0
1087  in_boundary(i) = (g%mask2dT(i,j) > 0.0)
1088  enddo
1089  do k=nz,2,-1 ; do i=is,ie
1090  if (in_boundary(i)) then
1091  htot(i) = htot(i) + h(i,j,k)
1092  ! If diapycnal mixing has been suppressed because this is a massless
1093  ! layer near the bottom, add some mixing of tracers between these
1094  ! layers. This flux is based on the harmonic mean of the two
1095  ! thicknesses, as this corresponds pretty closely (to within
1096  ! differences in the density jumps between layers) with what is done
1097  ! in the calculation of the fluxes in the first place. Kd_min_tr
1098  ! should be much less than the values that have been set in Kd_int,
1099  ! perhaps a molecular diffusivity.
1100  add_ent = ((dt * cs%Kd_min_tr) * gv%Z_to_H**2) * &
1101  ((h(i,j,k-1)+h(i,j,k)+h_neglect) / &
1102  (h(i,j,k-1)*h(i,j,k)+h_neglect2)) - &
1103  0.5*(ea_s(i,j,k) + eb_s(i,j,k-1))
1104  if (htot(i) < tr_ea_bbl) then
1105  add_ent = max(0.0, add_ent, &
1106  (tr_ea_bbl - htot(i)) - min(ea_s(i,j,k),eb_s(i,j,k-1)))
1107  elseif (add_ent < 0.0) then
1108  add_ent = 0.0 ; in_boundary(i) = .false.
1109  endif
1110 
1111  ebtr(i,j,k-1) = eb_s(i,j,k-1) + add_ent
1112  eatr(i,j,k) = ea_s(i,j,k) + add_ent
1113  else
1114  ebtr(i,j,k-1) = eb_s(i,j,k-1) ; eatr(i,j,k) = ea_s(i,j,k)
1115  endif
1116 
1117  if (associated(visc%Kd_extra_S)) then ; if (visc%Kd_extra_S(i,j,k) > 0.0) then
1118  if (cs%use_legacy_diabatic) then
1119  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
1120  (0.25 * ((h(i,j,k-1) + h(i,j,k)) + (hold(i,j,k-1) + hold(i,j,k))) + h_neglect)
1121  else
1122  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
1123  (0.5 * (h(i,j,k-1) + h(i,j,k)) + &
1124  h_neglect)
1125  endif
1126  ebtr(i,j,k-1) = ebtr(i,j,k-1) + add_ent
1127  eatr(i,j,k) = eatr(i,j,k) + add_ent
1128  endif ; endif
1129  enddo ; enddo
1130  do i=is,ie ; eatr(i,j,1) = ea_s(i,j,1) ; enddo
1131 
1132  enddo
1133 
1134  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1135  ! so hold should be h_orig
1136  call call_tracer_column_fns(h_prebound, h, ea_s, eb_s, fluxes, hml, dt, g, gv, us, tv, &
1137  cs%optics, cs%tracer_flow_CSp, cs%debug, &
1138  evap_cfl_limit = cs%evap_CFL_limit, &
1139  minimum_forcing_depth=cs%minimum_forcing_depth)
1140 
1141  elseif (associated(visc%Kd_extra_S)) then ! extra diffusivity for passive tracers
1142 
1143  do j=js,je ; do i=is,ie
1144  ebtr(i,j,nz) = eb_s(i,j,nz) ; eatr(i,j,1) = ea_s(i,j,1)
1145  enddo ; enddo
1146  !$OMP parallel do default(shared) private(add_ent)
1147  do k=nz,2,-1 ; do j=js,je ; do i=is,ie
1148  if (visc%Kd_extra_S(i,j,k) > 0.0) then
1149  if (cs%use_legacy_diabatic) then
1150  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
1151  (0.25 * ((h(i,j,k-1) + h(i,j,k)) + (hold(i,j,k-1) + hold(i,j,k))) + h_neglect)
1152  else
1153  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
1154  (0.5 * (h(i,j,k-1) + h(i,j,k)) + &
1155  h_neglect)
1156  endif
1157  else
1158  add_ent = 0.0
1159  endif
1160  ebtr(i,j,k-1) = eb_s(i,j,k-1) + add_ent
1161  eatr(i,j,k) = ea_s(i,j,k) + add_ent
1162  enddo ; enddo ; enddo
1163 
1164  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1165  call call_tracer_column_fns(h_prebound, h, eatr, ebtr, fluxes, hml, dt, g, gv, us, tv, &
1166  cs%optics, cs%tracer_flow_CSp, cs%debug,&
1167  evap_cfl_limit = cs%evap_CFL_limit, &
1168  minimum_forcing_depth=cs%minimum_forcing_depth)
1169  else
1170  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1171  call call_tracer_column_fns(h_prebound, h, eatr, ebtr, fluxes, hml, dt, g, gv, us, tv, &
1172  cs%optics, cs%tracer_flow_CSp, cs%debug, &
1173  evap_cfl_limit = cs%evap_CFL_limit, &
1174  minimum_forcing_depth=cs%minimum_forcing_depth)
1175  endif ! (CS%mix_boundary_tracers)
1176 
1177  call cpu_clock_end(id_clock_tracers)
1178 
1179  ! Apply ALE sponge
1180  if (cs%use_sponge) then
1181  call cpu_clock_begin(id_clock_sponge)
1182  if (associated(cs%ALE_sponge_CSp)) then
1183  call apply_ale_sponge(h, dt, g, gv, us, cs%ALE_sponge_CSp, cs%Time)
1184  endif
1185 
1186  call cpu_clock_end(id_clock_sponge)
1187  if (cs%debug) then
1188  call mom_state_chksum("apply_sponge ", u, v, h, g, gv, us, haloshift=0)
1189  call mom_thermovar_chksum("apply_sponge ", tv, g)
1190  endif
1191  endif ! CS%use_sponge
1192 
1193  call disable_averaging(cs%diag)
1194  ! Diagnose the diapycnal diffusivities and other related quantities.
1195  call enable_averages(dt, time_end, cs%diag)
1196 
1197  if (cs%id_Kd_interface > 0) call post_data(cs%id_Kd_interface, kd_int, cs%diag)
1198  if (cs%id_Kd_heat > 0) call post_data(cs%id_Kd_heat, kd_heat, cs%diag)
1199  if (cs%id_Kd_salt > 0) call post_data(cs%id_Kd_salt, kd_salt, cs%diag)
1200  if (cs%id_Kd_ePBL > 0) call post_data(cs%id_Kd_ePBL, kd_epbl, cs%diag)
1201 
1202  if (cs%id_ea > 0) call post_data(cs%id_ea, ea_s, cs%diag)
1203  if (cs%id_eb > 0) call post_data(cs%id_eb, eb_s, cs%diag)
1204  if (cs%id_ea_t > 0) call post_data(cs%id_ea_t, ea_t, cs%diag)
1205  if (cs%id_eb_t > 0) call post_data(cs%id_eb_t, eb_t, cs%diag)
1206  if (cs%id_ea_s > 0) call post_data(cs%id_ea_s, ea_s, cs%diag)
1207  if (cs%id_eb_s > 0) call post_data(cs%id_eb_s, eb_s, cs%diag)
1208 
1209  if (cs%id_dudt_dia > 0) call post_data(cs%id_dudt_dia, adp%du_dt_dia, cs%diag)
1210  if (cs%id_dvdt_dia > 0) call post_data(cs%id_dvdt_dia, adp%dv_dt_dia, cs%diag)
1211  if (cs%id_wd > 0) call post_data(cs%id_wd, cdp%diapyc_vel, cs%diag)
1212 
1213  if (cs%id_Tdif > 0) call post_data(cs%id_Tdif, tdif_flx, cs%diag)
1214  if (cs%id_Tadv > 0) call post_data(cs%id_Tadv, tadv_flx, cs%diag)
1215  if (cs%id_Sdif > 0) call post_data(cs%id_Sdif, sdif_flx, cs%diag)
1216  if (cs%id_Sadv > 0) call post_data(cs%id_Sadv, sadv_flx, cs%diag)
1217 
1218  call disable_averaging(cs%diag)
1219 
1220  if (showcalltree) call calltree_leave("diabatic_ALE_legacy()")
1221 
1222 end subroutine diabatic_ale_legacy
1223 
1224 
1225 !> This subroutine imposes the diapycnal mass fluxes and the
1226 !! accompanying diapycnal advection of momentum and tracers.
1227 subroutine diabatic_ale(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, &
1228  G, GV, US, CS, Waves)
1229  type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1230  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
1231  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1232  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
1233  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
1234  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
1235  type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
1236  !! unused have NULL ptrs
1237  real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [m]
1238  type(forcing), intent(inout) :: fluxes !< points to forcing fields
1239  !! unused fields have NULL ptrs
1240  type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and
1241  type(accel_diag_ptrs), intent(inout) :: ADp !< related points to accelerations in momentum
1242  !! equations, to enable the later derived
1243  !! diagnostics, like energy budgets
1244  type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
1245  real, intent(in) :: dt !< time increment [T ~> s]
1246  type(time_type), intent(in) :: Time_end !< Time at the end of the interval
1247  type(diabatic_cs), pointer :: CS !< module control structure
1248  type(wave_parameters_cs), optional, pointer :: Waves !< Surface gravity waves
1249 
1250  ! local variables
1251  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
1252  ea_s, & ! amount of fluid entrained from the layer above within
1253  ! one time step [H ~> m or kg m-2]
1254  eb_s, & ! amount of fluid entrained from the layer below within
1255  ! one time step [H ~> m or kg m-2]
1256  ea_t, & ! amount of fluid entrained from the layer above within
1257  ! one time step [H ~> m or kg m-2]
1258  eb_t, & ! amount of fluid entrained from the layer below within
1259  ! one time step [H ~> m or kg m-2]
1260  kd_lay, & ! diapycnal diffusivity of layers [Z2 T-1 ~> m2 s-1]
1261  h_orig, & ! initial layer thicknesses [H ~> m or kg m-2]
1262  h_prebound, & ! initial layer thicknesses [H ~> m or kg m-2]
1263 ! hold, & ! layer thickness before diapycnal entrainment, and later
1264  ! the initial layer thicknesses (if a mixed layer is used),
1265  ! [H ~> m or kg m-2]
1266  dsv_dt, & ! The partial derivative of specific volume with temperature [R-1 degC-1 ~> m3 kg-1 degC-1]
1267  dsv_ds, & ! The partial derivative of specific volume with salinity [R-1 ppt-1 ~> m3 kg-1 ppt-1].
1268  ctke, & ! convective TKE requirements for each layer [R Z3 T-2 ~> J m-2].
1269  u_h, & ! zonal and meridional velocities at thickness points after
1270  v_h ! entrainment [L T-1 ~> m s-1]
1271  real, dimension(SZI_(G),SZJ_(G)) :: &
1272  Rcv_ml, & ! coordinate density of mixed layer, used for applying sponges
1273  SkinBuoyFlux! 2d surface buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL
1274  real, dimension(SZI_(G),SZJ_(G),G%ke) :: h_diag ! diagnostic array for thickness
1275  real, dimension(SZI_(G),SZJ_(G),G%ke) :: temp_diag ! diagnostic array for temp
1276  real, dimension(SZI_(G),SZJ_(G),G%ke) :: saln_diag ! diagnostic array for salinity
1277  real, dimension(SZI_(G),SZJ_(G)) :: tendency_2d ! depth integrated content tendency for diagn
1278 
1279  real :: net_ent ! The net of ea-eb at an interface.
1280 
1281  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
1282  eatr, & ! The equivalent of ea and eb for tracers, which differ from ea and
1283  ebtr ! eb in that they tend to homogenize tracers in massless layers
1284  ! near the boundaries [H ~> m or kg m-2] (for Bous or non-Bouss)
1285 
1286  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), target :: &
1287  Kd_int, & ! diapycnal diffusivity of interfaces [Z2 T-1 ~> m2 s-1]
1288  Kd_heat, & ! diapycnal diffusivity of heat [Z2 T-1 ~> m2 s-1]
1289  Kd_salt, & ! diapycnal diffusivity of salt and passive tracers [Z2 T-1 ~> m2 s-1]
1290  Kd_ePBL, & ! test array of diapycnal diffusivities at interfaces [Z2 T-1 ~> m2 s-1]
1291  Tdif_flx, & ! diffusive diapycnal heat flux across interfaces [degC H T-1 ~> degC m s-1 or degC kg m-2 s-1]
1292  Tadv_flx, & ! advective diapycnal heat flux across interfaces [degC H T-1 ~> degC m s-1 or degC kg m-2 s-1]
1293  Sdif_flx, & ! diffusive diapycnal salt flux across interfaces [ppt H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
1294  Sadv_flx ! advective diapycnal salt flux across interfaces [ppt H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
1295 
1296  logical :: in_boundary(SZI_(G)) ! True if there are no massive layers below,
1297  ! where massive is defined as sufficiently thick that
1298  ! the no-flux boundary conditions have not restricted
1299  ! the entrainment - usually sqrt(Kd*dt).
1300 
1301  real :: b_denom_1 ! The first term in the denominator of b1
1302  ! [H ~> m or kg m-2]
1303  real :: h_neglect ! A thickness that is so small it is usually lost
1304  ! in roundoff and can be neglected
1305  ! [H ~> m or kg m-2]
1306  real :: h_neglect2 ! h_neglect^2 [H2 ~> m2 or kg2 m-4]
1307  real :: add_ent ! Entrainment that needs to be added when mixing tracers
1308  ! [H ~> m or kg m-2]
1309  real :: eaval ! eaval is 2*ea at velocity grid points [H ~> m or kg m-2]
1310  real :: hval ! hval is 2*h at velocity grid points [H ~> m or kg m-2]
1311  real :: h_tr ! h_tr is h at tracer points with a tiny thickness
1312  ! added to ensure positive definiteness [H ~> m or kg m-2]
1313  real :: Tr_ea_BBL ! The diffusive tracer thickness in the BBL that is
1314  ! coupled to the bottom within a timestep [H ~> m or kg m-2]
1315 
1316  real :: htot(SZIB_(G)) ! The summed thickness from the bottom [H ~> m or kg m-2].
1317  real :: b1(SZIB_(G)), d1(SZIB_(G)) ! b1, c1, and d1 are variables used by the
1318  real :: c1(SZIB_(G),SZK_(G)) ! tridiagonal solver.
1319 
1320  real :: Ent_int ! The diffusive entrainment rate at an interface [H ~> m or kg m-2]
1321  real :: Idt ! The inverse time step [T-1 ~> s-1]
1322 
1323  integer :: dir_flag ! An integer encoding the directions in which to do halo updates.
1324  logical :: showCallTree ! If true, show the call tree
1325  integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb, m, halo
1326 
1327  integer :: ig, jg ! global indices for testing testing itide point source (BDM)
1328  real :: Kd_add_here ! An added diffusivity [Z2 T-1 ~> m2 s-1].
1329 
1330  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1331  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
1332  nkmb = gv%nk_rho_varies
1333  h_neglect = gv%H_subroundoff ; h_neglect2 = h_neglect*h_neglect
1334  kd_heat(:,:,:) = 0.0 ; kd_salt(:,:,:) = 0.0
1335 
1336  showcalltree = calltree_showquery()
1337  if (showcalltree) call calltree_enter("diabatic_ALE(), MOM_diabatic_driver.F90")
1338 
1339  if (.not. (cs%useALEalgorithm)) call mom_error(fatal, "MOM_diabatic_driver: "// &
1340  "The ALE algorithm must be enabled when using MOM_diabatic_driver.")
1341 
1342  ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep
1343  call enable_averages(dt, time_end, cs%diag)
1344 
1345  if (cs%use_geothermal) then
1346  halo = cs%halo_TS_diff
1347  !$OMP parallel do default(shared)
1348  do k=1,nz ; do j=js-halo,je+halo ; do i=is-halo,ie+halo
1349  h_orig(i,j,k) = h(i,j,k) ; eatr(i,j,k) = 0.0 ; ebtr(i,j,k) = 0.0
1350  enddo ; enddo ; enddo
1351  endif
1352 
1353  if (cs%use_geothermal) then
1354  call cpu_clock_begin(id_clock_geothermal)
1355  call geothermal(h, tv, dt, eatr, ebtr, g, gv, us, cs%geothermal_CSp, halo=cs%halo_TS_diff)
1356  call cpu_clock_end(id_clock_geothermal)
1357  if (showcalltree) call calltree_waypoint("geothermal (diabatic)")
1358  if (cs%debugConservation) call mom_state_stats('geothermal', u, v, h, tv%T, tv%S, g, gv, us)
1359  endif
1360 
1361  ! Whenever thickness changes let the diag manager know, target grids
1362  ! for vertical remapping may need to be regenerated.
1363  call diag_update_remap_grids(cs%diag)
1364 
1365  ! Set_pen_shortwave estimates the optical properties of the water column.
1366  ! It will need to be modified later to include information about the
1367  ! biological properties and layer thicknesses.
1368  if (associated(cs%optics)) &
1369  call set_pen_shortwave(cs%optics, fluxes, g, gv, cs%diabatic_aux_CSp, cs%opacity_CSp, cs%tracer_flow_CSp)
1370 
1371  if (cs%debug) call mom_state_chksum("before find_uv_at_h", u, v, h, g, gv, us, haloshift=0)
1372 
1373  if (cs%use_kappa_shear .or. cs%use_CVMix_shear) then
1374  if (cs%use_geothermal) then
1375  call find_uv_at_h(u, v, h_orig, u_h, v_h, g, gv, us, eatr, ebtr)
1376  if (cs%debug) then
1377  call hchksum(eatr, "after find_uv_at_h eatr",g%HI, scale=gv%H_to_m)
1378  call hchksum(ebtr, "after find_uv_at_h ebtr",g%HI, scale=gv%H_to_m)
1379  endif
1380  else
1381  call find_uv_at_h(u, v, h, u_h, v_h, g, gv, us)
1382  endif
1383  if (showcalltree) call calltree_waypoint("done with find_uv_at_h (diabatic)")
1384  endif
1385 
1386  call cpu_clock_begin(id_clock_set_diffusivity)
1387  ! Sets: Kd_lay, Kd_int, visc%Kd_extra_T, visc%Kd_extra_S and visc%TKE_turb
1388  ! Also changes: visc%Kd_shear, visc%Kv_shear and visc%Kv_slow
1389  call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, cs%optics, &
1390  visc, dt, g, gv, us,cs%set_diff_CSp, kd_lay, kd_int)
1391  call cpu_clock_end(id_clock_set_diffusivity)
1392  if (showcalltree) call calltree_waypoint("done with set_diffusivity (diabatic)")
1393 
1394  if (cs%debug) then
1395  call mom_state_chksum("after set_diffusivity ", u, v, h, g, gv, us, haloshift=0)
1396  call mom_forcing_chksum("after set_diffusivity ", fluxes, g, us, haloshift=0)
1397  call mom_thermovar_chksum("after set_diffusivity ", tv, g)
1398  call hchksum(kd_int, "after set_diffusivity Kd_Int", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
1399  endif
1400 
1401  ! Set diffusivities for heat and salt separately
1402 
1403  !$OMP parallel do default(shared)
1404  do k=1,nz+1 ; do j=js,je ; do i=is,ie
1405  kd_salt(i,j,k) = kd_int(i,j,k)
1406  kd_heat(i,j,k) = kd_int(i,j,k)
1407  enddo ; enddo ; enddo
1408  ! Add contribution from double diffusion
1409  if (associated(visc%Kd_extra_S)) then
1410  !$OMP parallel do default(shared)
1411  do k=1,nz+1 ; do j=js,je ; do i=is,ie
1412  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
1413  enddo ; enddo ; enddo
1414  endif
1415  if (associated(visc%Kd_extra_T)) then
1416  !$OMP parallel do default(shared)
1417  do k=1,nz+1 ; do j=js,je ; do i=is,ie
1418  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
1419  enddo ; enddo ; enddo
1420  endif
1421 
1422  if (cs%debug) then
1423  call hchksum(kd_heat, "after set_diffusivity Kd_heat", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
1424  call hchksum(kd_salt, "after set_diffusivity Kd_salt", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
1425  endif
1426 
1427  if (cs%useKPP) then
1428  call cpu_clock_begin(id_clock_kpp)
1429  ! total vertical viscosity in the interior is represented via visc%Kv_shear
1430  do k=1,nz+1 ; do j=js,je ; do i=is,ie
1431  visc%Kv_shear(i,j,k) = visc%Kv_shear(i,j,k) + visc%Kv_slow(i,j,k)
1432  enddo ; enddo ; enddo
1433 
1434  ! KPP needs the surface buoyancy flux but does not update state variables.
1435  ! We could make this call higher up to avoid a repeat unpacking of the surface fluxes.
1436  ! Sets: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux
1437  ! NOTE: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux are returned as rates (i.e. stuff per second)
1438  ! unlike other instances where the fluxes are integrated in time over a time-step.
1439  call calculatebuoyancyflux2d(g, gv, us, fluxes, cs%optics, h, tv%T, tv%S, tv, &
1440  cs%KPP_buoy_flux, cs%KPP_temp_flux, cs%KPP_salt_flux)
1441  ! The KPP scheme calculates boundary layer diffusivities and non-local transport.
1442 
1443  call kpp_compute_bld(cs%KPP_CSp, g, gv, us, h, tv%T, tv%S, u, v, tv%eqn_of_state, &
1444  fluxes%ustar, cs%KPP_buoy_flux, waves=waves)
1445 
1446  call kpp_calculate(cs%KPP_CSp, g, gv, us, h, fluxes%ustar, cs%KPP_buoy_flux, kd_heat, &
1447  kd_salt, visc%Kv_shear, cs%KPP_NLTheat, cs%KPP_NLTscalar, waves=waves)
1448 
1449  if (associated(hml)) then
1450  !$OMP parallel default(shared)
1451  call kpp_get_bld(cs%KPP_CSp, hml(:,:), g)
1452  !$OMP end parallel
1453  call pass_var(hml, g%domain, halo=1)
1454  ! If visc%MLD exists, copy KPP's BLD into it
1455  if (associated(visc%MLD)) visc%MLD(:,:) = hml(:,:)
1456  endif
1457 
1458  call cpu_clock_end(id_clock_kpp)
1459  if (showcalltree) call calltree_waypoint("done with KPP_calculate (diabatic)")
1460  if (cs%debug) then
1461  call mom_state_chksum("after KPP", u, v, h, g, gv, us, haloshift=0)
1462  call mom_forcing_chksum("after KPP", fluxes, g, us, haloshift=0)
1463  call mom_thermovar_chksum("after KPP", tv, g)
1464  call hchksum(kd_heat, "after KPP Kd_heat", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
1465  call hchksum(kd_salt, "after KPP Kd_salt", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
1466  endif
1467 
1468  endif ! endif for KPP
1469 
1470 
1471  if (cs%useKPP) then
1472  call cpu_clock_begin(id_clock_kpp)
1473  if (cs%debug) then
1474  call hchksum(cs%KPP_temp_flux, "before KPP_applyNLT netHeat", g%HI, haloshift=0, scale=gv%H_to_m)
1475  call hchksum(cs%KPP_salt_flux, "before KPP_applyNLT netSalt", g%HI, haloshift=0, scale=gv%H_to_m)
1476  call hchksum(cs%KPP_NLTheat, "before KPP_applyNLT NLTheat", g%HI, haloshift=0)
1477  call hchksum(cs%KPP_NLTscalar, "before KPP_applyNLT NLTscalar", g%HI, haloshift=0)
1478  endif
1479  ! Apply non-local transport of heat and salt
1480  ! Changes: tv%T, tv%S
1481  call kpp_nonlocaltransport_temp(cs%KPP_CSp, g, gv, h, cs%KPP_NLTheat, cs%KPP_temp_flux, &
1482  us%T_to_s*dt, tv%T, tv%C_p)
1483  call kpp_nonlocaltransport_saln(cs%KPP_CSp, g, gv, h, cs%KPP_NLTscalar, cs%KPP_salt_flux, &
1484  us%T_to_s*dt, tv%S)
1485  call cpu_clock_end(id_clock_kpp)
1486  if (showcalltree) call calltree_waypoint("done with KPP_applyNonLocalTransport (diabatic)")
1487  if (cs%debugConservation) call mom_state_stats('KPP_applyNonLocalTransport', u, v, h, tv%T, tv%S, g, gv, us)
1488 
1489  if (cs%debug) then
1490  call mom_state_chksum("after KPP_applyNLT ", u, v, h, g, gv, us, haloshift=0)
1491  call mom_forcing_chksum("after KPP_applyNLT ", fluxes, g, us, haloshift=0)
1492  call mom_thermovar_chksum("after KPP_applyNLT ", tv, g)
1493  endif
1494  endif ! endif for KPP
1495 
1496  ! This is the "old" method for applying differential diffusion.
1497  ! Changes: tv%T, tv%S
1498  if (associated(visc%Kd_extra_T) .and. associated(visc%Kd_extra_S) .and. associated(tv%T) .and. &
1499  (.not.cs%use_CVMix_ddiff)) then
1500 
1501  call cpu_clock_begin(id_clock_differential_diff)
1502  call differential_diffuse_t_s(h, tv, visc, dt, g, gv)
1503  call cpu_clock_end(id_clock_differential_diff)
1504 
1505  if (showcalltree) call calltree_waypoint("done with differential_diffuse_T_S (diabatic)")
1506  if (cs%debugConservation) call mom_state_stats('differential_diffuse_T_S', u, v, h, tv%T, tv%S, g, gv, us)
1507 
1508  ! increment heat and salt diffusivity.
1509  ! CS%useKPP==.true. already has extra_T and extra_S included
1510  if (.not. cs%useKPP) then
1511  !$OMP parallel do default(shared)
1512  do k=2,nz ; do j=js,je ; do i=is,ie
1513  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
1514  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
1515  enddo ; enddo ; enddo
1516  endif
1517 
1518  endif
1519 
1520  ! Calculate vertical mixing due to convection (computed via CVMix)
1521  if (cs%use_CVMix_conv) then
1522  call calculate_cvmix_conv(h, tv, g, gv, us, cs%CVMix_conv_csp, hml)
1523  ! Increment vertical diffusion and viscosity due to convection
1524  !$OMP parallel do default(shared)
1525  do k=1,nz+1 ; do j=js,je ; do i=is,ie
1526  kd_heat(i,j,k) = kd_heat(i,j,k) + cs%CVMix_conv_csp%kd_conv(i,j,k)
1527  kd_salt(i,j,k) = kd_salt(i,j,k) + cs%CVMix_conv_csp%kd_conv(i,j,k)
1528  if (cs%useKPP) then
1529  visc%Kv_shear(i,j,k) = visc%Kv_shear(i,j,k) + cs%CVMix_conv_csp%kv_conv(i,j,k)
1530  else
1531  visc%Kv_slow(i,j,k) = visc%Kv_slow(i,j,k) + cs%CVMix_conv_csp%kv_conv(i,j,k)
1532  endif
1533  enddo ; enddo ; enddo
1534  endif
1535 
1536  ! Save fields before boundary forcing is applied for tendency diagnostics
1537  if (cs%boundary_forcing_tendency_diag) then
1538  do k=1,nz ; do j=js,je ; do i=is,ie
1539  h_diag(i,j,k) = h(i,j,k)
1540  temp_diag(i,j,k) = tv%T(i,j,k)
1541  saln_diag(i,j,k) = tv%S(i,j,k)
1542  enddo ; enddo ; enddo
1543  endif
1544 
1545  ! Apply forcing
1546  call cpu_clock_begin(id_clock_remap)
1547 
1548  ! Changes made to following fields: h, tv%T and tv%S.
1549  do k=1,nz ; do j=js,je ; do i=is,ie
1550  h_prebound(i,j,k) = h(i,j,k)
1551  enddo ; enddo ; enddo
1552  if (cs%use_energetic_PBL) then
1553 
1554  skinbuoyflux(:,:) = 0.0
1555  call applyboundaryfluxesinout(cs%diabatic_aux_CSp, g, gv, us, dt, fluxes, cs%optics, &
1556  optics_nbands(cs%optics), h, tv, cs%aggregate_FW_forcing, cs%evap_CFL_limit, &
1557  cs%minimum_forcing_depth, ctke, dsv_dt, dsv_ds, skinbuoyflux=skinbuoyflux)
1558 
1559  if (cs%debug) then
1560  call hchksum(ea_t, "after applyBoundaryFluxes ea_t",g%HI,haloshift=0, scale=gv%H_to_m)
1561  call hchksum(eb_t, "after applyBoundaryFluxes eb_t",g%HI,haloshift=0, scale=gv%H_to_m)
1562  call hchksum(ea_s, "after applyBoundaryFluxes ea_s",g%HI,haloshift=0, scale=gv%H_to_m)
1563  call hchksum(eb_s, "after applyBoundaryFluxes eb_s",g%HI,haloshift=0, scale=gv%H_to_m)
1564  call hchksum(ctke, "after applyBoundaryFluxes cTKE",g%HI,haloshift=0, &
1565  scale=us%R_to_kg_m3*us%Z_to_m**3*us%s_to_T**2)
1566  call hchksum(dsv_dt, "after applyBoundaryFluxes dSV_dT",g%HI,haloshift=0, scale=us%kg_m3_to_R)
1567  call hchksum(dsv_ds, "after applyBoundaryFluxes dSV_dS",g%HI,haloshift=0, scale=us%kg_m3_to_R)
1568  endif
1569 
1570  call find_uv_at_h(u, v, h, u_h, v_h, g, gv, us)
1571  call energetic_pbl(h, u_h, v_h, tv, fluxes, dt, kd_epbl, g, gv, us, &
1572  cs%energetic_PBL_CSp, dsv_dt, dsv_ds, ctke, skinbuoyflux, waves=waves)
1573 
1574  if (associated(hml)) then
1575  call energetic_pbl_get_mld(cs%energetic_PBL_CSp, hml(:,:), g, us)
1576  call pass_var(hml, g%domain, halo=1)
1577  ! If visc%MLD exists, copy ePBL's MLD into it
1578  if (associated(visc%MLD)) visc%MLD(:,:) = hml(:,:)
1579  elseif (associated(visc%MLD)) then
1580  call energetic_pbl_get_mld(cs%energetic_PBL_CSp, visc%MLD, g, us)
1581  call pass_var(visc%MLD, g%domain, halo=1)
1582  endif
1583 
1584  ! Augment the diffusivities and viscosity due to those diagnosed in energetic_PBL.
1585  do k=2,nz ; do j=js,je ; do i=is,ie
1586  !### These expressions assume a Prandtl number of 1.
1587  if (cs%ePBL_is_additive) then
1588  kd_add_here = kd_epbl(i,j,k)
1589  visc%Kv_shear(i,j,k) = visc%Kv_shear(i,j,k) + kd_epbl(i,j,k)
1590  else
1591  kd_add_here = max(kd_epbl(i,j,k) - visc%Kd_shear(i,j,k), 0.0)
1592  visc%Kv_shear(i,j,k) = max(visc%Kv_shear(i,j,k), kd_epbl(i,j,k))
1593  endif
1594 
1595  kd_heat(i,j,k) = kd_heat(i,j,k) + kd_add_here
1596  kd_salt(i,j,k) = kd_salt(i,j,k) + kd_add_here
1597 
1598  enddo ; enddo ; enddo
1599 
1600  if (cs%debug) then
1601  call hchksum(ea_t, "after ePBL ea_t",g%HI,haloshift=0, scale=gv%H_to_m)
1602  call hchksum(eb_t, "after ePBL eb_t",g%HI,haloshift=0, scale=gv%H_to_m)
1603  call hchksum(ea_s, "after ePBL ea_s",g%HI,haloshift=0, scale=gv%H_to_m)
1604  call hchksum(eb_s, "after ePBL eb_s",g%HI,haloshift=0, scale=gv%H_to_m)
1605  call hchksum(kd_epbl, "after ePBL Kd_ePBL", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
1606  endif
1607 
1608  else
1609  call applyboundaryfluxesinout(cs%diabatic_aux_CSp, g, gv, us, dt, fluxes, cs%optics, &
1610  optics_nbands(cs%optics), h, tv, cs%aggregate_FW_forcing, &
1611  cs%evap_CFL_limit, cs%minimum_forcing_depth)
1612 
1613  endif ! endif for CS%use_energetic_PBL
1614 
1615  ! diagnose the tendencies due to boundary forcing
1616  ! At this point, the diagnostic grids have not been updated since the call to the boundary layer scheme
1617  ! so all tendency diagnostics need to be posted on h_diag, and grids rebuilt afterwards
1618  if (cs%boundary_forcing_tendency_diag) then
1619  call diagnose_boundary_forcing_tendency(tv, h, temp_diag, saln_diag, h_diag, dt, g, gv, cs)
1620  if (cs%id_boundary_forcing_h > 0) call post_data(cs%id_boundary_forcing_h, h, cs%diag, alt_h = h_diag)
1621  endif
1622  ! Boundary fluxes may have changed T, S, and h
1623  call diag_update_remap_grids(cs%diag)
1624  call cpu_clock_end(id_clock_remap)
1625  if (cs%debug) then
1626  call mom_forcing_chksum("after applyBoundaryFluxes ", fluxes, g, us, haloshift=0)
1627  call mom_thermovar_chksum("after applyBoundaryFluxes ", tv, g)
1628  call mom_state_chksum("after applyBoundaryFluxes ", u, v, h, g, gv, us, haloshift=0)
1629  endif
1630  if (showcalltree) call calltree_waypoint("done with applyBoundaryFluxes (diabatic)")
1631  if (cs%debugConservation) call mom_state_stats('applyBoundaryFluxes', u, v, h, tv%T, tv%S, g, gv, us)
1632 
1633  if (showcalltree) call calltree_waypoint("done with h=ea-eb (diabatic)")
1634  if (cs%debugConservation) call mom_state_stats('h=ea-eb', u, v, h, tv%T, tv%S, g, gv, us)
1635 
1636  ! calculate change in temperature & salinity due to dia-coordinate surface diffusion
1637  if (associated(tv%T)) then
1638 
1639  if (cs%debug) then
1640  call hchksum(ea_t, "before triDiagTS ea_t ",g%HI,haloshift=0, scale=gv%H_to_m)
1641  call hchksum(eb_t, "before triDiagTS eb_t ",g%HI,haloshift=0, scale=gv%H_to_m)
1642  call hchksum(ea_s, "before triDiagTS ea_s ",g%HI,haloshift=0, scale=gv%H_to_m)
1643  call hchksum(eb_s, "before triDiagTS eb_s ",g%HI,haloshift=0, scale=gv%H_to_m)
1644  endif
1645 
1646  call cpu_clock_begin(id_clock_tridiag)
1647  ! Keep salinity from falling below a small but positive threshold.
1648  ! This constraint is needed for SIS1 ice model, which can extract
1649  ! more salt than is present in the ocean. SIS2 does not suffer
1650  ! from this limitation, in which case we can let salinity=0 and still
1651  ! have salt conserved with SIS2 ice. So for SIS2, we can run with
1652  ! BOUND_SALINITY=False in MOM.F90.
1653  if (associated(tv%S) .and. associated(tv%salt_deficit)) &
1654  call adjust_salt(h, tv, g, gv, cs%diabatic_aux_CSp)
1655 
1656  if (cs%diabatic_diff_tendency_diag) then
1657  do k=1,nz ; do j=js,je ; do i=is,ie
1658  temp_diag(i,j,k) = tv%T(i,j,k)
1659  saln_diag(i,j,k) = tv%S(i,j,k)
1660  enddo ; enddo ; enddo
1661  endif
1662 
1663  ! set ea_t=eb_t=Kd_heat and ea_s=eb_s=Kd_salt on interfaces for use in the
1664  ! tri-diagonal solver.
1665 
1666  do j=js,je ; do i=is,ie
1667  ea_t(i,j,1) = 0.; ea_s(i,j,1) = 0.
1668  enddo ; enddo
1669 
1670  !$OMP parallel do default(shared) private(hval)
1671  do k=2,nz ; do j=js,je ; do i=is,ie
1672  hval = 1.0 / (h_neglect + 0.5*(h(i,j,k-1) + h(i,j,k)))
1673  ea_t(i,j,k) = (gv%Z_to_H**2) * dt * hval * kd_heat(i,j,k)
1674  eb_t(i,j,k-1) = ea_t(i,j,k)
1675  ea_s(i,j,k) = (gv%Z_to_H**2) * dt * hval * kd_salt(i,j,k)
1676  eb_s(i,j,k-1) = ea_s(i,j,k)
1677  enddo ; enddo ; enddo
1678  do j=js,je ; do i=is,ie
1679  eb_t(i,j,nz) = 0. ; eb_s(i,j,nz) = 0.
1680  enddo ; enddo
1681  if (showcalltree) call calltree_waypoint("done setting ea_t,ea_s,eb_t,eb_s from Kd_heat" //&
1682  "and Kd_salt (diabatic)")
1683 
1684  ! Initialize halo regions of ea, eb, and hold to default values.
1685  !$OMP parallel do default(shared)
1686  do k=1,nz
1687  do i=is-1,ie+1
1688  ea_t(i,js-1,k) = 0.0 ; eb_t(i,js-1,k) = 0.0
1689  ea_s(i,js-1,k) = 0.0 ; eb_s(i,js-1,k) = 0.0
1690  ea_t(i,je+1,k) = 0.0 ; eb_t(i,je+1,k) = 0.0
1691  ea_s(i,je+1,k) = 0.0 ; eb_s(i,je+1,k) = 0.0
1692  enddo
1693  do j=js,je
1694  ea_t(is-1,j,k) = 0.0 ; eb_t(is-1,j,k) = 0.0
1695  ea_s(is-1,j,k) = 0.0 ; eb_s(is-1,j,k) = 0.0
1696  ea_t(ie+1,j,k) = 0.0 ; eb_t(ie+1,j,k) = 0.0
1697  ea_s(ie+1,j,k) = 0.0 ; eb_s(ie+1,j,k) = 0.0
1698  enddo
1699  enddo
1700 
1701  ! Changes T and S via the tridiagonal solver; no change to h
1702  call tracer_vertdiff(h, ea_t, eb_t, dt, tv%T, g, gv)
1703  call tracer_vertdiff(h, ea_s, eb_s, dt, tv%S, g, gv)
1704 
1705 
1706  ! In ALE-mode, layer thicknesses do not change. Therefore, we can use h below
1707  if (cs%diabatic_diff_tendency_diag) then
1708  call diagnose_diabatic_diff_tendency(tv, h, temp_diag, saln_diag, dt, g, gv, cs)
1709  endif
1710  call cpu_clock_end(id_clock_tridiag)
1711 
1712  if (showcalltree) call calltree_waypoint("done with triDiagTS (diabatic)")
1713 
1714  endif ! endif corresponding to if (associated(tv%T))
1715 
1716  if (cs%debugConservation) call mom_state_stats('triDiagTS', u, v, h, tv%T, tv%S, g, gv, us)
1717 
1718  if (cs%debug) then
1719  call mom_state_chksum("after mixed layer ", u, v, h, g, gv, us, haloshift=0)
1720  call mom_thermovar_chksum("after mixed layer ", tv, g)
1721  endif
1722 
1723  ! Whenever thickness changes let the diag manager know, as the
1724  ! target grids for vertical remapping may need to be regenerated.
1725  call diag_update_remap_grids(cs%diag)
1726 
1727  ! diagnostics
1728  idt = 1.0 / dt
1729  if ((cs%id_Tdif > 0) .or. (cs%id_Tadv > 0)) then
1730  do j=js,je ; do i=is,ie
1731  tdif_flx(i,j,1) = 0.0 ; tdif_flx(i,j,nz+1) = 0.0
1732  tadv_flx(i,j,1) = 0.0 ; tadv_flx(i,j,nz+1) = 0.0
1733  enddo ; enddo
1734  !$OMP parallel do default(shared)
1735  do k=2,nz ; do j=js,je ; do i=is,ie
1736  tdif_flx(i,j,k) = (idt * 0.5*(ea_t(i,j,k) + eb_t(i,j,k-1))) * &
1737  (tv%T(i,j,k-1) - tv%T(i,j,k))
1738  tadv_flx(i,j,k) = (idt * (ea_t(i,j,k) - eb_t(i,j,k-1))) * &
1739  0.5*(tv%T(i,j,k-1) + tv%T(i,j,k))
1740  enddo ; enddo ; enddo
1741  endif
1742  if ((cs%id_Sdif > 0) .or. (cs%id_Sadv > 0)) then
1743  do j=js,je ; do i=is,ie
1744  sdif_flx(i,j,1) = 0.0 ; sdif_flx(i,j,nz+1) = 0.0
1745  sadv_flx(i,j,1) = 0.0 ; sadv_flx(i,j,nz+1) = 0.0
1746  enddo ; enddo
1747  !$OMP parallel do default(shared)
1748  do k=2,nz ; do j=js,je ; do i=is,ie
1749  sdif_flx(i,j,k) = (idt * 0.5*(ea_s(i,j,k) + eb_s(i,j,k-1))) * &
1750  (tv%S(i,j,k-1) - tv%S(i,j,k))
1751  sadv_flx(i,j,k) = (idt * (ea_s(i,j,k) - eb_s(i,j,k-1))) * &
1752  0.5*(tv%S(i,j,k-1) + tv%S(i,j,k))
1753  enddo ; enddo ; enddo
1754  endif
1755 
1756  ! mixing of passive tracers from massless boundary layers to interior
1757  call cpu_clock_begin(id_clock_tracers)
1758 
1759  if (cs%mix_boundary_tracers) then
1760  tr_ea_bbl = gv%Z_to_H * sqrt(dt*cs%Kd_BBL_tr)
1761  !$OMP parallel do default(shared) private(htot,in_boundary,add_ent)
1762  do j=js,je
1763  do i=is,ie
1764  ebtr(i,j,nz) = eb_s(i,j,nz)
1765  htot(i) = 0.0
1766  in_boundary(i) = (g%mask2dT(i,j) > 0.0)
1767  enddo
1768  do k=nz,2,-1 ; do i=is,ie
1769  if (in_boundary(i)) then
1770  htot(i) = htot(i) + h(i,j,k)
1771  ! If diapycnal mixing has been suppressed because this is a massless
1772  ! layer near the bottom, add some mixing of tracers between these
1773  ! layers. This flux is based on the harmonic mean of the two
1774  ! thicknesses, as this corresponds pretty closely (to within
1775  ! differences in the density jumps between layers) with what is done
1776  ! in the calculation of the fluxes in the first place. Kd_min_tr
1777  ! should be much less than the values that have been set in Kd_int,
1778  ! perhaps a molecular diffusivity.
1779  add_ent = ((dt * cs%Kd_min_tr) * gv%Z_to_H**2) * &
1780  ((h(i,j,k-1)+h(i,j,k)+h_neglect) / &
1781  (h(i,j,k-1)*h(i,j,k)+h_neglect2)) - &
1782  0.5*(ea_s(i,j,k) + eb_s(i,j,k-1))
1783  if (htot(i) < tr_ea_bbl) then
1784  add_ent = max(0.0, add_ent, &
1785  (tr_ea_bbl - htot(i)) - min(ea_s(i,j,k),eb_s(i,j,k-1)))
1786  elseif (add_ent < 0.0) then
1787  add_ent = 0.0 ; in_boundary(i) = .false.
1788  endif
1789 
1790  ebtr(i,j,k-1) = eb_s(i,j,k-1) + add_ent
1791  eatr(i,j,k) = ea_s(i,j,k) + add_ent
1792  else
1793  ebtr(i,j,k-1) = eb_s(i,j,k-1) ; eatr(i,j,k) = ea_s(i,j,k)
1794  endif
1795 
1796  if (associated(visc%Kd_extra_S)) then ; if (visc%Kd_extra_S(i,j,k) > 0.0) then
1797  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
1798  (0.5 * (h(i,j,k-1) + h(i,j,k)) + &
1799  h_neglect)
1800  ebtr(i,j,k-1) = ebtr(i,j,k-1) + add_ent
1801  eatr(i,j,k) = eatr(i,j,k) + add_ent
1802  endif ; endif
1803  enddo ; enddo
1804  do i=is,ie ; eatr(i,j,1) = ea_s(i,j,1) ; enddo
1805 
1806  enddo
1807 
1808  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1809  ! so hold should be h_orig
1810  call call_tracer_column_fns(h_prebound, h, ea_s, eb_s, fluxes, hml, dt, g, gv, us, tv, &
1811  cs%optics, cs%tracer_flow_CSp, cs%debug, &
1812  evap_cfl_limit = cs%evap_CFL_limit, &
1813  minimum_forcing_depth=cs%minimum_forcing_depth)
1814 
1815  elseif (associated(visc%Kd_extra_S)) then ! extra diffusivity for passive tracers
1816 
1817  do j=js,je ; do i=is,ie
1818  ebtr(i,j,nz) = eb_s(i,j,nz) ; eatr(i,j,1) = ea_s(i,j,1)
1819  enddo ; enddo
1820  !$OMP parallel do default(shared) private(add_ent)
1821  do k=nz,2,-1 ; do j=js,je ; do i=is,ie
1822  if (visc%Kd_extra_S(i,j,k) > 0.0) then
1823  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
1824  (0.5 * (h(i,j,k-1) + h(i,j,k)) + &
1825  h_neglect)
1826  else
1827  add_ent = 0.0
1828  endif
1829  ebtr(i,j,k-1) = eb_s(i,j,k-1) + add_ent
1830  eatr(i,j,k) = ea_s(i,j,k) + add_ent
1831  enddo ; enddo ; enddo
1832 
1833  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1834  call call_tracer_column_fns(h_prebound, h, eatr, ebtr, fluxes, hml, dt, g, gv, us, tv, &
1835  cs%optics, cs%tracer_flow_CSp, cs%debug,&
1836  evap_cfl_limit = cs%evap_CFL_limit, &
1837  minimum_forcing_depth=cs%minimum_forcing_depth)
1838  else
1839  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1840  call call_tracer_column_fns(h_prebound, h, eatr, ebtr, fluxes, hml, dt, g, gv, us, tv, &
1841  cs%optics, cs%tracer_flow_CSp, cs%debug, &
1842  evap_cfl_limit = cs%evap_CFL_limit, &
1843  minimum_forcing_depth=cs%minimum_forcing_depth)
1844  endif ! (CS%mix_boundary_tracers)
1845 
1846  call cpu_clock_end(id_clock_tracers)
1847 
1848  ! Apply ALE sponge
1849  if (cs%use_sponge) then
1850  call cpu_clock_begin(id_clock_sponge)
1851  if (associated(cs%ALE_sponge_CSp)) then
1852  call apply_ale_sponge(h, dt, g, gv, us, cs%ALE_sponge_CSp, cs%Time)
1853  endif
1854 
1855  call cpu_clock_end(id_clock_sponge)
1856  if (cs%debug) then
1857  call mom_state_chksum("apply_sponge ", u, v, h, g, gv, us, haloshift=0)
1858  call mom_thermovar_chksum("apply_sponge ", tv, g)
1859  endif
1860  endif ! CS%use_sponge
1861 
1862  call cpu_clock_begin(id_clock_pass)
1863  if (g%symmetric) then ; dir_flag = to_all+omit_corners
1864  else ; dir_flag = to_west+to_south+omit_corners ; endif
1865  call create_group_pass(cs%pass_hold_eb_ea, eb_t, g%Domain, dir_flag, halo=1)
1866  call create_group_pass(cs%pass_hold_eb_ea, eb_s, g%Domain, dir_flag, halo=1)
1867  call create_group_pass(cs%pass_hold_eb_ea, ea_t, g%Domain, dir_flag, halo=1)
1868  call create_group_pass(cs%pass_hold_eb_ea, ea_s, g%Domain, dir_flag, halo=1)
1869  call do_group_pass(cs%pass_hold_eb_ea, g%Domain)
1870  ! visc%Kv_slow is not in the group pass because it has larger vertical extent.
1871  if (associated(visc%Kv_slow)) &
1872  call pass_var(visc%Kv_slow, g%Domain, to_all+omit_corners, halo=1)
1873  call cpu_clock_end(id_clock_pass)
1874 
1875  call disable_averaging(cs%diag)
1876 
1877  ! Diagnose the diapycnal diffusivities and other related quantities.
1878  call enable_averages(dt, time_end, cs%diag)
1879 
1880  if (cs%id_Kd_interface > 0) call post_data(cs%id_Kd_interface, kd_int, cs%diag)
1881  if (cs%id_Kd_heat > 0) call post_data(cs%id_Kd_heat, kd_heat, cs%diag)
1882  if (cs%id_Kd_salt > 0) call post_data(cs%id_Kd_salt, kd_salt, cs%diag)
1883  if (cs%id_Kd_ePBL > 0) call post_data(cs%id_Kd_ePBL, kd_epbl, cs%diag)
1884 
1885  if (cs%id_ea_t > 0) call post_data(cs%id_ea_t, ea_t, cs%diag)
1886  if (cs%id_eb_t > 0) call post_data(cs%id_eb_t, eb_t, cs%diag)
1887  if (cs%id_ea_s > 0) call post_data(cs%id_ea_s, ea_s, cs%diag)
1888  if (cs%id_eb_s > 0) call post_data(cs%id_eb_s, eb_s, cs%diag)
1889 
1890  if (cs%id_dudt_dia > 0) call post_data(cs%id_dudt_dia, adp%du_dt_dia, cs%diag)
1891  if (cs%id_dvdt_dia > 0) call post_data(cs%id_dvdt_dia, adp%dv_dt_dia, cs%diag)
1892 
1893  if (cs%id_Tdif > 0) call post_data(cs%id_Tdif, tdif_flx, cs%diag)
1894  if (cs%id_Tadv > 0) call post_data(cs%id_Tadv, tadv_flx, cs%diag)
1895  if (cs%id_Sdif > 0) call post_data(cs%id_Sdif, sdif_flx, cs%diag)
1896  if (cs%id_Sadv > 0) call post_data(cs%id_Sadv, sadv_flx, cs%diag)
1897 
1898  call disable_averaging(cs%diag)
1899 
1900  if (showcalltree) call calltree_leave("diabatic_ALE()")
1901 
1902 end subroutine diabatic_ale
1903 
1904 !> Imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentum and tracers
1905 !! using the original MOM6 algorithms.
1906 subroutine layered_diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, &
1907  G, GV, US, CS, WAVES)
1908  type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1909  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
1910  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1911  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
1912  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
1913  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
1914  type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
1915  !! unused have NULL ptrs
1916  real, dimension(:,:), pointer :: Hml !< Active mixed layer depth [m]
1917  type(forcing), intent(inout) :: fluxes !< points to forcing fields
1918  !! unused fields have NULL ptrs
1919  type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and
1920  type(accel_diag_ptrs), intent(inout) :: ADp !< related points to accelerations in momentum
1921  !! equations, to enable the later derived
1922  !! diagnostics, like energy budgets
1923  type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
1924  real, intent(in) :: dt !< time increment [T ~> s]
1925  type(time_type), intent(in) :: Time_end !< Time at the end of the interval
1926  type(diabatic_cs), pointer :: CS !< module control structure
1927  type(wave_parameters_cs), optional, pointer :: Waves !< Surface gravity waves
1928 
1929  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
1930  ea, & ! amount of fluid entrained from the layer above within
1931  ! one time step [H ~> m or kg m-2]
1932  eb, & ! amount of fluid entrained from the layer below within
1933  ! one time step [H ~> m or kg m-2]
1934  kd_lay, & ! diapycnal diffusivity of layers [Z2 T-1 ~> m2 s-1]
1935  h_orig, & ! initial layer thicknesses [H ~> m or kg m-2]
1936  h_prebound, & ! initial layer thicknesses [H ~> m or kg m-2]
1937  hold, & ! layer thickness before diapycnal entrainment, and later
1938  ! the initial layer thicknesses (if a mixed layer is used),
1939  ! [H ~> m or kg m-2]
1940  dsv_dt, & ! The partial derivative of specific volume with temperature [R-1 degC-1 ~> m3 kg-1 degC-1]
1941  dsv_ds, & ! The partial derivative of specific volume with salinity [R-1 ppt-1 ~> m3 kg-1 ppt-1].
1942  u_h, & ! zonal and meridional velocities at thickness points after
1943  v_h ! entrainment [L T-1 ~> m s-1]
1944  real, dimension(SZI_(G),SZJ_(G)) :: &
1945  Rcv_ml, & ! coordinate density of mixed layer, used for applying sponges
1946  SkinBuoyFlux! 2d surface buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL
1947  real, dimension(SZI_(G),SZJ_(G),G%ke) :: h_diag ! diagnostic array for thickness
1948  real, dimension(SZI_(G),SZJ_(G),G%ke) :: temp_diag ! diagnostic array for temp
1949  real, dimension(SZI_(G),SZJ_(G),G%ke) :: saln_diag ! diagnostic array for salinity
1950  real, dimension(SZI_(G),SZJ_(G)) :: tendency_2d ! depth integrated content tendency for diagn
1951 
1952  real :: net_ent ! The net of ea-eb at an interface.
1953 
1954  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), target :: &
1955  ! These are targets so that the space can be shared with eaml & ebml.
1956  eatr, & ! The equivalent of ea and eb for tracers, which differ from ea and
1957  ebtr ! eb in that they tend to homogenize tracers in massless layers
1958  ! near the boundaries [H ~> m or kg m-2] (for Bous or non-Bouss)
1959 
1960  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), target :: &
1961  Kd_int, & ! diapycnal diffusivity of interfaces [Z2 T-1 ~> m2 s-1]
1962  Kd_heat, & ! diapycnal diffusivity of heat [Z2 T-1 ~> m2 s-1]
1963  Kd_salt, & ! diapycnal diffusivity of salt and passive tracers [Z2 T-1 ~> m2 s-1]
1964  Kd_ePBL, & ! test array of diapycnal diffusivities at interfaces [Z2 T-1 ~> m2 s-1]
1965  Tdif_flx, & ! diffusive diapycnal heat flux across interfaces [degC H T-1 ~> degC m s-1 or degC kg m-2 s-1]
1966  Tadv_flx, & ! advective diapycnal heat flux across interfaces [degC H T-1 ~> degC m s-1 or degC kg m-2 s-1]
1967  Sdif_flx, & ! diffusive diapycnal salt flux across interfaces [ppt H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
1968  Sadv_flx ! advective diapycnal salt flux across interfaces [ppt H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
1969 
1970  ! The following 5 variables are only used with a bulk mixed layer.
1971  real, pointer, dimension(:,:,:) :: &
1972  eaml, & ! The equivalent of ea due to mixed layer processes [H ~> m or kg m-2].
1973  ebml ! The equivalent of eb due to mixed layer processes [H ~> m or kg m-2].
1974  ! eaml and ebml are pointers to eatr and ebtr so as to reuse the memory as
1975  ! the arrays are not needed at the same time.
1976 
1977  integer :: kb(SZI_(G),SZJ_(G)) ! index of the lightest layer denser
1978  ! than the buffer layer [nondim]
1979 
1980  real :: p_ref_cv(SZI_(G)) ! Reference pressure for the potential
1981  ! density which defines the coordinate
1982  ! variable, set to P_Ref [Pa].
1983 
1984  logical :: in_boundary(SZI_(G)) ! True if there are no massive layers below,
1985  ! where massive is defined as sufficiently thick that
1986  ! the no-flux boundary conditions have not restricted
1987  ! the entrainment - usually sqrt(Kd*dt).
1988 
1989  real :: b_denom_1 ! The first term in the denominator of b1
1990  ! [H ~> m or kg m-2]
1991  real :: h_neglect ! A thickness that is so small it is usually lost
1992  ! in roundoff and can be neglected
1993  ! [H ~> m or kg m-2]
1994  real :: h_neglect2 ! h_neglect^2 [H2 ~> m2 or kg2 m-4]
1995  real :: add_ent ! Entrainment that needs to be added when mixing tracers
1996  ! [H ~> m or kg m-2]
1997  real :: eaval ! eaval is 2*ea at velocity grid points [H ~> m or kg m-2]
1998  real :: hval ! hval is 2*h at velocity grid points [H ~> m or kg m-2]
1999  real :: h_tr ! h_tr is h at tracer points with a tiny thickness
2000  ! added to ensure positive definiteness [H ~> m or kg m-2]
2001  real :: Tr_ea_BBL ! The diffusive tracer thickness in the BBL that is
2002  ! coupled to the bottom within a timestep [H ~> m or kg m-2]
2003 
2004  real :: htot(SZIB_(G)) ! The summed thickness from the bottom [H ~> m or kg m-2].
2005  real :: b1(SZIB_(G)), d1(SZIB_(G)) ! b1, c1, and d1 are variables used by the
2006  real :: c1(SZIB_(G),SZK_(G)) ! tridiagonal solver.
2007 
2008  real :: Ent_int ! The diffusive entrainment rate at an interface [H ~> m or kg m-2]
2009  real :: dt_mix ! The amount of time over which to apply mixing [T ~> s]
2010  real :: Idt ! The inverse time step [T-1 ~> s-1]
2011  real :: Idt_accel ! The inverse time step times rescaling factors [T-1 ~> s-1]
2012 
2013  integer :: dir_flag ! An integer encoding the directions in which to do halo updates.
2014  logical :: showCallTree ! If true, show the call tree
2015  integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb, m, halo
2016 
2017  integer :: ig, jg ! global indices for testing testing itide point source (BDM)
2018  real :: Kd_add_here ! An added diffusivity [Z2 T-1 ~> m2 s-1].
2019 
2020  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
2021  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
2022  nkmb = gv%nk_rho_varies
2023  h_neglect = gv%H_subroundoff ; h_neglect2 = h_neglect*h_neglect
2024  kd_heat(:,:,:) = 0.0 ; kd_salt(:,:,:) = 0.0
2025 
2026 
2027  showcalltree = calltree_showquery()
2028  if (showcalltree) call calltree_enter("layered_diabatic(), MOM_diabatic_driver.F90")
2029 
2030  ! set equivalence between the same bits of memory for these arrays
2031  eaml => eatr ; ebml => ebtr
2032 
2033  ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep
2034  call enable_averages(dt, time_end, cs%diag)
2035 
2036  if ((cs%ML_mix_first > 0.0) .or. cs%use_geothermal) then
2037  halo = cs%halo_TS_diff
2038  !$OMP parallel do default(shared)
2039  do k=1,nz ; do j=js-halo,je+halo ; do i=is-halo,ie+halo
2040  h_orig(i,j,k) = h(i,j,k) ; eaml(i,j,k) = 0.0 ; ebml(i,j,k) = 0.0
2041  enddo ; enddo ; enddo
2042  endif
2043 
2044  if (cs%use_geothermal) then
2045  call cpu_clock_begin(id_clock_geothermal)
2046  call geothermal(h, tv, dt, eaml, ebml, g, gv, us, cs%geothermal_CSp, halo=cs%halo_TS_diff)
2047  call cpu_clock_end(id_clock_geothermal)
2048  if (showcalltree) call calltree_waypoint("geothermal (diabatic)")
2049  if (cs%debugConservation) call mom_state_stats('geothermal', u, v, h, tv%T, tv%S, g, gv, us)
2050  endif
2051 
2052  ! Whenever thickness changes let the diag manager know, target grids
2053  ! for vertical remapping may need to be regenerated.
2054  call diag_update_remap_grids(cs%diag)
2055 
2056  ! Set_pen_shortwave estimates the optical properties of the water column.
2057  ! It will need to be modified later to include information about the
2058  ! biological properties and layer thicknesses.
2059  if (associated(cs%optics)) &
2060  call set_pen_shortwave(cs%optics, fluxes, g, gv, cs%diabatic_aux_CSp, cs%opacity_CSp, cs%tracer_flow_CSp)
2061 
2062  if (cs%bulkmixedlayer) then
2063  if (cs%debug) call mom_forcing_chksum("Before mixedlayer", fluxes, g, us, haloshift=0)
2064 
2065  if (cs%ML_mix_first > 0.0) then
2066 ! This subroutine
2067 ! (1) Cools the mixed layer.
2068 ! (2) Performs convective adjustment by mixed layer entrainment.
2069 ! (3) Heats the mixed layer and causes it to detrain to
2070 ! Monin-Obukhov depth or minimum mixed layer depth.
2071 ! (4) Uses any remaining TKE to drive mixed layer entrainment.
2072 ! (5) Possibly splits buffer layer into two isopycnal layers (when using isopycnal coordinate)
2073  call find_uv_at_h(u, v, h, u_h, v_h, g, gv, us)
2074 
2075  call cpu_clock_begin(id_clock_mixedlayer)
2076  if (cs%ML_mix_first < 1.0) then
2077  ! Changes: h, tv%T, tv%S, eaml and ebml (G is also inout???)
2078  call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt*cs%ML_mix_first, &
2079  eaml,ebml, g, gv, us, cs%bulkmixedlayer_CSp, cs%optics, &
2080  hml, cs%aggregate_FW_forcing, dt, last_call=.false.)
2081  if (cs%salt_reject_below_ML) &
2082  call insert_brine(h, tv, g, gv, us, fluxes, nkmb, cs%diabatic_aux_CSp, &
2083  dt*cs%ML_mix_first, cs%id_brine_lay)
2084  else
2085  ! Changes: h, tv%T, tv%S, eaml and ebml (G is also inout???)
2086  call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt, eaml, ebml, &
2087  g, gv, us, cs%bulkmixedlayer_CSp, cs%optics, &
2088  hml, cs%aggregate_FW_forcing, dt, last_call=.true.)
2089  endif
2090 
2091  ! Keep salinity from falling below a small but positive threshold.
2092  ! This constraint is needed for SIS1 ice model, which can extract
2093  ! more salt than is present in the ocean. SIS2 does not suffer
2094  ! from this limitation, in which case we can let salinity=0 and still
2095  ! have salt conserved with SIS2 ice. So for SIS2, we can run with
2096  ! BOUND_SALINITY=False in MOM.F90.
2097  if (associated(tv%S) .and. associated(tv%salt_deficit)) &
2098  call adjust_salt(h, tv, g, gv, cs%diabatic_aux_CSp)
2099  call cpu_clock_end(id_clock_mixedlayer)
2100  if (cs%debug) then
2101  call mom_state_chksum("After mixedlayer ", u, v, h, g, gv, us, haloshift=0)
2102  call mom_forcing_chksum("After mixedlayer", fluxes, g, us, haloshift=0)
2103  endif
2104  if (showcalltree) call calltree_waypoint("done with 1st bulkmixedlayer (diabatic)")
2105  if (cs%debugConservation) call mom_state_stats('1st bulkmixedlayer', u, v, h, tv%T, tv%S, g, gv, us)
2106  endif
2107  endif
2108 
2109  if (cs%debug) &
2110  call mom_state_chksum("before find_uv_at_h", u, v, h, g, gv, us, haloshift=0)
2111  if (cs%use_kappa_shear .or. cs%use_CVMix_shear) then
2112  if ((cs%ML_mix_first > 0.0) .or. cs%use_geothermal) then
2113  call find_uv_at_h(u, v, h_orig, u_h, v_h, g, gv, us, eaml, ebml)
2114  if (cs%debug) then
2115  call hchksum(eaml, "after find_uv_at_h eaml",g%HI, scale=gv%H_to_m)
2116  call hchksum(ebml, "after find_uv_at_h ebml",g%HI, scale=gv%H_to_m)
2117  endif
2118  else
2119  call find_uv_at_h(u, v, h, u_h, v_h, g, gv, us)
2120  endif
2121  if (showcalltree) call calltree_waypoint("done with find_uv_at_h (diabatic)")
2122  endif
2123 
2124  call cpu_clock_begin(id_clock_set_diffusivity)
2125  ! Sets: Kd_lay, Kd_int, visc%Kd_extra_T, visc%Kd_extra_S and visc%TKE_turb
2126  ! Also changes: visc%Kd_shear and visc%Kv_shear
2127  if ((cs%halo_TS_diff > 0) .and. (cs%ML_mix_first > 0.0)) then
2128  if (associated(tv%T)) call pass_var(tv%T, g%Domain, halo=cs%halo_TS_diff, complete=.false.)
2129  if (associated(tv%T)) call pass_var(tv%S, g%Domain, halo=cs%halo_TS_diff, complete=.false.)
2130  call pass_var(h, g%domain, halo=cs%halo_TS_diff, complete=.true.)
2131  endif
2132  call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, cs%optics, &
2133  visc, dt, g, gv, us, cs%set_diff_CSp, kd_lay, kd_int)
2134  call cpu_clock_end(id_clock_set_diffusivity)
2135  if (showcalltree) call calltree_waypoint("done with set_diffusivity (diabatic)")
2136 
2137  if (cs%debug) then
2138  call mom_state_chksum("after set_diffusivity ", u, v, h, g, gv, us, haloshift=0)
2139  call mom_forcing_chksum("after set_diffusivity ", fluxes, g, us, haloshift=0)
2140  call mom_thermovar_chksum("after set_diffusivity ", tv, g)
2141  call hchksum(kd_lay, "after set_diffusivity Kd_lay", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
2142  call hchksum(kd_int, "after set_diffusivity Kd_Int", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
2143  endif
2144 
2145 
2146  if (cs%useKPP) then
2147  call cpu_clock_begin(id_clock_kpp)
2148  ! KPP needs the surface buoyancy flux but does not update state variables.
2149  ! We could make this call higher up to avoid a repeat unpacking of the surface fluxes.
2150  ! Sets: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux
2151  ! NOTE: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux are returned as rates (i.e. stuff per second)
2152  ! unlike other instances where the fluxes are integrated in time over a time-step.
2153  call calculatebuoyancyflux2d(g, gv, us, fluxes, cs%optics, h, tv%T, tv%S, tv, &
2154  cs%KPP_buoy_flux, cs%KPP_temp_flux, cs%KPP_salt_flux)
2155  ! The KPP scheme calculates boundary layer diffusivities and non-local transport.
2156 
2157  ! Set diffusivities for heat and salt separately
2158 
2159  !$OMP parallel do default(shared)
2160  do k=1,nz+1 ; do j=js,je ; do i=is,ie
2161  kd_salt(i,j,k) = kd_int(i,j,k)
2162  kd_heat(i,j,k) = kd_int(i,j,k)
2163  enddo ; enddo ; enddo
2164  ! Add contribution from double diffusion
2165  if (associated(visc%Kd_extra_S)) then
2166  !$OMP parallel do default(shared)
2167  do k=1,nz+1 ; do j=js,je ; do i=is,ie
2168  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
2169  enddo ; enddo ; enddo
2170  endif
2171  if (associated(visc%Kd_extra_T)) then
2172  !$OMP parallel do default(shared)
2173  do k=1,nz+1 ; do j=js,je ; do i=is,ie
2174  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
2175  enddo ; enddo ; enddo
2176  endif
2177 
2178  call kpp_compute_bld(cs%KPP_CSp, g, gv, us, h, tv%T, tv%S, u, v, tv%eqn_of_state, &
2179  fluxes%ustar, cs%KPP_buoy_flux, waves=waves)
2180 
2181  call kpp_calculate(cs%KPP_CSp, g, gv, us, h, fluxes%ustar, cs%KPP_buoy_flux, kd_heat, &
2182  kd_salt, visc%Kv_shear, cs%KPP_NLTheat, cs%KPP_NLTscalar, waves=waves)
2183 
2184  if (associated(hml)) then
2185  call kpp_get_bld(cs%KPP_CSp, hml(:,:), g)
2186  call pass_var(hml, g%domain, halo=1)
2187  ! If visc%MLD exists, copy KPP's BLD into it
2188  if (associated(visc%MLD)) visc%MLD(:,:) = hml(:,:)
2189  endif
2190 
2191  if (.not. cs%KPPisPassive) then
2192  !$OMP parallel do default(shared)
2193  do k=1,nz+1 ; do j=js,je ; do i=is,ie
2194  kd_int(i,j,k) = min( kd_salt(i,j,k), kd_heat(i,j,k) )
2195  enddo ; enddo ; enddo
2196  if (associated(visc%Kd_extra_S)) then
2197  !$OMP parallel do default(shared)
2198  do k=1,nz+1 ; do j=js,je ; do i=is,ie
2199  visc%Kd_extra_S(i,j,k) = (kd_salt(i,j,k) - kd_int(i,j,k))
2200  enddo ; enddo ; enddo
2201  endif
2202  if (associated(visc%Kd_extra_T)) then
2203  !$OMP parallel do default(shared)
2204  do k=1,nz+1 ; do j=js,je ; do i=is,ie
2205  visc%Kd_extra_T(i,j,k) = (kd_heat(i,j,k) - kd_int(i,j,k))
2206  enddo ; enddo ; enddo
2207  endif
2208  endif ! not passive
2209 
2210  call cpu_clock_end(id_clock_kpp)
2211  if (showcalltree) call calltree_waypoint("done with KPP_calculate (diabatic)")
2212  if (cs%debug) then
2213  call mom_state_chksum("after KPP", u, v, h, g, gv, us, haloshift=0)
2214  call mom_forcing_chksum("after KPP", fluxes, g, us, haloshift=0)
2215  call mom_thermovar_chksum("after KPP", tv, g)
2216  call hchksum(kd_lay, "after KPP Kd_lay", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
2217  call hchksum(kd_int, "after KPP Kd_Int", g%HI, haloshift=0, scale=us%Z2_T_to_m2_s)
2218  endif
2219 
2220  endif ! endif for KPP
2221 
2222  ! Add vertical diff./visc. due to convection (computed via CVMix)
2223  if (cs%use_CVMix_conv) then
2224  call calculate_cvmix_conv(h, tv, g, gv, us, cs%CVMix_conv_csp, hml)
2225 
2226  do k=1,nz+1 ; do j=js,je ; do i=is,ie
2227  kd_int(i,j,k) = kd_int(i,j,k) + cs%CVMix_conv_csp%kd_conv(i,j,k)
2228  visc%Kv_slow(i,j,k) = visc%Kv_slow(i,j,k) + cs%CVMix_conv_csp%kv_conv(i,j,k)
2229  enddo ; enddo ; enddo
2230  endif
2231 
2232  if (cs%useKPP) then
2233  call cpu_clock_begin(id_clock_kpp)
2234  if (cs%debug) then
2235  call hchksum(cs%KPP_temp_flux, "before KPP_applyNLT netHeat", g%HI, haloshift=0, scale=gv%H_to_m)
2236  call hchksum(cs%KPP_salt_flux, "before KPP_applyNLT netSalt", g%HI, haloshift=0, scale=gv%H_to_m)
2237  call hchksum(cs%KPP_NLTheat, "before KPP_applyNLT NLTheat", g%HI, haloshift=0)
2238  call hchksum(cs%KPP_NLTscalar, "before KPP_applyNLT NLTscalar", g%HI, haloshift=0)
2239  endif
2240  ! Apply non-local transport of heat and salt
2241  ! Changes: tv%T, tv%S
2242  call kpp_nonlocaltransport_temp(cs%KPP_CSp, g, gv, h, cs%KPP_NLTheat, cs%KPP_temp_flux, &
2243  us%T_to_s*dt, tv%T, tv%C_p)
2244  call kpp_nonlocaltransport_saln(cs%KPP_CSp, g, gv, h, cs%KPP_NLTscalar, cs%KPP_salt_flux, &
2245  us%T_to_s*dt, tv%S)
2246  call cpu_clock_end(id_clock_kpp)
2247  if (showcalltree) call calltree_waypoint("done with KPP_applyNonLocalTransport (diabatic)")
2248  if (cs%debugConservation) call mom_state_stats('KPP_applyNonLocalTransport', u, v, h, tv%T, tv%S, g, gv, us)
2249 
2250  if (cs%debug) then
2251  call mom_state_chksum("after KPP_applyNLT ", u, v, h, g, gv, us, haloshift=0)
2252  call mom_forcing_chksum("after KPP_applyNLT ", fluxes, g, us, haloshift=0)
2253  call mom_thermovar_chksum("after KPP_applyNLT ", tv, g)
2254  endif
2255  endif ! endif for KPP
2256 
2257  ! Differential diffusion done here.
2258  ! Changes: tv%T, tv%S
2259  if (associated(visc%Kd_extra_T) .and. associated(visc%Kd_extra_S) .and. associated(tv%T)) then
2260 
2261  call cpu_clock_begin(id_clock_differential_diff)
2262  call differential_diffuse_t_s(h, tv, visc, dt, g, gv)
2263  call cpu_clock_end(id_clock_differential_diff)
2264  if (showcalltree) call calltree_waypoint("done with differential_diffuse_T_S (diabatic)")
2265  if (cs%debugConservation) call mom_state_stats('differential_diffuse_T_S', u, v, h, tv%T, tv%S, g, gv, us)
2266 
2267  ! increment heat and salt diffusivity.
2268  ! CS%useKPP==.true. already has extra_T and extra_S included
2269  if (.not. cs%useKPP) then
2270  !$OMP parallel do default(shared)
2271  do k=2,nz ; do j=js,je ; do i=is,ie
2272  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
2273  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
2274  enddo ; enddo ; enddo
2275  endif
2276 
2277  endif
2278 
2279  ! This block sets ea, eb from Kd or Kd_int.
2280  ! Otherwise, call entrainment_diffusive() which sets ea and eb
2281  ! based on KD and target densities (ie. does remapping as well).
2282  ! When not using ALE, calculate layer entrainments/detrainments from
2283  ! diffusivities and differences between layer and target densities
2284  call cpu_clock_begin(id_clock_entrain)
2285  ! Calculate appropriately limited diapycnal mass fluxes to account
2286  ! for diapycnal diffusion and advection. Sets: ea, eb. Changes: kb
2287  call entrainment_diffusive(h, tv, fluxes, dt, g, gv, us, cs%entrain_diffusive_CSp, &
2288  ea, eb, kb, kd_lay=kd_lay, kd_int=kd_int)
2289  call cpu_clock_end(id_clock_entrain)
2290  if (showcalltree) call calltree_waypoint("done with Entrainment_diffusive (diabatic)")
2291 
2292  if (cs%debug) then
2293  call mom_forcing_chksum("after calc_entrain ", fluxes, g, us, haloshift=0)
2294  call mom_thermovar_chksum("after calc_entrain ", tv, g)
2295  call mom_state_chksum("after calc_entrain ", u, v, h, g, gv, us, haloshift=0)
2296  call hchksum(ea, "after calc_entrain ea", g%HI, haloshift=0, scale=gv%H_to_m)
2297  call hchksum(eb, "after calc_entrain eb", g%HI, haloshift=0, scale=gv%H_to_m)
2298  endif
2299 
2300  ! Save fields before boundary forcing is applied for tendency diagnostics
2301  if (cs%boundary_forcing_tendency_diag) then
2302  do k=1,nz ; do j=js,je ; do i=is,ie
2303  h_diag(i,j,k) = h(i,j,k)
2304  temp_diag(i,j,k) = tv%T(i,j,k)
2305  saln_diag(i,j,k) = tv%S(i,j,k)
2306  enddo ; enddo ; enddo
2307  endif
2308 
2309  ! Update h according to divergence of the difference between
2310  ! ea and eb. We keep a record of the original h in hold.
2311  ! In the following, the checks for negative values are to guard
2312  ! against instances where entrainment drives a layer to
2313  ! negative thickness. This situation will never happen if
2314  ! enough iterations are permitted in Calculate_Entrainment.
2315  ! Even if too few iterations are allowed, it is still guarded
2316  ! against. In other words the checks are probably unnecessary.
2317  !$OMP parallel do default(shared)
2318  do j=js,je
2319  do i=is,ie
2320  hold(i,j,1) = h(i,j,1)
2321  h(i,j,1) = h(i,j,1) + (eb(i,j,1) - ea(i,j,2))
2322  hold(i,j,nz) = h(i,j,nz)
2323  h(i,j,nz) = h(i,j,nz) + (ea(i,j,nz) - eb(i,j,nz-1))
2324  if (h(i,j,1) <= 0.0) then
2325  h(i,j,1) = gv%Angstrom_H
2326  endif
2327  if (h(i,j,nz) <= 0.0) then
2328  h(i,j,nz) = gv%Angstrom_H
2329  endif
2330  enddo
2331  do k=2,nz-1 ; do i=is,ie
2332  hold(i,j,k) = h(i,j,k)
2333  h(i,j,k) = h(i,j,k) + ((ea(i,j,k) - eb(i,j,k-1)) + &
2334  (eb(i,j,k) - ea(i,j,k+1)))
2335  if (h(i,j,k) <= 0.0) then
2336  h(i,j,k) = gv%Angstrom_H
2337  endif
2338  enddo ; enddo
2339  enddo
2340  ! Checks for negative thickness may have changed layer thicknesses
2341  call diag_update_remap_grids(cs%diag)
2342 
2343  if (cs%debug) then
2344  call mom_state_chksum("after negative check ", u, v, h, g, gv, us, haloshift=0)
2345  call mom_forcing_chksum("after negative check ", fluxes, g, us, haloshift=0)
2346  call mom_thermovar_chksum("after negative check ", tv, g)
2347  endif
2348  if (showcalltree) call calltree_waypoint("done with h=ea-eb (diabatic)")
2349  if (cs%debugConservation) call mom_state_stats('h=ea-eb', u, v, h, tv%T, tv%S, g, gv, us)
2350 
2351  ! Here, T and S are updated according to ea and eb.
2352  ! If using the bulk mixed layer, T and S are also updated
2353  ! by surface fluxes (in fluxes%*).
2354  ! This is a very long block.
2355  if (cs%bulkmixedlayer) then
2356 
2357  if (associated(tv%T)) then
2358  call cpu_clock_begin(id_clock_tridiag)
2359  ! Temperature and salinity (as state variables) are treated
2360  ! differently from other tracers to insure massless layers that
2361  ! are lighter than the mixed layer have temperatures and salinities
2362  ! that correspond to their prescribed densities.
2363  if (cs%massless_match_targets) then
2364  !$OMP parallel do default (shared) private(h_tr,b1,d1,c1,b_denom_1)
2365  do j=js,je
2366  do i=is,ie
2367  h_tr = hold(i,j,1) + h_neglect
2368  b1(i) = 1.0 / (h_tr + eb(i,j,1))
2369  d1(i) = h_tr * b1(i)
2370  tv%T(i,j,1) = b1(i) * (h_tr*tv%T(i,j,1))
2371  tv%S(i,j,1) = b1(i) * (h_tr*tv%S(i,j,1))
2372  enddo
2373  do k=2,nkmb ; do i=is,ie
2374  c1(i,k) = eb(i,j,k-1) * b1(i)
2375  h_tr = hold(i,j,k) + h_neglect
2376  b_denom_1 = h_tr + d1(i)*ea(i,j,k)
2377  b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
2378  if (k<nkmb) d1(i) = b_denom_1 * b1(i)
2379  tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,k-1))
2380  tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,k-1))
2381  enddo ; enddo
2382 
2383  do k=nkmb+1,nz ; do i=is,ie
2384  if (k == kb(i,j)) then
2385  c1(i,k) = eb(i,j,k-1) * b1(i)
2386  d1(i) = (((eb(i,j,nkmb)-eb(i,j,k-1)) + hold(i,j,nkmb) + h_neglect) + &
2387  d1(i)*ea(i,j,nkmb)) * b1(i)
2388  h_tr = hold(i,j,k) + h_neglect
2389  b_denom_1 = h_tr + d1(i)*ea(i,j,k)
2390  b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
2391  d1(i) = b_denom_1 * b1(i)
2392  tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,nkmb))
2393  tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,nkmb))
2394  elseif (k > kb(i,j)) then
2395  c1(i,k) = eb(i,j,k-1) * b1(i)
2396  h_tr = hold(i,j,k) + h_neglect
2397  b_denom_1 = h_tr + d1(i)*ea(i,j,k)
2398  b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
2399  d1(i) = b_denom_1 * b1(i)
2400  tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,k-1))
2401  tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,k-1))
2402  elseif (eb(i,j,k) < eb(i,j,k-1)) then ! (note that k < kb(i,j))
2403  ! The bottommost buffer layer might entrain all the mass from some
2404  ! of the interior layers that are thin and lighter in the coordinate
2405  ! density than that buffer layer. The T and S of these newly
2406  ! massless interior layers are unchanged.
2407  tv%T(i,j,nkmb) = tv%T(i,j,nkmb) + b1(i) * (eb(i,j,k-1) - eb(i,j,k)) * tv%T(i,j,k)
2408  tv%S(i,j,nkmb) = tv%S(i,j,nkmb) + b1(i) * (eb(i,j,k-1) - eb(i,j,k)) * tv%S(i,j,k)
2409  endif
2410  enddo ; enddo
2411 
2412  do k=nz-1,nkmb,-1 ; do i=is,ie
2413  if (k >= kb(i,j)) then
2414  tv%T(i,j,k) = tv%T(i,j,k) + c1(i,k+1)*tv%T(i,j,k+1)
2415  tv%S(i,j,k) = tv%S(i,j,k) + c1(i,k+1)*tv%S(i,j,k+1)
2416  endif
2417  enddo ; enddo
2418  do i=is,ie ; if (kb(i,j) <= nz) then
2419  tv%T(i,j,nkmb) = tv%T(i,j,nkmb) + c1(i,kb(i,j))*tv%T(i,j,kb(i,j))
2420  tv%S(i,j,nkmb) = tv%S(i,j,nkmb) + c1(i,kb(i,j))*tv%S(i,j,kb(i,j))
2421  endif ; enddo
2422  do k=nkmb-1,1,-1 ; do i=is,ie
2423  tv%T(i,j,k) = tv%T(i,j,k) + c1(i,k+1)*tv%T(i,j,k+1)
2424  tv%S(i,j,k) = tv%S(i,j,k) + c1(i,k+1)*tv%S(i,j,k+1)
2425  enddo ; enddo
2426  enddo ! end of j loop
2427  else ! .not. massless_match_targets
2428  ! This simpler form allows T & S to be too dense for the layers
2429  ! between the buffer layers and the interior.
2430  ! Changes: T, S
2431  if (cs%tracer_tridiag) then
2432  call tracer_vertdiff(hold, ea, eb, dt, tv%T, g, gv)
2433  call tracer_vertdiff(hold, ea, eb, dt, tv%S, g, gv)
2434  else
2435  call tridiagts(g, gv, is, ie, js, je, hold, ea, eb, tv%T, tv%S)
2436  endif
2437  endif ! massless_match_targets
2438  call cpu_clock_end(id_clock_tridiag)
2439 
2440  endif ! endif for associated(T)
2441  if (cs%debugConservation) call mom_state_stats('BML tridiag', u, v, h, tv%T, tv%S, g, gv, us)
2442 
2443  if ((cs%ML_mix_first > 0.0) .or. cs%use_geothermal) then
2444  ! The mixed layer code has already been called, but there is some needed
2445  ! bookkeeping.
2446  !$OMP parallel do default(shared)
2447  do k=1,nz ; do j=js,je ; do i=is,ie
2448  hold(i,j,k) = h_orig(i,j,k)
2449  ea(i,j,k) = ea(i,j,k) + eaml(i,j,k)
2450  eb(i,j,k) = eb(i,j,k) + ebml(i,j,k)
2451  enddo ; enddo ; enddo
2452  if (cs%debug) then
2453  call hchksum(ea, "after ea = ea + eaml",g%HI,haloshift=0, scale=gv%H_to_m)
2454  call hchksum(eb, "after eb = eb + ebml",g%HI,haloshift=0, scale=gv%H_to_m)
2455  endif
2456  endif
2457 
2458  if (cs%ML_mix_first < 1.0) then
2459  ! Call the mixed layer code now, perhaps for a second time.
2460  ! This subroutine (1) Cools the mixed layer.
2461  ! (2) Performs convective adjustment by mixed layer entrainment.
2462  ! (3) Heats the mixed layer and causes it to detrain to
2463  ! Monin-Obukhov depth or minimum mixed layer depth.
2464  ! (4) Uses any remaining TKE to drive mixed layer entrainment.
2465  ! (5) Possibly splits the buffer layer into two isopycnal layers.
2466 
2467  call find_uv_at_h(u, v, hold, u_h, v_h, g, gv, us, ea, eb)
2468  if (cs%debug) call mom_state_chksum("find_uv_at_h1 ", u, v, h, g, gv, us, haloshift=0)
2469 
2470  dt_mix = min(dt, dt*(1.0 - cs%ML_mix_first))
2471  call cpu_clock_begin(id_clock_mixedlayer)
2472  ! Changes: h, tv%T, tv%S, ea and eb (G is also inout???)
2473  call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt_mix, ea, eb, &
2474  g, gv, us, cs%bulkmixedlayer_CSp, cs%optics, &
2475  hml, cs%aggregate_FW_forcing, dt, last_call=.true.)
2476 
2477  if (cs%salt_reject_below_ML) &
2478  call insert_brine(h, tv, g, gv, us, fluxes, nkmb, cs%diabatic_aux_CSp, dt_mix, &
2479  cs%id_brine_lay)
2480 
2481  ! Keep salinity from falling below a small but positive threshold.
2482  ! This constraint is needed for SIS1 ice model, which can extract
2483  ! more salt than is present in the ocean. SIS2 does not suffer
2484  ! from this limitation, in which case we can let salinity=0 and still
2485  ! have salt conserved with SIS2 ice. So for SIS2, we can run with
2486  ! BOUND_SALINITY=False in MOM.F90.
2487  if (associated(tv%S) .and. associated(tv%salt_deficit)) &
2488  call adjust_salt(h, tv, g, gv, cs%diabatic_aux_CSp)
2489 
2490  call cpu_clock_end(id_clock_mixedlayer)
2491  if (showcalltree) call calltree_waypoint("done with 2nd bulkmixedlayer (diabatic)")
2492  if (cs%debugConservation) call mom_state_stats('2nd bulkmixedlayer', u, v, h, tv%T, tv%S, g, gv, us)
2493  endif
2494 
2495  else ! following block for when NOT using BULKMIXEDLAYER
2496 
2497  ! calculate change in temperature & salinity due to dia-coordinate surface diffusion
2498  if (associated(tv%T)) then
2499 
2500  if (cs%debug) then
2501  call hchksum(ea, "before triDiagTS ea ",g%HI,haloshift=0, scale=gv%H_to_m)
2502  call hchksum(eb, "before triDiagTS eb ",g%HI,haloshift=0, scale=gv%H_to_m)
2503  endif
2504  call cpu_clock_begin(id_clock_tridiag)
2505 
2506  ! Keep salinity from falling below a small but positive threshold.
2507  ! This constraint is needed for SIS1 ice model, which can extract
2508  ! more salt than is present in the ocean. SIS2 does not suffer
2509  ! from this limitation, in which case we can let salinity=0 and still
2510  ! have salt conserved with SIS2 ice. So for SIS2, we can run with
2511  ! BOUND_SALINITY=False in MOM.F90.
2512  if (associated(tv%S) .and. associated(tv%salt_deficit)) &
2513  call adjust_salt(h, tv, g, gv, cs%diabatic_aux_CSp)
2514 
2515  if (cs%diabatic_diff_tendency_diag) then
2516  do k=1,nz ; do j=js,je ; do i=is,ie
2517  temp_diag(i,j,k) = tv%T(i,j,k)
2518  saln_diag(i,j,k) = tv%S(i,j,k)
2519  enddo ; enddo ; enddo
2520  endif
2521 
2522  ! Changes T and S via the tridiagonal solver; no change to h
2523  if (cs%tracer_tridiag) then
2524  call tracer_vertdiff(hold, ea, eb, dt, tv%T, g, gv)
2525  call tracer_vertdiff(hold, ea, eb, dt, tv%S, g, gv)
2526  else
2527  call tridiagts(g, gv, is, ie, js, je, hold, ea, eb, tv%T, tv%S)
2528  endif
2529 
2530  ! diagnose temperature, salinity, heat, and salt tendencies
2531  ! Note: hold here refers to the thicknesses from before the dual-entraintment when using
2532  ! the bulk mixed layer scheme, so tendencies should be posted on hold.
2533  if (cs%diabatic_diff_tendency_diag) then
2534  call diagnose_diabatic_diff_tendency(tv, hold, temp_diag, saln_diag, dt, g, gv, cs)
2535  if (cs%id_diabatic_diff_h > 0) call post_data(cs%id_diabatic_diff_h, hold, cs%diag, alt_h=hold)
2536  endif
2537 
2538  call cpu_clock_end(id_clock_tridiag)
2539  if (showcalltree) call calltree_waypoint("done with triDiagTS (diabatic)")
2540 
2541  endif ! endif corresponding to if (associated(tv%T))
2542  if (cs%debugConservation) call mom_state_stats('triDiagTS', u, v, h, tv%T, tv%S, g, gv, us)
2543 
2544  endif ! endif for the BULKMIXEDLAYER block
2545 
2546  if (cs%debug) then
2547  call mom_state_chksum("after mixed layer ", u, v, h, g, gv, us, haloshift=0)
2548  call mom_thermovar_chksum("after mixed layer ", tv, g)
2549  call hchksum(ea, "after mixed layer ea", g%HI, scale=gv%H_to_m)
2550  call hchksum(eb, "after mixed layer eb", g%HI, scale=gv%H_to_m)
2551  endif
2552 
2553  call cpu_clock_begin(id_clock_remap)
2554  call regularize_layers(h, tv, dt, ea, eb, g, gv, us, cs%regularize_layers_CSp)
2555  call cpu_clock_end(id_clock_remap)
2556  if (showcalltree) call calltree_waypoint("done with regularize_layers (diabatic)")
2557  if (cs%debugConservation) call mom_state_stats('regularize_layers', u, v, h, tv%T, tv%S, g, gv, us)
2558 
2559  ! Whenever thickness changes let the diag manager know, as the
2560  ! target grids for vertical remapping may need to be regenerated.
2561  if (cs%id_dudt_dia > 0 .or. cs%id_dvdt_dia > 0) &
2562  ! Remapped d[uv]dt_dia require east/north halo updates of h
2563  call pass_var(h, g%domain, to_west+to_south+omit_corners, halo=1)
2564  call diag_update_remap_grids(cs%diag)
2565 
2566  ! diagnostics
2567  idt = 1.0 / dt
2568  if ((cs%id_Tdif > 0) .or. (cs%id_Tadv > 0)) then
2569  do j=js,je ; do i=is,ie
2570  tdif_flx(i,j,1) = 0.0 ; tdif_flx(i,j,nz+1) = 0.0
2571  tadv_flx(i,j,1) = 0.0 ; tadv_flx(i,j,nz+1) = 0.0
2572  enddo ; enddo
2573  !$OMP parallel do default(shared)
2574  do k=2,nz ; do j=js,je ; do i=is,ie
2575  tdif_flx(i,j,k) = (idt * 0.5*(ea(i,j,k) + eb(i,j,k-1))) * &
2576  (tv%T(i,j,k-1) - tv%T(i,j,k))
2577  tadv_flx(i,j,k) = (idt * (ea(i,j,k) - eb(i,j,k-1))) * &
2578  0.5*(tv%T(i,j,k-1) + tv%T(i,j,k))
2579  enddo ; enddo ; enddo
2580  endif
2581  if ((cs%id_Sdif > 0) .or. (cs%id_Sadv > 0)) then
2582  do j=js,je ; do i=is,ie
2583  sdif_flx(i,j,1) = 0.0 ; sdif_flx(i,j,nz+1) = 0.0
2584  sadv_flx(i,j,1) = 0.0 ; sadv_flx(i,j,nz+1) = 0.0
2585  enddo ; enddo
2586  !$OMP parallel do default(shared)
2587  do k=2,nz ; do j=js,je ; do i=is,ie
2588  sdif_flx(i,j,k) = (idt * 0.5*(ea(i,j,k) + eb(i,j,k-1))) * &
2589  (tv%S(i,j,k-1) - tv%S(i,j,k))
2590  sadv_flx(i,j,k) = (idt * (ea(i,j,k) - eb(i,j,k-1))) * &
2591  0.5*(tv%S(i,j,k-1) + tv%S(i,j,k))
2592  enddo ; enddo ; enddo
2593  endif
2594 
2595  ! mixing of passive tracers from massless boundary layers to interior
2596  call cpu_clock_begin(id_clock_tracers)
2597  if (cs%mix_boundary_tracers) then
2598  tr_ea_bbl = gv%Z_to_H * sqrt(dt*cs%Kd_BBL_tr)
2599  !$OMP parallel do default(shared) private(htot,in_boundary,add_ent)
2600  do j=js,je
2601  do i=is,ie
2602  ebtr(i,j,nz) = eb(i,j,nz)
2603  htot(i) = 0.0
2604  in_boundary(i) = (g%mask2dT(i,j) > 0.0)
2605  enddo
2606  do k=nz,2,-1 ; do i=is,ie
2607  if (in_boundary(i)) then
2608  htot(i) = htot(i) + h(i,j,k)
2609  ! If diapycnal mixing has been suppressed because this is a massless
2610  ! layer near the bottom, add some mixing of tracers between these
2611  ! layers. This flux is based on the harmonic mean of the two
2612  ! thicknesses, as this corresponds pretty closely (to within
2613  ! differences in the density jumps between layers) with what is done
2614  ! in the calculation of the fluxes in the first place. Kd_min_tr
2615  ! should be much less than the values that have been set in Kd_lay,
2616  ! perhaps a molecular diffusivity.
2617  add_ent = ((dt * cs%Kd_min_tr) * gv%Z_to_H**2) * &
2618  ((h(i,j,k-1)+h(i,j,k)+h_neglect) / &
2619  (h(i,j,k-1)*h(i,j,k)+h_neglect2)) - &
2620  0.5*(ea(i,j,k) + eb(i,j,k-1))
2621  if (htot(i) < tr_ea_bbl) then
2622  add_ent = max(0.0, add_ent, &
2623  (tr_ea_bbl - htot(i)) - min(ea(i,j,k),eb(i,j,k-1)))
2624  elseif (add_ent < 0.0) then
2625  add_ent = 0.0 ; in_boundary(i) = .false.
2626  endif
2627 
2628  ebtr(i,j,k-1) = eb(i,j,k-1) + add_ent
2629  eatr(i,j,k) = ea(i,j,k) + add_ent
2630  else
2631  ebtr(i,j,k-1) = eb(i,j,k-1) ; eatr(i,j,k) = ea(i,j,k)
2632  endif
2633  if (associated(visc%Kd_extra_S)) then ; if (visc%Kd_extra_S(i,j,k) > 0.0) then
2634  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
2635  (0.25 * ((h(i,j,k-1) + h(i,j,k)) + (hold(i,j,k-1) + hold(i,j,k))) + &
2636  h_neglect)
2637  ebtr(i,j,k-1) = ebtr(i,j,k-1) + add_ent
2638  eatr(i,j,k) = eatr(i,j,k) + add_ent
2639  endif ; endif
2640  enddo ; enddo
2641  do i=is,ie ; eatr(i,j,1) = ea(i,j,1) ; enddo
2642 
2643  enddo
2644 
2645  call call_tracer_column_fns(hold, h, eatr, ebtr, fluxes, hml, dt, g, gv, us, tv, &
2646  cs%optics, cs%tracer_flow_CSp, cs%debug)
2647 
2648  elseif (associated(visc%Kd_extra_S)) then ! extra diffusivity for passive tracers
2649 
2650  do j=js,je ; do i=is,ie
2651  ebtr(i,j,nz) = eb(i,j,nz) ; eatr(i,j,1) = ea(i,j,1)
2652  enddo ; enddo
2653  !$OMP parallel do default(shared) private(add_ent)
2654  do k=nz,2,-1 ; do j=js,je ; do i=is,ie
2655  if (visc%Kd_extra_S(i,j,k) > 0.0) then
2656  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%Z_to_H**2) / &
2657  (0.25 * ((h(i,j,k-1) + h(i,j,k)) + (hold(i,j,k-1) + hold(i,j,k))) + &
2658  h_neglect)
2659  else
2660  add_ent = 0.0
2661  endif
2662  ebtr(i,j,k-1) = eb(i,j,k-1) + add_ent
2663  eatr(i,j,k) = ea(i,j,k) + add_ent
2664  enddo ; enddo ; enddo
2665 
2666  call call_tracer_column_fns(hold, h, eatr, ebtr, fluxes, hml, dt, g, gv, us, tv, &
2667  cs%optics, cs%tracer_flow_CSp, cs%debug)
2668 
2669  else
2670  call call_tracer_column_fns(hold, h, ea, eb, fluxes, hml, dt, g, gv, us, tv, &
2671  cs%optics, cs%tracer_flow_CSp, cs%debug)
2672 
2673  endif ! (CS%mix_boundary_tracers)
2674 
2675  call cpu_clock_end(id_clock_tracers)
2676 
2677  ! sponges
2678  if (cs%use_sponge) then
2679  call cpu_clock_begin(id_clock_sponge)
2680  ! Layer mode sponge
2681  if (cs%bulkmixedlayer .and. associated(tv%eqn_of_state)) then
2682  do i=is,ie ; p_ref_cv(i) = tv%P_Ref ; enddo
2683  !$OMP parallel do default(shared)
2684  do j=js,je
2685  call calculate_density(tv%T(:,j,1), tv%S(:,j,1), p_ref_cv, rcv_ml(:,j), &
2686  is, ie-is+1, tv%eqn_of_state, scale=us%kg_m3_to_R)
2687  enddo
2688  call apply_sponge(h, dt, g, gv, us, ea, eb, cs%sponge_CSp, rcv_ml)
2689  else
2690  call apply_sponge(h, dt, g, gv, us, ea, eb, cs%sponge_CSp)
2691  endif
2692  call cpu_clock_end(id_clock_sponge)
2693  if (cs%debug) then
2694  call mom_state_chksum("apply_sponge ", u, v, h, g, gv, us, haloshift=0)
2695  call mom_thermovar_chksum("apply_sponge ", tv, g)
2696  endif
2697  endif ! CS%use_sponge
2698 
2699 ! Save the diapycnal mass fluxes as a diagnostic field.
2700  if (associated(cdp%diapyc_vel)) then
2701  !$OMP parallel do default(shared)
2702  do j=js,je
2703  do k=2,nz ; do i=is,ie
2704  cdp%diapyc_vel(i,j,k) = us%s_to_T*idt * (ea(i,j,k) - eb(i,j,k-1))
2705  enddo ; enddo
2706  do i=is,ie
2707  cdp%diapyc_vel(i,j,1) = 0.0
2708  cdp%diapyc_vel(i,j,nz+1) = 0.0
2709  enddo
2710  enddo
2711  endif
2712 
2713 ! For momentum, it is only the net flux that homogenizes within
2714 ! the mixed layer. Vertical viscosity that is proportional to the
2715 ! mixed layer turbulence is applied elsewhere.
2716  if (cs%bulkmixedlayer) then
2717  if (cs%debug) then
2718  call hchksum(ea, "before net flux rearrangement ea",g%HI, scale=gv%H_to_m)
2719  call hchksum(eb, "before net flux rearrangement eb",g%HI, scale=gv%H_to_m)
2720  endif
2721  !$OMP parallel do default(shared) private(net_ent)
2722  do j=js,je
2723  do k=2,gv%nkml ; do i=is,ie
2724  net_ent = ea(i,j,k) - eb(i,j,k-1)
2725  ea(i,j,k) = max(net_ent, 0.0)
2726  eb(i,j,k-1) = max(-net_ent, 0.0)
2727  enddo ; enddo
2728  enddo
2729  if (cs%debug) then
2730  call hchksum(ea, "after net flux rearrangement ea",g%HI, scale=gv%H_to_m)
2731  call hchksum(eb, "after net flux rearrangement eb",g%HI, scale=gv%H_to_m)
2732  endif
2733  endif
2734 
2735 ! Initialize halo regions of ea, eb, and hold to default values.
2736  !$OMP parallel do default(shared)
2737  do k=1,nz
2738  do i=is-1,ie+1
2739  hold(i,js-1,k) = gv%Angstrom_H ; ea(i,js-1,k) = 0.0 ; eb(i,js-1,k) = 0.0
2740  hold(i,je+1,k) = gv%Angstrom_H ; ea(i,je+1,k) = 0.0 ; eb(i,je+1,k) = 0.0
2741  enddo
2742  do j=js,je
2743  hold(is-1,j,k) = gv%Angstrom_H ; ea(is-1,j,k) = 0.0 ; eb(is-1,j,k) = 0.0
2744  hold(ie+1,j,k) = gv%Angstrom_H ; ea(ie+1,j,k) = 0.0 ; eb(ie+1,j,k) = 0.0
2745  enddo
2746  enddo
2747 
2748  call cpu_clock_begin(id_clock_pass)
2749  if (g%symmetric) then ; dir_flag = to_all+omit_corners
2750  else ; dir_flag = to_west+to_south+omit_corners ; endif
2751  call create_group_pass(cs%pass_hold_eb_ea, hold, g%Domain, dir_flag, halo=1)
2752  call create_group_pass(cs%pass_hold_eb_ea, eb, g%Domain, dir_flag, halo=1)
2753  call create_group_pass(cs%pass_hold_eb_ea, ea, g%Domain, dir_flag, halo=1)
2754  call do_group_pass(cs%pass_hold_eb_ea, g%Domain)
2755  call cpu_clock_end(id_clock_pass)
2756 
2757  ! Use a tridiagonal solver to determine effect of the diapycnal
2758  ! advection on velocity field. It is assumed that water leaves
2759  ! or enters the ocean with the surface velocity.
2760  if (cs%debug) then
2761  call mom_state_chksum("before u/v tridiag ", u, v, h, g, gv, us, haloshift=0)
2762  call hchksum(ea, "before u/v tridiag ea",g%HI, scale=gv%H_to_m)
2763  call hchksum(eb, "before u/v tridiag eb",g%HI, scale=gv%H_to_m)
2764  call hchksum(hold, "before u/v tridiag hold",g%HI, scale=gv%H_to_m)
2765  endif
2766  call cpu_clock_begin(id_clock_tridiag)
2767  idt_accel = 1.0 / dt
2768  !$OMP parallel do default(shared) private(hval,b1,d1,c1,eaval)
2769  do j=js,je
2770  do i=isq,ieq
2771  if (associated(adp%du_dt_dia)) adp%du_dt_dia(i,j,1) = u(i,j,1)
2772  hval = (hold(i,j,1) + hold(i+1,j,1)) + (ea(i,j,1) + ea(i+1,j,1)) + h_neglect
2773  b1(i) = 1.0 / (hval + (eb(i,j,1) + eb(i+1,j,1)))
2774  d1(i) = hval * b1(i)
2775  u(i,j,1) = b1(i) * (hval * u(i,j,1))
2776  enddo
2777  do k=2,nz ; do i=isq,ieq
2778  if (associated(adp%du_dt_dia)) adp%du_dt_dia(i,j,k) = u(i,j,k)
2779  c1(i,k) = (eb(i,j,k-1)+eb(i+1,j,k-1)) * b1(i)
2780  eaval = ea(i,j,k) + ea(i+1,j,k)
2781  hval = hold(i,j,k) + hold(i+1,j,k) + h_neglect
2782  b1(i) = 1.0 / ((eb(i,j,k) + eb(i+1,j,k)) + (hval + d1(i)*eaval))
2783  d1(i) = (hval + d1(i)*eaval) * b1(i)
2784  u(i,j,k) = (hval*u(i,j,k) + eaval*u(i,j,k-1))*b1(i)
2785  enddo ; enddo
2786  do k=nz-1,1,-1 ; do i=isq,ieq
2787  u(i,j,k) = u(i,j,k) + c1(i,k+1)*u(i,j,k+1)
2788  if (associated(adp%du_dt_dia)) &
2789  adp%du_dt_dia(i,j,k) = (u(i,j,k) - adp%du_dt_dia(i,j,k)) * idt_accel
2790  enddo ; enddo
2791  if (associated(adp%du_dt_dia)) then
2792  do i=isq,ieq
2793  adp%du_dt_dia(i,j,nz) = (u(i,j,nz)-adp%du_dt_dia(i,j,nz)) * idt_accel
2794  enddo
2795  endif
2796  enddo
2797  if (cs%debug) then
2798  call mom_state_chksum("aft 1st loop tridiag ", u, v, h, g, gv, us, haloshift=0)
2799  endif
2800  !$OMP parallel do default(shared) private(hval,b1,d1,c1,eaval)
2801  do j=jsq,jeq
2802  do i=is,ie
2803  if (associated(adp%dv_dt_dia)) adp%dv_dt_dia(i,j,1) = v(i,j,1)
2804  hval = (hold(i,j,1) + hold(i,j+1,1)) + (ea(i,j,1) + ea(i,j+1,1)) + h_neglect
2805  b1(i) = 1.0 / (hval + (eb(i,j,1) + eb(i,j+1,1)))
2806  d1(i) = hval * b1(i)
2807  v(i,j,1) = b1(i) * (hval * v(i,j,1))
2808  enddo
2809  do k=2,nz ; do i=is,ie
2810  if (associated(adp%dv_dt_dia)) adp%dv_dt_dia(i,j,k) = v(i,j,k)
2811  c1(i,k) = (eb(i,j,k-1)+eb(i,j+1,k-1)) * b1(i)
2812  eaval = ea(i,j,k) + ea(i,j+1,k)
2813  hval = hold(i,j,k) + hold(i,j+1,k) + h_neglect
2814  b1(i) = 1.0 / ((eb(i,j,k) + eb(i,j+1,k)) + (hval + d1(i)*eaval))
2815  d1(i) = (hval + d1(i)*eaval) * b1(i)
2816  v(i,j,k) = (hval*v(i,j,k) + eaval*v(i,j,k-1))*b1(i)
2817  enddo ; enddo
2818  do k=nz-1,1,-1 ; do i=is,ie
2819  v(i,j,k) = v(i,j,k) + c1(i,k+1)*v(i,j,k+1)
2820  if (associated(adp%dv_dt_dia)) &
2821  adp%dv_dt_dia(i,j,k) = (v(i,j,k) - adp%dv_dt_dia(i,j,k)) * idt_accel
2822  enddo ; enddo
2823  if (associated(adp%dv_dt_dia)) then
2824  do i=is,ie
2825  adp%dv_dt_dia(i,j,nz) = (v(i,j,nz)-adp%dv_dt_dia(i,j,nz)) * idt_accel
2826  enddo
2827  endif
2828  enddo
2829  call cpu_clock_end(id_clock_tridiag)
2830  if (cs%debug) then
2831  call mom_state_chksum("after u/v tridiag ", u, v, h, g, gv, us, haloshift=0)
2832  endif
2833 
2834  call disable_averaging(cs%diag)
2835  ! Diagnose the diapycnal diffusivities and other related quantities.
2836  call enable_averages(dt, time_end, cs%diag)
2837 
2838  if (cs%id_Kd_interface > 0) call post_data(cs%id_Kd_interface, kd_int, cs%diag)
2839  if (cs%id_Kd_heat > 0) call post_data(cs%id_Kd_heat, kd_heat, cs%diag)
2840  if (cs%id_Kd_salt > 0) call post_data(cs%id_Kd_salt, kd_salt, cs%diag)
2841  if (cs%id_Kd_ePBL > 0) call post_data(cs%id_Kd_ePBL, kd_epbl, cs%diag)
2842 
2843  if (cs%id_ea > 0) call post_data(cs%id_ea, ea, cs%diag)
2844  if (cs%id_eb > 0) call post_data(cs%id_eb, eb, cs%diag)
2845 
2846  if (cs%id_dudt_dia > 0) call post_data(cs%id_dudt_dia, adp%du_dt_dia, cs%diag)
2847  if (cs%id_dvdt_dia > 0) call post_data(cs%id_dvdt_dia, adp%dv_dt_dia, cs%diag)
2848  if (cs%id_wd > 0) call post_data(cs%id_wd, cdp%diapyc_vel, cs%diag)
2849 
2850  if (cs%id_Tdif > 0) call post_data(cs%id_Tdif, tdif_flx, cs%diag)
2851  if (cs%id_Tadv > 0) call post_data(cs%id_Tadv, tadv_flx, cs%diag)
2852  if (cs%id_Sdif > 0) call post_data(cs%id_Sdif, sdif_flx, cs%diag)
2853  if (cs%id_Sadv > 0) call post_data(cs%id_Sadv, sadv_flx, cs%diag)
2854 
2855  call disable_averaging(cs%diag)
2856 
2857  if (showcalltree) call calltree_leave("layered_diabatic()")
2858 
2859 end subroutine layered_diabatic
2860 
2861 !> Returns pointers or values of members within the diabatic_CS type. For extensibility,
2862 !! each returned argument is an optional argument
2863 subroutine extract_diabatic_member(CS, opacity_CSp, optics_CSp, evap_CFL_limit, &
2864  minimum_forcing_depth, KPP_CSp, energetic_PBL_CSp, diabatic_aux_CSp)
2865  type(diabatic_cs), intent(in ) :: cs !< module control structure
2866  ! All output arguments are optional
2867  type(opacity_cs), optional, pointer :: opacity_csp !< A pointer to be set to the opacity control structure
2868  type(optics_type), optional, pointer :: optics_csp !< A pointer to be set to the optics control structure
2869  type(kpp_cs), optional, pointer :: kpp_csp !< A pointer to be set to the KPP CS
2870  type(energetic_pbl_cs), optional, pointer :: energetic_pbl_csp !< A pointer to be set to the ePBL CS
2871  real, optional, intent( out) :: evap_cfl_limit !<The largest fraction of a layer that can be
2872  !! evaporated in one time-step [nondim].
2873  real, optional, intent( out) :: minimum_forcing_depth !< The smallest depth over which heat
2874  !! and freshwater fluxes are applied [H ~> m or kg m-2].
2875  type(diabatic_aux_cs), optional, pointer :: diabatic_aux_csp !< A pointer to be set to the diabatic_aux
2876  !! control structure
2877 
2878  ! Pointers to control structures
2879  if (present(opacity_csp)) opacity_csp => cs%opacity_CSp
2880  if (present(optics_csp)) optics_csp => cs%optics
2881  if (present(kpp_csp)) kpp_csp => cs%KPP_CSp
2882  if (present(energetic_pbl_csp)) energetic_pbl_csp => cs%energetic_PBL_CSp
2883 
2884  ! Constants within diabatic_CS
2885  if (present(evap_cfl_limit)) evap_cfl_limit = cs%evap_CFL_limit
2886  if (present(minimum_forcing_depth)) minimum_forcing_depth = cs%minimum_forcing_depth
2887 
2888 end subroutine extract_diabatic_member
2889 
2890 !> Routine called for adiabatic physics
2891 subroutine adiabatic(h, tv, fluxes, dt, G, GV, US, CS)
2892  type(ocean_grid_type), intent(inout) :: g !< ocean grid structure
2893  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
2894  intent(inout) :: h !< thickness [H ~> m or kg m-2]
2895  type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
2896  type(forcing), intent(inout) :: fluxes !< boundary fluxes
2897  real, intent(in) :: dt !< time step [T ~> s]
2898  type(verticalgrid_type), intent(in) :: gv !< ocean vertical grid structure
2899  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
2900  type(diabatic_cs), pointer :: cs !< module control structure
2901 
2902  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: zeros ! An array of zeros.
2903 
2904  zeros(:,:,:) = 0.0
2905 
2906  call call_tracer_column_fns(h, h, zeros, zeros, fluxes, zeros(:,:,1), dt, g, gv, us, tv, &
2907  cs%optics, cs%tracer_flow_CSp, cs%debug)
2908 
2909 end subroutine adiabatic
2910 
2911 
2912 !> This routine diagnoses tendencies from application of diabatic diffusion
2913 !! using ALE algorithm. Note that layer thickness is not altered by
2914 !! diabatic diffusion.
2915 subroutine diagnose_diabatic_diff_tendency(tv, h, temp_old, saln_old, dt, G, GV, CS)
2916  type(ocean_grid_type), intent(in) :: G !< ocean grid structure
2917  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
2918  type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
2919  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< thickness [H ~> m or kg m-2]
2920  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: temp_old !< temperature prior to diabatic physics
2921  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: saln_old !< salinity prior to diabatic physics [ppt]
2922  real, intent(in) :: dt !< time step [T ~> s]
2923  type(diabatic_cs), pointer :: CS !< module control structure
2924 
2925  ! Local variables
2926  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: work_3d
2927  real, dimension(SZI_(G),SZJ_(G)) :: work_2d
2928  real :: Idt ! The inverse of the timestep [T-1 ~> s-1]
2929  real :: ppt2mks = 0.001 ! Conversion factor from g/kg to kg/kg.
2930  integer :: i, j, k, is, ie, js, je, nz
2931  logical :: do_saln_tend ! Calculate salinity-based tendency diagnosics
2932 
2933  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
2934  idt = 0.0 ; if (dt > 0.0) idt = 1. / dt
2935  work_3d(:,:,:) = 0.0
2936  work_2d(:,:) = 0.0
2937 
2938 
2939  ! temperature tendency
2940  do k=1,nz ; do j=js,je ; do i=is,ie
2941  work_3d(i,j,k) = (tv%T(i,j,k)-temp_old(i,j,k))*idt
2942  enddo ; enddo ; enddo
2943  if (cs%id_diabatic_diff_temp_tend > 0) then
2944  call post_data(cs%id_diabatic_diff_temp_tend, work_3d, cs%diag, alt_h=h)
2945  endif
2946 
2947  ! heat tendency
2948  if (cs%id_diabatic_diff_heat_tend > 0 .or. cs%id_diabatic_diff_heat_tend_2d > 0) then
2949  do k=1,nz ; do j=js,je ; do i=is,ie
2950  work_3d(i,j,k) = h(i,j,k) * gv%H_to_kg_m2 * tv%C_p * work_3d(i,j,k)
2951  enddo ; enddo ; enddo
2952  if (cs%id_diabatic_diff_heat_tend > 0) then
2953  call post_data(cs%id_diabatic_diff_heat_tend, work_3d, cs%diag, alt_h=h)
2954  endif
2955  if (cs%id_diabatic_diff_heat_tend_2d > 0) then
2956  do j=js,je ; do i=is,ie
2957  work_2d(i,j) = 0.0
2958  do k=1,nz
2959  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
2960  enddo
2961  enddo ; enddo
2962  call post_data(cs%id_diabatic_diff_heat_tend_2d, work_2d, cs%diag)
2963  endif
2964  endif
2965 
2966  ! salinity tendency
2967  do_saln_tend = cs%id_diabatic_diff_saln_tend > 0 &
2968  .or. cs%id_diabatic_diff_salt_tend > 0 &
2969  .or. cs%id_diabatic_diff_salt_tend_2d > 0
2970 
2971  if (do_saln_tend) then
2972  do k=1,nz ; do j=js,je ; do i=is,ie
2973  work_3d(i,j,k) = (tv%S(i,j,k) - saln_old(i,j,k)) * idt
2974  enddo ; enddo ; enddo
2975 
2976  if (cs%id_diabatic_diff_saln_tend > 0) &
2977  call post_data(cs%id_diabatic_diff_saln_tend, work_3d, cs%diag, alt_h=h)
2978 
2979  ! salt tendency
2980  if (cs%id_diabatic_diff_salt_tend > 0 .or. cs%id_diabatic_diff_salt_tend_2d > 0) then
2981  do k=1,nz ; do j=js,je ; do i=is,ie
2982  work_3d(i,j,k) = h(i,j,k) * gv%H_to_kg_m2 * ppt2mks * work_3d(i,j,k)
2983  enddo ; enddo ; enddo
2984  if (cs%id_diabatic_diff_salt_tend > 0) then
2985  call post_data(cs%id_diabatic_diff_salt_tend, work_3d, cs%diag, alt_h=h)
2986  endif
2987  if (cs%id_diabatic_diff_salt_tend_2d > 0) then
2988  do j=js,je ; do i=is,ie
2989  work_2d(i,j) = 0.0
2990  do k=1,nz
2991  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
2992  enddo
2993  enddo ; enddo
2994  call post_data(cs%id_diabatic_diff_salt_tend_2d, work_2d, cs%diag)
2995  endif
2996  endif
2997  endif
2998 
2999 end subroutine diagnose_diabatic_diff_tendency
3000 
3001 
3002 !> This routine diagnoses tendencies from application of boundary fluxes.
3003 !! These impacts are generally 3d, in particular for penetrative shortwave.
3004 !! Other fluxes contribute 3d in cases when the layers vanish or are very thin,
3005 !! in which case we distribute the flux into k > 1 layers.
3006 subroutine diagnose_boundary_forcing_tendency(tv, h, temp_old, saln_old, h_old, &
3007  dt, G, GV, CS)
3008  type(ocean_grid_type), intent(in) :: G !< ocean grid structure
3009  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
3010  type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
3011  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
3012  intent(in) :: h !< thickness after boundary flux application [H ~> m or kg m-2]
3013  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
3014  intent(in) :: temp_old !< temperature prior to boundary flux application [degC]
3015  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
3016  intent(in) :: saln_old !< salinity prior to boundary flux application [ppt]
3017  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), &
3018  intent(in) :: h_old !< thickness prior to boundary flux application [H ~> m or kg m-2]
3019  real, intent(in) :: dt !< time step [T ~> s]
3020  type(diabatic_cs), pointer :: CS !< module control structure
3021 
3022  ! Local variables
3023  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: work_3d
3024  real, dimension(SZI_(G),SZJ_(G)) :: work_2d
3025  real :: Idt ! The inverse of the timestep [T-1 ~> s-1]
3026  real :: ppt2mks = 0.001 ! Conversion factor from g/kg to kg/kg.
3027  integer :: i, j, k, is, ie, js, je, nz
3028 
3029  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
3030  idt = 0.0 ; if (dt > 0.0) idt = 1. / dt
3031  work_3d(:,:,:) = 0.0
3032  work_2d(:,:) = 0.0
3033 
3034  ! Thickness tendency
3035  if (cs%id_boundary_forcing_h_tendency > 0) then
3036  do k=1,nz ; do j=js,je ; do i=is,ie
3037  work_3d(i,j,k) = (h(i,j,k) - h_old(i,j,k))*idt
3038  enddo ; enddo ; enddo
3039  call post_data(cs%id_boundary_forcing_h_tendency, work_3d, cs%diag, alt_h=h_old)
3040  endif
3041 
3042  ! temperature tendency
3043  if (cs%id_boundary_forcing_temp_tend > 0) then
3044  do k=1,nz ; do j=js,je ; do i=is,ie
3045  work_3d(i,j,k) = (tv%T(i,j,k)-temp_old(i,j,k))*idt
3046  enddo ; enddo ; enddo
3047  call post_data(cs%id_boundary_forcing_temp_tend, work_3d, cs%diag, alt_h=h_old)
3048  endif
3049 
3050  ! heat tendency
3051  if (cs%id_boundary_forcing_heat_tend > 0 .or. cs%id_boundary_forcing_heat_tend_2d > 0) then
3052  do k=1,nz ; do j=js,je ; do i=is,ie
3053  work_3d(i,j,k) = gv%H_to_kg_m2 * tv%C_p * idt * (h(i,j,k) * tv%T(i,j,k) - h_old(i,j,k) * temp_old(i,j,k))
3054  enddo ; enddo ; enddo
3055  if (cs%id_boundary_forcing_heat_tend > 0) then
3056  call post_data(cs%id_boundary_forcing_heat_tend, work_3d, cs%diag, alt_h = h_old)
3057  endif
3058  if (cs%id_boundary_forcing_heat_tend_2d > 0) then
3059  do j=js,je ; do i=is,ie
3060  work_2d(i,j) = 0.0
3061  do k=1,nz
3062  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
3063  enddo
3064  enddo ; enddo
3065  call post_data(cs%id_boundary_forcing_heat_tend_2d, work_2d, cs%diag)
3066  endif
3067  endif
3068 
3069  ! salinity tendency
3070  if (cs%id_boundary_forcing_saln_tend > 0) then
3071  do k=1,nz ; do j=js,je ; do i=is,ie
3072  work_3d(i,j,k) = (tv%S(i,j,k)-saln_old(i,j,k))*idt
3073  enddo ; enddo ; enddo
3074  call post_data(cs%id_boundary_forcing_saln_tend, work_3d, cs%diag, alt_h = h_old)
3075  endif
3076 
3077  ! salt tendency
3078  if (cs%id_boundary_forcing_salt_tend > 0 .or. cs%id_boundary_forcing_salt_tend_2d > 0) then
3079  do k=1,nz ; do j=js,je ; do i=is,ie
3080  work_3d(i,j,k) = gv%H_to_kg_m2 * ppt2mks * idt * (h(i,j,k) * tv%S(i,j,k) - h_old(i,j,k) * saln_old(i,j,k))
3081  enddo ; enddo ; enddo
3082  if (cs%id_boundary_forcing_salt_tend > 0) then
3083  call post_data(cs%id_boundary_forcing_salt_tend, work_3d, cs%diag, alt_h = h_old)
3084  endif
3085  if (cs%id_boundary_forcing_salt_tend_2d > 0) then
3086  do j=js,je ; do i=is,ie
3087  work_2d(i,j) = 0.0
3088  do k=1,nz
3089  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
3090  enddo
3091  enddo ; enddo
3092  call post_data(cs%id_boundary_forcing_salt_tend_2d, work_2d, cs%diag)
3093  endif
3094  endif
3095 
3097 
3098 
3099 !> This routine diagnoses tendencies for temperature and heat from frazil formation.
3100 !! This routine is called twice from within subroutine diabatic; at start and at
3101 !! end of the diabatic processes. The impacts from frazil are generally a function
3102 !! of depth. Hence, when checking heat budget, be sure to remove HFSIFRAZIL from HFDS in k=1.
3103 subroutine diagnose_frazil_tendency(tv, h, temp_old, dt, G, GV, CS)
3104  type(ocean_grid_type), intent(in) :: G !< ocean grid structure
3105  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
3106  type(diabatic_cs), pointer :: CS !< module control structure
3107  type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
3108  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< thickness [H ~> m or kg m-2]
3109  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: temp_old !< temperature prior to frazil formation [degC]
3110  real, intent(in) :: dt !< time step [T ~> s]
3111 
3112  real, dimension(SZI_(G),SZJ_(G)) :: work_2d
3113  real :: Idt ! The inverse of the timestep [T-1 ~> s-1]
3114  integer :: i, j, k, is, ie, js, je, nz
3115 
3116  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
3117  idt = 0.0 ; if (dt > 0.0) idt = 1. / dt
3118 
3119  ! temperature tendency
3120  if (cs%id_frazil_temp_tend > 0) then
3121  do k=1,nz ; do j=js,je ; do i=is,ie
3122  cs%frazil_temp_diag(i,j,k) = idt * (tv%T(i,j,k)-temp_old(i,j,k))
3123  enddo ; enddo ; enddo
3124  call post_data(cs%id_frazil_temp_tend, cs%frazil_temp_diag(:,:,:), cs%diag)
3125  endif
3126 
3127  ! heat tendency
3128  if (cs%id_frazil_heat_tend > 0 .or. cs%id_frazil_heat_tend_2d > 0) then
3129  do k=1,nz ; do j=js,je ; do i=is,ie
3130  cs%frazil_heat_diag(i,j,k) = gv%H_to_kg_m2 * tv%C_p * h(i,j,k) * idt * (tv%T(i,j,k)-temp_old(i,j,k))
3131  enddo ; enddo ; enddo
3132  if (cs%id_frazil_heat_tend > 0) call post_data(cs%id_frazil_heat_tend, cs%frazil_heat_diag(:,:,:), cs%diag)
3133 
3134  ! As a consistency check, we must have
3135  ! FRAZIL_HEAT_TENDENCY_2d = HFSIFRAZIL
3136  if (cs%id_frazil_heat_tend_2d > 0) then
3137  do j=js,je ; do i=is,ie
3138  work_2d(i,j) = 0.0
3139  do k=1,nz
3140  work_2d(i,j) = work_2d(i,j) + cs%frazil_heat_diag(i,j,k)
3141  enddo
3142  enddo ; enddo
3143  call post_data(cs%id_frazil_heat_tend_2d, work_2d, cs%diag)
3144  endif
3145  endif
3146 
3147 end subroutine diagnose_frazil_tendency
3148 
3149 
3150 !> A simplified version of diabatic_driver_init that will allow
3151 !! tracer column functions to be called without allowing any
3152 !! of the diabatic processes to be used.
3153 subroutine adiabatic_driver_init(Time, G, param_file, diag, CS, &
3154  tracer_flow_CSp)
3155  type(time_type), intent(in) :: time !< current model time
3156  type(ocean_grid_type), intent(in) :: g !< model grid structure
3157  type(param_file_type), intent(in) :: param_file !< the file to parse for parameter values
3158  type(diag_ctrl), target, intent(inout) :: diag !< regulates diagnostic output
3159  type(diabatic_cs), pointer :: cs !< module control structure
3160  type(tracer_flow_control_cs), pointer :: tracer_flow_csp !< pointer to control structure of the
3161  !! tracer flow control module
3162 
3163 ! This "include" declares and sets the variable "version".
3164 #include "version_variable.h"
3165  character(len=40) :: mdl = "MOM_diabatic_driver" ! This module's name.
3166 
3167  if (associated(cs)) then
3168  call mom_error(warning, "adiabatic_driver_init called with an "// &
3169  "associated control structure.")
3170  return
3171  else ; allocate(cs) ; endif
3172 
3173  cs%diag => diag
3174  if (associated(tracer_flow_csp)) cs%tracer_flow_CSp => tracer_flow_csp
3175 
3176 ! Set default, read and log parameters
3177  call log_version(param_file, mdl, version, &
3178  "The following parameters are used for diabatic processes.")
3179 
3180 end subroutine adiabatic_driver_init
3181 
3182 
3183 !> This routine initializes the diabatic driver module.
3184 subroutine diabatic_driver_init(Time, G, GV, US, param_file, useALEalgorithm, diag, &
3185  ADp, CDp, CS, tracer_flow_CSp, sponge_CSp, &
3186  ALE_sponge_CSp)
3187  type(time_type), target :: time !< model time
3188  type(ocean_grid_type), intent(inout) :: g !< model grid structure
3189  type(verticalgrid_type), intent(in) :: gv !< model vertical grid structure
3190  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
3191  type(param_file_type), intent(in) :: param_file !< file to parse for parameter values
3192  logical, intent(in) :: usealealgorithm !< logical for whether to use ALE remapping
3193  type(diag_ctrl), target, intent(inout) :: diag !< structure to regulate diagnostic output
3194  type(accel_diag_ptrs), intent(inout) :: adp !< pointers to accelerations in momentum equations,
3195  !! to enable diagnostics, like energy budgets
3196  type(cont_diag_ptrs), intent(inout) :: cdp !< pointers to terms in continuity equations
3197  type(diabatic_cs), pointer :: cs !< module control structure
3198  type(tracer_flow_control_cs), pointer :: tracer_flow_csp !< pointer to control structure of the
3199  !! tracer flow control module
3200  type(sponge_cs), pointer :: sponge_csp !< pointer to the sponge module control structure
3201  type(ale_sponge_cs), pointer :: ale_sponge_csp !< pointer to the ALE sponge module control structure
3202 
3203  real :: kd
3204  integer :: num_mode
3205  logical :: use_temperature, differentialdiffusion
3206 
3207 ! This "include" declares and sets the variable "version".
3208 #include "version_variable.h"
3209  character(len=40) :: mdl = "MOM_diabatic_driver" ! This module's name.
3210  character(len=48) :: thickness_units
3211  character(len=40) :: var_name
3212  character(len=160) :: var_descript
3213  integer :: isd, ied, jsd, jed, isdb, iedb, jsdb, jedb, nz, nbands, m
3214  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
3215  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
3216 
3217  if (associated(cs)) then
3218  call mom_error(warning, "diabatic_driver_init called with an "// &
3219  "associated control structure.")
3220  return
3221  else
3222  allocate(cs)
3223  endif
3224 
3225  cs%diag => diag
3226  cs%Time => time
3227 
3228  if (associated(tracer_flow_csp)) cs%tracer_flow_CSp => tracer_flow_csp
3229  if (associated(sponge_csp)) cs%sponge_CSp => sponge_csp
3230  if (associated(ale_sponge_csp)) cs%ALE_sponge_CSp => ale_sponge_csp
3231 
3232  cs%useALEalgorithm = usealealgorithm
3233  cs%bulkmixedlayer = (gv%nkml > 0)
3234 
3235  ! Set default, read and log parameters
3236  call log_version(param_file, mdl, version, &
3237  "The following parameters are used for diabatic processes.")
3238  call get_param(param_file, mdl, "USE_LEGACY_DIABATIC_DRIVER", cs%use_legacy_diabatic, &
3239  "If true, use a legacy version of the diabatic subroutine. "//&
3240  "This is temporary and is needed to avoid change in answers.", &
3241  default=.true.)
3242  call get_param(param_file, mdl, "SPONGE", cs%use_sponge, &
3243  "If true, sponges may be applied anywhere in the domain. "//&
3244  "The exact location and properties of those sponges are "//&
3245  "specified via calls to initialize_sponge and possibly "//&
3246  "set_up_sponge_field.", default=.false.)
3247  call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", use_temperature, &
3248  "If true, temperature and salinity are used as state "//&
3249  "variables.", default=.true.)
3250  call get_param(param_file, mdl, "ENERGETICS_SFC_PBL", cs%use_energetic_PBL, &
3251  "If true, use an implied energetics planetary boundary "//&
3252  "layer scheme to determine the diffusivity and viscosity "//&
3253  "in the surface boundary layer.", default=.false.)
3254  call get_param(param_file, mdl, "EPBL_IS_ADDITIVE", cs%ePBL_is_additive, &
3255  "If true, the diffusivity from ePBL is added to all "//&
3256  "other diffusivities. Otherwise, the larger of kappa-shear "//&
3257  "and ePBL diffusivities are used.", default=.true.)
3258  call get_param(param_file, mdl, "DOUBLE_DIFFUSION", differentialdiffusion, &
3259  "If true, apply parameterization of double-diffusion.", &
3260  default=.false. )
3261  call get_param(param_file, mdl, "USE_KPP", cs%use_KPP, &
3262  "If true, turns on the [CVMix] KPP scheme of Large et al., 1994, "//&
3263  "to calculate diffusivities and non-local transport in the OBL.", &
3264  default=.false., do_not_log=.true.)
3265  cs%use_CVMix_ddiff = cvmix_ddiff_is_used(param_file)
3266 
3267  if (cs%use_CVMix_ddiff .and. differentialdiffusion) then
3268  call mom_error(fatal, 'diabatic_driver_init: '// &
3269  'Multiple double-diffusion options selected (DOUBLE_DIFFUSION and'//&
3270  'USE_CVMIX_DDIFF), please disable all but one option to proceed.')
3271  endif
3272 
3273  cs%use_kappa_shear = kappa_shear_is_used(param_file)
3274  cs%use_CVMix_shear = cvmix_shear_is_used(param_file)
3275 
3276  if (cs%bulkmixedlayer) then
3277  call get_param(param_file, mdl, "ML_MIX_FIRST", cs%ML_mix_first, &
3278  "The fraction of the mixed layer mixing that is applied "//&
3279  "before interior diapycnal mixing. 0 by default.", &
3280  units="nondim", default=0.0)
3281  call get_param(param_file, mdl, "NKBL", cs%nkbl, default=2, do_not_log=.true.)
3282  else
3283  cs%ML_mix_first = 0.0
3284  endif
3285  if (use_temperature) then
3286  call get_param(param_file, mdl, "DO_GEOTHERMAL", cs%use_geothermal, &
3287  "If true, apply geothermal heating.", default=.false.)
3288  else
3289  cs%use_geothermal = .false.
3290  endif
3291  call get_param(param_file, mdl, "INTERNAL_TIDES", cs%use_int_tides, &
3292  "If true, use the code that advances a separate set of "//&
3293  "equations for the internal tide energy density.", default=.false.)
3294  cs%nMode = 1
3295  if (cs%use_int_tides) then
3296  call get_param(param_file, mdl, "INTERNAL_TIDE_MODES", cs%nMode, &
3297  "The number of distinct internal tide modes "//&
3298  "that will be calculated.", default=1, do_not_log=.true.)
3299  call get_param(param_file, mdl, "UNIFORM_TEST_CG", cs%uniform_test_cg, &
3300  "If positive, a uniform group velocity of internal tide for test case", &
3301  default=-1., units="m s-1", scale=us%m_s_to_L_T)
3302  endif
3303 
3304  call get_param(param_file, mdl, "MASSLESS_MATCH_TARGETS", &
3305  cs%massless_match_targets, &
3306  "If true, the temperature and salinity of massless layers "//&
3307  "are kept consistent with their target densities. "//&
3308  "Otherwise the properties of massless layers evolve "//&
3309  "diffusively to match massive neighboring layers.", &
3310  default=.true.)
3311 
3312  call get_param(param_file, mdl, "AGGREGATE_FW_FORCING", cs%aggregate_FW_forcing, &
3313  "If true, the net incoming and outgoing fresh water fluxes are combined "//&
3314  "and applied as either incoming or outgoing depending on the sign of the net. "//&
3315  "If false, the net incoming fresh water flux is added to the model and "//&
3316  "thereafter the net outgoing is removed from the topmost non-vanished "//&
3317  "layers of the updated state.", default=.true.)
3318 
3319  call get_param(param_file, mdl, "DEBUG", cs%debug, &
3320  "If true, write out verbose debugging data.", &
3321  default=.false., debuggingparam=.true.)
3322  call get_param(param_file, mdl, "DEBUG_CONSERVATION", cs%debugConservation, &
3323  "If true, monitor conservation and extrema.", &
3324  default=.false., debuggingparam=.true.)
3325 
3326  call get_param(param_file, mdl, "DEBUG_ENERGY_REQ", cs%debug_energy_req, &
3327  "If true, debug the energy requirements.", default=.false., do_not_log=.true.)
3328  call get_param(param_file, mdl, "MIX_BOUNDARY_TRACERS", cs%mix_boundary_tracers, &
3329  "If true, mix the passive tracers in massless layers at "//&
3330  "the bottom into the interior as though a diffusivity of "//&
3331  "KD_MIN_TR were operating.", default=.true.)
3332 
3333  if (cs%mix_boundary_tracers) then
3334  call get_param(param_file, mdl, "KD", kd, fail_if_missing=.true.)
3335  call get_param(param_file, mdl, "KD_MIN_TR", cs%Kd_min_tr, &
3336  "A minimal diffusivity that should always be applied to "//&
3337  "tracers, especially in massless layers near the bottom. "//&
3338  "The default is 0.1*KD.", units="m2 s-1", default=0.1*kd, scale=us%m2_s_to_Z2_T)
3339  call get_param(param_file, mdl, "KD_BBL_TR", cs%Kd_BBL_tr, &
3340  "A bottom boundary layer tracer diffusivity that will "//&
3341  "allow for explicitly specified bottom fluxes. The "//&
3342  "entrainment at the bottom is at least sqrt(Kd_BBL_tr*dt) "//&
3343  "over the same distance.", units="m2 s-1", default=0., scale=us%m2_s_to_Z2_T)
3344  endif
3345 
3346  call get_param(param_file, mdl, "TRACER_TRIDIAG", cs%tracer_tridiag, &
3347  "If true, use the passive tracer tridiagonal solver for T and S", &
3348  default=.false.)
3349 
3350  call get_param(param_file, mdl, "MINIMUM_FORCING_DEPTH", cs%minimum_forcing_depth, &
3351  "The smallest depth over which forcing can be applied. This "//&
3352  "only takes effect when near-surface layers become thin "//&
3353  "relative to this scale, in which case the forcing tendencies "//&
3354  "scaled down by distributing the forcing over this depth scale.", &
3355  units="m", default=0.001, scale=gv%m_to_H)
3356  call get_param(param_file, mdl, "EVAP_CFL_LIMIT", cs%evap_CFL_limit, &
3357  "The largest fraction of a layer than can be lost to forcing "//&
3358  "(e.g. evaporation, sea-ice formation) in one time-step. The unused "//&
3359  "mass loss is passed down through the column.", &
3360  units="nondim", default=0.8)
3361 
3362 
3363  ! Register all available diagnostics for this module.
3364  thickness_units = get_thickness_units(gv)
3365 
3366  cs%id_ea_t = register_diag_field('ocean_model','ea_t',diag%axesTL,time, &
3367  'Layer (heat) entrainment from above per timestep','m', &
3368  conversion=gv%H_to_m)
3369  cs%id_eb_t = register_diag_field('ocean_model','eb_t',diag%axesTL,time, &
3370  'Layer (heat) entrainment from below per timestep', 'm', &
3371  conversion=gv%H_to_m)
3372  cs%id_ea_s = register_diag_field('ocean_model','ea_s',diag%axesTL,time, &
3373  'Layer (salt) entrainment from above per timestep','m', &
3374  conversion=gv%H_to_m)
3375  cs%id_eb_s = register_diag_field('ocean_model','eb_s',diag%axesTL,time, &
3376  'Layer (salt) entrainment from below per timestep', 'm', &
3377  conversion=gv%H_to_m)
3378  ! used by layer diabatic
3379  cs%id_ea = register_diag_field('ocean_model','ea',diag%axesTL,time, &
3380  'Layer entrainment from above per timestep','m', &
3381  conversion=gv%H_to_m)
3382  cs%id_eb = register_diag_field('ocean_model','eb',diag%axesTL,time, &
3383  'Layer entrainment from below per timestep', 'm', &
3384  conversion=gv%H_to_m)
3385  cs%id_wd = register_diag_field('ocean_model','wd',diag%axesTi,time, &
3386  'Diapycnal velocity', 'm s-1', conversion=gv%H_to_m)
3387  if (cs%id_wd > 0) call safe_alloc_ptr(cdp%diapyc_vel,isd,ied,jsd,jed,nz+1)
3388 
3389  cs%id_dudt_dia = register_diag_field('ocean_model','dudt_dia',diag%axesCuL,time, &
3390  'Zonal Acceleration from Diapycnal Mixing', 'm s-2', conversion=us%L_T2_to_m_s2)
3391  cs%id_dvdt_dia = register_diag_field('ocean_model','dvdt_dia',diag%axesCvL,time, &
3392  'Meridional Acceleration from Diapycnal Mixing', 'm s-2', conversion=us%L_T2_to_m_s2)
3393 
3394  if (cs%use_int_tides) then
3395  cs%id_cg1 = register_diag_field('ocean_model','cn1', diag%axesT1, &
3396  time, 'First baroclinic mode (eigen) speed', 'm s-1')
3397  allocate(cs%id_cn(cs%nMode)) ; cs%id_cn(:) = -1
3398  do m=1,cs%nMode
3399  write(var_name, '("cn_mode",i1)') m
3400  write(var_descript, '("Baroclinic (eigen) speed of mode ",i1)') m
3401  cs%id_cn(m) = register_diag_field('ocean_model',var_name, diag%axesT1, &
3402  time, var_descript, 'm s-1')
3403  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
3404  enddo
3405  endif
3406 
3407  if (use_temperature) then
3408  cs%id_Tdif = register_diag_field('ocean_model',"Tflx_dia_diff",diag%axesTi, &
3409  time, "Diffusive diapycnal temperature flux across interfaces", &
3410  "degC m s-1", conversion=gv%H_to_m*us%s_to_T)
3411  cs%id_Tadv = register_diag_field('ocean_model',"Tflx_dia_adv",diag%axesTi, &
3412  time, "Advective diapycnal temperature flux across interfaces", &
3413  "degC m s-1", conversion=gv%H_to_m*us%s_to_T)
3414  cs%id_Sdif = register_diag_field('ocean_model',"Sflx_dia_diff",diag%axesTi, &
3415  time, "Diffusive diapycnal salnity flux across interfaces", &
3416  "psu m s-1", conversion=gv%H_to_m*us%s_to_T)
3417  cs%id_Sadv = register_diag_field('ocean_model',"Sflx_dia_adv",diag%axesTi, &
3418  time, "Advective diapycnal salnity flux across interfaces", &
3419  "psu m s-1", conversion=gv%H_to_m*us%s_to_T)
3420  cs%id_MLD_003 = register_diag_field('ocean_model', 'MLD_003', diag%axesT1, time, &
3421  'Mixed layer depth (delta rho = 0.03)', 'm', conversion=us%Z_to_m, &
3422  cmor_field_name='mlotst', cmor_long_name='Ocean Mixed Layer Thickness Defined by Sigma T', &
3423  cmor_standard_name='ocean_mixed_layer_thickness_defined_by_sigma_t')
3424  cs%id_mlotstsq = register_diag_field('ocean_model','mlotstsq',diag%axesT1, time, &
3425  long_name='Square of Ocean Mixed Layer Thickness Defined by Sigma T', &
3426  standard_name='square_of_ocean_mixed_layer_thickness_defined_by_sigma_t', &
3427  units='m2', conversion=us%Z_to_m**2)
3428  cs%id_MLD_0125 = register_diag_field('ocean_model','MLD_0125',diag%axesT1,time, &
3429  'Mixed layer depth (delta rho = 0.125)', 'm', conversion=us%Z_to_m)
3430  cs%id_subMLN2 = register_diag_field('ocean_model','subML_N2',diag%axesT1,time, &
3431  'Squared buoyancy frequency below mixed layer', 's-2', conversion=us%s_to_T**2)
3432  cs%id_MLD_user = register_diag_field('ocean_model','MLD_user',diag%axesT1,time, &
3433  'Mixed layer depth (used defined)', 'm', conversion=us%Z_to_m)
3434  endif
3435  call get_param(param_file, mdl, "DIAG_MLD_DENSITY_DIFF", cs%MLDdensityDifference, &
3436  "The density difference used to determine a diagnostic mixed "//&
3437  "layer depth, MLD_user, following the definition of Levitus 1982. "//&
3438  "The MLD is the depth at which the density is larger than the "//&
3439  "surface density by the specified amount.", &
3440  units='kg/m3', default=0.1, scale=us%kg_m3_to_R)
3441  call get_param(param_file, mdl, "DIAG_DEPTH_SUBML_N2", cs%dz_subML_N2, &
3442  "The distance over which to calculate a diagnostic of the "//&
3443  "stratification at the base of the mixed layer.", &
3444  units='m', default=50.0, scale=us%m_to_Z)
3445 
3446  if (cs%id_dudt_dia > 0) call safe_alloc_ptr(adp%du_dt_dia,isdb,iedb,jsd,jed,nz)
3447  if (cs%id_dvdt_dia > 0) call safe_alloc_ptr(adp%dv_dt_dia,isd,ied,jsdb,jedb,nz)
3448 
3449  ! diagnostics for values prior to diabatic and prior to ALE
3450  cs%id_u_predia = register_diag_field('ocean_model', 'u_predia', diag%axesCuL, time, &
3451  'Zonal velocity before diabatic forcing', 'm s-1', conversion=us%L_T_to_m_s)
3452  cs%id_v_predia = register_diag_field('ocean_model', 'v_predia', diag%axesCvL, time, &
3453  'Meridional velocity before diabatic forcing', 'm s-1', conversion=us%L_T_to_m_s)
3454  cs%id_h_predia = register_diag_field('ocean_model', 'h_predia', diag%axesTL, time, &
3455  'Layer Thickness before diabatic forcing', trim(thickness_units), &
3456  conversion=gv%H_to_MKS, v_extensive=.true.)
3457  cs%id_e_predia = register_diag_field('ocean_model', 'e_predia', diag%axesTi, time, &
3458  'Interface Heights before diabatic forcing', 'm')
3459  if (use_temperature) then
3460  cs%id_T_predia = register_diag_field('ocean_model', 'temp_predia', diag%axesTL, time, &
3461  'Potential Temperature', 'degC')
3462  cs%id_S_predia = register_diag_field('ocean_model', 'salt_predia', diag%axesTL, time, &
3463  'Salinity', 'PSU')
3464  endif
3465 
3466 
3467  !call set_diffusivity_init(Time, G, param_file, diag, CS%set_diff_CSp, CS%int_tide_CSp)
3468  cs%id_Kd_interface = register_diag_field('ocean_model', 'Kd_interface', diag%axesTi, time, &
3469  'Total diapycnal diffusivity at interfaces', 'm2 s-1', conversion=us%Z2_T_to_m2_s)
3470  if (cs%use_energetic_PBL) then
3471  cs%id_Kd_ePBL = register_diag_field('ocean_model', 'Kd_ePBL', diag%axesTi, time, &
3472  'ePBL diapycnal diffusivity at interfaces', 'm2 s-1', conversion=us%Z2_T_to_m2_s)
3473  endif
3474 
3475  cs%id_Kd_heat = register_diag_field('ocean_model', 'Kd_heat', diag%axesTi, time, &
3476  'Total diapycnal diffusivity for heat at interfaces', 'm2 s-1', conversion=us%Z2_T_to_m2_s, &
3477  cmor_field_name='difvho', &
3478  cmor_standard_name='ocean_vertical_heat_diffusivity', &
3479  cmor_long_name='Ocean vertical heat diffusivity')
3480  cs%id_Kd_salt = register_diag_field('ocean_model', 'Kd_salt', diag%axesTi, time, &
3481  'Total diapycnal diffusivity for salt at interfaces', 'm2 s-1', conversion=us%Z2_T_to_m2_s, &
3482  cmor_field_name='difvso', &
3483  cmor_standard_name='ocean_vertical_salt_diffusivity', &
3484  cmor_long_name='Ocean vertical salt diffusivity')
3485 
3486  ! CS%useKPP is set to True if KPP-scheme is to be used, False otherwise.
3487  ! KPP_init() allocated CS%KPP_Csp and also sets CS%KPPisPassive
3488  cs%useKPP = kpp_init(param_file, g, gv, us, diag, time, cs%KPP_CSp, passive=cs%KPPisPassive)
3489  if (cs%useKPP) then
3490  allocate( cs%KPP_NLTheat(isd:ied,jsd:jed,nz+1) ) ; cs%KPP_NLTheat(:,:,:) = 0.
3491  allocate( cs%KPP_NLTscalar(isd:ied,jsd:jed,nz+1) ) ; cs%KPP_NLTscalar(:,:,:) = 0.
3492  endif
3493  if (cs%useKPP) then
3494  allocate( cs%KPP_buoy_flux(isd:ied,jsd:jed,nz+1) ) ; cs%KPP_buoy_flux(:,:,:) = 0.
3495  allocate( cs%KPP_temp_flux(isd:ied,jsd:jed) ) ; cs%KPP_temp_flux(:,:) = 0.
3496  allocate( cs%KPP_salt_flux(isd:ied,jsd:jed) ) ; cs%KPP_salt_flux(:,:) = 0.
3497  endif
3498 
3499  if (cs%useKPP .and. differentialdiffusion) then
3500  call mom_error(fatal, 'diabatic_driver_init: '// &
3501  'DOUBLE_DIFFUSION (old method) does not work with KPP. Please'//&
3502  'set DOUBLE_DIFFUSION=False and USE_CVMIX_DDIFF=True.')
3503  endif
3504 
3505  call get_param(param_file, mdl, "SALT_REJECT_BELOW_ML", cs%salt_reject_below_ML, &
3506  "If true, place salt from brine rejection below the mixed layer, "// &
3507  "into the first non-vanished layer for which the column remains stable", &
3508  default=.false.)
3509 
3510  if (cs%salt_reject_below_ML) then
3511  cs%id_brine_lay = register_diag_field('ocean_model','brine_layer',diag%axesT1,time, &
3512  'Brine insertion layer','none')
3513  endif
3514 
3515 
3516  ! diagnostics for tendencies of temp and saln due to diabatic processes
3517  ! available only for ALE algorithm.
3518  ! diagnostics for tendencies of temp and heat due to frazil
3519  cs%id_diabatic_diff_h = register_diag_field('ocean_model', 'diabatic_diff_h', diag%axesTL, time, &
3520  long_name='Cell thickness used during diabatic diffusion', units='m', &
3521  conversion=gv%H_to_m, v_extensive=.true.)
3522  if (cs%useALEalgorithm) then
3523  cs%id_diabatic_diff_temp_tend = register_diag_field('ocean_model', &
3524  'diabatic_diff_temp_tendency', diag%axesTL, time, &
3525  'Diabatic diffusion temperature tendency', 'degC s-1', conversion=us%s_to_T)
3526  if (cs%id_diabatic_diff_temp_tend > 0) then
3527  cs%diabatic_diff_tendency_diag = .true.
3528  endif
3529 
3530  cs%id_diabatic_diff_saln_tend = register_diag_field('ocean_model',&
3531  'diabatic_diff_saln_tendency', diag%axesTL, time, &
3532  'Diabatic diffusion salinity tendency', 'psu s-1', conversion=us%s_to_T)
3533  if (cs%id_diabatic_diff_saln_tend > 0) then
3534  cs%diabatic_diff_tendency_diag = .true.
3535  endif
3536 
3537  cs%id_diabatic_diff_heat_tend = register_diag_field('ocean_model', &
3538  'diabatic_heat_tendency', diag%axesTL, time, &
3539  'Diabatic diffusion heat tendency', &
3540  'W m-2', conversion=us%s_to_T, cmor_field_name='opottempdiff', &
3541  cmor_standard_name='tendency_of_sea_water_potential_temperature_expressed_as_heat_content_'// &
3542  'due_to_parameterized_dianeutral_mixing', &
3543  cmor_long_name='Tendency of sea water potential temperature expressed as heat content '// &
3544  'due to parameterized dianeutral mixing', &
3545  v_extensive=.true.)
3546  if (cs%id_diabatic_diff_heat_tend > 0) then
3547  cs%diabatic_diff_tendency_diag = .true.
3548  endif
3549 
3550  cs%id_diabatic_diff_salt_tend = register_diag_field('ocean_model', &
3551  'diabatic_salt_tendency', diag%axesTL, time, &
3552  'Diabatic diffusion of salt tendency', &
3553  'kg m-2 s-1', conversion=us%s_to_T, cmor_field_name='osaltdiff', &
3554  cmor_standard_name='tendency_of_sea_water_salinity_expressed_as_salt_content_'// &
3555  'due_to_parameterized_dianeutral_mixing', &
3556  cmor_long_name='Tendency of sea water salinity expressed as salt content '// &
3557  'due to parameterized dianeutral mixing', &
3558  v_extensive=.true.)
3559  if (cs%id_diabatic_diff_salt_tend > 0) then
3560  cs%diabatic_diff_tendency_diag = .true.
3561  endif
3562 
3563  ! This diagnostic should equal to roundoff if all is working well.
3564  cs%id_diabatic_diff_heat_tend_2d = register_diag_field('ocean_model', &
3565  'diabatic_heat_tendency_2d', diag%axesT1, time, &
3566  'Depth integrated diabatic diffusion heat tendency', &
3567  'W m-2', conversion=us%s_to_T, cmor_field_name='opottempdiff_2d', &
3568  cmor_standard_name='tendency_of_sea_water_potential_temperature_expressed_as_heat_content_'//&
3569  'due_to_parameterized_dianeutral_mixing_depth_integrated', &
3570  cmor_long_name='Tendency of sea water potential temperature expressed as heat content '//&
3571  'due to parameterized dianeutral mixing depth integrated')
3572  if (cs%id_diabatic_diff_heat_tend_2d > 0) then
3573  cs%diabatic_diff_tendency_diag = .true.
3574  endif
3575 
3576  ! This diagnostic should equal to roundoff if all is working well.
3577  cs%id_diabatic_diff_salt_tend_2d = register_diag_field('ocean_model', &
3578  'diabatic_salt_tendency_2d', diag%axesT1, time, &
3579  'Depth integrated diabatic diffusion salt tendency', &
3580  'kg m-2 s-1', conversion=us%s_to_T, cmor_field_name='osaltdiff_2d', &
3581  cmor_standard_name='tendency_of_sea_water_salinity_expressed_as_salt_content_'// &
3582  'due_to_parameterized_dianeutral_mixing_depth_integrated', &
3583  cmor_long_name='Tendency of sea water salinity expressed as salt content '// &
3584  'due to parameterized dianeutral mixing depth integrated')
3585  if (cs%id_diabatic_diff_salt_tend_2d > 0) then
3586  cs%diabatic_diff_tendency_diag = .true.
3587  endif
3588 
3589  ! diagnostics for tendencies of thickness temp and saln due to boundary forcing
3590  ! available only for ALE algorithm.
3591  ! diagnostics for tendencies of temp and heat due to frazil
3592  cs%id_boundary_forcing_h = register_diag_field('ocean_model', 'boundary_forcing_h', diag%axesTL, time, &
3593  long_name='Cell thickness after applying boundary forcing', units='m', &
3594  conversion=gv%H_to_m, v_extensive=.true.)
3595  cs%id_boundary_forcing_h_tendency = register_diag_field('ocean_model', &
3596  'boundary_forcing_h_tendency', diag%axesTL, time, &
3597  'Cell thickness tendency due to boundary forcing', 'm s-1', conversion=us%s_to_T, &
3598  v_extensive = .true.)
3599  if (cs%id_boundary_forcing_h_tendency > 0) then
3600  cs%boundary_forcing_tendency_diag = .true.
3601  endif
3602 
3603  cs%id_boundary_forcing_temp_tend = register_diag_field('ocean_model',&
3604  'boundary_forcing_temp_tendency', diag%axesTL, time, &
3605  'Boundary forcing temperature tendency', 'degC s-1', conversion=us%s_to_T)
3606  if (cs%id_boundary_forcing_temp_tend > 0) then
3607  cs%boundary_forcing_tendency_diag = .true.
3608  endif
3609 
3610  cs%id_boundary_forcing_saln_tend = register_diag_field('ocean_model',&
3611  'boundary_forcing_saln_tendency', diag%axesTL, time, &
3612  'Boundary forcing saln tendency', 'psu s-1', conversion=us%s_to_T)
3613  if (cs%id_boundary_forcing_saln_tend > 0) then
3614  cs%boundary_forcing_tendency_diag = .true.
3615  endif
3616 
3617  cs%id_boundary_forcing_heat_tend = register_diag_field('ocean_model',&
3618  'boundary_forcing_heat_tendency', diag%axesTL, time, &
3619  'Boundary forcing heat tendency', 'W m-2', conversion=us%s_to_T, &
3620  v_extensive = .true.)
3621  if (cs%id_boundary_forcing_heat_tend > 0) then
3622  cs%boundary_forcing_tendency_diag = .true.
3623  endif
3624 
3625  cs%id_boundary_forcing_salt_tend = register_diag_field('ocean_model',&
3626  'boundary_forcing_salt_tendency', diag%axesTL, time, &
3627  'Boundary forcing salt tendency', 'kg m-2 s-1', conversion=us%s_to_T, &
3628  v_extensive = .true.)
3629  if (cs%id_boundary_forcing_salt_tend > 0) then
3630  cs%boundary_forcing_tendency_diag = .true.
3631  endif
3632 
3633  ! This diagnostic should equal to surface heat flux if all is working well.
3634  cs%id_boundary_forcing_heat_tend_2d = register_diag_field('ocean_model',&
3635  'boundary_forcing_heat_tendency_2d', diag%axesT1, time, &
3636  'Depth integrated boundary forcing of ocean heat', 'W m-2', conversion=us%s_to_T)
3637  if (cs%id_boundary_forcing_heat_tend_2d > 0) then
3638  cs%boundary_forcing_tendency_diag = .true.
3639  endif
3640 
3641  ! This diagnostic should equal to surface salt flux if all is working well.
3642  cs%id_boundary_forcing_salt_tend_2d = register_diag_field('ocean_model',&
3643  'boundary_forcing_salt_tendency_2d', diag%axesT1, time, &
3644  'Depth integrated boundary forcing of ocean salt','kg m-2 s-1', conversion=us%s_to_T)
3645  if (cs%id_boundary_forcing_salt_tend_2d > 0) then
3646  cs%boundary_forcing_tendency_diag = .true.
3647  endif
3648  endif
3649 
3650  ! diagnostics for tendencies of temp and heat due to frazil
3651  cs%id_frazil_h = register_diag_field('ocean_model', 'frazil_h', diag%axesTL, time, &
3652  long_name='Cell Thickness', standard_name='cell_thickness', units='m', &
3653  conversion=gv%H_to_m, v_extensive=.true.)
3654 
3655  ! diagnostic for tendency of temp due to frazil
3656  cs%id_frazil_temp_tend = register_diag_field('ocean_model',&
3657  'frazil_temp_tendency', diag%axesTL, time, &
3658  'Temperature tendency due to frazil formation', 'degC s-1', conversion=us%s_to_T)
3659  if (cs%id_frazil_temp_tend > 0) then
3660  cs%frazil_tendency_diag = .true.
3661  endif
3662 
3663  ! diagnostic for tendency of heat due to frazil
3664  cs%id_frazil_heat_tend = register_diag_field('ocean_model',&
3665  'frazil_heat_tendency', diag%axesTL, time, &
3666  'Heat tendency due to frazil formation', 'W m-2', conversion=us%s_to_T, v_extensive=.true.)
3667  if (cs%id_frazil_heat_tend > 0) then
3668  cs%frazil_tendency_diag = .true.
3669  endif
3670 
3671  ! if all is working propertly, this diagnostic should equal to hfsifrazil
3672  cs%id_frazil_heat_tend_2d = register_diag_field('ocean_model',&
3673  'frazil_heat_tendency_2d', diag%axesT1, time, &
3674  'Depth integrated heat tendency due to frazil formation', 'W m-2', conversion=us%s_to_T)
3675  if (cs%id_frazil_heat_tend_2d > 0) then
3676  cs%frazil_tendency_diag = .true.
3677  endif
3678 
3679  if (cs%frazil_tendency_diag) then
3680  allocate(cs%frazil_temp_diag(isd:ied,jsd:jed,nz) ) ; cs%frazil_temp_diag(:,:,:) = 0.
3681  allocate(cs%frazil_heat_diag(isd:ied,jsd:jed,nz) ) ; cs%frazil_heat_diag(:,:,:) = 0.
3682  endif
3683 
3684  ! CS%use_tidal_mixing is set to True if an internal tidal dissipation scheme is to be used.
3685  cs%use_tidal_mixing = tidal_mixing_init(time, g, gv, us, param_file, diag, &
3686  cs%tidal_mixing_CSp)
3687 
3688  ! CS%use_CVMix_conv is set to True if CVMix convection will be used, otherwise
3689  ! False.
3690  cs%use_CVMix_conv = cvmix_conv_init(time, g, gv, us, param_file, diag, cs%CVMix_conv_csp)
3691 
3692  call entrain_diffusive_init(time, g, gv, us, param_file, diag, cs%entrain_diffusive_CSp)
3693 
3694  ! initialize the geothermal heating module
3695  if (cs%use_geothermal) &
3696  call geothermal_init(time, g, gv, us, param_file, diag, cs%geothermal_CSp)
3697 
3698  ! initialize module for internal tide induced mixing
3699  if (cs%use_int_tides) then
3700  call int_tide_input_init(time, g, gv, us, param_file, diag, cs%int_tide_input_CSp, &
3701  cs%int_tide_input)
3702  call internal_tides_init(time, g, gv, us, param_file, diag, cs%int_tide_CSp)
3703  endif
3704 
3705  ! initialize module for setting diffusivities
3706  call set_diffusivity_init(time, g, gv, us, param_file, diag, cs%set_diff_CSp, &
3707  cs%int_tide_CSp, cs%tidal_mixing_CSp, cs%halo_TS_diff)
3708 
3709  ! set up the clocks for this module
3710  id_clock_entrain = cpu_clock_id('(Ocean diabatic entrain)', grain=clock_module)
3711  if (cs%bulkmixedlayer) &
3712  id_clock_mixedlayer = cpu_clock_id('(Ocean mixed layer)', grain=clock_module)
3713  id_clock_remap = cpu_clock_id('(Ocean vert remap)', grain=clock_module)
3714  if (cs%use_geothermal) &
3715  id_clock_geothermal = cpu_clock_id('(Ocean geothermal)', grain=clock_routine)
3716  id_clock_set_diffusivity = cpu_clock_id('(Ocean set_diffusivity)', grain=clock_module)
3717  id_clock_kpp = cpu_clock_id('(Ocean KPP)', grain=clock_module)
3718  id_clock_tracers = cpu_clock_id('(Ocean tracer_columns)', grain=clock_module_driver+5)
3719  if (cs%use_sponge) &
3720  id_clock_sponge = cpu_clock_id('(Ocean sponges)', grain=clock_module)
3721  id_clock_tridiag = cpu_clock_id('(Ocean diabatic tridiag)', grain=clock_routine)
3722  id_clock_pass = cpu_clock_id('(Ocean diabatic message passing)', grain=clock_routine)
3723  id_clock_differential_diff = -1 ; if (differentialdiffusion) &
3724  id_clock_differential_diff = cpu_clock_id('(Ocean differential diffusion)', grain=clock_routine)
3725 
3726  ! initialize the auxiliary diabatic driver module
3727  call diabatic_aux_init(time, g, gv, us, param_file, diag, cs%diabatic_aux_CSp, &
3728  cs%useALEalgorithm, cs%use_energetic_PBL)
3729 
3730  ! initialize the boundary layer modules
3731  if (cs%bulkmixedlayer) &
3732  call bulkmixedlayer_init(time, g, gv, us, param_file, diag, cs%bulkmixedlayer_CSp)
3733  if (cs%use_energetic_PBL) &
3734  call energetic_pbl_init(time, g, gv, us, param_file, diag, cs%energetic_PBL_CSp)
3735 
3736  call regularize_layers_init(time, g, gv, param_file, diag, cs%regularize_layers_CSp)
3737 
3738  if (cs%debug_energy_req) &
3739  call diapyc_energy_req_init(time, g, gv, us, param_file, diag, cs%diapyc_en_rec_CSp)
3740 
3741  ! obtain information about the number of bands for penetrative shortwave
3742  if (use_temperature) then
3743  call get_param(param_file, mdl, "PEN_SW_NBANDS", nbands, default=1)
3744  if (nbands > 0) then
3745  allocate(cs%optics)
3746  call opacity_init(time, g, gv, us, param_file, diag, cs%opacity_CSp, cs%optics)
3747  endif
3748  endif
3749 
3750  ! Initialize the diagnostic grid storage
3751  call diag_grid_storage_init(cs%diag_grids_prev, g, diag)
3752 
3753 end subroutine diabatic_driver_init
3754 
3755 
3756 !> Routine to close the diabatic driver module
3757 subroutine diabatic_driver_end(CS)
3758  type(diabatic_cs), pointer :: cs !< module control structure
3759 
3760  if (.not.associated(cs)) return
3761 
3762  call diabatic_aux_end(cs%diabatic_aux_CSp)
3763 
3764  call entrain_diffusive_end(cs%entrain_diffusive_CSp)
3765  call set_diffusivity_end(cs%set_diff_CSp)
3766 
3767  if (cs%useKPP) then
3768  deallocate( cs%KPP_buoy_flux )
3769  deallocate( cs%KPP_temp_flux )
3770  deallocate( cs%KPP_salt_flux )
3771  endif
3772  if (cs%useKPP) then
3773  deallocate( cs%KPP_NLTheat )
3774  deallocate( cs%KPP_NLTscalar )
3775  call kpp_end(cs%KPP_CSp)
3776  endif
3777 
3778  if (cs%use_tidal_mixing) call tidal_mixing_end(cs%tidal_mixing_CSp)
3779 
3780  if (cs%use_CVMix_conv) call cvmix_conv_end(cs%CVMix_conv_csp)
3781 
3782  if (cs%use_energetic_PBL) &
3783  call energetic_pbl_end(cs%energetic_PBL_CSp)
3784  if (cs%debug_energy_req) &
3785  call diapyc_energy_req_end(cs%diapyc_en_rec_CSp)
3786 
3787  if (associated(cs%optics)) then
3788  call opacity_end(cs%opacity_CSp, cs%optics)
3789  deallocate(cs%optics)
3790  endif
3791 
3792  ! GMM, the following is commented out because arrays in
3793  ! CS%diag_grids_prev are neither pointers or allocatables
3794  ! and, therefore, cannot be deallocated.
3795 
3796  !call diag_grid_storage_end(CS%diag_grids_prev)
3797 
3798  deallocate(cs)
3799 
3800 end subroutine diabatic_driver_end
3801 
3802 
3803 !> \namespace mom_diabatic_driver
3804 !!
3805 !! By Robert Hallberg, Alistair Adcroft, and Stephen Griffies
3806 !!
3807 !! This program contains the subroutine that, along with the
3808 !! subroutines that it calls, implements diapycnal mass and momentum
3809 !! fluxes and a bulk mixed layer. The diapycnal diffusion can be
3810 !! used without the bulk mixed layer.
3811 !!
3812 !! \section section_diabatic Outline of MOM diabatic
3813 !!
3814 !! * diabatic first determines the (diffusive) diapycnal mass fluxes
3815 !! based on the convergence of the buoyancy fluxes within each layer.
3816 !!
3817 !! * The dual-stream entrainment scheme of MacDougall and Dewar (JPO,
3818 !! 1997) is used for combined diapycnal advection and diffusion,
3819 !! calculated implicitly and potentially with the Richardson number
3820 !! dependent mixing, as described by Hallberg (MWR, 2000).
3821 !!
3822 !! * Diapycnal advection is the residual of diapycnal diffusion,
3823 !! so the fully implicit upwind differencing scheme that is used is
3824 !! entirely appropriate.
3825 !!
3826 !! * The downward buoyancy flux in each layer is determined from
3827 !! an implicit calculation based on the previously
3828 !! calculated flux of the layer above and an estimated flux in the
3829 !! layer below. This flux is subject to the following conditions:
3830 !! (1) the flux in the top and bottom layers are set by the boundary
3831 !! conditions, and (2) no layer may be driven below an Angstrom thick-
3832 !! ness. If there is a bulk mixed layer, the buffer layer is treated
3833 !! as a fixed density layer with vanishingly small diffusivity.
3834 !!
3835 !! diabatic takes 5 arguments: the two velocities (u and v), the
3836 !! thicknesses (h), a structure containing the forcing fields, and
3837 !! the length of time over which to act (dt). The velocities and
3838 !! thickness are taken as inputs and modified within the subroutine.
3839 !! There is no limit on the time step.
3840 
3841 end module mom_diabatic_driver
mom_diabatic_aux::adjust_salt
subroutine, public adjust_salt(h, tv, G, GV, CS, halo)
This subroutine keeps salinity from falling below a small but positive threshold. This usually occurs...
Definition: MOM_diabatic_aux.F90:326
mom_diapyc_energy_req::diapyc_energy_req_calc
subroutine, public diapyc_energy_req_calc(h_in, T_in, S_in, Kd, energy_Kd, dt, tv, G, GV, US, may_print, CS)
This subroutine uses a substantially refactored tridiagonal equation for diapycnal mixing of temperat...
Definition: MOM_diapyc_energy_req.F90:122
mom_time_manager
Wraps the FMS time manager functions.
Definition: MOM_time_manager.F90:2
mom_diag_mediator::diag_restore_grids
subroutine, public diag_restore_grids(diag)
Restore the diagnostic grids from the temporary structure within diag.
Definition: MOM_diag_mediator.F90:3564
mom_forcing_type::forcing_singlepointprint
subroutine, public forcing_singlepointprint(fluxes, G, i, j, mesg)
Write out values of the fluxes arrays at the i,j location. This is a debugging tool.
Definition: MOM_forcing_type.F90:1161
mom_cvmix_ddiff::cvmix_ddiff_is_used
logical function, public cvmix_ddiff_is_used(param_file)
Reads the parameter "USE_CVMIX_DDIFF" and returns state. This function allows other modules to know w...
Definition: MOM_CVMix_ddiff.F90:299
mom_set_diffusivity::set_bbl_tke
subroutine, public set_bbl_tke(u, v, h, fluxes, visc, G, GV, US, CS)
This subroutine calculates several properties related to bottom boundary layer turbulence.
Definition: MOM_set_diffusivity.F90:1635
mom_checksum_packages::mom_state_chksum
Write out checksums of the MOM6 state variables.
Definition: MOM_checksum_packages.F90:23
mom_int_tide_input::int_tide_input_init
subroutine, public int_tide_input_init(Time, G, GV, US, param_file, diag, CS, itide)
Initializes the data related to the internal tide input module.
Definition: MOM_internal_tide_input.F90:267
mom_regularize_layers::regularize_layers
subroutine, public regularize_layers(h, tv, dt, ea, eb, G, GV, US, CS)
This subroutine partially steps the bulk mixed layer model. The following processes are executed,...
Definition: MOM_regularize_layers.F90:79
mom_opacity::absorbremainingsw
subroutine, public absorbremainingsw(G, GV, US, h, opacity_band, nsw, optics, j, dt, H_limit_fluxes, adjustAbsorptionProfile, absorbAllSW, T, Pen_SW_bnd, eps, ksort, htot, Ttot, TKE, dSV_dT)
Apply shortwave heating below the boundary layer (when running with the bulk mixed layer inhereted fr...
Definition: MOM_opacity.F90:512
mom_diabatic_aux::tridiagts
subroutine, public tridiagts(G, GV, is, ie, js, je, hold, ea, eb, T, S)
This is a simple tri-diagonal solver for T and S. "Simple" means it only uses arrays hold,...
Definition: MOM_diabatic_aux.F90:508
mom_diabatic_driver::id_clock_sponge
integer id_clock_sponge
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:249
mom_diag_mediator::query_averaging_enabled
logical function, public query_averaging_enabled(diag_cs, time_int, time_end)
Call this subroutine to determine whether the averaging is currently enabled. .true....
Definition: MOM_diag_mediator.F90:1850
mom_verticalgrid
Provides a transparent vertical ocean grid type and supporting routines.
Definition: MOM_verticalGrid.F90:2
mom_energetic_pbl::energetic_pbl_end
subroutine, public energetic_pbl_end(CS)
Clean up and deallocate memory associated with the energetic_PBL module.
Definition: MOM_energetic_PBL.F90:2379
mom_cvmix_kpp::kpp_get_bld
subroutine, public kpp_get_bld(CS, BLD, G)
Copies KPP surface boundary layer depth into BLD.
Definition: MOM_CVMix_KPP.F90:1469
mom_opacity::opacity_init
subroutine, public opacity_init(Time, G, GV, US, param_file, diag, CS, optics)
This routine initalizes the opacity module, including an optics_type.
Definition: MOM_opacity.F90:922
mom_cvmix_kpp::kpp_compute_bld
subroutine, public kpp_compute_bld(CS, G, GV, US, h, Temp, Salt, u, v, EOS, uStar, buoyFlux, Waves)
Compute OBL depth.
Definition: MOM_CVMix_KPP.F90:892
mom_set_diffusivity::set_diffusivity
subroutine, public set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, optics, visc, dt, G, GV, US, CS, Kd_lay, Kd_int)
Sets the interior vertical diffusion of scalars due to the following processes:
Definition: MOM_set_diffusivity.F90:206
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_opacity::opacity_cs
The control structure with paramters for the MOM_opacity module.
Definition: MOM_opacity.F90:50
mom_diabatic_driver::layered_diabatic
subroutine layered_diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, G, GV, US, CS, WAVES)
Imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentum and tracers us...
Definition: MOM_diabatic_driver.F90:1908
mom_diabatic_aux::set_pen_shortwave
subroutine, public set_pen_shortwave(optics, fluxes, G, GV, CS, opacity_CSp, tracer_flow_CSp)
Definition: MOM_diabatic_aux.F90:657
mom_cvmix_kpp::kpp_end
subroutine, public kpp_end(CS)
Clear pointers, deallocate memory.
Definition: MOM_CVMix_KPP.F90:1603
mom_int_tide_input::int_tide_input_cs
This control structure holds parameters that regulate internal tide energy inputs.
Definition: MOM_internal_tide_input.F90:35
mom_diag_mediator
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Definition: MOM_diag_mediator.F90:3
mom_variables::thermo_var_ptrs
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Definition: MOM_variables.F90:78
mom_tracer_flow_control::call_tracer_column_fns
subroutine, public call_tracer_column_fns(h_old, h_new, ea, eb, fluxes, Hml, dt, G, GV, US, tv, optics, CS, debug, evap_CFL_limit, minimum_forcing_depth)
This subroutine calls all registered tracer column physics subroutines.
Definition: MOM_tracer_flow_control.F90:407
mom_entrain_diffusive
Diapycnal mixing and advection in isopycnal mode.
Definition: MOM_entrain_diffusive.F90:2
mom_diag_mediator::register_diag_field
integer function, public register_diag_field(module_name, field_name, axes_in, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name, cell_methods, x_cell_method, y_cell_method, v_cell_method, conversion, v_extensive)
Returns the "diag_mediator" handle for a group (native, CMOR, z-coord, ...) of diagnostics derived fr...
Definition: MOM_diag_mediator.F90:1878
mom_diabatic_aux::diabatic_aux_init
subroutine, public diabatic_aux_init(Time, G, GV, US, param_file, diag, CS, useALEalgorithm, use_ePBL)
This subroutine initializes the parameters and control structure of the diabatic_aux module.
Definition: MOM_diabatic_aux.F90:1395
mom_diag_mediator::diag_save_grids
subroutine, public diag_save_grids(diag)
Save the current diagnostic grids in the temporary structure within diag.
Definition: MOM_diag_mediator.F90:3548
mom_verticalgrid::get_thickness_units
character(len=48) function, public get_thickness_units(GV)
Returns the model's thickness units, usually m or kg/m^2.
Definition: MOM_verticalGrid.F90:190
mom_diabatic_driver::diabatic_ale_legacy
subroutine diabatic_ale_legacy(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, G, GV, US, CS, WAVES)
Applies diabatic forcing and diapycnal mixing of temperature, salinity and other tracers for use with...
Definition: MOM_diabatic_driver.F90:446
mom_energetic_pbl
Energetically consistent planetary boundary layer parameterization.
Definition: MOM_energetic_PBL.F90:2
mom_ale_sponge::ale_sponge_cs
ALE sponge control structure.
Definition: MOM_ALE_sponge.F90:84
mom_diabatic_aux::make_frazil
subroutine, public make_frazil(h, tv, G, GV, CS, p_surf, halo)
Frazil formation keeps the temperature above the freezing point. This subroutine warms any water that...
Definition: MOM_diabatic_aux.F90:103
mom_geothermal::geothermal
subroutine, public geothermal(h, tv, dt, ea, eb, G, GV, US, CS, halo)
Applies geothermal heating, including the movement of water between isopycnal layers to match the tar...
Definition: MOM_geothermal.F90:54
mom_error_handler::mom_mesg
subroutine, public mom_mesg(message, verb, all_print)
This provides a convenient interface for writing an informative comment.
Definition: MOM_error_handler.F90:53
mom_eos
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
mom_set_diffusivity
Calculate vertical diffusivity from all mixing processes.
Definition: MOM_set_diffusivity.F90:2
mom_geothermal::geothermal_init
subroutine, public geothermal_init(Time, G, GV, US, param_file, diag, CS)
Initialize parameters and allocate memory associated with the geothermal heating module.
Definition: MOM_geothermal.F90:379
mom_cvmix_kpp::kpp_calculate
subroutine, public kpp_calculate(CS, G, GV, US, h, uStar, buoyFlux, Kt, Ks, Kv, nonLocalTransHeat, nonLocalTransScalar, waves)
KPP vertical diffusivity/viscosity and non-local tracer transport.
Definition: MOM_CVMix_KPP.F90:590
mom_domains::pass_var
Do a halo update on an array.
Definition: MOM_domains.F90:49
mom_bulk_mixed_layer
Build mixed layer parameterization.
Definition: MOM_bulk_mixed_layer.F90:2
mom_cvmix_conv::cvmix_conv_init
logical function, public cvmix_conv_init(Time, G, GV, US, param_file, diag, CS)
Initialized the CVMix convection mixing routine.
Definition: MOM_CVMix_conv.F90:56
mom_diabatic_aux::diabatic_aux_end
subroutine, public diabatic_aux_end(CS)
This subroutine initializes the control structure and any related memory for the diabatic_aux module.
Definition: MOM_diabatic_aux.F90:1560
mom_int_tide_input::set_int_tide_input
subroutine, public set_int_tide_input(u, v, h, tv, fluxes, itide, dt, G, GV, US, CS)
Sets the model-state dependent internal tide energy sources.
Definition: MOM_internal_tide_input.F90:75
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
mom_checksum_packages
Provides routines that do checksums of groups of MOM variables.
Definition: MOM_checksum_packages.F90:2
mom_diag_mediator::diag_grid_storage_end
subroutine, public diag_grid_storage_end(grid_storage)
Deallocates the fields in the remapping fields container.
Definition: MOM_diag_mediator.F90:3581
mom_int_tide_input
Calculates energy input to the internal tides.
Definition: MOM_internal_tide_input.F90:2
mom_diabatic_driver::diabatic_driver_init
subroutine, public diabatic_driver_init(Time, G, GV, US, param_file, useALEalgorithm, diag, ADp, CDp, CS, tracer_flow_CSp, sponge_CSp, ALE_sponge_CSp)
This routine initializes the diabatic driver module.
Definition: MOM_diabatic_driver.F90:3187
mom_diabatic_driver::id_clock_set_diffusivity
integer id_clock_set_diffusivity
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:248
mom_ale_sponge
This module contains the routines used to apply sponge layers when using the ALE mode.
Definition: MOM_ALE_sponge.F90:11
mom_diabatic_driver::adiabatic_driver_init
subroutine, public adiabatic_driver_init(Time, G, param_file, diag, CS, tracer_flow_CSp)
A simplified version of diabatic_driver_init that will allow tracer column functions to be called wit...
Definition: MOM_diabatic_driver.F90:3155
mom_diabatic_driver::diagnose_frazil_tendency
subroutine diagnose_frazil_tendency(tv, h, temp_old, dt, G, GV, CS)
This routine diagnoses tendencies for temperature and heat from frazil formation. This routine is cal...
Definition: MOM_diabatic_driver.F90:3104
mom_cvmix_kpp::kpp_nonlocaltransport_temp
subroutine, public kpp_nonlocaltransport_temp(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar, C_p)
Apply KPP non-local transport of surface fluxes for temperature.
Definition: MOM_CVMix_KPP.F90:1483
mom_cvmix_kpp::kpp_nonlocaltransport_saln
subroutine, public kpp_nonlocaltransport_saln(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar)
Apply KPP non-local transport of surface fluxes for salinity. This routine is a useful prototype for ...
Definition: MOM_CVMix_KPP.F90:1543
mom_bulk_mixed_layer::bulkmixedlayer_init
subroutine, public bulkmixedlayer_init(Time, G, GV, US, param_file, diag, CS)
This subroutine initializes the MOM bulk mixed layer module.
Definition: MOM_bulk_mixed_layer.F90:3382
mom_set_diffusivity::set_diffusivity_init
subroutine, public set_diffusivity_init(Time, G, GV, US, param_file, diag, CS, int_tide_CSp, tm_CSp, halo_TS)
Definition: MOM_set_diffusivity.F90:1878
mom_ale_sponge::apply_ale_sponge
subroutine, public apply_ale_sponge(h, dt, G, GV, US, CS, Time)
This subroutine applies damping to the layers thicknesses, temp, salt and a variety of tracers for ev...
Definition: MOM_ALE_sponge.F90:756
mom_unit_scaling::unit_scale_type
Describes various unit conversion factors.
Definition: MOM_unit_scaling.F90:14
mom_entrain_diffusive::entrain_diffusive_init
subroutine, public entrain_diffusive_init(Time, G, GV, US, param_file, diag, CS)
This subroutine initializes the parameters and memory associated with the entrain_diffusive module.
Definition: MOM_entrain_diffusive.F90:2084
mom_tracer_diabatic
This module contains routines that implement physical fluxes of tracers (e.g. due to surface fluxes o...
Definition: MOM_tracer_diabatic.F90:4
mom_internal_tides::int_tide_cs
This control structure has parameters for the MOM_internal_tides module.
Definition: MOM_internal_tides.F90:38
mom_eos::calculate_tfreeze
Calculates the freezing point of sea water from T, S and P.
Definition: MOM_EOS.F90:81
mom_diabatic_driver::extract_diabatic_member
subroutine, public extract_diabatic_member(CS, opacity_CSp, optics_CSp, evap_CFL_limit, minimum_forcing_depth, KPP_CSp, energetic_PBL_CSp, diabatic_aux_CSp)
Returns pointers or values of members within the diabatic_CS type. For extensibility,...
Definition: MOM_diabatic_driver.F90:2865
mom_diabatic_driver::id_clock_remap
integer id_clock_remap
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:250
mom_diag_mediator::post_data
Make a diagnostic available for averaging or output.
Definition: MOM_diag_mediator.F90:70
mom_diabatic_driver::diabatic_driver_end
subroutine, public diabatic_driver_end(CS)
Routine to close the diabatic driver module.
Definition: MOM_diabatic_driver.F90:3758
mom_entrain_diffusive::entrainment_diffusive
subroutine, public entrainment_diffusive(h, tv, fluxes, dt, G, GV, US, CS, ea, eb, kb_out, Kd_Lay, Kd_int)
This subroutine calculates ea and eb, the rates at which a layer entrains from the layers above and b...
Definition: MOM_entrain_diffusive.F90:54
mom_diabatic_aux::differential_diffuse_t_s
subroutine, public differential_diffuse_t_s(h, tv, visc, dt, G, GV)
This subroutine applies double diffusion to T & S, assuming no diapycal mass fluxes,...
Definition: MOM_diabatic_aux.F90:223
mom_geothermal::geothermal_end
subroutine, public geothermal_end(CS)
Clean up and deallocate memory associated with the geothermal heating module.
Definition: MOM_geothermal.F90:482
mom_regularize_layers::regularize_layers_cs
This control structure holds parameters used by the MOM_regularize_layers module.
Definition: MOM_regularize_layers.F90:26
mom_sponge::p3d
A structure for creating arrays of pointers to 3D arrays.
Definition: MOM_sponge.F90:32
mom_cvmix_conv::calculate_cvmix_conv
subroutine, public calculate_cvmix_conv(h, tv, G, GV, US, CS, hbl)
Subroutine for calculating enhanced diffusivity/viscosity due to convection via CVMix.
Definition: MOM_CVMix_conv.F90:151
mom_energetic_pbl::energetic_pbl_init
subroutine, public energetic_pbl_init(Time, G, GV, US, param_file, diag, CS)
This subroutine initializes the energetic_PBL module.
Definition: MOM_energetic_PBL.F90:1941
mom_forcing_type
This module implements boundary forcing for MOM6.
Definition: MOM_forcing_type.F90:2
mom_diabatic_driver::diagnose_diabatic_diff_tendency
subroutine diagnose_diabatic_diff_tendency(tv, h, temp_old, saln_old, dt, G, GV, CS)
This routine diagnoses tendencies from application of diabatic diffusion using ALE algorithm....
Definition: MOM_diabatic_driver.F90:2916
mom_domains::to_all
integer, parameter, public to_all
A flag for passing in all directions.
Definition: MOM_domains.F90:132
mom_geothermal
Implemented geothermal heating at the ocean bottom.
Definition: MOM_geothermal.F90:2
mom_wave_interface
Interface for surface waves.
Definition: MOM_wave_interface.F90:2
mom_diabatic_aux::diagnosemldbydensitydifference
subroutine, public diagnosemldbydensitydifference(id_MLD, h, tv, densityDiff, G, GV, US, diagPtr, id_N2subML, id_MLDsq, dz_subML)
Diagnose a mixed layer depth (MLD) determined by a given density difference with the surface....
Definition: MOM_diabatic_aux.F90:717
mom_diag_mediator::diag_grid_storage
Stores all the remapping grids and the model's native space thicknesses.
Definition: MOM_diag_mediator.F90:146
mom_int_tide_input::int_tide_input_type
This type is used to exchange fields related to the internal tides.
Definition: MOM_internal_tide_input.F90:63
mom_wave_interface::wave_parameters_cs
Container for all surface wave related parameters.
Definition: MOM_wave_interface.F90:47
mom_diag_mediator::diag_update_remap_grids
subroutine, public diag_update_remap_grids(diag_cs, alt_h, alt_T, alt_S)
Build/update vertical grids for diagnostic remapping.
Definition: MOM_diag_mediator.F90:3187
mom_variables::vertvisc_type
Vertical viscosities, drag coefficients, and related fields.
Definition: MOM_variables.F90:196
mom_diabatic_driver::id_clock_kpp
integer id_clock_kpp
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:251
mom_tracer_diabatic::tracer_vertdiff
subroutine, public tracer_vertdiff(h_old, ea, eb, dt, tr, G, GV, sfc_flux, btm_flux, btm_reservoir, sink_rate, convert_flux_in)
This subroutine solves a tridiagonal equation for the final tracer concentrations after the dual-entr...
Definition: MOM_tracer_diabatic.F90:27
mom_verticalgrid::verticalgrid_type
Describes the vertical ocean grid, including unit conversion factors.
Definition: MOM_verticalGrid.F90:24
mom_cvmix_shear::cvmix_shear_is_used
logical function, public cvmix_shear_is_used(param_file)
Reads the parameters "LMD94" and "PP81" and returns state. This function allows other modules to know...
Definition: MOM_CVMix_shear.F90:303
mom_domains::do_group_pass
subroutine, public do_group_pass(group, MOM_dom, clock)
do_group_pass carries out a group halo update.
Definition: MOM_domains.F90:1090
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
mom_variables
Provides transparent structures with groups of MOM6 variables and supporting routines.
Definition: MOM_variables.F90:2
mom_variables::mom_thermovar_chksum
subroutine, public mom_thermovar_chksum(mesg, tv, G)
Diagnostic checksums on various elements of a thermo_var_ptrs type for debugging.
Definition: MOM_variables.F90:452
mom_forcing_type::mom_forcing_chksum
subroutine, public mom_forcing_chksum(mesg, fluxes, G, US, haloshift)
Write out chksums for thermodynamic fluxes.
Definition: MOM_forcing_type.F90:1012
mom_geothermal::geothermal_cs
Control structure for geothermal heating.
Definition: MOM_geothermal.F90:25
mom_diabatic_driver::diabatic_ale
subroutine diabatic_ale(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, G, GV, US, CS, Waves)
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:1229
mom_regularize_layers
Provides regularization of layers in isopycnal mode.
Definition: MOM_regularize_layers.F90:2
mom_tidal_mixing
Interface to vertical tidal mixing schemes including CVMix tidal mixing.
Definition: MOM_tidal_mixing.F90:2
mom_set_diffusivity::set_diffusivity_cs
This control structure contains parameters for MOM_set_diffusivity.
Definition: MOM_set_diffusivity.F90:56
mom_diabatic_driver::id_clock_tridiag
integer id_clock_tridiag
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:249
mom_bulk_mixed_layer::bulkmixedlayer_cs
The control structure with parameters for the MOM_bulk_mixed_layer module.
Definition: MOM_bulk_mixed_layer.F90:32
mom_kappa_shear::kappa_shear_is_used
logical function, public kappa_shear_is_used(param_file)
This function indicates to other modules whether the Jackson et al shear mixing parameterization will...
Definition: MOM_kappa_shear.F90:2109
mom_time_manager::real_to_time
type(time_type) function, public real_to_time(x, err_msg)
This is an alternate implementation of the FMS function real_to_time_type that is accurate over a lar...
Definition: MOM_time_manager.F90:47
mom_checksum_packages::mom_state_stats
subroutine, public mom_state_stats(mesg, u, v, h, Temp, Salt, G, GV, US, allowChange, permitDiminishing)
Monitor and write out statistics for the model's state variables.
Definition: MOM_checksum_packages.F90:233
mom_entrain_diffusive::entrain_diffusive_cs
The control structure holding parametes for the MOM_entrain_diffusive module.
Definition: MOM_entrain_diffusive.F90:29
mom_cpu_clock
Wraps the MPP cpu clock functions.
Definition: MOM_cpu_clock.F90:2
mom_energetic_pbl::energetic_pbl_get_mld
subroutine, public energetic_pbl_get_mld(CS, MLD, G, US, m_to_MLD_units)
Copies the ePBL active mixed layer depth into MLD.
Definition: MOM_energetic_PBL.F90:1920
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_sponge
Implements sponge regions in isopycnal mode.
Definition: MOM_sponge.F90:2
mom_error_handler::calltree_leave
subroutine, public calltree_leave(mesg)
Writes a message about leaving a subroutine if call tree reporting is active.
Definition: MOM_error_handler.F90:151
mom_bulk_mixed_layer::bulkmixedlayer
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,...
Definition: MOM_bulk_mixed_layer.F90:189
mom_variables::cont_diag_ptrs
Pointers to arrays with transports, which can later be used for derived diagnostics,...
Definition: MOM_variables.F90:181
mom_tracer_flow_control
Orchestrates the registration and calling of tracer packages.
Definition: MOM_tracer_flow_control.F90:2
mom_cvmix_ddiff
Interface to CVMix double diffusion scheme.
Definition: MOM_CVMix_ddiff.F90:2
mom_variables::accel_diag_ptrs
Pointers to arrays with accelerations, which can later be used for derived diagnostics,...
Definition: MOM_variables.F90:151
mom_diabatic_driver::diabatic
subroutine, public diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, Time_end, G, GV, US, CS, WAVES)
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:259
mom_diapyc_energy_req::diapyc_energy_req_init
subroutine, public diapyc_energy_req_init(Time, G, GV, US, param_file, diag, CS)
Initialize parameters and allocate memory associated with the diapycnal energy requirement module.
Definition: MOM_diapyc_energy_req.F90:1271
mom_energetic_pbl::energetic_pbl_cs
This control structure holds parameters for the MOM_energetic_PBL module.
Definition: MOM_energetic_PBL.F90:35
mom_opacity::optics_type
This type is used to store information about ocean optical properties.
Definition: MOM_opacity.F90:25
mom_interface_heights::find_eta
Calculates the heights of sruface or all interfaces from layer thicknesses.
Definition: MOM_interface_heights.F90:21
mom_diabatic_driver
This routine drives the diabatic/dianeutral physics for MOM.
Definition: MOM_diabatic_driver.F90:2
mom_internal_tides::internal_tides_end
subroutine, public internal_tides_end(CS)
This subroutine deallocates the memory associated with the internal tides control structure.
Definition: MOM_internal_tides.F90:2532
mom_diabatic_aux::insert_brine
subroutine, public insert_brine(h, tv, G, GV, US, fluxes, nkmb, CS, dt, id_brine_lay)
Insert salt from brine rejection into the first layer below the mixed layer which both contains mass ...
Definition: MOM_diabatic_aux.F90:386
mom_diapyc_energy_req::diapyc_energy_req_test
subroutine, public diapyc_energy_req_test(h_3d, dt, tv, G, GV, US, CS, Kd_int)
This subroutine helps test the accuracy of the diapycnal mixing energy requirement code by writing di...
Definition: MOM_diapyc_energy_req.F90:50
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_cvmix_shear
Interface to CVMix interior shear schemes.
Definition: MOM_CVMix_shear.F90:2
mom_sponge::sponge_cs
This control structure holds memory and parameters for the MOM_sponge module.
Definition: MOM_sponge.F90:41
mom_diag_mediator::disable_averaging
subroutine, public disable_averaging(diag_cs)
Call this subroutine to avoid averaging any offered fields.
Definition: MOM_diag_mediator.F90:1840
mom_wave_speed::wave_speeds
subroutine, public wave_speeds(h, tv, G, GV, US, nmodes, cn, CS, full_halos)
Calculates the wave speeds for the first few barolinic modes.
Definition: MOM_wave_speed.F90:561
mom_diapyc_energy_req::diapyc_energy_req_end
subroutine, public diapyc_energy_req_end(CS)
Clean up and deallocate memory associated with the diapycnal energy requirement module.
Definition: MOM_diapyc_energy_req.F90:1345
mom_tidal_mixing::tidal_mixing_init
logical function, public tidal_mixing_init(Time, G, GV, US, param_file, diag, CS)
Initializes internal tidal dissipation scheme for diapycnal mixing.
Definition: MOM_tidal_mixing.F90:210
mom_unit_scaling
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Definition: MOM_unit_scaling.F90:2
mom_tracer_flow_control::tracer_flow_control_cs
The control structure for orchestrating the calling of tracer packages.
Definition: MOM_tracer_flow_control.F90:75
mom_diag_mediator::enable_averages
subroutine, public enable_averages(time_int, time_end, diag_CS, T_to_s)
Enable the accumulation of time averages over the specified time interval in time units.
Definition: MOM_diag_mediator.F90:1820
mom_wave_speed
Routines for calculating baroclinic wave speeds.
Definition: MOM_wave_speed.F90:2
mom_set_diffusivity::set_diffusivity_end
subroutine, public set_diffusivity_end(CS)
Clear pointers and dealocate memory.
Definition: MOM_set_diffusivity.F90:2207
mom_forcing_type::forcing
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
Definition: MOM_forcing_type.F90:50
mom_diabatic_aux::diabatic_aux_cs
Control structure for diabatic_aux.
Definition: MOM_diabatic_aux.F90:42
mom_diabatic_driver::id_clock_pass
integer id_clock_pass
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:249
mom_diag_mediator::diag_copy_diag_to_storage
subroutine, public diag_copy_diag_to_storage(grid_storage, h_state, diag)
Copy from the main diagnostic arrays to the grid storage as well as the native thicknesses.
Definition: MOM_diag_mediator.F90:3511
mom_sponge::apply_sponge
subroutine, public apply_sponge(h, dt, G, GV, US, ea, eb, CS, Rcv_ml)
This subroutine applies damping to the layers thicknesses, mixed layer buoyancy, and a variety of tra...
Definition: MOM_sponge.F90:324
mom_debugging
Provides checksumming functions for debugging.
Definition: MOM_debugging.F90:7
mom_cvmix_kpp::kpp_init
logical function, public kpp_init(paramFile, G, GV, US, diag, Time, CS, passive, Waves)
Initialize the CVMix KPP module and set up diagnostics Returns True if KPP is to be used,...
Definition: MOM_CVMix_KPP.F90:181
mom_diapyc_energy_req::diapyc_energy_req_cs
This control structure holds parameters for the MOM_diapyc_energy_req module.
Definition: MOM_diapyc_energy_req.F90:27
mom_error_handler::calltree_showquery
logical function, public calltree_showquery()
Returns True, if the verbosity>=6 indicating to show the call tree.
Definition: MOM_error_handler.F90:123
mom_tidal_mixing::tidal_mixing_end
subroutine, public tidal_mixing_end(CS)
Clear pointers and deallocate memory.
Definition: MOM_tidal_mixing.F90:1675
mom_int_tide_input::int_tide_input_end
subroutine, public int_tide_input_end(CS)
Deallocates any memory related to the internal tide input module.
Definition: MOM_internal_tide_input.F90:424
mom_eos::calculate_specific_vol_derivs
subroutine, public calculate_specific_vol_derivs(T, S, pressure, dSV_dT, dSV_dS, start, npts, EOS, scale)
Calls the appropriate subroutine to calculate specific volume derivatives for an array.
Definition: MOM_EOS.F90:546
mom_error_handler::mom_error
subroutine, public mom_error(level, message, all_print)
This provides a convenient interface for writing an mpp_error message with run-time filter based on a...
Definition: MOM_error_handler.F90:72
mom_diabatic_driver::id_clock_mixedlayer
integer id_clock_mixedlayer
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:248
mom_error_handler::calltree_waypoint
subroutine, public calltree_waypoint(mesg, n)
Writes a message about reaching a milestone if call tree reporting is active.
Definition: MOM_error_handler.F90:161
mom_cvmix_conv::cvmix_conv_end
subroutine, public cvmix_conv_end(CS)
Clear pointers and dealocate memory.
Definition: MOM_CVMix_conv.F90:272
mom_internal_tides
Subroutines that use the ray-tracing equations to propagate the internal tide energy density.
Definition: MOM_internal_tides.F90:4
mom_energetic_pbl::energetic_pbl
subroutine, public energetic_pbl(h_3d, u_3d, v_3d, tv, fluxes, dt, Kd_int, G, GV, US, CS, dSV_dT, dSV_dS, TKE_forced, buoy_flux, dt_diag, last_call, dT_expected, dS_expected, Waves)
This subroutine determines the diffusivities from the integrated energetics mixed layer model....
Definition: MOM_energetic_PBL.F90:243
mom_diabatic_driver::adiabatic
subroutine, public adiabatic(h, tv, fluxes, dt, G, GV, US, CS)
Routine called for adiabatic physics.
Definition: MOM_diabatic_driver.F90:2892
mom_diabatic_driver::id_clock_tracers
integer id_clock_tracers
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:249
mom_diabatic_driver::id_clock_differential_diff
integer id_clock_differential_diff
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:250
mom_opacity::opacity_end
subroutine, public opacity_end(CS, optics)
Definition: MOM_opacity.F90:1121
mom_forcing_type::calculatebuoyancyflux2d
subroutine, public calculatebuoyancyflux2d(G, GV, US, fluxes, optics, h, Temp, Salt, tv, buoyancyFlux, netHeatMinusSW, netSalt, skip_diags)
Calculates surface buoyancy flux by adding up the heat, FW and salt fluxes, for 2d arrays....
Definition: MOM_forcing_type.F90:976
mom_diabatic_driver::diagnose_boundary_forcing_tendency
subroutine diagnose_boundary_forcing_tendency(tv, h, temp_old, saln_old, h_old, dt, G, GV, CS)
This routine diagnoses tendencies from application of boundary fluxes. These impacts are generally 3d...
Definition: MOM_diabatic_driver.F90:3008
mom_opacity::optics_nbands
integer function, public optics_nbands(optics)
Return the number of bands of penetrating shortwave radiation.
Definition: MOM_opacity.F90:495
mom_cvmix_conv::cvmix_conv_cs
Control structure including parameters for CVMix convection.
Definition: MOM_CVMix_conv.F90:27
mom_internal_tides::propagate_int_tide
subroutine, public propagate_int_tide(h, tv, cn, TKE_itidal_input, vel_btTide, Nb, dt, G, GV, US, CS)
Calls subroutines in this file that are needed to refract, propagate, and dissipate energy density of...
Definition: MOM_internal_tides.F90:154
mom_diabatic_driver::id_clock_entrain
integer id_clock_entrain
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:248
mom_tidal_mixing::tidal_mixing_cs
Control structure with parameters for the tidal mixing module.
Definition: MOM_tidal_mixing.F90:71
mom_cvmix_kpp
Provides the K-Profile Parameterization (KPP) of Large et al., 1994, via CVMix.
Definition: MOM_CVMix_KPP.F90:2
mom_domains::create_group_pass
Set up a group of halo updates.
Definition: MOM_domains.F90:79
mom_opacity
Routines used to calculate the opacity of the ocean.
Definition: MOM_opacity.F90:2
mom_entrain_diffusive::entrain_diffusive_end
subroutine, public entrain_diffusive_end(CS)
This subroutine cleans up and deallocates any memory associated with the entrain_diffusive module.
Definition: MOM_entrain_diffusive.F90:2152
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_kappa_shear
Shear-dependent mixing following Jackson et al. 2008.
Definition: MOM_kappa_shear.F90:2
mom_interface_heights
Functions for calculating interface heights, including free surface height.
Definition: MOM_interface_heights.F90:2
mom_diabatic_aux
Provides functions for some diabatic processes such as fraxil, brine rejection, tendency due to surfa...
Definition: MOM_diabatic_aux.F90:3
mom_error_handler::calltree_enter
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.
Definition: MOM_error_handler.F90:130
mom_cvmix_kpp::kpp_cs
Control structure for containing KPP parameters/data.
Definition: MOM_CVMix_KPP.F90:71
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
mom_regularize_layers::regularize_layers_init
subroutine, public regularize_layers_init(Time, G, GV, param_file, diag, CS)
Initializes the regularize_layers control structure.
Definition: MOM_regularize_layers.F90:878
mom_diabatic_aux::applyboundaryfluxesinout
subroutine, public applyboundaryfluxesinout(CS, G, GV, US, dt, fluxes, optics, nsw, h, tv, aggregate_FW_forcing, evap_CFL_limit, minimum_forcing_depth, cTKE, dSV_dT, dSV_dS, SkinBuoyFlux)
Update the thickness, temperature, and salinity due to thermodynamic boundary forcing (contained in f...
Definition: MOM_diabatic_aux.F90:853
mom_internal_tides::internal_tides_init
subroutine, public internal_tides_init(Time, G, GV, US, param_file, diag, CS)
This subroutine initializes the internal tides module.
Definition: MOM_internal_tides.F90:2100
mom_diabatic_driver::diabatic_cs
Control structure for this module.
Definition: MOM_diabatic_driver.F90:92
mom_diag_mediator::diag_copy_storage_to_diag
subroutine, public diag_copy_storage_to_diag(diag, grid_storage)
Copy from the stored diagnostic arrays to the main diagnostic grids.
Definition: MOM_diag_mediator.F90:3530
mom_diag_mediator::diag_grid_storage_init
subroutine, public diag_grid_storage_init(grid_storage, G, diag)
Allocates fields necessary to store diagnostic remapping fields.
Definition: MOM_diag_mediator.F90:3486
mom_diag_mediator::diag_ctrl
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Definition: MOM_diag_mediator.F90:239
mom_diabatic_aux::find_uv_at_h
subroutine, public find_uv_at_h(u, v, h, u_h, v_h, G, GV, US, ea, eb)
This subroutine calculates u_h and v_h (velocities at thickness points), optionally using the entrain...
Definition: MOM_diabatic_aux.F90:557
mom_diabatic_driver::id_clock_geothermal
integer id_clock_geothermal
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
Definition: MOM_diabatic_driver.F90:250
mom_diapyc_energy_req
Calculates the energy requirements of mixing.
Definition: MOM_diapyc_energy_req.F90:2
mom_cvmix_conv
Interface to CVMix convection scheme.
Definition: MOM_CVMix_conv.F90:2
mom_eos::calculate_density
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:60
mom_file_parser::read_param
An overloaded interface to read various types of parameters.
Definition: MOM_file_parser.F90:90