MOM6
MOM_diabatic_driver.F90
Go to the documentation of this file.
1 !> This routine drives the diabatic/dianeutral physics for MOM
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 
8 use mom_debugging, only : hchksum
10 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
11 use mom_cpu_clock, only : clock_module_driver, clock_module, clock_routine
16 use mom_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
24 use mom_domains, only : pass_var, to_west, to_south, to_all, omit_corners
25 use mom_domains, only : create_group_pass, do_group_pass, group_pass_type
33 use mom_error_handler, only : mom_error, fatal, warning, calltree_showquery,mom_mesg
39 use mom_grid, only : ocean_grid_type
40 use mom_io, only : vardesc, var_desc
56 use mom_time_manager, only : operator(<=), time_type ! for testing itides (BDM)
62 use mom_wave_speed, only : wave_speeds
63 use time_manager_mod, only : increment_time ! for testing itides (BDM)
64 
65 
66 implicit none ; private
67 
68 #include <MOM_memory.h>
69 
70 public diabatic
74 public adiabatic
76 
77 !> Control structure for this module
78 type, public:: diabatic_cs ; private
79  logical :: bulkmixedlayer !< If true, a refined bulk mixed layer is used with
80  !! nkml sublayers (and additional buffer layers).
81  logical :: use_energetic_pbl !< If true, use the implicit energetics planetary
82  !! boundary layer scheme to determine the diffusivity
83  !! in the surface boundary layer.
84  logical :: use_kappa_shear !< If true, use the kappa_shear module to find the
85  !! shear-driven diapycnal diffusivity.
86  logical :: use_cvmix_shear !< If true, use the CVMix module to find the
87  !! shear-driven diapycnal diffusivity.
88  logical :: use_sponge !< If true, sponges may be applied anywhere in the
89  !! domain. The exact location and properties of
90  !! those sponges are set by calls to
91  !! initialize_sponge and set_up_sponge_field.
92  logical :: use_geothermal !< If true, apply geothermal heating.
93  logical :: use_int_tides !< If true, use the code that advances a separate set
94  !! of equations for the internal tide energy density.
95  logical :: epbl_is_additive !< If true, the diffusivity from ePBL is added to all
96  !! other diffusivities. Otherwise, the larger of kappa-
97  !! shear and ePBL diffusivities are used.
98  integer :: nmode = 1 !< Number of baroclinic modes to consider
99  logical :: int_tide_source_test !< If true, apply an arbitrary generation site
100  !! for internal tide testing (BDM)
101  real :: int_tide_source_x !< X Location of generation site
102  !! for internal tide for testing (BDM)
103  real :: int_tide_source_y !< Y Location of generation site
104  !! for internal tide for testing (BDM)
105  integer :: tlen_days !< Time interval from start for adding wave source
106  !! for testing internal tides (BDM)
107  logical :: uniform_cg !< If true, set cg = cg_test everywhere
108  !! for testing internal tides (BDM)
109  real :: cg_test !< Uniform group velocity of internal tide
110  !! for testing internal tides (BDM)
111  type(time_type) :: time_max_source !< For use in testing internal tides (BDM)
112  type(time_type) :: time_end !< For use in testing internal tides (BDM)
113  logical :: usealealgorithm !< If true, use the ALE algorithm rather than layered
114  !! isopycnal/stacked shallow water mode. This logical
115  !! passed by argument to diabatic_driver_init.
116  logical :: aggregate_fw_forcing !< Determines whether net incoming/outgoing surface
117  !! FW fluxes are applied separately or combined before
118  !! being applied.
119  real :: ml_mix_first !< The nondimensional fraction of the mixed layer
120  !! algorithm that is applied before diffusive mixing.
121  !! The default is 0, while 0.5 gives Strang splitting
122  !! and 1 is a sensible value too. Note that if there
123  !! are convective instabilities in the initial state,
124  !! the first call may do much more than the second.
125  integer :: nkbl !< The number of buffer layers (if bulk_mixed_layer)
126  logical :: massless_match_targets !< If true (the default), keep the T & S
127  !! consistent with the target values.
128  logical :: mix_boundary_tracers !< If true, mix the passive tracers in massless
129  !! layers at the bottom into the interior as though
130  !! a diffusivity of Kd_min_tr (see below) were
131  !! operating.
132  real :: kd_bbl_tr !< A bottom boundary layer tracer diffusivity that
133  !! will allow for explicitly specified bottom fluxes
134  !! in m2 s-1. The entrainment at the bottom is at
135  !! least sqrt(Kd_BBL_tr*dt) over the same distance.
136  real :: kd_min_tr !< A minimal diffusivity that should always be
137  !! applied to tracers, especially in massless layers
138  !! near the bottom, in m2 s-1.
139  real :: minimum_forcing_depth = 0.001 !< The smallest depth over which heat and freshwater
140  !! fluxes is applied, in m.
141  real :: evap_cfl_limit = 0.8 !< The largest fraction of a layer that can be
142  !! evaporated in one time-step (non-dim).
143 
144  logical :: usekpp !< use CVmix/KPP diffusivities and non-local transport
145  logical :: salt_reject_below_ml !< If true, add salt below mixed layer (layer mode only)
146  logical :: kppispassive !< If true, KPP is in passive mode, not changing answers.
147  logical :: useconvection !< If true, calculate large diffusivities when column
148  !! is statically unstable.
149  logical :: debug !< If true, write verbose checksums for debugging purposes.
150  logical :: debugconservation !< If true, monitor conservation and extrema.
151  logical :: tracer_tridiag !< If true, use tracer_vertdiff instead of tridiagTS for
152  !< vertical diffusion of T and S
153  logical :: debug_energy_req ! If true, test the mixing energy requirement code.
154  type(diag_ctrl), pointer :: diag !< structure used to regulate timing of diagnostic output
155  real :: mlddensitydifference !< Density difference used to determine MLD_user
156  integer :: nsw !< SW_NBANDS
157 
158  integer :: id_cg1 = -1 ! diag handle for mode-1 speed (BDM)
159  integer, allocatable, dimension(:) :: id_cn ! diag handle for all mode speeds (BDM)
160  integer :: id_dudt_dia = -1, id_dvdt_dia = -1, id_wd = -1
161  integer :: id_ea = -1, id_eb = -1, id_kd_z = -1
162  integer :: id_kd_heat = -1, id_kd_salt = -1, id_kd_interface = -1, id_kd_epbl = -1
163  integer :: id_tdif_z = -1, id_tadv_z = -1, id_sdif_z = -1, id_sadv_z = -1
164  integer :: id_tdif = -1, id_tadv = -1, id_sdif = -1, id_sadv = -1
165  integer :: id_mld_003 = -1, id_mld_0125 = -1, id_mld_user = -1, id_mlotstsq = -1
166  integer :: id_submln2 = -1, id_brine_lay = -1
167 
168  integer :: id_diabatic_diff_temp_tend = -1
169  integer :: id_diabatic_diff_saln_tend = -1
170  integer :: id_diabatic_diff_heat_tend = -1
171  integer :: id_diabatic_diff_salt_tend = -1
172  integer :: id_diabatic_diff_heat_tend_2d = -1
173  integer :: id_diabatic_diff_salt_tend_2d = -1
174  logical :: diabatic_diff_tendency_diag = .false.
175 
176  integer :: id_boundary_forcing_temp_tend = -1
177  integer :: id_boundary_forcing_saln_tend = -1
178  integer :: id_boundary_forcing_heat_tend = -1
179  integer :: id_boundary_forcing_salt_tend = -1
180  integer :: id_boundary_forcing_heat_tend_2d = -1
181  integer :: id_boundary_forcing_salt_tend_2d = -1
182  logical :: boundary_forcing_tendency_diag = .false.
183 
184  integer :: id_frazil_temp_tend = -1
185  integer :: id_frazil_heat_tend = -1
186  integer :: id_frazil_heat_tend_2d = -1
187  logical :: frazil_tendency_diag = .false.
188  real, allocatable, dimension(:,:,:) :: frazil_heat_diag !< diagnose 3d heat tendency from frazil
189  real, allocatable, dimension(:,:,:) :: frazil_temp_diag !< diagnose 3d temp tendency from frazil
190 
191  real :: ppt2mks = 0.001
192 
193  type(diabatic_aux_cs), pointer :: diabatic_aux_csp => null()
194  type(entrain_diffusive_cs), pointer :: entrain_diffusive_csp => null()
195  type(bulkmixedlayer_cs), pointer :: bulkmixedlayer_csp => null()
196  type(energetic_pbl_cs), pointer :: energetic_pbl_csp => null()
197  type(regularize_layers_cs), pointer :: regularize_layers_csp => null()
198  type(geothermal_cs), pointer :: geothermal_csp => null()
199  type(int_tide_cs), pointer :: int_tide_csp => null()
200  type(int_tide_input_cs), pointer :: int_tide_input_csp => null()
201  type(int_tide_input_type), pointer :: int_tide_input => null()
202  type(opacity_cs), pointer :: opacity_csp => null()
203  type(set_diffusivity_cs), pointer :: set_diff_csp => null()
204  type(sponge_cs), pointer :: sponge_csp => null()
205  type(ale_sponge_cs), pointer :: ale_sponge_csp => null()
206  type(tracer_flow_control_cs), pointer :: tracer_flow_csp => null()
207  type(optics_type), pointer :: optics => null()
208  type(diag_to_z_cs), pointer :: diag_to_z_csp => null()
209  type(kpp_cs), pointer :: kpp_csp => null()
210  type(diffconvection_cs), pointer :: conv_csp => null()
211  type(diapyc_energy_req_cs), pointer :: diapyc_en_rec_csp => null()
212 
213  type(group_pass_type) :: pass_hold_eb_ea !< For group halo pass
214 
215  ! Data arrays for communicating between components
216  real, allocatable, dimension(:,:,:) :: kpp_nltheat !< KPP non-local transport for heat (m/s)
217  real, allocatable, dimension(:,:,:) :: kpp_nltscalar !< KPP non-local transport for scalars (m/s)
218  real, allocatable, dimension(:,:,:) :: kpp_buoy_flux !< KPP forcing buoyancy flux (m^2/s^3)
219  real, allocatable, dimension(:,:) :: kpp_temp_flux !< KPP effective temperature flux (K m/s)
220  real, allocatable, dimension(:,:) :: kpp_salt_flux !< KPP effective salt flux (ppt m/s)
221 
222 end type diabatic_cs
223 
224 ! clock ids
228 integer :: id_clock_kpp
229 
230 contains
231 
232 !> This subroutine imposes the diapycnal mass fluxes and the
233 !! accompanying diapycnal advection of momentum and tracers.
234 subroutine diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, G, GV, CS)
235  type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
236  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
237  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: u !< zonal velocity (m/s)
238  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: v !< meridional velocity (m/s)
239  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< thickness (m for Bouss / kg/m2 for non-Bouss)
240  type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields; unused have NULL ptrs
241  real, dimension(:,:), pointer :: Hml !< active mixed layer depth
242  type(forcing), intent(inout) :: fluxes !< points to forcing fields; unused fields have NULL ptrs
243  type(vertvisc_type), intent(inout) :: visc !< vertical viscosities, BBL properies, and related
244  type(accel_diag_ptrs), intent(inout) :: ADp !< points to accelerations in momentum equations,
245  !! to enable the later derived diagn, like energy budgets
246  type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
247  real, intent(in) :: dt !< time increment (seconds)
248  type(diabatic_cs), pointer :: CS !< module control structure
249 
250  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: &
251  ea, & ! amount of fluid entrained from the layer above within
252  ! one time step (m for Bouss, kg/m^2 for non-Bouss)
253  eb, & ! amount of fluid entrained from the layer below within
254  ! one time step (m for Bouss, kg/m^2 for non-Bouss)
255  kd, & ! diapycnal diffusivity of layers (m^2/sec)
256  h_orig, & ! initial layer thicknesses (m for Bouss, kg/m^2 for non-Bouss)
257  h_prebound, & ! initial layer thicknesses (m for Bouss, kg/m^2 for non-Bouss)
258  hold, & ! layer thickness before diapycnal entrainment, and later
259  ! the initial layer thicknesses (if a mixed layer is used),
260  ! (m for Bouss, kg/m^2 for non-Bouss)
261  dsv_dt, & ! The partial derivatives of specific volume with temperature
262  dsv_ds, & ! and salinity in m^3/(kg K) and m^3/(kg ppt).
263  ctke, & ! convective TKE requirements for each layer in J/m^2.
264  u_h, & ! zonal and meridional velocities at thickness points after
265  v_h ! entrainment (m/s)
266 
267  real, dimension(SZI_(G),SZJ_(G),CS%nMode) :: &
268  cn ! baroclinic gravity wave speeds (formerly cg1 - BDM)
269 
270  real, dimension(SZI_(G),SZJ_(G)) :: &
271  Rcv_ml, & ! coordinate density of mixed layer, used for applying sponges
272  SkinBuoyFlux! 2d surface buoyancy flux (m2/s3), used by ePBL
273  real, dimension(SZI_(G),SZJ_(G),G%ke) :: h_diag ! diagnostic array for thickness
274  real, dimension(SZI_(G),SZJ_(G),G%ke) :: temp_diag ! diagnostic array for temp
275  real, dimension(SZI_(G),SZJ_(G),G%ke) :: saln_diag ! diagnostic array for salinity
276  real, dimension(SZI_(G),SZJ_(G)) :: tendency_2d ! depth integrated content tendency for diagn
277  real, dimension(SZI_(G),SZJ_(G)) :: TKE_itidal_input_test ! override of energy input for testing (BDM)
278 
279  real :: net_ent ! The net of ea-eb at an interface.
280 
281  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), target :: &
282  ! These are targets so that the space can be shared with eaml & ebml.
283  eatr, & ! The equivalent of ea and eb for tracers, which differ from ea and
284  ebtr ! eb in that they tend to homogenize tracers in massless layers
285  ! near the boundaries (m for Bouss and kg/m^2 for non-Bouss)
286 
287  real, dimension(SZI_(G),SZJ_(G),SZK_(G)+1), target :: &
288  Kd_int, & ! diapycnal diffusivity of interfaces (m^2/s)
289  Kd_heat, & ! diapycnal diffusivity of heat (m^2/s)
290  Kd_salt, & ! diapycnal diffusivity of salt and passive tracers (m^2/s)
291  Kd_ePBL, & ! test array of diapycnal diffusivities at interfaces (m^2/s)
292  Tdif_flx, & ! diffusive diapycnal heat flux across interfaces (K m/s)
293  Tadv_flx, & ! advective diapycnal heat flux across interfaces (K m/s)
294  Sdif_flx, & ! diffusive diapycnal salt flux across interfaces (ppt m/s)
295  Sadv_flx ! advective diapycnal salt flux across interfaces (ppt m/s)
296 
297  ! The following 5 variables are only used with a bulk mixed layer.
298  real, pointer, dimension(:,:,:) :: &
299  eaml, & ! The equivalent of ea and eb due to mixed layer processes,
300  ebml ! (m for Bouss and kg/m^2 for non-Bouss). These will be
301  ! pointers to eatr and ebtr so as to reuse the memory as
302  ! the arrays are not needed at the same time.
303 
304  integer :: kb(szi_(g),szj_(g)) ! index of the lightest layer denser
305  ! than the buffer laye (nondimensional)
306 
307  real :: p_ref_cv(szi_(g)) ! Reference pressure for the potential
308  ! density which defines the coordinate
309  ! variable, set to P_Ref, in Pa.
310 
311  logical :: in_boundary(szi_(g)) ! True if there are no massive layers below,
312  ! where massive is defined as sufficiently thick that
313  ! the no-flux boundary conditions have not restricted
314  ! the entrainment - usually sqrt(Kd*dt).
315 
316  real :: b_denom_1 ! The first term in the denominator of b1
317  ! (m for Bouss, kg/m^2 for non-Bouss)
318  real :: h_neglect ! A thickness that is so small it is usually lost
319  ! in roundoff and can be neglected
320  ! (m for Bouss and kg/m^2 for non-Bouss)
321  real :: h_neglect2 ! h_neglect^2 (m^2 for Bouss, kg^2/m^4 for non-Bouss)
322  real :: add_ent ! Entrainment that needs to be added when mixing tracers
323  ! (m for Bouss and kg/m^2 for non-Bouss)
324  real :: eaval ! eaval is 2*ea at velocity grid points (m for Bouss, kg/m^2 for non-Bouss)
325  real :: hval ! hval is 2*h at velocity grid points (m for Bouss, kg/m^2 for non-Bouss)
326  real :: h_tr ! h_tr is h at tracer points with a tiny thickness
327  ! added to ensure positive definiteness (m for Bouss, kg/m^2 for non-Bouss)
328  real :: Tr_ea_BBL ! The diffusive tracer thickness in the BBL that is
329  ! coupled to the bottom within a timestep (m)
330 
331  real :: htot(szib_(g)) ! The summed thickness from the bottom, in m.
332  real :: b1(szib_(g)), d1(szib_(g)) ! b1, c1, and d1 are variables used by the
333  real :: c1(szib_(g),szk_(g)) ! tridiagonal solver.
334 
335  real :: Ent_int ! The diffusive entrainment rate at an interface
336  ! (H units = m for Bouss, kg/m^2 for non-Bouss).
337  real :: dt_mix ! amount of time over which to apply mixing (seconds)
338  real :: Idt ! inverse time step (1/s)
339 
340  type(p3d) :: z_ptrs(7) ! pointers to diagnostics to be interpolated to depth
341  integer :: num_z_diags ! number of diagnostics to be interpolated to depth
342  integer :: z_ids(7) ! id numbers of diagnostics to be interpolated to depth
343  logical :: showCallTree ! If true, show the call tree
344  integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb, m
345 
346  integer :: ig, jg ! global indices for testing testing itide point source (BDM)
347  logical :: avg_enabled ! for testing internal tides (BDM)
348  real :: Kd_add_here ! An added diffusivity in m2/s
349 
350  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
351  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
352  nkmb = gv%nk_rho_varies
353  h_neglect = gv%H_subroundoff ; h_neglect2 = h_neglect*h_neglect
354  kd_heat(:,:,:) = 0.0 ; kd_salt(:,:,:) = 0.0
355 
356 
357  if (nz == 1) return
358  showcalltree = calltree_showquery()
359  if (showcalltree) call calltree_enter("diabatic(), MOM_diabatic_driver.F90")
360 
361  ! set equivalence between the same bits of memory for these arrays
362  eaml => eatr ; ebml => ebtr
363 
364  ! inverse time step
365  idt = 1.0 / dt
366 
367  if (.not. associated(cs)) call mom_error(fatal, "MOM_diabatic_driver: "// &
368  "Module must be initialized before it is used.")
369 
370  if (cs%debug) then
371  call mom_state_chksum("Start of diabatic ", u, v, h, g, gv, haloshift=0)
372  call mom_forcing_chksum("Start of diabatic", fluxes, g, haloshift=0)
373  endif
374  if (cs%debugConservation) call mom_state_stats('Start of diabatic', u, v, h, tv%T, tv%S, g)
375 
376  if (cs%debug_energy_req) &
377  call diapyc_energy_req_test(h, dt, tv, g, gv, cs%diapyc_en_rec_CSp)
378 
379 
380  call cpu_clock_begin(id_clock_set_diffusivity)
381  call set_bbl_tke(u, v, h, fluxes, visc, g, gv, cs%set_diff_CSp)
382  call cpu_clock_end(id_clock_set_diffusivity)
383 
384  ! Frazil formation keeps the temperature above the freezing point.
385  ! make_frazil is deliberately called at both the beginning and at
386  ! the end of the diabatic processes.
387  if (ASSOCIATED(tv%T) .AND. ASSOCIATED(tv%frazil)) then
388 
389  if(cs%frazil_tendency_diag) then
390  do k=1,nz ; do j=js,je ; do i=is,ie
391  temp_diag(i,j,k) = tv%T(i,j,k)
392  enddo ; enddo ; enddo
393  endif
394 
395  if (ASSOCIATED(fluxes%p_surf_full)) then
396  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp, fluxes%p_surf_full)
397  else
398  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp)
399  endif
400  if (showcalltree) call calltree_waypoint("done with 1st make_frazil (diabatic)")
401 
402  if (cs%frazil_tendency_diag) then
403  call diagnose_frazil_tendency(tv, h, temp_diag, dt, g, gv, cs, 1)
404  endif
405 
406  endif
407 
408  if (cs%debugConservation) call mom_state_stats('1st make_frazil', u, v, h, tv%T, tv%S, g)
409 
410  if ((cs%ML_mix_first > 0.0) .or. cs%use_geothermal) then
411 !$OMP parallel do default(none) shared(is,ie,js,je,nz,h_orig,h,eaml,ebml)
412  do k=1,nz ; do j=js,je ; do i=is,ie
413  h_orig(i,j,k) = h(i,j,k) ; eaml(i,j,k) = 0.0 ; ebml(i,j,k) = 0.0
414  enddo ; enddo ; enddo
415  endif
416 
417  if (cs%use_geothermal) then
418  call cpu_clock_begin(id_clock_geothermal)
419  call geothermal(h, tv, dt, eaml, ebml, g, gv, cs%geothermal_CSp)
420  call cpu_clock_end(id_clock_geothermal)
421  if (showcalltree) call calltree_waypoint("geothermal (diabatic)")
422  if (cs%debugConservation) call mom_state_stats('geothermal', u, v, h, tv%T, tv%S, g)
423  endif
424 
425 
426  ! Whenever thickness changes let the diag manager know, target grids
427  ! for vertical remapping may need to be regenerated.
428  call diag_update_remap_grids(cs%diag)
429 
430  ! Set_opacity estimates the optical properties of the water column.
431  ! It will need to be modified later to include information about the
432  ! biological properties and layer thicknesses.
433  if (associated(cs%optics)) &
434  call set_opacity(cs%optics, fluxes, g, gv, cs%opacity_CSp)
435 
436  if (cs%bulkmixedlayer) then
437  if (cs%debug) then
438  call mom_forcing_chksum("Before mixedlayer", fluxes, g, haloshift=0)
439  endif
440 
441  if (cs%ML_mix_first > 0.0) then
442 ! This subroutine
443 ! (1) Cools the mixed layer.
444 ! (2) Performs convective adjustment by mixed layer entrainment.
445 ! (3) Heats the mixed layer and causes it to detrain to
446 ! Monin-Obukhov depth or minimum mixed layer depth.
447 ! (4) Uses any remaining TKE to drive mixed layer entrainment.
448 ! (5) Possibly splits buffer layer into two isopycnal layers (when using isopycnal coordinate)
449  call find_uv_at_h(u, v, h, u_h, v_h, g, gv)
450 
451  call cpu_clock_begin(id_clock_mixedlayer)
452  if (cs%ML_mix_first < 1.0) then
453  ! Changes: h, tv%T, tv%S, eaml and ebml (G is also inout???)
454  call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt*cs%ML_mix_first, &
455  eaml,ebml, g, gv, cs%bulkmixedlayer_CSp, cs%optics, &
456  hml, cs%aggregate_FW_forcing, dt, last_call=.false.)
457  if (cs%salt_reject_below_ML) &
458  call insert_brine(h, tv, g, gv, fluxes, nkmb, cs%diabatic_aux_CSp, &
459  dt*cs%ML_mix_first, cs%id_brine_lay)
460  else
461  ! Changes: h, tv%T, tv%S, eaml and ebml (G is also inout???)
462  call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt, eaml, ebml, &
463  g, gv, cs%bulkmixedlayer_CSp, cs%optics, &
464  hml, cs%aggregate_FW_forcing, dt, last_call=.true.)
465  endif
466 
467  ! Keep salinity from falling below a small but positive threshold.
468  ! This constraint is needed for SIS1 ice model, which can extract
469  ! more salt than is present in the ocean. SIS2 does not suffer
470  ! from this limitation, in which case we can let salinity=0 and still
471  ! have salt conserved with SIS2 ice. So for SIS2, we can run with
472  ! BOUND_SALINITY=False in MOM.F90.
473  if (ASSOCIATED(tv%S) .and. ASSOCIATED(tv%salt_deficit)) &
474  call adjust_salt(h, tv, g, gv, cs%diabatic_aux_CSp)
475  call cpu_clock_end(id_clock_mixedlayer)
476  if (cs%debug) then
477  call mom_state_chksum("After mixedlayer ", u, v, h, g, gv, haloshift=0)
478  call mom_forcing_chksum("After mixedlayer", fluxes, g, haloshift=0)
479  endif
480  if (showcalltree) call calltree_waypoint("done with 1st bulkmixedlayer (diabatic)")
481  if (cs%debugConservation) call mom_state_stats('1st bulkmixedlayer', u, v, h, tv%T, tv%S, g)
482  endif
483  endif
484 
485  if (cs%debug) then
486  call mom_state_chksum("before find_uv_at_h", u, v, h, g, gv, haloshift=0)
487  endif
488  if (cs%use_kappa_shear .or. cs%use_CVMix_shear) then
489  if ((cs%ML_mix_first > 0.0) .or. cs%use_geothermal) then
490  call find_uv_at_h(u, v, h_orig, u_h, v_h, g, gv, eaml, ebml)
491  if (cs%debug) then
492  call hchksum(eaml, "after find_uv_at_h eaml",g%HI, scale=gv%H_to_m)
493  call hchksum(ebml, "after find_uv_at_h ebml",g%HI, scale=gv%H_to_m)
494  endif
495  else
496  call find_uv_at_h(u, v, h, u_h, v_h, g, gv)
497  endif
498  if (showcalltree) call calltree_waypoint("done with find_uv_at_h (diabatic)")
499  endif
500 
501  if (cs%use_int_tides) then
502  ! This block provides an interface for the unresolved low-mode internal
503  ! tide module (BDM).
504 
505  ! PROVIDE ENERGY DISTRIBUTION (calculate time-varying energy source)
506  call set_int_tide_input(u, v, h, tv, fluxes, cs%int_tide_input, dt, g, gv, &
507  cs%int_tide_input_CSp)
508  ! CALCULATE MODAL VELOCITIES
509  cn(:,:,:) = 0.0
510  if (cs%uniform_cg) then
511  ! SET TO CONSTANT VALUE TO TEST PROPAGATE CODE
512  do m=1,cs%nMode ; cn(:,:,m) = cs%cg_test ; enddo
513  else
514  call wave_speeds(h, tv, g, gv, cs%nMode, cn, full_halos=.true.)
515  ! uncomment the lines below for a hard-coded cn that changes linearly with latitude
516  !do j=G%jsd,G%jed ; do i=G%isd,G%ied
517  ! cn(i,j,:) = ((7.-1.)/14000000.)*G%geoLatBu(i,j) + (1.-((7.-1.)/14000000.)*-7000000.)
518  !enddo ; enddo
519  endif
520 
521  if (cs%int_tide_source_test) then
522  ! BUILD 2D ARRAY WITH POINT SOURCE FOR TESTING
523  ! This block of code should be moved into set_int_tide_input. -RWH
524  tke_itidal_input_test(:,:) = 0.0
525  avg_enabled = query_averaging_enabled(cs%diag,time_end=cs%time_end)
526  if (cs%time_end <= cs%time_max_source) then
527  do j=g%jsc,g%jec ; do i=g%isc,g%iec
528  !INPUT ARBITRARY ENERGY POINT SOURCE
529  if ((g%idg_offset + i == cs%int_tide_source_x) .and. &
530  (g%jdg_offset + j == cs%int_tide_source_y)) then
531  tke_itidal_input_test(i,j) = 1.0
532  endif
533  enddo ; enddo
534  endif
535  ! CALL ROUTINE USING PRESCRIBED KE FOR TESTING
536  call propagate_int_tide(h, tv, cn, tke_itidal_input_test, &
537  cs%int_tide_input%tideamp, cs%int_tide_input%Nb, dt, g, gv, cs%int_tide_CSp)
538  else
539  ! CALL ROUTINE USING CALCULATED KE INPUT
540  call propagate_int_tide(h, tv, cn, cs%int_tide_input%TKE_itidal_input, &
541  cs%int_tide_input%tideamp, cs%int_tide_input%Nb, dt, g, gv, cs%int_tide_CSp)
542  endif
543  if (showcalltree) call calltree_waypoint("done with propagate_int_tide (diabatic)")
544  endif
545 
546  call cpu_clock_begin(id_clock_set_diffusivity)
547  ! Sets: Kd, Kd_int, visc%Kd_extra_T, visc%Kd_extra_S
548  ! Also changes: visc%Kd_turb, visc%TKE_turb (not clear that TKE_turb is used as input ????)
549  ! And sets visc%Kv_turb
550  call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, cs%optics, visc, dt, g, gv, cs%set_diff_CSp, kd, kd_int)
551  call cpu_clock_end(id_clock_set_diffusivity)
552  if (showcalltree) call calltree_waypoint("done with set_diffusivity (diabatic)")
553 
554  if (cs%debug) then
555  call mom_state_chksum("after set_diffusivity ", u, v, h, g, gv, haloshift=0)
556  call mom_forcing_chksum("after set_diffusivity ", fluxes, g, haloshift=0)
557  call mom_thermovar_chksum("after set_diffusivity ", tv, g)
558  call hchksum(kd, "after set_diffusivity Kd",g%HI,haloshift=0)
559  call hchksum(kd_int, "after set_diffusivity Kd_Int",g%HI,haloshift=0)
560  endif
561 
562 
563  if (cs%useKPP) then
564  call cpu_clock_begin(id_clock_kpp)
565  ! KPP needs the surface buoyancy flux but does not update state variables.
566  ! We could make this call higher up to avoid a repeat unpacking of the surface fluxes.
567  ! Sets: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux
568  ! NOTE: CS%KPP_buoy_flux, CS%KPP_temp_flux, CS%KPP_salt_flux are returned as rates (i.e. stuff per second)
569  ! unlike other instances where the fluxes are integrated in time over a time-step.
570  call calculatebuoyancyflux2d(g, gv, fluxes, cs%optics, h, tv%T, tv%S, tv, &
571  cs%KPP_buoy_flux, cs%KPP_temp_flux, cs%KPP_salt_flux)
572  ! The KPP scheme calculates boundary layer diffusivities and non-local transport.
573  ! MOM6 implementation of KPP matches the boundary layer to zero interior diffusivity,
574  ! since the matching to nonzero interior diffusivity can be problematic.
575  ! Changes: Kd_int. Sets: KPP_NLTheat, KPP_NLTscalar
576 
577 !$OMP parallel default(none) shared(is,ie,js,je,nz,Kd_salt,Kd_int,visc,CS,Kd_heat)
578 !$OMP do
579  do k=1,nz+1 ; do j=js,je ; do i=is,ie
580  kd_salt(i,j,k) = kd_int(i,j,k)
581  kd_heat(i,j,k) = kd_int(i,j,k)
582  enddo ; enddo ; enddo
583  if (associated(visc%Kd_extra_S)) then
584 !$OMP do
585  do k=1,nz+1 ; do j=js,je ; do i=is,ie
586  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
587  enddo ; enddo ; enddo
588  endif
589  if (associated(visc%Kd_extra_T)) then
590 !$OMP do
591  do k=1,nz+1 ; do j=js,je ; do i=is,ie
592  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
593  enddo ; enddo ; enddo
594  endif
595 !$OMP end parallel
596 
597  call kpp_calculate(cs%KPP_CSp, g, gv, h, tv%T, tv%S, u, v, tv%eqn_of_state, &
598  fluxes%ustar, cs%KPP_buoy_flux, kd_heat, kd_salt, visc%Kv_turb, cs%KPP_NLTheat, cs%KPP_NLTscalar)
599 !$OMP parallel default(none) shared(is,ie,js,je,nz,Kd_salt,Kd_int,visc,CS,Kd_heat)
600 
601  if (.not. cs%KPPisPassive) then
602 !$OMP do
603  do k=1,nz+1 ; do j=js,je ; do i=is,ie
604  kd_int(i,j,k) = min( kd_salt(i,j,k), kd_heat(i,j,k) )
605  enddo ; enddo ; enddo
606  if (associated(visc%Kd_extra_S)) then
607 !$OMP do
608  do k=1,nz+1 ; do j=js,je ; do i=is,ie
609  visc%Kd_extra_S(i,j,k) = kd_salt(i,j,k) - kd_int(i,j,k)
610  enddo ; enddo ; enddo
611  endif
612  if (associated(visc%Kd_extra_T)) then
613 !$OMP do
614  do k=1,nz+1 ; do j=js,je ; do i=is,ie
615  visc%Kd_extra_T(i,j,k) = kd_heat(i,j,k) - kd_int(i,j,k)
616  enddo ; enddo ; enddo
617  endif
618  endif ! not passive
619 !$OMP end parallel
620  call cpu_clock_end(id_clock_kpp)
621  if (showcalltree) call calltree_waypoint("done with KPP_calculate (diabatic)")
622  if (cs%debug) then
623  call mom_state_chksum("after KPP", u, v, h, g, gv, haloshift=0)
624  call mom_forcing_chksum("after KPP", fluxes, g, haloshift=0)
625  call mom_thermovar_chksum("after KPP", tv, g)
626  call hchksum(kd, "after KPP Kd",g%HI,haloshift=0)
627  call hchksum(kd_int, "after KPP Kd_Int",g%HI,haloshift=0)
628  endif
629 
630  endif ! endif for KPP
631 
632  ! Check for static instabilities and increase Kd_int where unstable
633  if (cs%useConvection) call diffconvection_calculate(cs%Conv_CSp, &
634  g, gv, h, tv%T, tv%S, tv%eqn_of_state, kd_int)
635 
636  if (cs%useKPP) then
637 
638  call cpu_clock_begin(id_clock_kpp)
639  if (cs%debug) then
640  call hchksum(cs%KPP_temp_flux, "before KPP_applyNLT netHeat",g%HI,haloshift=0, scale=gv%H_to_m)
641  call hchksum(cs%KPP_salt_flux, "before KPP_applyNLT netSalt",g%HI,haloshift=0, scale=gv%H_to_m)
642  call hchksum(cs%KPP_NLTheat, "before KPP_applyNLT NLTheat",g%HI,haloshift=0)
643  call hchksum(cs%KPP_NLTscalar, "before KPP_applyNLT NLTscalar",g%HI,haloshift=0)
644  endif
645  ! Apply non-local transport of heat and salt
646  ! Changes: tv%T, tv%S
647  call kpp_nonlocaltransport_temp(cs%KPP_CSp, g, gv, h, cs%KPP_NLTheat, cs%KPP_temp_flux, dt, tv%T, tv%C_p)
648  call kpp_nonlocaltransport_saln(cs%KPP_CSp, g, gv, h, cs%KPP_NLTscalar, cs%KPP_salt_flux, dt, tv%S)
649  call cpu_clock_end(id_clock_kpp)
650  if (showcalltree) call calltree_waypoint("done with KPP_applyNonLocalTransport (diabatic)")
651  if (cs%debugConservation) call mom_state_stats('KPP_applyNonLocalTransport', u, v, h, tv%T, tv%S, g)
652 
653  if (cs%debug) then
654  call mom_state_chksum("after KPP_applyNLT ", u, v, h, g, gv, haloshift=0)
655  call mom_forcing_chksum("after KPP_applyNLT ", fluxes, g, haloshift=0)
656  call mom_thermovar_chksum("after KPP_applyNLT ", tv, g)
657  endif
658 
659  endif ! endif for KPP
660 
661  ! Differential diffusion done here.
662  ! Changes: tv%T, tv%S
663  ! If using matching within the KPP scheme, then this step needs to provide
664  ! a diffusivity and happen before KPP. But generally in MOM, we do not match
665  ! KPP boundary layer to interior, so this diffusivity can be computed when convenient.
666  if (associated(visc%Kd_extra_T) .and. associated(visc%Kd_extra_S) .and. associated(tv%T)) then
667  call cpu_clock_begin(id_clock_differential_diff)
668 
669  call differential_diffuse_t_s(h, tv, visc, dt, g, gv)
670  call cpu_clock_end(id_clock_differential_diff)
671  if (showcalltree) call calltree_waypoint("done with differential_diffuse_T_S (diabatic)")
672  if (cs%debugConservation) call mom_state_stats('differential_diffuse_T_S', u, v, h, tv%T, tv%S, g)
673 
674  ! increment heat and salt diffusivity.
675  ! CS%useKPP==.true. already has extra_T and extra_S included
676  if(.not. cs%useKPP) then
677  do k=2,nz ; do j=js,je ; do i=is,ie
678  kd_heat(i,j,k) = kd_heat(i,j,k) + visc%Kd_extra_T(i,j,k)
679  kd_salt(i,j,k) = kd_salt(i,j,k) + visc%Kd_extra_S(i,j,k)
680  enddo ; enddo ; enddo
681  endif
682 
683 
684  endif
685 
686 
687  ! This block sets ea, eb from Kd or Kd_int.
688  ! If using ALE algorithm, set ea=eb=Kd_int on interfaces for
689  ! use in the tri-diagonal solver.
690  ! Otherwise, call entrainment_diffusive() which sets ea and eb
691  ! based on KD and target densities (ie. does remapping as well).
692  if (cs%useALEalgorithm) then
693 
694  do j=js,je ; do i=is,ie
695  ea(i,j,1) = 0.
696  enddo ; enddo
697 !$OMP parallel do default(none) shared(is,ie,js,je,nz,h_neglect,h,ea,GV,dt,Kd_int,eb) &
698 !$OMP private(hval)
699  do k=2,nz ; do j=js,je ; do i=is,ie
700  hval=1.0/(h_neglect + 0.5*(h(i,j,k-1) + h(i,j,k)))
701  ea(i,j,k) = (gv%m_to_H**2) * dt * hval * kd_int(i,j,k)
702  eb(i,j,k-1) = ea(i,j,k)
703  enddo ; enddo ; enddo
704  do j=js,je ; do i=is,ie
705  eb(i,j,nz) = 0.
706  enddo ; enddo
707  if (showcalltree) call calltree_waypoint("done setting ea,eb from Kd_int (diabatic)")
708 
709  else ! .not. CS%useALEalgorithm
710  ! When not using ALE, calculate layer entrainments/detrainments from
711  ! diffusivities and differences between layer and target densities
712  call cpu_clock_begin(id_clock_entrain)
713  ! Calculate appropriately limited diapycnal mass fluxes to account
714  ! for diapycnal diffusion and advection. Sets: ea, eb. Changes: kb
715  call entrainment_diffusive(u, v, h, tv, fluxes, dt, g, gv, cs%entrain_diffusive_CSp, &
716  ea, eb, kb, kd_lay=kd, kd_int=kd_int)
717  call cpu_clock_end(id_clock_entrain)
718  if (showcalltree) call calltree_waypoint("done with Entrainment_diffusive (diabatic)")
719 
720  endif ! endif for (CS%useALEalgorithm)
721 
722  if (cs%debug) then
723  call mom_forcing_chksum("after calc_entrain ", fluxes, g, haloshift=0)
724  call mom_thermovar_chksum("after calc_entrain ", tv, g)
725  call mom_state_chksum("after calc_entrain ", u, v, h, g, gv, haloshift=0)
726  call hchksum(ea, "after calc_entrain ea", g%HI, haloshift=0, scale=gv%H_to_m)
727  call hchksum(eb, "after calc_entrain eb", g%HI, haloshift=0, scale=gv%H_to_m)
728  endif
729 
730  ! Apply forcing when using the ALE algorithm
731  if (cs%useALEalgorithm) then
732  call cpu_clock_begin(id_clock_remap)
733 
734  ! Changes made to following fields: h, tv%T and tv%S.
735 
736  ! save prior values for diagnostics
737  if(cs%boundary_forcing_tendency_diag) then
738  do k=1,nz ; do j=js,je ; do i=is,ie
739  h_diag(i,j,k) = h(i,j,k)
740  temp_diag(i,j,k) = tv%T(i,j,k)
741  saln_diag(i,j,k) = tv%S(i,j,k)
742  enddo ; enddo ; enddo
743  endif
744 
745  do k=1,nz ; do j=js,je ; do i=is,ie
746  h_prebound(i,j,k) = h(i,j,k)
747  enddo ; enddo ; enddo
748  if (cs%use_energetic_PBL) then
749 
750  skinbuoyflux(:,:) = 0.0
751  call applyboundaryfluxesinout(cs%diabatic_aux_CSp, g, gv, dt, fluxes, cs%optics, &
752  h, tv, cs%aggregate_FW_forcing, cs%evap_CFL_limit, &
753  cs%minimum_forcing_depth, ctke, dsv_dt, dsv_ds, skinbuoyflux=skinbuoyflux)
754 
755  if (cs%debug) then
756  call hchksum(ea, "after applyBoundaryFluxes ea",g%HI,haloshift=0, scale=gv%H_to_m)
757  call hchksum(eb, "after applyBoundaryFluxes eb",g%HI,haloshift=0, scale=gv%H_to_m)
758  call hchksum(ctke, "after applyBoundaryFluxes cTKE",g%HI,haloshift=0)
759  call hchksum(dsv_dt, "after applyBoundaryFluxes dSV_dT",g%HI,haloshift=0)
760  call hchksum(dsv_ds, "after applyBoundaryFluxes dSV_dS",g%HI,haloshift=0)
761  endif
762 
763  call find_uv_at_h(u, v, h, u_h, v_h, g, gv)
764  call energetic_pbl(h, u_h, v_h, tv, fluxes, dt, kd_epbl, g, gv, &
765  cs%energetic_PBL_CSp, dsv_dt, dsv_ds, ctke, skinbuoyflux)
766 
767  ! If visc%MLD exists, copy the ePBL's MLD into it
768  if (associated(visc%MLD)) then
769  call energetic_pbl_get_mld(cs%energetic_PBL_CSp, visc%MLD, g)
770  call pass_var(visc%MLD, g%domain, halo=1)
771  hml(:,:) = visc%MLD(:,:)
772  endif
773 
774  ! Augment the diffusivities due to those diagnosed in energetic_PBL.
775  do k=2,nz ; do j=js,je ; do i=is,ie
776 
777  if (cs%ePBL_is_additive) then
778  kd_add_here = kd_epbl(i,j,k)
779  visc%Kv_turb(i,j,k) = visc%Kv_turb(i,j,k) + kd_epbl(i,j,k)
780  else
781  kd_add_here = max(kd_epbl(i,j,k) - visc%Kd_turb(i,j,k), 0.0)
782  visc%Kv_turb(i,j,k) = max(visc%Kv_turb(i,j,k), kd_epbl(i,j,k))
783  endif
784  ent_int = kd_add_here * (gv%m_to_H**2 * dt) / &
785  (0.5*(h(i,j,k-1) + h(i,j,k)) + h_neglect)
786  eb(i,j,k-1) = eb(i,j,k-1) + ent_int
787  ea(i,j,k) = ea(i,j,k) + ent_int
788  kd_int(i,j,k) = kd_int(i,j,k) + kd_add_here
789 
790  ! for diagnostics
791  kd_heat(i,j,k) = kd_heat(i,j,k) + kd_int(i,j,k)
792  kd_salt(i,j,k) = kd_salt(i,j,k) + kd_int(i,j,k)
793 
794  enddo ; enddo ; enddo
795 
796  if (cs%debug) then
797  call hchksum(ea, "after ePBL ea",g%HI,haloshift=0, scale=gv%H_to_m)
798  call hchksum(eb, "after ePBL eb",g%HI,haloshift=0, scale=gv%H_to_m)
799  call hchksum(kd_epbl, "after ePBL Kd_ePBL",g%HI,haloshift=0)
800  endif
801 
802  else
803  call applyboundaryfluxesinout(cs%diabatic_aux_CSp, g, gv, dt, fluxes, cs%optics, &
804  h, tv, cs%aggregate_FW_forcing, &
805  cs%evap_CFL_limit, cs%minimum_forcing_depth)
806 
807  endif ! endif for CS%use_energetic_PBL
808 
809  ! diagnose the tendencies due to boundary forcing
810  if(cs%boundary_forcing_tendency_diag) then
811  call diagnose_boundary_forcing_tendency(tv, h, temp_diag, saln_diag, h_diag, dt, g, gv, cs)
812  endif
813 
814  call cpu_clock_end(id_clock_remap)
815  if (cs%debug) then
816  call mom_forcing_chksum("after applyBoundaryFluxes ", fluxes, g, haloshift=0)
817  call mom_thermovar_chksum("after applyBoundaryFluxes ", tv, g)
818  call mom_state_chksum("after applyBoundaryFluxes ", u, v, h, g, gv, haloshift=0)
819  endif
820  if (showcalltree) call calltree_waypoint("done with applyBoundaryFluxes (diabatic)")
821  if (cs%debugConservation) call mom_state_stats('applyBoundaryFluxes', u, v, h, tv%T, tv%S, g)
822 
823  endif ! endif for (CS%useALEalgorithm)
824 
825  ! Update h according to divergence of the difference between
826  ! ea and eb. We keep a record of the original h in hold.
827  ! In the following, the checks for negative values are to guard
828  ! against instances where entrainment drives a layer to
829  ! negative thickness. This situation will never happen if
830  ! enough iterations are permitted in Calculate_Entrainment.
831  ! Even if too few iterations are allowed, it is still guarded
832  ! against. In other words the checks are probably unnecessary.
833 !$OMP parallel do default(none) shared(is,ie,js,je,nz,hold,h,eb,ea,GV)
834  do j=js,je
835  do i=is,ie
836  hold(i,j,1) = h(i,j,1)
837  h(i,j,1) = h(i,j,1) + (eb(i,j,1) - ea(i,j,2))
838  hold(i,j,nz) = h(i,j,nz)
839  h(i,j,nz) = h(i,j,nz) + (ea(i,j,nz) - eb(i,j,nz-1))
840  if (h(i,j,1) <= 0.0) then
841  h(i,j,1) = gv%Angstrom
842  endif
843  if (h(i,j,nz) <= 0.0) then
844  h(i,j,nz) = gv%Angstrom
845  endif
846  enddo
847  do k=2,nz-1 ; do i=is,ie
848  hold(i,j,k) = h(i,j,k)
849  h(i,j,k) = h(i,j,k) + ((ea(i,j,k) - eb(i,j,k-1)) + &
850  (eb(i,j,k) - ea(i,j,k+1)))
851  if (h(i,j,k) <= 0.0) then
852  h(i,j,k) = gv%Angstrom
853  endif
854  enddo ; enddo
855  enddo
856  if (cs%debug) then
857  call mom_state_chksum("after negative check ", u, v, h, g, gv, haloshift=0)
858  call mom_forcing_chksum("after negative check ", fluxes, g, haloshift=0)
859  call mom_thermovar_chksum("after negative check ", tv, g)
860  endif
861  if (showcalltree) call calltree_waypoint("done with h=ea-eb (diabatic)")
862  if (cs%debugConservation) call mom_state_stats('h=ea-eb', u, v, h, tv%T, tv%S, g)
863 
864 
865  ! Here, T and S are updated according to ea and eb.
866  ! If using the bulk mixed layer, T and S are also updated
867  ! by surface fluxes (in fluxes%*).
868  ! This is a very long block.
869  if (cs%bulkmixedlayer) then
870 
871  if (ASSOCIATED(tv%T)) then
872  call cpu_clock_begin(id_clock_tridiag)
873  ! Temperature and salinity (as state variables) are treated
874  ! differently from other tracers to insure massless layers that
875  ! are lighter than the mixed layer have temperatures and salinities
876  ! that correspond to their prescribed densities.
877  if (cs%massless_match_targets) then
878 !$OMP parallel do default (none) shared(is,ie,js,je,nkmb,hold,h_neglect,eb,ea,nz,kb,tv) &
879 !$OMP private(h_tr,b1,d1,c1,b_denom_1)
880  do j=js,je
881  do i=is,ie
882  h_tr = hold(i,j,1) + h_neglect
883  b1(i) = 1.0 / (h_tr + eb(i,j,1))
884  d1(i) = h_tr * b1(i)
885  tv%T(i,j,1) = b1(i) * (h_tr*tv%T(i,j,1))
886  tv%S(i,j,1) = b1(i) * (h_tr*tv%S(i,j,1))
887  enddo
888  do k=2,nkmb ; do i=is,ie
889  c1(i,k) = eb(i,j,k-1) * b1(i)
890  h_tr = hold(i,j,k) + h_neglect
891  b_denom_1 = h_tr + d1(i)*ea(i,j,k)
892  b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
893  if (k<nkmb) d1(i) = b_denom_1 * b1(i)
894  tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,k-1))
895  tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,k-1))
896  enddo ; enddo
897 
898  do k=nkmb+1,nz ; do i=is,ie
899  if (k == kb(i,j)) then
900  c1(i,k) = eb(i,j,k-1) * b1(i)
901  d1(i) = (((eb(i,j,nkmb)-eb(i,j,k-1)) + hold(i,j,nkmb) + h_neglect) + &
902  d1(i)*ea(i,j,nkmb)) * b1(i)
903  h_tr = hold(i,j,k) + h_neglect
904  b_denom_1 = h_tr + d1(i)*ea(i,j,k)
905  b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
906  d1(i) = b_denom_1 * b1(i)
907  tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,nkmb))
908  tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,nkmb))
909  elseif (k > kb(i,j)) then
910  c1(i,k) = eb(i,j,k-1) * b1(i)
911  h_tr = hold(i,j,k) + h_neglect
912  b_denom_1 = h_tr + d1(i)*ea(i,j,k)
913  b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
914  d1(i) = b_denom_1 * b1(i)
915  tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,k-1))
916  tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,k-1))
917  elseif (eb(i,j,k) < eb(i,j,k-1)) then ! (note that k < kb(i,j))
918  ! The bottommost buffer layer might entrain all the mass from some
919  ! of the interior layers that are thin and lighter in the coordinate
920  ! density than that buffer layer. The T and S of these newly
921  ! massless interior layers are unchanged.
922  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)
923  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)
924  endif
925  enddo ; enddo
926 
927  do k=nz-1,nkmb,-1 ; do i=is,ie
928  if (k >= kb(i,j)) then
929  tv%T(i,j,k) = tv%T(i,j,k) + c1(i,k+1)*tv%T(i,j,k+1)
930  tv%S(i,j,k) = tv%S(i,j,k) + c1(i,k+1)*tv%S(i,j,k+1)
931  endif
932  enddo ; enddo
933  do i=is,ie ; if (kb(i,j) <= nz) then
934  tv%T(i,j,nkmb) = tv%T(i,j,nkmb) + c1(i,kb(i,j))*tv%T(i,j,kb(i,j))
935  tv%S(i,j,nkmb) = tv%S(i,j,nkmb) + c1(i,kb(i,j))*tv%S(i,j,kb(i,j))
936  endif ; enddo
937  do k=nkmb-1,1,-1 ; do i=is,ie
938  tv%T(i,j,k) = tv%T(i,j,k) + c1(i,k+1)*tv%T(i,j,k+1)
939  tv%S(i,j,k) = tv%S(i,j,k) + c1(i,k+1)*tv%S(i,j,k+1)
940  enddo ; enddo
941  enddo ! end of j loop
942  else ! .not. massless_match_targets
943  ! This simpler form allows T & S to be too dense for the layers
944  ! between the buffer layers and the interior.
945  ! Changes: T, S
946  if (cs%tracer_tridiag) then
947  call tracer_vertdiff(hold, ea, eb, dt, tv%T, g, gv)
948  call tracer_vertdiff(hold, ea, eb, dt, tv%S, g, gv)
949  else
950  call tridiagts(g, gv, is, ie, js, je, hold, ea, eb, tv%T, tv%S)
951  endif
952  endif ! massless_match_targets
953  call cpu_clock_end(id_clock_tridiag)
954 
955  endif ! endif for ASSOCIATED(T)
956  if (cs%debugConservation) call mom_state_stats('BML tridiag', u, v, h, tv%T, tv%S, g)
957 
958  if ((cs%ML_mix_first > 0.0) .or. cs%use_geothermal) then
959  ! The mixed layer code has already been called, but there is some needed
960  ! bookkeeping.
961 !$OMP parallel do default(none) shared(is,ie,js,je,nz,hold,h_orig,ea,eaml,eb,ebml)
962  do k=1,nz ; do j=js,je ; do i=is,ie
963  hold(i,j,k) = h_orig(i,j,k)
964  ea(i,j,k) = ea(i,j,k) + eaml(i,j,k)
965  eb(i,j,k) = eb(i,j,k) + ebml(i,j,k)
966  enddo ; enddo ; enddo
967  if (cs%debug) then
968  call hchksum(ea, "after ea = ea + eaml",g%HI,haloshift=0, scale=gv%H_to_m)
969  call hchksum(eb, "after eb = eb + ebml",g%HI,haloshift=0, scale=gv%H_to_m)
970  endif
971  endif
972 
973  if (cs%ML_mix_first < 1.0) then
974  ! Call the mixed layer code now, perhaps for a second time.
975  ! This subroutine (1) Cools the mixed layer.
976  ! (2) Performs convective adjustment by mixed layer entrainment.
977  ! (3) Heats the mixed layer and causes it to detrain to
978  ! Monin-Obukhov depth or minimum mixed layer depth.
979  ! (4) Uses any remaining TKE to drive mixed layer entrainment.
980  ! (5) Possibly splits the buffer layer into two isopycnal layers.
981 
982  call find_uv_at_h(u, v, hold, u_h, v_h, g, gv, ea, eb)
983  if (cs%debug) call mom_state_chksum("find_uv_at_h1 ", u, v, h, g, gv, haloshift=0)
984 
985  dt_mix = min(dt,dt*(1.0 - cs%ML_mix_first))
986  call cpu_clock_begin(id_clock_mixedlayer)
987  ! Changes: h, tv%T, tv%S, ea and eb (G is also inout???)
988  call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt_mix, ea, eb, &
989  g, gv, cs%bulkmixedlayer_CSp, cs%optics, &
990  hml, cs%aggregate_FW_forcing, dt, last_call=.true.)
991 
992  if (cs%salt_reject_below_ML) &
993  call insert_brine(h, tv, g, gv, fluxes, nkmb, cs%diabatic_aux_CSp, dt_mix, &
994  cs%id_brine_lay)
995 
996  ! Keep salinity from falling below a small but positive threshold.
997  ! This constraint is needed for SIS1 ice model, which can extract
998  ! more salt than is present in the ocean. SIS2 does not suffer
999  ! from this limitation, in which case we can let salinity=0 and still
1000  ! have salt conserved with SIS2 ice. So for SIS2, we can run with
1001  ! BOUND_SALINITY=False in MOM.F90.
1002  if (ASSOCIATED(tv%S) .and. ASSOCIATED(tv%salt_deficit)) &
1003  call adjust_salt(h, tv, g, gv, cs%diabatic_aux_CSp)
1004 
1005  call cpu_clock_end(id_clock_mixedlayer)
1006  if (showcalltree) call calltree_waypoint("done with 2nd bulkmixedlayer (diabatic)")
1007  if (cs%debugConservation) call mom_state_stats('2nd bulkmixedlayer', u, v, h, tv%T, tv%S, g)
1008  endif
1009 
1010  else ! following block for when NOT using BULKMIXEDLAYER
1011 
1012 
1013  ! calculate change in temperature & salinity due to dia-coordinate surface diffusion
1014  if (ASSOCIATED(tv%T)) then
1015 
1016  if (cs%debug) then
1017  call hchksum(ea, "before triDiagTS ea ",g%HI,haloshift=0, scale=gv%H_to_m)
1018  call hchksum(eb, "before triDiagTS eb ",g%HI,haloshift=0, scale=gv%H_to_m)
1019  endif
1020  call cpu_clock_begin(id_clock_tridiag)
1021 
1022  if(cs%diabatic_diff_tendency_diag) then
1023  do k=1,nz ; do j=js,je ; do i=is,ie
1024  temp_diag(i,j,k) = tv%T(i,j,k)
1025  saln_diag(i,j,k) = tv%S(i,j,k)
1026  enddo ; enddo ; enddo
1027  endif
1028 
1029  ! Changes T and S via the tridiagonal solver; no change to h
1030  if(cs%tracer_tridiag) then
1031  call tracer_vertdiff(hold, ea, eb, dt, tv%T, g, gv)
1032  call tracer_vertdiff(hold, ea, eb, dt, tv%S, g, gv)
1033  else
1034  call tridiagts(g, gv, is, ie, js, je, hold, ea, eb, tv%T, tv%S)
1035  endif
1036 
1037  ! diagnose temperature, salinity, heat, and salt tendencies
1038  if(cs%diabatic_diff_tendency_diag) then
1039  call diagnose_diabatic_diff_tendency(tv, hold, temp_diag, saln_diag, dt, g, gv, cs)
1040  endif
1041 
1042  call cpu_clock_end(id_clock_tridiag)
1043  if (showcalltree) call calltree_waypoint("done with triDiagTS (diabatic)")
1044 
1045  endif ! endif corresponding to if (ASSOCIATED(tv%T))
1046  if (cs%debugConservation) call mom_state_stats('triDiagTS', u, v, h, tv%T, tv%S, g)
1047 
1048 
1049  endif ! endif for the BULKMIXEDLAYER block
1050 
1051 
1052  if (cs%debug) then
1053  call mom_state_chksum("after mixed layer ", u, v, h, g, gv, haloshift=0)
1054  call mom_thermovar_chksum("after mixed layer ", tv, g)
1055  call hchksum(ea, "after mixed layer ea", g%HI, scale=gv%H_to_m)
1056  call hchksum(eb, "after mixed layer eb", g%HI, scale=gv%H_to_m)
1057  endif
1058 
1059  if (.not. cs%useALEalgorithm) then
1060  call cpu_clock_begin(id_clock_remap)
1061  call regularize_layers(h, tv, dt, ea, eb, g, gv, cs%regularize_layers_CSp)
1062  call cpu_clock_end(id_clock_remap)
1063  if (showcalltree) call calltree_waypoint("done with regularize_layers (diabatic)")
1064  if (cs%debugConservation) call mom_state_stats('regularize_layers', u, v, h, tv%T, tv%S, g)
1065  endif
1066 
1067  ! Whenever thickness changes let the diag manager know, as the
1068  ! target grids for vertical remapping may need to be regenerated.
1069  call diag_update_remap_grids(cs%diag)
1070 
1071  ! diagnostics
1072  if ((cs%id_Tdif > 0) .or. (cs%id_Tdif_z > 0) .or. &
1073  (cs%id_Tadv > 0) .or. (cs%id_Tadv_z > 0)) then
1074  do j=js,je ; do i=is,ie
1075  tdif_flx(i,j,1) = 0.0 ; tdif_flx(i,j,nz+1) = 0.0
1076  tadv_flx(i,j,1) = 0.0 ; tadv_flx(i,j,nz+1) = 0.0
1077  enddo ; enddo
1078 !$OMP parallel do default(none) shared(is,ie,js,je,nz,Tdif_flx,Idt,ea,eb,Tadv_flx,tv)
1079  do k=2,nz ; do j=js,je ; do i=is,ie
1080  tdif_flx(i,j,k) = (idt * 0.5*(ea(i,j,k) + eb(i,j,k-1))) * &
1081  (tv%T(i,j,k-1) - tv%T(i,j,k))
1082  tadv_flx(i,j,k) = (idt * (ea(i,j,k) - eb(i,j,k-1))) * &
1083  0.5*(tv%T(i,j,k-1) + tv%T(i,j,k))
1084  enddo ; enddo ; enddo
1085  endif
1086  if ((cs%id_Sdif > 0) .or. (cs%id_Sdif_z > 0) .or. &
1087  (cs%id_Sadv > 0) .or. (cs%id_Sadv_z > 0)) then
1088  do j=js,je ; do i=is,ie
1089  sdif_flx(i,j,1) = 0.0 ; sdif_flx(i,j,nz+1) = 0.0
1090  sadv_flx(i,j,1) = 0.0 ; sadv_flx(i,j,nz+1) = 0.0
1091  enddo ; enddo
1092 !$OMP parallel do default(none) shared(is,ie,js,je,nz,Sdif_flx,Idt,ea,eb,Sadv_flx,tv)
1093  do k=2,nz ; do j=js,je ; do i=is,ie
1094  sdif_flx(i,j,k) = (idt * 0.5*(ea(i,j,k) + eb(i,j,k-1))) * &
1095  (tv%S(i,j,k-1) - tv%S(i,j,k))
1096  sadv_flx(i,j,k) = (idt * (ea(i,j,k) - eb(i,j,k-1))) * &
1097  0.5*(tv%S(i,j,k-1) + tv%S(i,j,k))
1098  enddo ; enddo ; enddo
1099  endif
1100 
1101  ! mixing of passive tracers from massless boundary layers to interior
1102  call cpu_clock_begin(id_clock_tracers)
1103  if (cs%mix_boundary_tracers) then
1104  tr_ea_bbl = sqrt(dt*cs%Kd_BBL_tr)
1105 !$OMP parallel do default(none) shared(is,ie,js,je,ebtr,nz,G,GV,h,dt,CS,h_neglect, &
1106 !$OMP ea,eb,Tr_ea_BBL,eatr,visc,hold,h_neglect2 ) &
1107 !$OMP private(htot,in_boundary,add_ent)
1108  do j=js,je
1109  do i=is,ie
1110  ebtr(i,j,nz) = eb(i,j,nz)
1111  htot(i) = 0.0
1112  in_boundary(i) = (g%mask2dT(i,j) > 0.0)
1113  enddo
1114  do k=nz,2,-1 ; do i=is,ie
1115  if (in_boundary(i)) then
1116  htot(i) = htot(i) + h(i,j,k)
1117  ! If diapycnal mixing has been suppressed because this is a massless
1118  ! layer near the bottom, add some mixing of tracers between these
1119  ! layers. This flux is based on the harmonic mean of the two
1120  ! thicknesses, as this corresponds pretty closely (to within
1121  ! differences in the density jumps between layers) with what is done
1122  ! in the calculation of the fluxes in the first place. Kd_min_tr
1123  ! should be much less than the values that have been set in Kd,
1124  ! perhaps a molecular diffusivity.
1125  add_ent = ((dt * cs%Kd_min_tr) * gv%m_to_H**2) * &
1126  ((h(i,j,k-1)+h(i,j,k)+h_neglect) / &
1127  (h(i,j,k-1)*h(i,j,k)+h_neglect2)) - &
1128  0.5*(ea(i,j,k) + eb(i,j,k-1))
1129  if (htot(i) < tr_ea_bbl) then
1130  add_ent = max(0.0, add_ent, &
1131  (tr_ea_bbl - htot(i)) - min(ea(i,j,k),eb(i,j,k-1)))
1132  elseif (add_ent < 0.0) then
1133  add_ent = 0.0 ; in_boundary(i) = .false.
1134  endif
1135 
1136  ebtr(i,j,k-1) = eb(i,j,k-1) + add_ent
1137  eatr(i,j,k) = ea(i,j,k) + add_ent
1138  else
1139  ebtr(i,j,k-1) = eb(i,j,k-1) ; eatr(i,j,k) = ea(i,j,k)
1140  endif
1141  if (associated(visc%Kd_extra_S)) then ; if (visc%Kd_extra_S(i,j,k) > 0.0) then
1142  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%m_to_H**2) / &
1143  (0.25 * ((h(i,j,k-1) + h(i,j,k)) + (hold(i,j,k-1) + hold(i,j,k))) + &
1144  h_neglect)
1145  ebtr(i,j,k-1) = ebtr(i,j,k-1) + add_ent
1146  eatr(i,j,k) = eatr(i,j,k) + add_ent
1147  endif ; endif
1148  enddo ; enddo
1149  do i=is,ie ; eatr(i,j,1) = ea(i,j,1) ; enddo
1150 
1151  enddo
1152 
1153  if (cs%useALEalgorithm) then
1154  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1155  ! so hold should be h_orig
1156  call call_tracer_column_fns(h_prebound, h, ea, eb, fluxes, hml, dt, g, gv, tv, &
1157  cs%optics, cs%tracer_flow_CSp, cs%debug, &
1158  evap_cfl_limit = cs%evap_CFL_limit, &
1159  minimum_forcing_depth = cs%minimum_forcing_depth)
1160  else
1161  call call_tracer_column_fns(hold, h, eatr, ebtr, fluxes, hml, dt, g, gv, tv, &
1162  cs%optics, cs%tracer_flow_CSp, cs%debug)
1163  endif
1164 
1165  elseif (associated(visc%Kd_extra_S)) then ! extra diffusivity for passive tracers
1166 
1167  do j=js,je ; do i=is,ie
1168  ebtr(i,j,nz) = eb(i,j,nz) ; eatr(i,j,1) = ea(i,j,1)
1169  enddo ; enddo
1170 !$OMP parallel do default(none) shared(nz,is,ie,js,je,visc,dt,GV,h,hold,h_neglect,&
1171 !$OMP ebtr,eb,eatr,ea ) &
1172 !$OMP private(add_ent)
1173  do k=nz,2,-1 ; do j=js,je ; do i=is,ie
1174  if (visc%Kd_extra_S(i,j,k) > 0.0) then
1175  add_ent = ((dt * visc%Kd_extra_S(i,j,k)) * gv%m_to_H**2) / &
1176  (0.25 * ((h(i,j,k-1) + h(i,j,k)) + (hold(i,j,k-1) + hold(i,j,k))) + &
1177  h_neglect)
1178  else
1179  add_ent = 0.0
1180  endif
1181  ebtr(i,j,k-1) = eb(i,j,k-1) + add_ent
1182  eatr(i,j,k) = ea(i,j,k) + add_ent
1183  enddo ; enddo ; enddo
1184 
1185  if (cs%useALEalgorithm) then
1186  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1187  call call_tracer_column_fns(h_prebound, h, eatr, ebtr, fluxes, hml, dt, g, gv, tv, &
1188  cs%optics, cs%tracer_flow_CSp, cs%debug,&
1189  evap_cfl_limit = cs%evap_CFL_limit, &
1190  minimum_forcing_depth = cs%minimum_forcing_depth)
1191  else
1192  call call_tracer_column_fns(hold, h, eatr, ebtr, fluxes, hml, dt, g, gv, tv, &
1193  cs%optics, cs%tracer_flow_CSp, cs%debug)
1194  endif
1195 
1196  else
1197  if (cs%useALEalgorithm) then
1198  ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1199  call call_tracer_column_fns(h_prebound, h, eatr, ebtr, fluxes, hml, dt, g, gv, tv, &
1200  cs%optics, cs%tracer_flow_CSp, cs%debug, &
1201  evap_cfl_limit = cs%evap_CFL_limit, &
1202  minimum_forcing_depth = cs%minimum_forcing_depth)
1203  else
1204  call call_tracer_column_fns(hold, h, ea, eb, fluxes, hml, dt, g, gv, tv, &
1205  cs%optics, cs%tracer_flow_CSp, cs%debug)
1206  endif
1207 
1208  endif ! (CS%mix_boundary_tracers)
1209 
1210 
1211 
1212  call cpu_clock_end(id_clock_tracers)
1213 
1214 
1215  ! sponges
1216  if (cs%use_sponge) then
1217  call cpu_clock_begin(id_clock_sponge)
1218  if (associated(cs%ALE_sponge_CSp)) then
1219  ! ALE sponge
1220  call apply_ale_sponge(h, dt, g, cs%ALE_sponge_CSp)
1221  else
1222  ! Layer mode sponge
1223  if (cs%bulkmixedlayer .and. ASSOCIATED(tv%eqn_of_state)) then
1224  do i=is,ie ; p_ref_cv(i) = tv%P_Ref ; enddo
1225 !$OMP parallel do default(none) shared(js,je,p_ref_cv,Rcv_ml,is,ie,tv)
1226  do j=js,je
1227  call calculate_density(tv%T(:,j,1), tv%S(:,j,1), p_ref_cv, rcv_ml(:,j), &
1228  is, ie-is+1, tv%eqn_of_state)
1229  enddo
1230  call apply_sponge(h, dt, g, gv, ea, eb, cs%sponge_CSp, rcv_ml)
1231  else
1232  call apply_sponge(h, dt, g, gv, ea, eb, cs%sponge_CSp)
1233  endif
1234  endif
1235  call cpu_clock_end(id_clock_sponge)
1236  if (cs%debug) then
1237  call mom_state_chksum("apply_sponge ", u, v, h, g, gv, haloshift=0)
1238  call mom_thermovar_chksum("apply_sponge ", tv, g)
1239  endif
1240  endif ! CS%use_sponge
1241 
1242 
1243 !$OMP parallel default(none) shared(is,ie,js,je,nz,CDp,Idt,G,GV,ea,eb,CS,hold) private(net_ent)
1244 ! Save the diapycnal mass fluxes as a diagnostic field.
1245  if (ASSOCIATED(cdp%diapyc_vel)) then
1246 !$OMP do
1247  do j=js,je
1248  do k=2,nz ; do i=is,ie
1249  cdp%diapyc_vel(i,j,k) = idt * (gv%H_to_m * (ea(i,j,k) - eb(i,j,k-1)))
1250  enddo ; enddo
1251  do i=is,ie
1252  cdp%diapyc_vel(i,j,1) = 0.0
1253  cdp%diapyc_vel(i,j,nz+1) = 0.0
1254  enddo
1255  enddo
1256  endif
1257 
1258 ! For momentum, it is only the net flux that homogenizes within
1259 ! the mixed layer. Vertical viscosity that is proportional to the
1260 ! mixed layer turbulence is applied elsewhere.
1261  if (cs%bulkmixedlayer) then
1262  if (cs%debug) then
1263  call hchksum(ea, "before net flux rearrangement ea",g%HI, scale=gv%H_to_m)
1264  call hchksum(eb, "before net flux rearrangement eb",g%HI, scale=gv%H_to_m)
1265  endif
1266 !$OMP do
1267  do j=js,je
1268  do k=2,gv%nkml ; do i=is,ie
1269  net_ent = ea(i,j,k) - eb(i,j,k-1)
1270  ea(i,j,k) = max(net_ent, 0.0)
1271  eb(i,j,k-1) = max(-net_ent, 0.0)
1272  enddo ; enddo
1273  enddo
1274  if (cs%debug) then
1275  call hchksum(ea, "after net flux rearrangement ea",g%HI, scale=gv%H_to_m)
1276  call hchksum(eb, "after net flux rearrangement eb",g%HI, scale=gv%H_to_m)
1277  endif
1278  endif
1279 
1280 
1281 ! Initialize halo regions of ea, eb, and hold to default values.
1282 !$OMP do
1283  do k=1,nz
1284  do i=is-1,ie+1
1285  hold(i,js-1,k) = gv%Angstrom ; ea(i,js-1,k) = 0.0 ; eb(i,js-1,k) = 0.0
1286  hold(i,je+1,k) = gv%Angstrom ; ea(i,je+1,k) = 0.0 ; eb(i,je+1,k) = 0.0
1287  enddo
1288  do j=js,je
1289  hold(is-1,j,k) = gv%Angstrom ; ea(is-1,j,k) = 0.0 ; eb(is-1,j,k) = 0.0
1290  hold(ie+1,j,k) = gv%Angstrom ; ea(ie+1,j,k) = 0.0 ; eb(ie+1,j,k) = 0.0
1291  enddo
1292  enddo
1293 !$OMP end parallel
1294 
1295  call cpu_clock_begin(id_clock_pass)
1296  if (g%symmetric) then
1297  call create_group_pass(cs%pass_hold_eb_ea,hold,g%Domain,to_all+omit_corners,halo=1)
1298  call create_group_pass(cs%pass_hold_eb_ea,eb,g%Domain,to_all+omit_corners,halo=1)
1299  call create_group_pass(cs%pass_hold_eb_ea,ea,g%Domain,to_all+omit_corners,halo=1)
1300  else
1301  call create_group_pass(cs%pass_hold_eb_ea,hold,g%Domain,to_west+to_south+omit_corners,halo=1)
1302  call create_group_pass(cs%pass_hold_eb_ea,eb,g%Domain,to_west+to_south+omit_corners,halo=1)
1303  call create_group_pass(cs%pass_hold_eb_ea,ea,g%Domain,to_west+to_south+omit_corners,halo=1)
1304  endif
1305  call do_group_pass(cs%pass_hold_eb_ea,g%Domain)
1306  call cpu_clock_end(id_clock_pass)
1307 
1308  if (.not. cs%useALEalgorithm) then
1309  ! Use a tridiagonal solver to determine effect of the diapycnal
1310  ! advection on velocity field. It is assumed that water leaves
1311  ! or enters the ocean with the surface velocity.
1312  if (cs%debug) then
1313  call mom_state_chksum("before u/v tridiag ", u, v, h, g, gv, haloshift=0)
1314  call hchksum(ea, "before u/v tridiag ea",g%HI, scale=gv%H_to_m)
1315  call hchksum(eb, "before u/v tridiag eb",g%HI, scale=gv%H_to_m)
1316  call hchksum(hold, "before u/v tridiag hold",g%HI, scale=gv%H_to_m)
1317  endif
1318  call cpu_clock_begin(id_clock_tridiag)
1319 !$OMP parallel do default(none) shared(js,je,Isq,Ieq,ADp,u,hold,ea,h_neglect,eb,nz,Idt) &
1320 !$OMP private(hval,b1,d1,c1,eaval)
1321  do j=js,je
1322  do i=isq,ieq
1323  if (ASSOCIATED(adp%du_dt_dia)) adp%du_dt_dia(i,j,1) = u(i,j,1)
1324  hval = (hold(i,j,1) + hold(i+1,j,1)) + (ea(i,j,1) + ea(i+1,j,1)) + h_neglect
1325  b1(i) = 1.0 / (hval + (eb(i,j,1) + eb(i+1,j,1)))
1326  d1(i) = hval * b1(i)
1327  u(i,j,1) = b1(i) * (hval * u(i,j,1))
1328  enddo
1329  do k=2,nz ; do i=isq,ieq
1330  if (ASSOCIATED(adp%du_dt_dia)) adp%du_dt_dia(i,j,k) = u(i,j,k)
1331  c1(i,k) = (eb(i,j,k-1)+eb(i+1,j,k-1)) * b1(i)
1332  eaval = ea(i,j,k) + ea(i+1,j,k)
1333  hval = hold(i,j,k) + hold(i+1,j,k) + h_neglect
1334  b1(i) = 1.0 / ((eb(i,j,k) + eb(i+1,j,k)) + (hval + d1(i)*eaval))
1335  d1(i) = (hval + d1(i)*eaval) * b1(i)
1336  u(i,j,k) = (hval*u(i,j,k) + eaval*u(i,j,k-1))*b1(i)
1337  enddo ; enddo
1338  do k=nz-1,1,-1 ; do i=isq,ieq
1339  u(i,j,k) = u(i,j,k) + c1(i,k+1)*u(i,j,k+1)
1340  if (ASSOCIATED(adp%du_dt_dia)) &
1341  adp%du_dt_dia(i,j,k) = (u(i,j,k) - adp%du_dt_dia(i,j,k)) * idt
1342  enddo ; enddo
1343  if (ASSOCIATED(adp%du_dt_dia)) then
1344  do i=isq,ieq
1345  adp%du_dt_dia(i,j,nz) = (u(i,j,nz)-adp%du_dt_dia(i,j,nz)) * idt
1346  enddo
1347  endif
1348  enddo
1349  if (cs%debug) then
1350  call mom_state_chksum("aft 1st loop tridiag ", u, v, h, g, gv, haloshift=0)
1351  endif
1352 !$OMP parallel do default(none) shared(Jsq,Jeq,is,ie,ADp,v,hold,ea,h_neglect,eb,nz,Idt) &
1353 !$OMP private(hval,b1,d1,c1,eaval)
1354  do j=jsq,jeq
1355  do i=is,ie
1356  if (ASSOCIATED(adp%dv_dt_dia)) adp%dv_dt_dia(i,j,1) = v(i,j,1)
1357  hval = (hold(i,j,1) + hold(i,j+1,1)) + (ea(i,j,1) + ea(i,j+1,1)) + h_neglect
1358  b1(i) = 1.0 / (hval + (eb(i,j,1) + eb(i,j+1,1)))
1359  d1(i) = hval * b1(i)
1360  v(i,j,1) = b1(i) * (hval * v(i,j,1))
1361  enddo
1362  do k=2,nz ; do i=is,ie
1363  if (ASSOCIATED(adp%dv_dt_dia)) adp%dv_dt_dia(i,j,k) = v(i,j,k)
1364  c1(i,k) = (eb(i,j,k-1)+eb(i,j+1,k-1)) * b1(i)
1365  eaval = ea(i,j,k) + ea(i,j+1,k)
1366  hval = hold(i,j,k) + hold(i,j+1,k) + h_neglect
1367  b1(i) = 1.0 / ((eb(i,j,k) + eb(i,j+1,k)) + (hval + d1(i)*eaval))
1368  d1(i) = (hval + d1(i)*eaval) * b1(i)
1369  v(i,j,k) = (hval*v(i,j,k) + eaval*v(i,j,k-1))*b1(i)
1370  enddo ; enddo
1371  do k=nz-1,1,-1 ; do i=is,ie
1372  v(i,j,k) = v(i,j,k) + c1(i,k+1)*v(i,j,k+1)
1373  if (ASSOCIATED(adp%dv_dt_dia)) &
1374  adp%dv_dt_dia(i,j,k) = (v(i,j,k) - adp%dv_dt_dia(i,j,k)) * idt
1375  enddo ; enddo
1376  if (ASSOCIATED(adp%dv_dt_dia)) then
1377  do i=is,ie
1378  adp%dv_dt_dia(i,j,nz) = (v(i,j,nz)-adp%dv_dt_dia(i,j,nz)) * idt
1379  enddo
1380  endif
1381  enddo
1382  call cpu_clock_end(id_clock_tridiag)
1383  if (cs%debug) then
1384  call mom_state_chksum("after u/v tridiag ", u, v, h, g, gv, haloshift=0)
1385  endif
1386  endif ! useALEalgorithm
1387 
1388  ! Frazil formation keeps temperature above the freezing point.
1389  ! make_frazil is deliberately called at both the beginning and at
1390  ! the end of the diabatic processes.
1391  if (ASSOCIATED(tv%T) .AND. ASSOCIATED(tv%frazil)) then
1392 
1393  if(cs%frazil_tendency_diag) then
1394  do k=1,nz ; do j=js,je ; do i=is,ie
1395  temp_diag(i,j,k) = tv%T(i,j,k)
1396  enddo ; enddo ; enddo
1397  endif
1398 
1399  if (ASSOCIATED(fluxes%p_surf_full)) then
1400  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp, fluxes%p_surf_full)
1401  else
1402  call make_frazil(h, tv, g, gv, cs%diabatic_aux_CSp)
1403  endif
1404 
1405  if (cs%frazil_tendency_diag) then
1406  call diagnose_frazil_tendency(tv, h, temp_diag, dt, g, gv, cs, 2)
1407  endif
1408 
1409  if (showcalltree) call calltree_waypoint("done with 2nd make_frazil (diabatic)")
1410  if (cs%debugConservation) call mom_state_stats('2nd make_frazil', u, v, h, tv%T, tv%S, g)
1411 
1412  endif ! endif for frazil
1413 
1414 
1415  ! Diagnose the diapycnal diffusivities and other related quantities.
1416  if (cs%id_Kd_interface > 0) call post_data(cs%id_Kd_interface, kd_int, cs%diag)
1417  if (cs%id_Kd_heat > 0) call post_data(cs%id_Kd_heat, kd_heat, cs%diag)
1418  if (cs%id_Kd_salt > 0) call post_data(cs%id_Kd_salt, kd_salt, cs%diag)
1419  if (cs%id_Kd_ePBL > 0) call post_data(cs%id_Kd_ePBL, kd_epbl, cs%diag)
1420 
1421  if (cs%id_ea > 0) call post_data(cs%id_ea, ea, cs%diag)
1422  if (cs%id_eb > 0) call post_data(cs%id_eb, eb, cs%diag)
1423 
1424  if (cs%id_dudt_dia > 0) call post_data(cs%id_dudt_dia, adp%du_dt_dia, cs%diag)
1425  if (cs%id_dvdt_dia > 0) call post_data(cs%id_dvdt_dia, adp%dv_dt_dia, cs%diag)
1426  if (cs%id_wd > 0) call post_data(cs%id_wd, cdp%diapyc_vel, cs%diag)
1427 
1428  if (cs%id_MLD_003 > 0 .or. cs%id_subMLN2 > 0 .or. cs%id_mlotstsq > 0) then
1429  call diagnosemldbydensitydifference(cs%id_MLD_003, h, tv, 0.03, g, gv, cs%diag, &
1430  id_n2subml=cs%id_subMLN2, id_mldsq=cs%id_mlotstsq)
1431  endif
1432  if (cs%id_MLD_0125 > 0) then
1433  call diagnosemldbydensitydifference(cs%id_MLD_0125, h, tv, 0.125, g, gv, cs%diag)
1434  endif
1435  if (cs%id_MLD_user > 0) then
1436  call diagnosemldbydensitydifference(cs%id_MLD_user, h, tv, cs%MLDdensityDifference, g, gv, cs%diag)
1437  endif
1438 
1439  if (cs%id_Tdif > 0) call post_data(cs%id_Tdif, tdif_flx, cs%diag)
1440  if (cs%id_Tadv > 0) call post_data(cs%id_Tadv, tadv_flx, cs%diag)
1441  if (cs%id_Sdif > 0) call post_data(cs%id_Sdif, sdif_flx, cs%diag)
1442  if (cs%id_Sadv > 0) call post_data(cs%id_Sadv, sadv_flx, cs%diag)
1443  if (cs%use_int_tides) then
1444  if (cs%id_cg1 > 0) call post_data(cs%id_cg1, cn(:,:,1),cs%diag)
1445  do m=1,cs%nMode
1446  if (cs%id_cn(m) > 0) call post_data(cs%id_cn(m),cn(:,:,m),cs%diag)
1447  enddo
1448  endif
1449 
1450  num_z_diags = 0
1451  if (cs%id_Kd_z > 0) then
1452  num_z_diags = num_z_diags + 1
1453  z_ids(num_z_diags) = cs%id_Kd_z ; z_ptrs(num_z_diags)%p => kd_int
1454  endif
1455  if (cs%id_Tdif_z > 0) then
1456  num_z_diags = num_z_diags + 1
1457  z_ids(num_z_diags) = cs%id_Tdif_z ; z_ptrs(num_z_diags)%p => tdif_flx
1458  endif
1459  if (cs%id_Tadv_z > 0) then
1460  num_z_diags = num_z_diags + 1
1461  z_ids(num_z_diags) = cs%id_Tadv_z ; z_ptrs(num_z_diags)%p => tadv_flx
1462  endif
1463  if (cs%id_Sdif_z > 0) then
1464  num_z_diags = num_z_diags + 1
1465  z_ids(num_z_diags) = cs%id_Sdif_z ; z_ptrs(num_z_diags)%p => sdif_flx
1466  endif
1467  if (cs%id_Sadv_z > 0) then
1468  num_z_diags = num_z_diags + 1
1469  z_ids(num_z_diags) = cs%id_Sadv_z ; z_ptrs(num_z_diags)%p => sadv_flx
1470  endif
1471 
1472  if (num_z_diags > 0) &
1473  call calc_zint_diags(h, z_ptrs, z_ids, num_z_diags, g, gv, cs%diag_to_Z_CSp)
1474 
1475  if (cs%debugConservation) call mom_state_stats('leaving diabatic', u, v, h, tv%T, tv%S, g)
1476  if (showcalltree) call calltree_leave("diabatic()")
1477 
1478 end subroutine diabatic
1479 
1480 !> Returns pointers or values of members within the diabatic_CS type. For extensibility,
1481 !! each returned argument is an optional argument
1482 subroutine extract_diabatic_member(CS, opacity_CSp, optics_CSp, &
1483  evap_CFL_limit, minimum_forcing_depth)
1484  type(diabatic_cs), intent(in ) :: CS
1485  ! All output arguments are optional
1486  type(opacity_cs), pointer, optional, intent( out) :: opacity_CSp
1487  type(optics_type), pointer, optional, intent( out) :: optics_CSp
1488  real, optional, intent( out) :: evap_CFL_limit
1489  real, optional, intent( out) :: minimum_forcing_depth
1490 
1491  ! Pointers to control structures
1492  if (present(opacity_csp)) opacity_csp => cs%opacity_CSp
1493  if (present(optics_csp)) optics_csp => cs%optics
1494 
1495  ! Constants within diabatic_CS
1496  if (present(evap_cfl_limit)) evap_cfl_limit = cs%evap_CFL_limit
1497  if (present(minimum_forcing_depth)) minimum_forcing_depth = cs%minimum_forcing_depth
1498 
1499 end subroutine
1500 
1501 !> Routine called for adiabatic physics
1502 subroutine adiabatic(h, tv, fluxes, dt, G, GV, CS)
1503  type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1504  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< thickness (m for Bouss or kg/m2 for non-Bouss)
1505  type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
1506  type(forcing), intent(inout) :: fluxes !< boundary fluxes
1507  real, intent(in) :: dt !< time step (seconds)
1508  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
1509  type(diabatic_cs), pointer :: CS !< module control structure
1510 
1511  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: zeros ! An array of zeros.
1512 
1513  zeros(:,:,:) = 0.0
1514 
1515  call call_tracer_column_fns(h, h, zeros, zeros, fluxes, zeros(:,:,1), dt, g, gv, tv, &
1516  cs%optics, cs%tracer_flow_CSp, cs%debug)
1517 
1518 end subroutine adiabatic
1519 
1520 
1521 !> This routine diagnoses tendencies from application of diabatic diffusion
1522 !! using ALE algorithm. Note that layer thickness is not altered by
1523 !! diabatic diffusion.
1524 subroutine diagnose_diabatic_diff_tendency(tv, h, temp_old, saln_old, dt, G, GV, CS)
1525  type(ocean_grid_type), intent(in) :: G !< ocean grid structure
1526  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
1527  type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
1528  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< thickness (m or kg/m2)
1529  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: temp_old !< temperature prior to diabatic physics
1530  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: saln_old !< salinity prior to diabatic physics (PPT)
1531  real, intent(in) :: dt !< time step (sec)
1532  type(diabatic_cs), pointer :: CS !< module control structure
1533 
1534  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: work_3d
1535  real, dimension(SZI_(G),SZJ_(G)) :: work_2d
1536  real :: Idt
1537  integer :: i, j, k, is, ie, js, je, nz
1538 
1539  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1540  idt = 1/dt
1541  work_3d(:,:,:) = 0.0
1542  work_2d(:,:) = 0.0
1543 
1544 
1545  ! temperature tendency
1546  do k=1,nz ; do j=js,je ; do i=is,ie
1547  work_3d(i,j,k) = (tv%T(i,j,k)-temp_old(i,j,k))*idt
1548  enddo ; enddo ; enddo
1549  if(cs%id_diabatic_diff_temp_tend > 0) then
1550  call post_data(cs%id_diabatic_diff_temp_tend, work_3d, cs%diag)
1551  endif
1552 
1553  ! heat tendency
1554  if(cs%id_diabatic_diff_heat_tend > 0 .or. cs%id_diabatic_diff_heat_tend_2d > 0) then
1555  do k=1,nz ; do j=js,je ; do i=is,ie
1556  work_3d(i,j,k) = h(i,j,k) * gv%H_to_kg_m2 * tv%C_p * work_3d(i,j,k)
1557  enddo ; enddo ; enddo
1558  if(cs%id_diabatic_diff_heat_tend > 0) then
1559  call post_data(cs%id_diabatic_diff_heat_tend, work_3d, cs%diag)
1560  endif
1561  if(cs%id_diabatic_diff_heat_tend_2d > 0) then
1562  do j=js,je ; do i=is,ie
1563  work_2d(i,j) = 0.0
1564  do k=1,nz
1565  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
1566  enddo
1567  enddo ; enddo
1568  call post_data(cs%id_diabatic_diff_heat_tend_2d, work_2d, cs%diag)
1569  endif
1570  endif
1571 
1572  ! salinity tendency
1573  do k=1,nz ; do j=js,je ; do i=is,ie
1574  work_3d(i,j,k) = (tv%S(i,j,k)-saln_old(i,j,k))*idt
1575  enddo ; enddo ; enddo
1576  if(cs%id_diabatic_diff_saln_tend > 0) then
1577  call post_data(cs%id_diabatic_diff_saln_tend, work_3d, cs%diag)
1578  endif
1579 
1580  ! salt tendency
1581  if(cs%id_diabatic_diff_salt_tend > 0 .or. cs%id_diabatic_diff_salt_tend_2d > 0) then
1582  do k=1,nz ; do j=js,je ; do i=is,ie
1583  work_3d(i,j,k) = h(i,j,k) * gv%H_to_kg_m2 * cs%ppt2mks * work_3d(i,j,k)
1584  enddo ; enddo ; enddo
1585  if(cs%id_diabatic_diff_salt_tend > 0) then
1586  call post_data(cs%id_diabatic_diff_salt_tend, work_3d, cs%diag)
1587  endif
1588  if(cs%id_diabatic_diff_salt_tend_2d > 0) then
1589  do j=js,je ; do i=is,ie
1590  work_2d(i,j) = 0.0
1591  do k=1,nz
1592  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
1593  enddo
1594  enddo ; enddo
1595  call post_data(cs%id_diabatic_diff_salt_tend_2d, work_2d, cs%diag)
1596  endif
1597  endif
1598 
1599 end subroutine diagnose_diabatic_diff_tendency
1600 
1601 
1602 !> This routine diagnoses tendencies from application of boundary fluxes.
1603 !! These impacts are generally 3d, in particular for penetrative shortwave.
1604 !! Other fluxes contribute 3d in cases when the layers vanish or are very thin,
1605 !! in which case we distribute the flux into k > 1 layers.
1606 subroutine diagnose_boundary_forcing_tendency(tv, h, temp_old, saln_old, h_old, &
1607  dt, G, GV, CS)
1608  type(ocean_grid_type), intent(in) :: G !< ocean grid structure
1609  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
1610  type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
1611  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< thickness after boundary flux application (m or kg/m2)
1612  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: temp_old !< temperature prior to boundary flux application
1613  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: saln_old !< salinity prior to boundary flux application (PPT)
1614  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h_old !< thickness prior to boundary flux application (m or kg/m2)
1615  real, intent(in) :: dt !< time step (sec)
1616  type(diabatic_cs), pointer :: CS !< module control structure
1617 
1618  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: work_3d
1619  real, dimension(SZI_(G),SZJ_(G)) :: work_2d
1620  real :: Idt
1621  integer :: i, j, k, is, ie, js, je, nz
1622 
1623  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1624  idt = 1/dt
1625  work_3d(:,:,:) = 0.0
1626  work_2d(:,:) = 0.0
1627 
1628  ! temperature tendency
1629  if(cs%id_boundary_forcing_temp_tend > 0) then
1630  do k=1,nz ; do j=js,je ; do i=is,ie
1631  work_3d(i,j,k) = (tv%T(i,j,k)-temp_old(i,j,k))*idt
1632  enddo ; enddo ; enddo
1633  call post_data(cs%id_boundary_forcing_temp_tend, work_3d, cs%diag)
1634  endif
1635 
1636  ! heat tendency
1637  if(cs%id_boundary_forcing_heat_tend > 0 .or. cs%id_boundary_forcing_heat_tend_2d > 0) then
1638  do k=1,nz ; do j=js,je ; do i=is,ie
1639  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))
1640  enddo ; enddo ; enddo
1641  if(cs%id_boundary_forcing_heat_tend > 0) then
1642  call post_data(cs%id_boundary_forcing_heat_tend, work_3d, cs%diag)
1643  endif
1644  if(cs%id_boundary_forcing_heat_tend_2d > 0) then
1645  do j=js,je ; do i=is,ie
1646  work_2d(i,j) = 0.0
1647  do k=1,nz
1648  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
1649  enddo
1650  enddo ; enddo
1651  call post_data(cs%id_boundary_forcing_heat_tend_2d, work_2d, cs%diag)
1652  endif
1653  endif
1654 
1655 
1656  ! salinity tendency
1657  if(cs%id_boundary_forcing_saln_tend > 0) then
1658  do k=1,nz ; do j=js,je ; do i=is,ie
1659  work_3d(i,j,k) = (tv%S(i,j,k)-saln_old(i,j,k))*idt
1660  enddo ; enddo ; enddo
1661  call post_data(cs%id_boundary_forcing_saln_tend, work_3d, cs%diag)
1662  endif
1663 
1664  ! salt tendency
1665  if(cs%id_boundary_forcing_salt_tend > 0 .or. cs%id_boundary_forcing_salt_tend_2d > 0) then
1666  do k=1,nz ; do j=js,je ; do i=is,ie
1667  work_3d(i,j,k) = gv%H_to_kg_m2 * cs%ppt2mks * idt * (h(i,j,k) * tv%S(i,j,k) - h_old(i,j,k) * saln_old(i,j,k))
1668  enddo ; enddo ; enddo
1669  if(cs%id_boundary_forcing_salt_tend > 0) then
1670  call post_data(cs%id_boundary_forcing_salt_tend, work_3d, cs%diag)
1671  endif
1672  if(cs%id_boundary_forcing_salt_tend_2d > 0) then
1673  do j=js,je ; do i=is,ie
1674  work_2d(i,j) = 0.0
1675  do k=1,nz
1676  work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
1677  enddo
1678  enddo ; enddo
1679  call post_data(cs%id_boundary_forcing_salt_tend_2d, work_2d, cs%diag)
1680  endif
1681  endif
1682 
1684 
1685 
1686 !> This routine diagnoses tendencies for temperature and heat from frazil formation.
1687 !! This routine is called twice from within subroutine diabatic; at start and at
1688 !! end of the diabatic processes. The impacts from frazil are generally a function
1689 !! of depth. Hence, when checking heat budget, be sure to remove HFSIFRAZIL from HFDS in k=1.
1690 subroutine diagnose_frazil_tendency(tv, h, temp_old, dt, G, GV, CS, ncall)
1691  type(ocean_grid_type), intent(in) :: G !< ocean grid structure
1692  type(verticalgrid_type), intent(in) :: GV !< ocean vertical grid structure
1693  type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
1694  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: h !< thickness (m or kg/m2)
1695  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(in) :: temp_old !< temperature prior to frazil formation
1696  real, intent(in) :: dt !< time step (sec)
1697  integer, intent(in) :: ncall !< the first or second call of this routine
1698  type(diabatic_cs), pointer :: CS !< module control structure
1699 
1700  real, dimension(SZI_(G),SZJ_(G)) :: work_2d
1701  real :: Idt
1702  integer :: i, j, k, is, ie, js, je, nz
1703 
1704  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
1705  idt = 1/dt
1706  work_2d(:,:) = 0.0
1707 
1708  ! zero the tendencies at start of first call
1709  if(ncall == 1) then
1710  cs%frazil_heat_diag(:,:,:) = 0.0
1711  cs%frazil_temp_diag(:,:,:) = 0.0
1712  endif
1713 
1714  ! temperature tendency
1715  if(cs%id_frazil_temp_tend > 0) then
1716  do k=1,nz ; do j=js,je ; do i=is,ie
1717  cs%frazil_temp_diag(i,j,k) = cs%frazil_temp_diag(i,j,k) + idt * (tv%T(i,j,k)-temp_old(i,j,k))
1718  enddo ; enddo ; enddo
1719  if(ncall == 2) then
1720  call post_data(cs%id_frazil_temp_tend, cs%frazil_temp_diag(:,:,:), cs%diag)
1721  endif
1722  endif
1723 
1724  ! heat tendency
1725  if(cs%id_frazil_heat_tend > 0 .or. cs%id_frazil_heat_tend_2d > 0) then
1726  do k=1,nz ; do j=js,je ; do i=is,ie
1727  cs%frazil_heat_diag(i,j,k) = cs%frazil_heat_diag(i,j,k) + &
1728  gv%H_to_kg_m2 * tv%C_p * h(i,j,k) * idt * (tv%T(i,j,k)-temp_old(i,j,k))
1729  enddo ; enddo ; enddo
1730  if(cs%id_frazil_heat_tend > 0 .and. ncall == 2) then
1731  call post_data(cs%id_frazil_heat_tend, cs%frazil_heat_diag(:,:,:), cs%diag)
1732  endif
1733 
1734  ! As a consistency check, we must have
1735  ! FRAZIL_HEAT_TENDENCY_2d = HFSIFRAZIL
1736  if(cs%id_frazil_heat_tend_2d > 0 .and. ncall == 2) then
1737  do j=js,je ; do i=is,ie
1738  work_2d(i,j) = 0.0
1739  do k=1,nz
1740  work_2d(i,j) = work_2d(i,j) + cs%frazil_heat_diag(i,j,k)
1741  enddo
1742  enddo ; enddo
1743  call post_data(cs%id_frazil_heat_tend_2d, work_2d, cs%diag)
1744  endif
1745  endif
1746 
1747 
1748 end subroutine diagnose_frazil_tendency
1749 
1750 
1751 !> A simplified version of diabatic_driver_init that will allow
1752 !! tracer column functions to be called without allowing any
1753 !! of the diabatic processes to be used.
1754 subroutine adiabatic_driver_init(Time, G, param_file, diag, CS, &
1755  tracer_flow_CSp, diag_to_Z_CSp)
1756  type(time_type), intent(in) :: Time !< current model time
1757  type(ocean_grid_type), intent(in) :: G !< model grid structure
1758  type(param_file_type), intent(in) :: param_file !< the file to parse for parameter values
1759  type(diag_ctrl), target, intent(inout) :: diag !< regulates diagnostic output
1760  type(diabatic_cs), pointer :: CS !< module control structure
1761  type(tracer_flow_control_cs), pointer :: tracer_flow_CSp !< points to control structure of tracer flow control module
1762  type(diag_to_z_cs), pointer :: diag_to_Z_CSp !< pointer to Z-diagnostics control structure
1763 
1764 ! This "include" declares and sets the variable "version".
1765 #include "version_variable.h"
1766  character(len=40) :: mod = "MOM_diabatic_driver" ! This module's name.
1767 
1768  if (associated(cs)) then
1769  call mom_error(warning, "adiabatic_driver_init called with an "// &
1770  "associated control structure.")
1771  return
1772  else ; allocate(cs) ; endif
1773 
1774  cs%diag => diag
1775  if (associated(tracer_flow_csp)) cs%tracer_flow_CSp => tracer_flow_csp
1776  if (associated(diag_to_z_csp)) cs%diag_to_Z_CSp => diag_to_z_csp
1777 
1778 ! Set default, read and log parameters
1779  call log_version(param_file, mod, version, &
1780  "The following parameters are used for diabatic processes.")
1781 
1782 end subroutine adiabatic_driver_init
1783 
1784 
1785 !> This routine initializes the diabatic driver module.
1786 subroutine diabatic_driver_init(Time, G, GV, param_file, useALEalgorithm, diag, &
1787  ADp, CDp, CS, tracer_flow_CSp, sponge_CSp, &
1788  ALE_sponge_CSp, diag_to_Z_CSp)
1789  type(time_type), intent(in) :: Time !< model time
1790  type(ocean_grid_type), intent(inout) :: G !< model grid structure
1791  type(verticalgrid_type), intent(in) :: GV !< model vertical grid structure
1792  type(param_file_type), intent(in) :: param_file !< file to parse for parameter values
1793  logical, intent(in) :: useALEalgorithm !< logical for whether to use ALE remapping
1794  type(diag_ctrl), target, intent(inout) :: diag !< structure to regulate diagnostic output
1795  type(accel_diag_ptrs), intent(inout) :: ADp !< pointers to accelerations in momentum equations,
1796  !! to enable diagnostics, like energy budgets
1797  type(cont_diag_ptrs), intent(inout) :: CDp !< pointers to terms in continuity equations
1798  type(diabatic_cs), pointer :: CS !< module control structure
1799  type(tracer_flow_control_cs), pointer :: tracer_flow_CSp !< pointer to control structure of tracer flow control module
1800  type(sponge_cs), pointer :: sponge_CSp !< pointer to the sponge module control structure
1801  type(ale_sponge_cs), pointer :: ALE_sponge_CSp !< pointer to the ALE sponge module control structure
1802  type(diag_to_z_cs), pointer :: diag_to_Z_CSp !< pointer to the Z-diagnostics control structure
1803 
1804  real :: Kd
1805  integer :: num_mode
1806  logical :: use_temperature, differentialDiffusion
1807  type(vardesc) :: vd
1808 
1809 ! This "include" declares and sets the variable "version".
1810 #include "version_variable.h"
1811  character(len=40) :: mod = "MOM_diabatic_driver" ! This module's name.
1812  character(len=48) :: thickness_units
1813  character(len=40) :: var_name
1814  character(len=160) :: var_descript
1815  integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz, nbands, m
1816  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
1817  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
1818 
1819  if (associated(cs)) then
1820  call mom_error(warning, "diabatic_driver_init called with an "// &
1821  "associated control structure.")
1822  return
1823  else
1824  allocate(cs)
1825  endif
1826 
1827  cs%diag => diag
1828  if (associated(tracer_flow_csp)) cs%tracer_flow_CSp => tracer_flow_csp
1829  if (associated(sponge_csp)) cs%sponge_CSp => sponge_csp
1830  if (associated(ale_sponge_csp)) cs%ALE_sponge_CSp => ale_sponge_csp
1831  if (associated(diag_to_z_csp)) cs%diag_to_Z_CSp => diag_to_z_csp
1832 
1833  cs%useALEalgorithm = usealealgorithm
1834  cs%bulkmixedlayer = (gv%nkml > 0)
1835 
1836  ! Set default, read and log parameters
1837  call log_version(param_file, mod, version, &
1838  "The following parameters are used for diabatic processes.")
1839 
1840  call get_param(param_file, mod, "SPONGE", cs%use_sponge, &
1841  "If true, sponges may be applied anywhere in the domain. \n"//&
1842  "The exact location and properties of those sponges are \n"//&
1843  "specified via calls to initialize_sponge and possibly \n"//&
1844  "set_up_sponge_field.", default=.false.)
1845  call get_param(param_file, mod, "ENABLE_THERMODYNAMICS", use_temperature, &
1846  "If true, temperature and salinity are used as state \n"//&
1847  "variables.", default=.true.)
1848  call get_param(param_file, mod, "ENERGETICS_SFC_PBL", cs%use_energetic_PBL, &
1849  "If true, use an implied energetics planetary boundary \n"//&
1850  "layer scheme to determine the diffusivity and viscosity \n"//&
1851  "in the surface boundary layer.", default=.false.)
1852  call get_param(param_file, mod, "EPBL_IS_ADDITIVE", cs%ePBL_is_additive, &
1853  "If true, the diffusivity from ePBL is added to all\n"//&
1854  "other diffusivities. Otherwise, the larger of kappa-\n"//&
1855  "shear and ePBL diffusivities are used.", default=.true.)
1856  call get_param(param_file, mod, "DOUBLE_DIFFUSION", differentialdiffusion, &
1857  "If true, apply parameterization of double-diffusion.", &
1858  default=.false. )
1859  cs%use_kappa_shear = kappa_shear_is_used(param_file)
1860  cs%use_CVMix_shear = cvmix_shear_is_used(param_file)
1861  if (cs%bulkmixedlayer) then
1862  call get_param(param_file, mod, "ML_MIX_FIRST", cs%ML_mix_first, &
1863  "The fraction of the mixed layer mixing that is applied \n"//&
1864  "before interior diapycnal mixing. 0 by default.", &
1865  units="nondim", default=0.0)
1866  call get_param(param_file, mod, "NKBL", cs%nkbl, default=2, do_not_log=.true.)
1867  else
1868  cs%ML_mix_first = 0.0
1869  endif
1870  if (use_temperature) then
1871  call get_param(param_file, mod, "DO_GEOTHERMAL", cs%use_geothermal, &
1872  "If true, apply geothermal heating.", default=.false.)
1873  else
1874  cs%use_geothermal = .false.
1875  endif
1876  call get_param(param_file, mod, "INTERNAL_TIDES", cs%use_int_tides, &
1877  "If true, use the code that advances a separate set of \n"//&
1878  "equations for the internal tide energy density.", default=.false.)
1879  cs%nMode = 1
1880  if (cs%use_int_tides) then
1881  ! SET NUMBER OF MODES TO CONSIDER
1882  call get_param(param_file, mod, "INTERNAL_TIDE_MODES", cs%nMode, &
1883  "The number of distinct internal tide modes \n"//&
1884  "that will be calculated.", default=1, do_not_log=.true.)
1885 
1886  ! The following parameters are used in testing the internal tide code.
1887  ! GET LOCATION AND DURATION OF ENERGY POINT SOURCE FOR TESTING (BDM)
1888  call get_param(param_file, mod, "INTERNAL_TIDE_SOURCE_TEST", cs%int_tide_source_test, &
1889  "If true, apply an arbitrary generation site for internal tide testing", &
1890  default=.false.)
1891  if(cs%int_tide_source_test)then
1892  call get_param(param_file, mod, "INTERNAL_TIDE_SOURCE_X", cs%int_tide_source_x, &
1893  "X Location of generation site for internal tide", default=1.)
1894  call get_param(param_file, mod, "INTERNAL_TIDE_SOURCE_Y", cs%int_tide_source_y, &
1895  "Y Location of generation site for internal tide", default=1.)
1896  call get_param(param_file, mod, "INTERNAL_TIDE_SOURCE_TLEN_DAYS", cs%tlen_days, &
1897  "Time interval from start of experiment for adding wave source", &
1898  units="days", default=0)
1899  cs%time_max_source = increment_time(time,0,days=cs%tlen_days)
1900  endif
1901  ! GET UNIFORM MODE VELOCITY FOR TESTING (BDM)
1902  call get_param(param_file, mod, "UNIFORM_CG", cs%uniform_cg, &
1903  "If true, set cg = cg_test everywhere for test case", default=.false.)
1904  if(cs%uniform_cg)then
1905  call get_param(param_file, mod, "CG_TEST", cs%cg_test, &
1906  "Uniform group velocity of internal tide for test case", default=1.)
1907  endif
1908  endif
1909 
1910  call get_param(param_file, mod, "MASSLESS_MATCH_TARGETS", &
1911  cs%massless_match_targets, &
1912  "If true, the temperature and salinity of massless layers \n"//&
1913  "are kept consistent with their target densities. \n"//&
1914  "Otherwise the properties of massless layers evolve \n"//&
1915  "diffusively to match massive neighboring layers.", &
1916  default=.true.)
1917 
1918  call get_param(param_file, mod, "AGGREGATE_FW_FORCING", cs%aggregate_FW_forcing, &
1919  "If true, the net incoming and outgoing fresh water fluxes are combined\n"//&
1920  "and applied as either incoming or outgoing depending on the sign of the net.\n"//&
1921  "If false, the net incoming fresh water flux is added to the model and\n"//&
1922  "thereafter the net outgoing is removed from the updated state."//&
1923  "into the first non-vanished layer for which the column remains stable", &
1924  default=.true.)
1925 
1926  call get_param(param_file, mod, "DEBUG", cs%debug, &
1927  "If true, write out verbose debugging data.", default=.false.)
1928  call get_param(param_file, mod, "DEBUG_CONSERVATION", cs%debugConservation, &
1929  "If true, monitor conservation and extrema.", default=.false.)
1930 
1931  call get_param(param_file, mod, "DEBUG_ENERGY_REQ", cs%debug_energy_req, &
1932  "If true, debug the energy requirements.", default=.false., do_not_log=.true.)
1933  call get_param(param_file, mod, "MIX_BOUNDARY_TRACERS", cs%mix_boundary_tracers, &
1934  "If true, mix the passive tracers in massless layers at \n"//&
1935  "the bottom into the interior as though a diffusivity of \n"//&
1936  "KD_MIN_TR were operating.", default=.true.)
1937 
1938  if (cs%mix_boundary_tracers) then
1939  call get_param(param_file, mod, "KD", kd, fail_if_missing=.true.)
1940  call get_param(param_file, mod, "KD_MIN_TR", cs%Kd_min_tr, &
1941  "A minimal diffusivity that should always be applied to \n"//&
1942  "tracers, especially in massless layers near the bottom. \n"//&
1943  "The default is 0.1*KD.", units="m2 s-1", default=0.1*kd)
1944  call get_param(param_file, mod, "KD_BBL_TR", cs%Kd_BBL_tr, &
1945  "A bottom boundary layer tracer diffusivity that will \n"//&
1946  "allow for explicitly specified bottom fluxes. The \n"//&
1947  "entrainment at the bottom is at least sqrt(Kd_BBL_tr*dt) \n"//&
1948  "over the same distance.", units="m2 s-1", default=0.)
1949  endif
1950 
1951  call get_param(param_file, mod, "TRACER_TRIDIAG", cs%tracer_tridiag, &
1952  "If true, use the passive tracer tridiagonal solver for T and S\n", &
1953  default=.false.)
1954 
1955  call get_param(param_file, mod, "MINIMUM_FORCING_DEPTH", cs%minimum_forcing_depth, &
1956  "The smallest depth over which forcing can be applied. This\n"//&
1957  "only takes effect when near-surface layers become thin\n"//&
1958  "relative to this scale, in which case the forcing tendencies\n"//&
1959  "scaled down by distributing the forcing over this depth scale.", &
1960  units="m", default=0.001)
1961  call get_param(param_file, mod, "EVAP_CFL_LIMIT", cs%evap_CFL_limit, &
1962  "The largest fraction of a layer than can be lost to forcing\n"//&
1963  "(e.g. evaporation, sea-ice formation) in one time-step. The unused\n"//&
1964  "mass loss is passed down through the column.", &
1965  units="nondim", default=0.8)
1966 
1967 
1968  ! Register all available diagnostics for this module.
1969  if (gv%Boussinesq) then ; thickness_units = "meter"
1970  else ; thickness_units = "kilogram meter-2" ; endif
1971 
1972  cs%id_ea = register_diag_field('ocean_model','ea',diag%axesTL,time, &
1973  'Layer entrainment from above per timestep','meter')
1974  cs%id_eb = register_diag_field('ocean_model','eb',diag%axesTL,time, &
1975  'Layer entrainment from below per timestep', 'meter')
1976  cs%id_dudt_dia = register_diag_field('ocean_model','dudt_dia',diag%axesCuL,time, &
1977  'Zonal Acceleration from Diapycnal Mixing', 'meter second-2')
1978  cs%id_dvdt_dia = register_diag_field('ocean_model','dvdt_dia',diag%axesCvL,time, &
1979  'Meridional Acceleration from Diapycnal Mixing', 'meter second-2')
1980  cs%id_wd = register_diag_field('ocean_model','wd',diag%axesTi,time, &
1981  'Diapycnal Velocity', 'meter second-1')
1982  if (cs%use_int_tides) then
1983  cs%id_cg1 = register_diag_field('ocean_model','cn1', diag%axesT1, &
1984  time, 'First baroclinic mode (eigen) speed', 'm s-1')
1985  allocate(cs%id_cn(cs%nMode)) ; cs%id_cn(:) = -1
1986  do m=1,cs%nMode
1987  write(var_name, '("cn_mode",i1)') m
1988  write(var_descript, '("Baroclinic (eigen) speed of mode ",i1)') m
1989  cs%id_cn(m) = register_diag_field('ocean_model',var_name, diag%axesT1, &
1990  time, var_descript, 'm s-1')
1991  call mom_mesg("Registering "//trim(var_name)//", Described as: "//var_descript, 5)
1992  enddo
1993  endif
1994 
1995  cs%id_Tdif = register_diag_field('ocean_model',"Tflx_dia_diff",diag%axesTi, &
1996  time, "Diffusive diapycnal temperature flux across interfaces", &
1997  "degC meter second-1")
1998  cs%id_Tadv = register_diag_field('ocean_model',"Tflx_dia_adv",diag%axesTi, &
1999  time, "Advective diapycnal temperature flux across interfaces", &
2000  "degC meter second-1")
2001  cs%id_Sdif = register_diag_field('ocean_model',"Sflx_dia_diff",diag%axesTi, &
2002  time, "Diffusive diapycnal salnity flux across interfaces", &
2003  "PSU meter second-1")
2004  cs%id_Sadv = register_diag_field('ocean_model',"Sflx_dia_adv",diag%axesTi, &
2005  time, "Advective diapycnal salnity flux across interfaces", &
2006  "PSU meter second-1")
2007  cs%id_MLD_003 = register_diag_field('ocean_model','MLD_003',diag%axesT1,time, &
2008  'Mixed layer depth (delta rho = 0.03)', 'meter', cmor_field_name='mlotst', &
2009  cmor_long_name='Ocean Mixed Layer Thickness Defined by Sigma T', cmor_units='m', &
2010  cmor_standard_name='ocean_mixed_layer_thickness_defined_by_sigma_t')
2011  cs%id_mlotstsq = register_diag_field('ocean_model','mlotstsq',diag%axesT1,time, &
2012  long_name='Square of Ocean Mixed Layer Thickness Defined by Sigma T', &
2013  standard_name='square_of_ocean_mixed_layer_thickness_defined_by_sigma_t',units='m2')
2014  cs%id_MLD_0125 = register_diag_field('ocean_model','MLD_0125',diag%axesT1,time, &
2015  'Mixed layer depth (delta rho = 0.125)', 'meter')
2016  cs%id_subMLN2 = register_diag_field('ocean_model','subML_N2',diag%axesT1,time, &
2017  'Squared buoyancy frequency below mixed layer', 's-2')
2018  cs%id_MLD_user = register_diag_field('ocean_model','MLD_user',diag%axesT1,time, &
2019  'Mixed layer depth (used defined)', 'meter')
2020  call get_param(param_file, mod, "DIAG_MLD_DENSITY_DIFF", cs%MLDdensityDifference, &
2021  "The density difference used to determine a diagnostic mixed\n"//&
2022  "layer depth, MLD_user, following the definition of Levitus 1982. \n"//&
2023  "The MLD is the depth at which the density is larger than the\n"//&
2024  "surface density by the specified amount.", units='kg/m3', default=0.1)
2025 
2026  ! diagnostics making use of the z-gridding code
2027  if (associated(diag_to_z_csp)) then
2028  vd = var_desc("Kd_interface", "meter2 second-1", &
2029  "Diapycnal diffusivity at interfaces, interpolated to z", z_grid='z')
2030  cs%id_Kd_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
2031  vd = var_desc("Tflx_dia_diff", "degC meter second-1", &
2032  "Diffusive diapycnal temperature flux across interfaces, interpolated to z", &
2033  z_grid='z')
2034  cs%id_Tdif_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
2035  vd = var_desc("Tflx_dia_adv", "degC meter second-1", &
2036  "Advective diapycnal temperature flux across interfaces, interpolated to z",&
2037  z_grid='z')
2038  cs%id_Tadv_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
2039  vd = var_desc("Sflx_dia_diff", "PSU meter second-1", &
2040  "Diffusive diapycnal salinity flux across interfaces, interpolated to z",&
2041  z_grid='z')
2042  cs%id_Sdif_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
2043  vd = var_desc("Sflx_dia_adv", "PSU meter second-1", &
2044  "Advective diapycnal salinity flux across interfaces, interpolated to z",&
2045  z_grid='z')
2046  cs%id_Sadv_z = register_zint_diag(vd, cs%diag_to_Z_CSp, time)
2047  endif
2048 
2049  if (cs%id_dudt_dia > 0) call safe_alloc_ptr(adp%du_dt_dia,isdb,iedb,jsd,jed,nz)
2050  if (cs%id_dvdt_dia > 0) call safe_alloc_ptr(adp%dv_dt_dia,isd,ied,jsdb,jedb,nz)
2051  if (cs%id_wd > 0) call safe_alloc_ptr(cdp%diapyc_vel,isd,ied,jsd,jed,nz+1)
2052 
2053  !call set_diffusivity_init(Time, G, param_file, diag, CS%set_diff_CSp, diag_to_Z_CSp, CS%int_tide_CSp)
2054  cs%id_Kd_interface = register_diag_field('ocean_model', 'Kd_interface', diag%axesTi, time, &
2055  'Total diapycnal diffusivity at interfaces', 'meter2 second-1')
2056  if (cs%use_energetic_PBL) then
2057  cs%id_Kd_ePBL = register_diag_field('ocean_model', 'Kd_ePBL', diag%axesTi, time, &
2058  'ePBL diapycnal diffusivity at interfaces', 'meter2 second-1')
2059  endif
2060 
2061  cs%id_Kd_heat = register_diag_field('ocean_model', 'Kd_heat', diag%axesTi, time, &
2062  'Total diapycnal diffusivity for heat at interfaces', 'meter2 second-1', &
2063  cmor_field_name='difvho', cmor_units='m2 s-1', &
2064  cmor_standard_name='ocean_vertical_heat_diffusivity', &
2065  cmor_long_name='Ocean vertical heat diffusivity')
2066  cs%id_Kd_salt = register_diag_field('ocean_model', 'Kd_salt', diag%axesTi, time, &
2067  'Total diapycnal diffusivity for salt at interfaces', 'meter2 second-1', &
2068  cmor_field_name='difvso', cmor_units='m2 s-1', &
2069  cmor_standard_name='ocean_vertical_salt_diffusivity', &
2070  cmor_long_name='Ocean vertical salt diffusivity')
2071 
2072  ! CS%useKPP is set to True if KPP-scheme is to be used, False otherwise.
2073  ! KPP_init() allocated CS%KPP_Csp and also sets CS%KPPisPassive
2074  cs%useKPP = kpp_init(param_file, g, diag, time, cs%KPP_CSp, passive=cs%KPPisPassive)
2075  if (cs%useKPP) then
2076  allocate( cs%KPP_NLTheat(isd:ied,jsd:jed,nz+1) ) ; cs%KPP_NLTheat(:,:,:) = 0.
2077  allocate( cs%KPP_NLTscalar(isd:ied,jsd:jed,nz+1) ) ; cs%KPP_NLTscalar(:,:,:) = 0.
2078  endif
2079  if (cs%useKPP) then
2080  allocate( cs%KPP_buoy_flux(isd:ied,jsd:jed,nz+1) ) ; cs%KPP_buoy_flux(:,:,:) = 0.
2081  allocate( cs%KPP_temp_flux(isd:ied,jsd:jed) ) ; cs%KPP_temp_flux(:,:) = 0.
2082  allocate( cs%KPP_salt_flux(isd:ied,jsd:jed) ) ; cs%KPP_salt_flux(:,:) = 0.
2083  endif
2084 
2085  call get_param(param_file, mod, "SALT_REJECT_BELOW_ML", cs%salt_reject_below_ML, &
2086  "If true, place salt from brine rejection below the mixed layer,\n"// &
2087  "into the first non-vanished layer for which the column remains stable", &
2088  default=.false.)
2089 
2090  if (cs%salt_reject_below_ML) then
2091  cs%id_brine_lay = register_diag_field('ocean_model','brine_layer',diag%axesT1,time, &
2092  'Brine insertion layer','none')
2093  endif
2094 
2095 
2096  ! diagnostics for tendencies of temp and saln due to diabatic processes;
2097  ! available only for ALE algorithm.
2098  if (cs%useALEalgorithm) then
2099  cs%id_diabatic_diff_temp_tend = register_diag_field('ocean_model', &
2100  'diabatic_diff_temp_tendency', diag%axesTL, time, &
2101  'Diabatic diffusion temperature tendency', 'Degree C per second')
2102  if (cs%id_diabatic_diff_temp_tend > 0) then
2103  cs%diabatic_diff_tendency_diag = .true.
2104  endif
2105 
2106  cs%id_diabatic_diff_saln_tend = register_diag_field('ocean_model',&
2107  'diabatic_diff_saln_tendency', diag%axesTL, time, &
2108  'Diabatic diffusion salinity tendency', 'PPT per second')
2109  if (cs%id_diabatic_diff_saln_tend > 0) then
2110  cs%diabatic_diff_tendency_diag = .true.
2111  endif
2112 
2113  cs%id_diabatic_diff_heat_tend = register_diag_field('ocean_model', &
2114  'diabatic_heat_tendency', diag%axesTL, time, &
2115  'Diabatic diffusion heat tendency', &
2116  'Watts/m2',cmor_field_name='opottempdiff', cmor_units='W m-2', &
2117  cmor_standard_name= &
2118  'tendency_of_sea_water_potential_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing',&
2119  cmor_long_name = &
2120  'Tendency of sea water potential temperature expressed as heat content due to parameterized dianeutral mixing',&
2121  v_extensive=.true.)
2122  if (cs%id_diabatic_diff_heat_tend > 0) then
2123  cs%diabatic_diff_tendency_diag = .true.
2124  endif
2125 
2126  cs%id_diabatic_diff_salt_tend = register_diag_field('ocean_model', &
2127  'diabatic_salt_tendency', diag%axesTL, time, &
2128  'Diabatic diffusion of salt tendency', &
2129  'kg/(m2 * s)',cmor_field_name='osaltdiff', cmor_units='kg m-2 s-1', &
2130  cmor_standard_name= &
2131  'tendency_of_sea_water_salinity_expressed_as_salt_content_due_to_parameterized_dianeutral_mixing', &
2132  cmor_long_name = &
2133  'Tendency of sea water salinity expressed as salt content due to parameterized dianeutral mixing', &
2134  v_extensive=.true.)
2135  if (cs%id_diabatic_diff_salt_tend > 0) then
2136  cs%diabatic_diff_tendency_diag = .true.
2137  endif
2138 
2139  ! This diagnostic should equal to roundoff if all is working well.
2140  cs%id_diabatic_diff_heat_tend_2d = register_diag_field('ocean_model', &
2141  'diabatic_heat_tendency_2d', diag%axesT1, time, &
2142  'Depth integrated diabatic diffusion heat tendency', &
2143  'Watts/m2',cmor_field_name='opottempdiff_2d', cmor_units='W m-2', &
2144  cmor_standard_name= &
2145  'tendency_of_sea_water_potential_temperature_expressed_as_heat_content_due_to_parameterized_dianeutral_mixing_depth_integrated',&
2146  cmor_long_name = &
2147  'Tendency of sea water potential temperature expressed as heat content due to parameterized dianeutral mixing depth integrated')
2148  if (cs%id_diabatic_diff_heat_tend_2d > 0) then
2149  cs%diabatic_diff_tendency_diag = .true.
2150  endif
2151 
2152  ! This diagnostic should equal to roundoff if all is working well.
2153  cs%id_diabatic_diff_salt_tend_2d = register_diag_field('ocean_model', &
2154  'diabatic_salt_tendency_2d', diag%axesT1, time, &
2155  'Depth integrated diabatic diffusion salt tendency', &
2156  'kg/(m2 * s)',cmor_field_name='osaltdiff_2d', cmor_units='kg m-2 s-1', &
2157  cmor_standard_name= &
2158  'tendency_of_sea_water_salinity_expressed_as_salt_content_due_to_parameterized_dianeutral_mixing_depth_integrated',&
2159  cmor_long_name = &
2160  'Tendency of sea water salinity expressed as salt content due to parameterized dianeutral mixing depth integrated')
2161  if (cs%id_diabatic_diff_salt_tend_2d > 0) then
2162  cs%diabatic_diff_tendency_diag = .true.
2163  endif
2164 
2165  ! diagnostics for tendencies of temp and saln due to boundary forcing;
2166  ! available only for ALE algorithm.
2167  cs%id_boundary_forcing_temp_tend = register_diag_field('ocean_model',&
2168  'boundary_forcing_temp_tendency', diag%axesTL, time, &
2169  'Boundary forcing temperature tendency', 'Degree C per second')
2170  if (cs%id_boundary_forcing_temp_tend > 0) then
2171  cs%boundary_forcing_tendency_diag = .true.
2172  endif
2173 
2174  cs%id_boundary_forcing_saln_tend = register_diag_field('ocean_model',&
2175  'boundary_forcing_saln_tendency', diag%axesTL, time, &
2176  'Boundary forcing saln tendency', 'PPT per second')
2177  if (cs%id_boundary_forcing_saln_tend > 0) then
2178  cs%boundary_forcing_tendency_diag = .true.
2179  endif
2180 
2181  cs%id_boundary_forcing_heat_tend = register_diag_field('ocean_model',&
2182  'boundary_forcing_heat_tendency', diag%axesTL, time, &
2183  'Boundary forcing heat tendency','Watts/m2')
2184  if (cs%id_boundary_forcing_heat_tend > 0) then
2185  cs%boundary_forcing_tendency_diag = .true.
2186  endif
2187 
2188  cs%id_boundary_forcing_salt_tend = register_diag_field('ocean_model',&
2189  'boundary_forcing_salt_tendency', diag%axesTL, time, &
2190  'Boundary forcing salt tendency','kg m-2 s-1')
2191  if (cs%id_boundary_forcing_salt_tend > 0) then
2192  cs%boundary_forcing_tendency_diag = .true.
2193  endif
2194 
2195  ! This diagnostic should equal to surface heat flux if all is working well.
2196  cs%id_boundary_forcing_heat_tend_2d = register_diag_field('ocean_model',&
2197  'boundary_forcing_heat_tendency_2d', diag%axesT1, time, &
2198  'Depth integrated boundary forcing of ocean heat','Watts/m2')
2199  if (cs%id_boundary_forcing_heat_tend_2d > 0) then
2200  cs%boundary_forcing_tendency_diag = .true.
2201  endif
2202 
2203  ! This diagnostic should equal to surface salt flux if all is working well.
2204  cs%id_boundary_forcing_salt_tend_2d = register_diag_field('ocean_model',&
2205  'boundary_forcing_salt_tendency_2d', diag%axesT1, time, &
2206  'Depth integrated boundary forcing of ocean salt','kg m-2 s-1')
2207  if (cs%id_boundary_forcing_salt_tend_2d > 0) then
2208  cs%boundary_forcing_tendency_diag = .true.
2209  endif
2210  endif
2211 
2212  ! diagnostics for tendencies of temp and heat due to frazil
2213 
2214  ! diagnostic for tendency of temp due to frazil
2215  cs%id_frazil_temp_tend = register_diag_field('ocean_model',&
2216  'frazil_temp_tendency', diag%axesTL, time, &
2217  'Temperature tendency due to frazil formation', 'Degree C per second')
2218  if (cs%id_frazil_temp_tend > 0) then
2219  cs%frazil_tendency_diag = .true.
2220  endif
2221 
2222  ! diagnostic for tendency of heat due to frazil
2223  cs%id_frazil_heat_tend = register_diag_field('ocean_model',&
2224  'frazil_heat_tendency', diag%axesTL, time, &
2225  'Heat tendency due to frazil formation','Watts/m2')
2226  if (cs%id_frazil_heat_tend > 0) then
2227  cs%frazil_tendency_diag = .true.
2228  endif
2229 
2230  ! if all is working propertly, this diagnostic should equal to hfsifrazil
2231  cs%id_frazil_heat_tend_2d = register_diag_field('ocean_model',&
2232  'frazil_heat_tendency_2d', diag%axesT1, time, &
2233  'Depth integrated heat tendency due to frazil formation','Watts/m2')
2234  if (cs%id_frazil_heat_tend_2d > 0) then
2235  cs%frazil_tendency_diag = .true.
2236  endif
2237 
2238  if (cs%frazil_tendency_diag) then
2239  allocate(cs%frazil_temp_diag(isd:ied,jsd:jed,nz) ) ; cs%frazil_temp_diag(:,:,:) = 0.
2240  allocate(cs%frazil_heat_diag(isd:ied,jsd:jed,nz) ) ; cs%frazil_heat_diag(:,:,:) = 0.
2241  endif
2242 
2243 
2244  ! CS%useConvection is set to True IF convection will be used, otherwise False.
2245  ! CS%Conv_CSp is allocated by diffConvection_init()
2246  cs%useConvection = diffconvection_init(param_file, g, diag, time, cs%Conv_CSp)
2247 
2248  call entrain_diffusive_init(time, g, gv, param_file, diag, cs%entrain_diffusive_CSp)
2249 
2250  ! initialize the geothermal heating module
2251  if (cs%use_geothermal) &
2252  call geothermal_init(time, g, param_file, diag, cs%geothermal_CSp)
2253 
2254  ! initialize module for internal tide induced mixing
2255  if (cs%use_int_tides) then
2256  call int_tide_input_init(time, g, gv, param_file, diag, cs%int_tide_input_CSp, &
2257  cs%int_tide_input)
2258  call internal_tides_init(time, g, gv, param_file, diag, cs%int_tide_CSp)
2259  endif
2260 
2261  ! initialize module for setting diffusivities
2262  call set_diffusivity_init(time, g, gv, param_file, diag, cs%set_diff_CSp, diag_to_z_csp, cs%int_tide_CSp)
2263 
2264 
2265  ! set up the clocks for this module
2266  id_clock_entrain = cpu_clock_id('(Ocean diabatic entrain)', grain=clock_module)
2267  if (cs%bulkmixedlayer) &
2268  id_clock_mixedlayer = cpu_clock_id('(Ocean mixed layer)', grain=clock_module)
2269  id_clock_remap = cpu_clock_id('(Ocean vert remap)', grain=clock_module)
2270  if (cs%use_geothermal) &
2271  id_clock_geothermal = cpu_clock_id('(Ocean geothermal)', grain=clock_routine)
2272  id_clock_set_diffusivity = cpu_clock_id('(Ocean set_diffusivity)', grain=clock_module)
2273  id_clock_kpp = cpu_clock_id('(Ocean KPP)', grain=clock_module)
2274  id_clock_tracers = cpu_clock_id('(Ocean tracer_columns)', grain=clock_module_driver+5)
2275  if (cs%use_sponge) &
2276  id_clock_sponge = cpu_clock_id('(Ocean sponges)', grain=clock_module)
2277  id_clock_tridiag = cpu_clock_id('(Ocean diabatic tridiag)', grain=clock_routine)
2278  id_clock_pass = cpu_clock_id('(Ocean diabatic message passing)', grain=clock_routine)
2279  id_clock_differential_diff = -1 ; if (differentialdiffusion) &
2280  id_clock_differential_diff = cpu_clock_id('(Ocean differential diffusion)', grain=clock_routine)
2281 
2282  ! initialize the auxiliary diabatic driver module
2283  call diabatic_aux_init(time, g, gv, param_file, diag, cs%diabatic_aux_CSp, &
2284  cs%useALEalgorithm, cs%use_energetic_PBL)
2285 
2286  ! initialize the boundary layer modules
2287  if (cs%bulkmixedlayer) &
2288  call bulkmixedlayer_init(time, g, gv, param_file, diag, cs%bulkmixedlayer_CSp)
2289  if (cs%use_energetic_PBL) &
2290  call energetic_pbl_init(time, g, gv, param_file, diag, cs%energetic_PBL_CSp)
2291 
2292  call regularize_layers_init(time, g, param_file, diag, cs%regularize_layers_CSp)
2293 
2294  if (cs%debug_energy_req) &
2295  call diapyc_energy_req_init(time, g, param_file, diag, cs%diapyc_en_rec_CSp)
2296 
2297  ! obtain information about the number of bands for penetrative shortwave
2298  if (use_temperature) then
2299  call get_param(param_file, mod, "PEN_SW_NBANDS", nbands, default=1)
2300  if (nbands > 0) then
2301  allocate(cs%optics)
2302  call opacity_init(time, g, param_file, diag, cs%tracer_flow_CSp, cs%opacity_CSp, cs%optics)
2303  endif
2304  endif
2305  cs%nsw = 0
2306  if (ASSOCIATED(cs%optics)) cs%nsw = cs%optics%nbands
2307 
2308 
2309 end subroutine diabatic_driver_init
2310 
2311 
2312 !> Routine to close the diabatic driver module
2313 subroutine diabatic_driver_end(CS)
2314  type(diabatic_cs), pointer :: CS !< module control structure
2315 
2316  if (.not.associated(cs)) return
2317 
2318  call diabatic_aux_end(cs%diabatic_aux_CSp)
2319 
2320  call entrain_diffusive_end(cs%entrain_diffusive_CSp)
2321  call set_diffusivity_end(cs%set_diff_CSp)
2322  if (cs%useKPP) then
2323  deallocate( cs%KPP_buoy_flux )
2324  deallocate( cs%KPP_temp_flux )
2325  deallocate( cs%KPP_salt_flux )
2326  endif
2327  if (cs%useKPP) then
2328  deallocate( cs%KPP_NLTheat )
2329  deallocate( cs%KPP_NLTscalar )
2330  call kpp_end(cs%KPP_CSp)
2331  endif
2332  if (cs%useConvection) call diffconvection_end(cs%Conv_CSp)
2333  if (cs%use_energetic_PBL) &
2334  call energetic_pbl_end(cs%energetic_PBL_CSp)
2335  if (cs%debug_energy_req) &
2336  call diapyc_energy_req_end(cs%diapyc_en_rec_CSp)
2337 
2338  if (associated(cs%optics)) then
2339  call opacity_end(cs%opacity_CSp, cs%optics)
2340  deallocate(cs%optics)
2341  endif
2342  if (associated(cs)) deallocate(cs)
2343 
2344 end subroutine diabatic_driver_end
2345 
2346 
2347 !> \namespace mom_diabatic_driver
2348 !!
2349 !! By Robert Hallberg, Alistair Adcroft, and Stephen Griffies
2350 !!
2351 !! This program contains the subroutine that, along with the
2352 !! subroutines that it calls, implements diapycnal mass and momentum
2353 !! fluxes and a bulk mixed layer. The diapycnal diffusion can be
2354 !! used without the bulk mixed layer.
2355 !!
2356 !! \section section_diabatic Outline of MOM diabatic
2357 !!
2358 !! * diabatic first determines the (diffusive) diapycnal mass fluxes
2359 !! based on the convergence of the buoyancy fluxes within each layer.
2360 !!
2361 !! * The dual-stream entrainment scheme of MacDougall and Dewar (JPO,
2362 !! 1997) is used for combined diapycnal advection and diffusion,
2363 !! calculated implicitly and potentially with the Richardson number
2364 !! dependent mixing, as described by Hallberg (MWR, 2000).
2365 !!
2366 !! * Diapycnal advection is the residual of diapycnal diffusion,
2367 !! so the fully implicit upwind differencing scheme that is used is
2368 !! entirely appropriate.
2369 !!
2370 !! * The downward buoyancy flux in each layer is determined from
2371 !! an implicit calculation based on the previously
2372 !! calculated flux of the layer above and an estimated flux in the
2373 !! layer below. This flux is subject to the following conditions:
2374 !! (1) the flux in the top and bottom layers are set by the boundary
2375 !! conditions, and (2) no layer may be driven below an Angstrom thick-
2376 !! ness. If there is a bulk mixed layer, the buffer layer is treated
2377 !! as a fixed density layer with vanishingly small diffusivity.
2378 !!
2379 !! diabatic takes 5 arguments: the two velocities (u and v), the
2380 !! thicknesses (h), a structure containing the forcing fields, and
2381 !! the length of time over which to act (dt). The velocities and
2382 !! thickness are taken as inputs and modified within the subroutine.
2383 !! There is no limit on the time step.
2384 
2385 end module mom_diabatic_driver
subroutine, public differential_diffuse_t_s(h, tv, visc, dt, G, GV)
subroutine, public geothermal(h, tv, dt, ea, eb, G, GV, CS)
This subroutine applies geothermal heating, including the movement of water between isopycnal layers ...
subroutine, public set_diffusivity_end(CS)
subroutine, public opacity_init(Time, G, param_file, diag, tracer_flow, CS, optics)
subroutine, public diabatic_aux_init(Time, G, GV, param_file, diag, CS, useALEalgorithm, use_ePBL)
subroutine, public diapyc_energy_req_init(Time, G, param_file, diag, CS)
type(vardesc) function, public var_desc(name, units, longname, hor_grid, z_grid, t_grid, cmor_field_name, cmor_units, conversion, caller)
Returns a vardesc type whose elements have been filled with the provided fields. The argument name is...
Definition: MOM_io.F90:585
subroutine, public opacity_end(CS, optics)
subroutine, public apply_ale_sponge(h, dt, G, CS)
This subroutine applies damping to the layers thicknesses, temp, salt and a variety of tracers for ev...
subroutine, public int_tide_input_init(Time, G, GV, param_file, diag, CS, itide)
This module implements boundary forcing for MOM6.
Interface to CVMix interior shear schemes.
subroutine, public insert_brine(h, tv, G, GV, fluxes, nkmb, CS, dt, id_brine_lay)
logical function, public diffconvection_init(paramFile, G, diag, Time, CS)
subroutine, public set_opacity(optics, fluxes, G, GV, CS)
subroutine, public internal_tides_init(Time, G, GV, param_file, diag, CS)
integer, parameter, public to_all
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:19
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
subroutine, public adiabatic_driver_init(Time, G, param_file, diag, CS, tracer_flow_CSp, diag_to_Z_CSp)
A simplified version of diabatic_driver_init that will allow tracer column functions to be called wit...
subroutine, public diapyc_energy_req_end(CS)
subroutine, public diffconvection_calculate(CS, G, GV, h, Temp, Salt, EOS, Kd_int)
subroutine, public diabatic(u, v, h, tv, Hml, fluxes, visc, ADp, CDp, dt, G, GV, CS)
This subroutine imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentu...
subroutine, public energetic_pbl_end(CS)
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
Calculates the freezing point of sea water from T, S and P.
Definition: MOM_EOS.F90:50
subroutine, public bulkmixedlayer_init(Time, G, GV, param_file, diag, CS)
subroutine, public mom_thermovar_chksum(mesg, tv, G)
MOM_thermovar_chksum does diagnostic checksums on various elements of a thermo_var_ptrs type for debu...
Provides the ocean grid type.
Definition: MOM_grid.F90:2
subroutine, public do_group_pass(group, MOM_dom)
subroutine, public absorbremainingsw(G, GV, h, opacity_band, nsw, j, dt, H_limit_fluxes, adjustAbsorptionProfile, absorbAllSW, T, Pen_SW_bnd, eps, ksort, htot, Ttot, TKE, dSV_dT)
Apply shortwave heating below surface boundary layer.
subroutine, public entrainment_diffusive(u, v, h, tv, fluxes, dt, G, GV, CS, ea, eb, kb_out, Kd_Lay, Kd_int)
This subroutine calculates ea and eb, the rates at which a layer entrains from the layers above and b...
The vertvisc_type structure contains vertical viscosities, drag coefficients, and related fields...
subroutine, public call_tracer_column_fns(h_old, h_new, ea, eb, fluxes, Hml, dt, G, GV, tv, optics, CS, debug, evap_CFL_limit, minimum_forcing_depth)
This subroutine calls all registered tracer column physics subroutines.
subroutine, public mom_forcing_chksum(mesg, fluxes, G, haloshift)
Write out chksums for basic state variables.
This routine drives the diabatic/dianeutral physics for MOM.
subroutine, public diffconvection_end(CS)
subroutine, public energetic_pbl(h_3d, u_3d, v_3d, tv, fluxes, dt, Kd_int, G, GV, CS, dSV_dT, dSV_dS, TKE_forced, Buoy_Flux, dt_diag, last_call, dT_expected, dS_expected)
This subroutine determines the diffusivities from the integrated energetics mixed layer model...
Routines for calculating baroclinic wave speeds.
subroutine, public calculate_specific_vol_derivs(T, S, pressure, dSV_dT, dSV_dS, start, npts, EOS)
Calls the appropriate subroutine to calculate specific volume derivatives for an array.
Definition: MOM_EOS.F90:247
subroutine, public calltree_leave(mesg)
Writes a message about leaving a subroutine if call tree reporting is active.
subroutine, public internal_tides_end(CS)
This module contains I/O framework code.
Definition: MOM_io.F90:2
Control structure for containing KPP parameters/data.
Definition: MOM_KPP.F90:48
The accel_diag_ptrs structure contains pointers to arrays with accelerations, which can later be used...
subroutine, public set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, optics, visc, dt, G, GV, CS, Kd, Kd_int)
This module contains the routines used to apply sponge layers when using the ALE mode. Applying sponges requires the following: (1) initialize_ALE_sponge (2) set_up_ALE_sponge_field (tracers) and set_up_ALE_sponge_vel_field (vel) (3) apply_ALE_sponge (4) init_ALE_sponge_diags (not being used for now) (5) ALE_sponge_end (not being used for now)
subroutine, public int_tide_input_end(CS)
SPONGE control structure.
subroutine, public applyboundaryfluxesinout(CS, G, GV, dt, fluxes, optics, h, tv, aggregate_FW_forcing, evap_CFL_limit, minimum_forcing_depth, cTKE, dSV_dT, dSV_dS, SkinBuoyFlux)
Update the thickness, temperature, and salinity due to thermodynamic boundary forcing (contained in f...
subroutine, public mom_state_stats(mesg, u, v, h, Temp, Salt, G, allowChange, permitDiminishing)
subroutine, public kpp_calculate(CS, G, GV, h, Temp, Salt, u, v, EOS, uStar, buoyFlux, Kt, Ks, Kv, nonLocalTransHeat, nonLocalTransScalar)
KPP vertical diffusivity/viscosity and non-local tracer transport.
Definition: MOM_KPP.F90:413
subroutine, public extract_diabatic_member(CS, opacity_CSp, optics_CSp, evap_CFL_limit, minimum_forcing_depth)
Returns pointers or values of members within the diabatic_CS type. For extensibility, each returned argument is an optional argument.
subroutine, public set_diffusivity_init(Time, G, GV, param_file, diag, CS, diag_to_Z_CSp, int_tide_CSp)
logical function, public query_averaging_enabled(diag_cs, time_int, time_end)
subroutine diagnose_diabatic_diff_tendency(tv, h, temp_old, saln_old, dt, G, GV, CS)
This routine diagnoses tendencies from application of diabatic diffusion using ALE algorithm...
subroutine, public propagate_int_tide(h, tv, cn, TKE_itidal_input, vel_btTide, Nb, dt, G, GV, CS)
This subroutine calls other subroutines in this file that are needed to refract, propagate, and dissipate energy density of the internal tide.
subroutine, public geothermal_end(CS)
subroutine, public calltree_waypoint(mesg, n)
Writes a message about reaching a milestone if call tree reporting is active.
subroutine diagnose_boundary_forcing_tendency(tv, h, temp_old, saln_old, h_old, dt, G, GV, CS)
This routine diagnoses tendencies from application of boundary fluxes. These impacts are generally 3d...
Control structure for diabatic_aux.
subroutine, public entrain_diffusive_end(CS)
The cont_diag_ptrs structure contains pointers to arrays with transports, which can later be used for...
This module contains routines that implement physical fluxes of tracers (e.g. due to surface fluxes o...
subroutine, public regularize_layers_init(Time, G, param_file, diag, CS)
subroutine, public diabatic_driver_end(CS)
Routine to close the diabatic driver module.
subroutine, public find_uv_at_h(u, v, h, u_h, v_h, G, GV, ea, eb)
subroutine, public diapyc_energy_req_calc(h_in, T_in, S_in, Kd, energy_Kd, dt, tv, G, GV, may_print, CS)
This subroutine uses a substantially refactored tridiagonal equation for diapycnal mixing of temperat...
subroutine, public kpp_end(CS)
Clear pointers, deallocate memory.
Definition: MOM_KPP.F90:1062
subroutine, public adiabatic(h, tv, fluxes, dt, G, GV, CS)
Routine called for adiabatic physics.
subroutine, public calculatebuoyancyflux2d(G, GV, fluxes, optics, h, Temp, Salt, tv, buoyancyFlux, netHeatMinusSW, netSalt, skip_diags)
Calculates surface buoyancy flux by adding up the heat, FW and salt fluxes, for 2d arrays...
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
subroutine, public geothermal_init(Time, G, param_file, diag, CS)
subroutine, public diapyc_energy_req_test(h_3d, dt, tv, G, GV, CS, Kd_int)
subroutine, public mom_mesg(message, verb, all_print)
logical function, public kpp_init(paramFile, G, diag, Time, CS, passive)
Initialize the CVmix KPP module and set up diagnostics Returns True if KPP is to be used...
Definition: MOM_KPP.F90:133
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
subroutine, public kpp_nonlocaltransport_temp(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar, C_p)
Apply KPP non-local transport of surface fluxes for temperature.
Definition: MOM_KPP.F90:944
logical function, public calltree_showquery()
Returns True, if the verbosity>=6 indicating to show the call tree.
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:51
Control structure for this module.
subroutine, public tracer_vertdiff(h_old, ea, eb, dt, tr, G, GV, sfc_flux, btm_flux, btm_reservoir, sink_rate, convert_flux_in)
This subroutine solves a tridiagonal equation for the final tracer concentrations after the dual-entr...
subroutine, public wave_speeds(h, tv, G, GV, nmodes, cn, CS, full_halos)
Calculates the wave speeds for the first few barolinic modes.
subroutine, public entrain_diffusive_init(Time, G, GV, param_file, diag, CS)
subroutine, public regularize_layers(h, tv, dt, ea, eb, G, GV, CS)
This subroutine partially steps the bulk mixed layer model. The following processes are executed...
subroutine, public set_bbl_tke(u, v, h, fluxes, visc, G, GV, CS)
This subroutine calculates several properties related to bottom boundary layer turbulence.
logical function, public cvmix_shear_is_used(param_file)
Reads the parameters "LMD94" and "PP81" and returns state. This function allows other modules to know...
subroutine, public kpp_nonlocaltransport_saln(CS, G, GV, h, nonLocalTrans, surfFlux, dt, scalar)
Apply KPP non-local transport of surface fluxes for salinity. This routine is a useful prototype for ...
Definition: MOM_KPP.F90:1003
subroutine, public diabatic_aux_end(CS)
subroutine, public apply_sponge(h, dt, G, GV, ea, eb, CS, Rcv_ml)
Definition: MOM_sponge.F90:380
The thermo_var_ptrs structure contains pointers to an assortment of thermodynamic fields that may be ...
subroutine, public set_int_tide_input(u, v, h, tv, fluxes, itide, dt, G, GV, CS)
Provides the K-Profile Parameterization (KPP) of Large et al., 1994, via CVMix.
Definition: MOM_KPP.F90:2
integer function, public register_zint_diag(var_desc, CS, day)
subroutine, public tridiagts(G, GV, is, ie, js, je, hold, ea, eb, T, S)
subroutine, public diagnosemldbydensitydifference(id_MLD, h, tv, densityDiff, G, GV, diagPtr, id_N2subML, id_MLDsq)
Diagnose a mixed layer depth (MLD) determined by a given density difference with the surface...
subroutine, public energetic_pbl_get_mld(CS, MLD, G)
Copies the ePBL active mixed layer depth into MLD.
subroutine, public make_frazil(h, tv, G, GV, CS, p_surf)
subroutine, public bulkmixedlayer(h_3d, u_3d, v_3d, tv, fluxes, dt, ea, eb, G, GV, CS, optics, Hml, aggregate_FW_forcing, dt_diag, last_call)
This subroutine partially steps the bulk mixed layer model. The following processes are executed...
subroutine, public adjust_salt(h, tv, G, GV, CS)
integer function, public register_diag_field(module_name, field_name, axes, init_time, long_name, units, missing_value, range, mask_variant, standard_name, verbose, do_not_log, err_msg, interp_method, tile_count, cmor_field_name, cmor_long_name, cmor_units, cmor_standard_name, cell_methods, x_cell_method, y_cell_method, v_cell_method, conversion, v_extensive)
Returns the "diag_mediator" handle for a group (native, CMOR, z-coord, ...) of diagnostics derived fr...
subroutine, public mom_error(level, message, all_print)
subroutine, public energetic_pbl_init(Time, G, GV, param_file, diag, CS)
subroutine, public calc_zint_diags(h, in_ptrs, ids, num_diags, G, GV, CS)
logical function, public kappa_shear_is_used(param_file)
subroutine diagnose_frazil_tendency(tv, h, temp_old, dt, G, GV, CS, ncall)
This routine diagnoses tendencies for temperature and heat from frazil formation. This routine is cal...
subroutine, public forcing_singlepointprint(fluxes, G, i, j, mesg)
Write out values of the fluxes arrays at the i,j location. This is a debugging tool.
subroutine, public diag_update_remap_grids(diag_cs, alt_h)
Build/update vertical grids for diagnostic remapping.
subroutine, public diabatic_driver_init(Time, G, GV, param_file, useALEalgorithm, diag, ADp, CDp, CS, tracer_flow_CSp, sponge_CSp, ALE_sponge_CSp, diag_to_Z_CSp)
This routine initializes the diabatic driver module.
subroutine, public calltree_enter(mesg, n)
Writes a message about entering a subroutine if call tree reporting is active.