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