← back to index

src/parameterizations/vertical/MOM_diabatic_driver.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> This routine drives the diabatic/dianeutral physics for MOM
6module MOM_diabatic_driver
7
8use MOM_bulk_mixed_layer, only : bulkmixedlayer, bulkmixedlayer_init, bulkmixedlayer_CS
9use MOM_debugging, only : hchksum
10use MOM_checksum_packages, only : MOM_state_chksum, MOM_state_stats
11use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
12use MOM_cpu_clock, only : CLOCK_MODULE_DRIVER, CLOCK_MODULE, CLOCK_ROUTINE
13use MOM_CVMix_shear, only : CVMix_shear_is_used
14use MOM_CVMix_ddiff, only : CVMix_ddiff_is_used
15use MOM_diabatic_aux, only : diabatic_aux_init, diabatic_aux_end, diabatic_aux_CS
16use MOM_diabatic_aux, only : make_frazil, adjust_salt, differential_diffuse_T_S, triDiagTS
17use MOM_diabatic_aux, only : triDiagTS_Eulerian, find_uv_at_h
18use MOM_diabatic_aux, only : applyBoundaryFluxesInOut, set_pen_shortwave
19use MOM_diag_mediator, only : post_data, register_diag_field, safe_alloc_ptr
20use MOM_diag_mediator, only : post_product_sum_u, post_product_sum_v
21use MOM_diag_mediator, only : diag_ctrl, time_type, diag_update_remap_grids
22use MOM_diag_mediator, only : diag_ctrl, query_averaging_enabled, enable_averages, disable_averaging
23use MOM_diag_mediator, only : diag_grid_storage, diag_grid_storage_init, diag_grid_storage_end
24use MOM_diag_mediator, only : diag_copy_diag_to_storage, diag_copy_storage_to_diag
25use MOM_diag_mediator, only : diag_save_grids, diag_restore_grids
26use MOM_diagnose_mld, only : diagnoseMLDbyDensityDifference, diagnoseMLDbyEnergy
27use MOM_diagnose_kdwork, only : vbf_CS, KdWork_init, KdWork_end, KdWork_diagnostics
28use MOM_diagnose_kdwork, only : Allocate_VBF_CS, Deallocate_VBF_CS
29use MOM_diapyc_energy_req, only : diapyc_energy_req_init, diapyc_energy_req_end
30use MOM_diapyc_energy_req, only : diapyc_energy_req_calc, diapyc_energy_req_test, diapyc_energy_req_CS
31use MOM_CVMix_conv, only : CVMix_conv_init, CVMix_conv_cs
32use MOM_CVMix_conv, only : calculate_CVMix_conv
33use MOM_domains, only : pass_var, To_West, To_South, To_All, Omit_Corners
34use MOM_domains, only : create_group_pass, do_group_pass, group_pass_type
35use MOM_energetic_PBL, only : energetic_PBL, energetic_PBL_init
36use MOM_energetic_PBL, only : energetic_PBL_end, energetic_PBL_CS
37use MOM_energetic_PBL, only : energetic_PBL_get_MLD
38use MOM_entrain_diffusive, only : entrainment_diffusive, entrain_diffusive_init
39use MOM_entrain_diffusive, only : entrain_diffusive_CS
40use MOM_EOS, only : calculate_density, calculate_density_derivs, calculate_TFreeze
41use MOM_EOS, only : calculate_specific_vol_derivs, EOS_domain
42use MOM_error_handler, only : MOM_error, FATAL, WARNING, callTree_showQuery,MOM_mesg
43use MOM_error_handler, only : callTree_enter, callTree_leave, callTree_waypoint
44use MOM_file_parser, only : get_param, log_version, param_file_type, read_param
45use MOM_forcing_type, only : forcing, MOM_forcing_chksum, find_ustar
46use MOM_forcing_type, only : calculateBuoyancyFlux2d, forcing_SinglePointPrint
47use MOM_geothermal, only : geothermal_entraining, geothermal_in_place
48use MOM_geothermal, only : geothermal_init, geothermal_end, geothermal_CS
49use MOM_grid, only : ocean_grid_type
50use MOM_int_tide_input, only : set_int_tide_input, int_tide_input_init
51use MOM_int_tide_input, only : int_tide_input_end, int_tide_input_CS, int_tide_input_type
52use MOM_interface_heights, only : find_eta, calc_derived_thermo, thickness_to_dz
53use MOM_interface_heights, only : convert_MLD_to_ML_thickness
54use MOM_internal_tides, only : propagate_int_tide, register_int_tide_restarts
55use MOM_internal_tides, only : internal_tides_init, internal_tides_end, int_tide_CS
56use MOM_kappa_shear, only : kappa_shear_is_used
57use MOM_CVMix_KPP, only : KPP_CS, KPP_init, KPP_compute_BLD, KPP_calculate
58use MOM_CVMix_KPP, only : KPP_end, KPP_get_BLD, register_KPP_restarts
59use MOM_CVMix_KPP, only : KPP_NonLocalTransport_temp, KPP_NonLocalTransport_saln
60use MOM_oda_incupd, only : apply_oda_incupd, oda_incupd_CS
61use MOM_opacity, only : opacity_init, opacity_end, opacity_CS
62use MOM_opacity, only : absorbRemainingSW, optics_type, optics_nbands
63use MOM_open_boundary, only : ocean_OBC_type
64use MOM_regularize_layers, only : regularize_layers, regularize_layers_init, regularize_layers_CS
65use MOM_restart, only : MOM_restart_CS
66use MOM_set_diffusivity, only : set_diffusivity, set_BBL_TKE
67use MOM_set_diffusivity, only : set_diffusivity_init, set_diffusivity_end
68use MOM_set_diffusivity, only : set_diffusivity_CS
69use MOM_sponge, only : apply_sponge, sponge_CS
70use MOM_ALE_sponge, only : apply_ALE_sponge, ALE_sponge_CS
71use MOM_time_manager, only : time_type, real_to_time, operator(-), operator(<=)
72use MOM_tracer_flow_control, only : call_tracer_column_fns, tracer_flow_control_CS
73use MOM_tracer_diabatic, only : tracer_vertdiff, tracer_vertdiff_Eulerian
74use MOM_unit_scaling, only : unit_scale_type
75use MOM_variables, only : thermo_var_ptrs, vertvisc_type, accel_diag_ptrs
76use MOM_variables, only : cont_diag_ptrs, MOM_thermovar_chksum, p3d
77use MOM_verticalGrid, only : verticalGrid_type, get_thickness_units
78use MOM_wave_interface, only : wave_parameters_CS
79use MOM_stochastics, only : stochastic_CS
80
81implicit none ; private
82
83#include <MOM_memory.h>
84
85public diabatic
86public diabatic_driver_init
87public diabatic_driver_end
88public extract_diabatic_member
89public adiabatic
90public adiabatic_driver_init
91public register_diabatic_restarts
92
93! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
94! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
95! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
96! vary with the Boussinesq approximation, the Boussinesq variant is given first.
97
98!> Control structure for this module
99type, public :: diabatic_CS ; private
100 logical :: initialized = .false. !< True if this control structure has been initialized.
101
102 logical :: use_legacy_diabatic !< If true (default), use a legacy version of the diabatic
103 !! algorithm. This is temporary and is needed to avoid change
104 !! in answers.
105 logical :: use_bulkmixedlayer !< If true, a refined bulk mixed layer is used with
106 !! nkml sublayers (and additional buffer layers).
107 logical :: use_energetic_PBL !< If true, use the implicit energetics planetary
108 !! boundary layer scheme to determine the diffusivity
109 !! in the surface boundary layer.
110 logical :: use_KPP !< If true, use CVMix/KPP boundary layer scheme to determine the
111 !! OBLD and the diffusivities within this layer.
112 logical :: use_kappa_shear !< If true, use the kappa_shear module to find the
113 !! shear-driven diapycnal diffusivity.
114 logical :: use_CVMix_shear !< If true, use the CVMix module to find the
115 !! shear-driven diapycnal diffusivity.
116 logical :: use_CVMix_ddiff !< If true, use the CVMix double diffusion module.
117 logical :: use_CVMix_conv !< If true, use the CVMix module to get enhanced
118 !! mixing due to convection.
119 logical :: double_diffuse !< If true, some form of double-diffusive mixing is used.
120 logical :: use_sponge !< If true, sponges may be applied anywhere in the
121 !! domain. The exact location and properties of
122 !! those sponges are set by calls to
123 !! initialize_sponge and set_up_sponge_field.
124 logical :: use_oda_incupd !< If True, DA incremental update is
125 !! applied everywhere
126 logical :: use_geothermal !< If true, apply geothermal heating.
127 logical :: use_int_tides !< If true, use the code that advances a separate set
128 !! of equations for the internal tide energy density.
129 logical :: ePBL_is_additive !< If true, the diffusivity from ePBL is added to all
130 !! other diffusivities. Otherwise, the larger of kappa-
131 !! shear and ePBL diffusivities are used.
132 real :: ePBL_Prandtl !< The Prandtl number used by ePBL to convert vertical
133 !! diffusivities into viscosities [nondim].
134 logical :: useALEalgorithm !< If true, use the ALE algorithm rather than layered
135 !! isopycnal/stacked shallow water mode. This logical
136 !! passed by argument to diabatic_driver_init.
137 logical :: aggregate_FW_forcing !< Determines whether net incoming/outgoing surface
138 !! FW fluxes are applied separately or combined before
139 !! being applied.
140 real :: ML_mix_first !< The nondimensional fraction of the mixed layer
141 !! algorithm that is applied before diffusive mixing [nondim].
142 !! The default is 0, while 0.5 gives Strang splitting
143 !! and 1 is a sensible value too. Note that if there
144 !! are convective instabilities in the initial state,
145 !! the first call may do much more than the second.
146 integer :: NKBL !< The number of buffer layers (if bulk_mixed_layer)
147 logical :: massless_match_targets !< If true (the default), keep the T & S
148 !! consistent with the target values.
149 logical :: mix_boundary_tracers !< If true, mix the passive tracers in massless layers at the
150 !! bottom into the interior as though a diffusivity of
151 !! Kd_min_tr (see below) were operating.
152 logical :: mix_boundary_tracer_ALE !< If true, in ALE mode mix the passive tracers in massless
153 !! layers at the bottom into the interior as though a
154 !! diffusivity of Kd_min_tr (see below) were operating.
155 real :: Kd_BBL_tr !< A bottom boundary layer tracer diffusivity that
156 !! will allow for explicitly specified bottom fluxes
157 !! [H2 T-1 ~> m2 s-1 or kg2 m-4 s-1]. The entrainment at the
158 !! bottom is at least sqrt(Kd_BBL_tr*dt) over the same distance.
159 real :: Kd_min_tr !< A minimal diffusivity that should always be
160 !! applied to tracers, especially in massless layers
161 !! near the bottom [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
162 real :: minimum_forcing_depth !< The smallest depth over which heat and freshwater
163 !! fluxes are applied [H ~> m or kg m-2].
164 real :: evap_CFL_limit = 0.8 !< The largest fraction of a layer that can be
165 !! evaporated in one time-step [nondim].
166 integer :: halo_TS_diff = 0 !< The temperature, salinity and thickness halo size that
167 !! must be valid for the diffusivity calculations.
168 integer :: halo_diabatic = 0 !< The temperature, salinity, specific volume and thickness
169 !! halo size that must be valid for the diabatic calculations,
170 !! including vertical mixing and internal tide propagation.
171 logical :: useKPP = .false. !< use CVMix/KPP diffusivities and non-local transport
172 logical :: KPPisPassive !< If true, KPP is in passive mode, not changing answers.
173 logical :: debug !< If true, write verbose checksums for debugging purposes.
174 logical :: debugConservation !< If true, monitor conservation and extrema.
175 logical :: tracer_tridiag !< If true, use tracer_vertdiff instead of tridiagTS for
176 !< vertical diffusion of T and S
177 logical :: debug_energy_req !< If true, test the mixing energy requirement code.
178 type(diag_ctrl), pointer :: diag !< structure used to regulate timing of diagnostic output
179 real :: MLDdensityDifference !< Density difference used to determine MLD_user [R ~> kg m-3]
180 real :: dz_subML_N2 !< The distance over which to calculate a diagnostic of the
181 !! average stratification at the base of the mixed layer [Z ~> m].
182 real :: MLD_En_vals(3) !< Energy values for energy mixed layer diagnostics [R Z3 T-2 ~> J m-2]
183 real :: BMLD_En_vals(3) !< Energy values for energy bottom mixed layer diagnostics [R Z3 T-2 ~> J m-2]
184 logical :: use_OM4_MLD_En_iter !< If true, uses an older iteration in the energetics MLD calculation to bitwise
185 !! reproduce OM4 era models
186 real :: ref_h_mld = 0.0 !< The depth of the "surface" density used in a difference mixed based
187 !! MLD calculation [Z ~> m].
188 logical :: Use_KdWork_diag = .false. !< Logical flag to indicate if any Kd_work diagnostics are on.
189 logical :: Use_N2_diag = .false. !< Logical flag to indicate if any N2 diagnostics are on.
190
191 !>@{ Diagnostic IDs
192 integer :: id_ea = -1, id_eb = -1 ! used by layer diabatic
193 integer :: id_ea_t = -1, id_eb_t = -1, id_ea_s = -1, id_eb_s = -1
194 integer :: id_Kd_heat = -1, id_Kd_salt = -1, id_Kd_int = -1, id_Kd_ePBL = -1
195 integer :: id_Tdif = -1, id_Sdif = -1, id_Tadv = -1, id_Sadv = -1
196 integer :: id_N2_dd = -1, id_N2_salt_dd = -1, id_N2_temp_dd
197 ! These are handles to diagnostics related to the mixed layer properties.
198 integer :: id_MLD_003 = -1, id_MLD_0125 = -1, id_MLD_user = -1, id_mlotstsq = -1
199 integer :: id_MLD_003_zr = -1, id_MLD_003_rr = -1
200 integer :: id_MLD_EN1 = -1, id_MLD_EN2 = -1, id_MLD_EN3 = -1, id_subMLN2 = -1
201 integer :: id_BMLD_EN1 = -1, id_BMLD_EN2 = -1, id_BMLD_EN3 = -1
202
203 ! These are handles to diagnostics that are only available in non-ALE layered mode.
204 integer :: id_wd = -1
205 integer :: id_dudt_dia = -1, id_dvdt_dia = -1
206 integer :: id_hf_dudt_dia_2d = -1, id_hf_dvdt_dia_2d = -1
207
208 ! diagnostic for fields prior to applying diapycnal physics
209 integer :: id_u_predia = -1, id_v_predia = -1, id_h_predia = -1
210 integer :: id_T_predia = -1, id_S_predia = -1, id_e_predia = -1
211
212 integer :: id_diabatic_diff_temp_tend = -1
213 integer :: id_diabatic_diff_saln_tend = -1
214 integer :: id_diabatic_diff_heat_tend = -1
215 integer :: id_diabatic_diff_salt_tend = -1
216 integer :: id_diabatic_diff_heat_tend_2d = -1
217 integer :: id_diabatic_diff_salt_tend_2d = -1
218 integer :: id_diabatic_diff_h = -1
219
220 integer :: id_boundary_forcing_h = -1
221 integer :: id_boundary_forcing_h_tendency = -1
222 integer :: id_boundary_forcing_temp_tend = -1
223 integer :: id_boundary_forcing_saln_tend = -1
224 integer :: id_boundary_forcing_heat_tend = -1
225 integer :: id_boundary_forcing_salt_tend = -1
226 integer :: id_boundary_forcing_heat_tend_2d = -1
227 integer :: id_boundary_forcing_salt_tend_2d = -1
228
229 integer :: id_frazil_h = -1
230 integer :: id_frazil_temp_tend = -1
231 integer :: id_frazil_heat_tend = -1
232 integer :: id_frazil_heat_tend_2d = -1
233 !>@}
234
235 logical :: diabatic_diff_tendency_diag = .false. !< If true calculate diffusive tendency diagnostics
236 logical :: boundary_forcing_tendency_diag = .false. !< If true calculate frazil diagnostics
237 logical :: frazil_tendency_diag = .false. !< If true calculate frazil tendency diagnostics
238
239 type(diabatic_aux_CS), pointer :: diabatic_aux_CSp => NULL() !< Control structure for a child module
240 type(int_tide_input_CS), pointer :: int_tide_input_CSp => NULL() !< Control structure for a child module
241 type(int_tide_input_type), pointer :: int_tide_input => NULL() !< Control structure for a child module
242 type(set_diffusivity_CS), pointer :: set_diff_CSp => NULL() !< Control structure for a child module
243 type(sponge_CS), pointer :: sponge_CSp => NULL() !< Control structure for a child module
244 type(ALE_sponge_CS), pointer :: ALE_sponge_CSp => NULL() !< Control structure for a child module
245 type(tracer_flow_control_CS), pointer :: tracer_flow_CSp => NULL() !< Control structure for a child module
246 type(optics_type), pointer :: optics => NULL() !< Control structure for a child module
247 type(KPP_CS), pointer :: KPP_CSp => NULL() !< Control structure for a child module
248 type(diapyc_energy_req_CS), pointer :: diapyc_en_rec_CSp => NULL() !< Control structure for a child module
249 type(oda_incupd_CS), pointer :: oda_incupd_CSp => NULL() !< Control structure for a child module
250 type(int_tide_CS), pointer :: int_tide_CSp => NULL() !< Control structure for a child module
251 type(vbf_CS), pointer :: VBF => NULL() !< Control structure for a child module
252
253
254 type(bulkmixedlayer_CS) :: bulkmixedlayer !< Bulk mixed layer control structure
255 type(CVMix_conv_CS) :: CVMix_conv !< CVMix convection control structure
256 type(energetic_PBL_CS) :: ePBL !< Energetic PBL control structure
257 type(entrain_diffusive_CS) :: entrain_diffusive !< Diffusive entrainment control structure
258 type(geothermal_CS) :: geothermal !< Geothermal control structure
259 type(opacity_CS) :: opacity !< Opacity control structure
260 type(regularize_layers_CS) :: regularize_layers !< Regularize layer control structure
261
262 type(group_pass_type) :: pass_hold_eb_ea !< For group halo pass
263 type(diag_grid_storage) :: diag_grids_prev !< Stores diagnostic grids at some previous point in the algorithm
264
265 type(time_type), pointer :: Time !< Pointer to model time (needed for sponges)
266end type diabatic_CS
267
268!>@{ clock ids
269integer :: id_clock_entrain, id_clock_mixedlayer, id_clock_set_diffusivity
270integer :: id_clock_tracers, id_clock_tridiag, id_clock_pass, id_clock_sponge
271integer :: id_clock_geothermal, id_clock_differential_diff, id_clock_remap
272integer :: id_clock_kpp, id_clock_oda_incupd
273!>@}
274
275contains
276
277!> This subroutine imposes the diapycnal mass fluxes and the
278!! accompanying diapycnal advection of momentum and tracers.
27912subroutine diabatic(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, &
280 G, GV, US, CS, stoch_CS, OBC, Waves)
281 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
282 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
283 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
284 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
285 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
286 type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
287 !! unused have NULL ptrs
288 real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: BLD !< Active mixed layer depth [Z ~> m]
289 type(forcing), intent(inout) :: fluxes !< points to forcing fields
290 !! unused fields have NULL ptrs
291 type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities,
292 !! BBL properties and related fields
293 type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum
294 !! equations, to enable the later derived
295 !! diagnostics, like energy budgets
296 type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
297 real, intent(in) :: dt !< time increment [T ~> s]
298 type(time_type), intent(in) :: Time_end !< Time at the end of the interval
299 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
300 type(diabatic_CS), pointer :: CS !< module control structure
301 type(stochastic_CS), pointer :: stoch_CS !< stochastic control structure
302 type(ocean_OBC_type), pointer :: OBC !< Open boundaries control structure.
303 type(Wave_parameters_CS), pointer :: Waves !< Surface gravity waves
304
305 ! local variables
306 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: &
30724 eta ! Interface heights before diapycnal mixing [Z ~> m]
30824 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: temp_diag ! Previous temperature for diagnostics [C ~> degC]
30924 real, dimension(SZI_(G)) :: T_freeze, & ! The freezing potential temperature at the current salinity [C ~> degC].
31024 ps ! Surface pressure [R L2 T-2 ~> Pa]
311 real, dimension(SZI_(G),SZK_(GV)) :: &
31224 pressure ! The pressure at the middle of each layer [R L2 T-2 ~> Pa].
313 real :: H_to_RL2_T2 ! A conversion factor from thicknesses in H to pressure [R L2 T-2 H-1 ~> Pa m-1 or Pa m2 kg-1]
314 integer :: i, j, k, is, ie, js, je, nz
315 logical :: showCallTree ! If true, show the call tree
316
31712 real, allocatable, dimension(:,:,:) :: h_in ! thickness before thermodynamics [H ~> m or kg m-2]
31812 real, allocatable, dimension(:,:,:) :: t_in ! temperature before thermodynamics [C ~> degC]
31912 real, allocatable, dimension(:,:,:) :: s_in ! salinity before thermodynamics [S ~> ppt]
320
32112 if (GV%ke == 1) return
322
32312 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
324
32512 if (.not. associated(CS)) call MOM_error(FATAL, "MOM_diabatic_driver: "// &
3260 "Module must be initialized before it is used.")
327
32812 if (.not. CS%initialized) call MOM_error(FATAL, "MOM_diabatic_driver: "// &
3290 "Module must be initialized before it is used.")
330
33112 if (dt == 0.0) call MOM_error(FATAL, "MOM_diabatic_driver: "// &
3320 "diabatic was called with a zero length timestep.")
33312 if (dt < 0.0) call MOM_error(FATAL, "MOM_diabatic_driver: "// &
3340 "diabatic was called with a negative timestep.")
335
33612 showCallTree = callTree_showQuery()
337
338 ! Offer diagnostics of various state variables at the start of diabatic
339 ! these are mostly for debugging purposes.
34012 if (CS%id_u_predia > 0) call post_data(CS%id_u_predia, u, CS%diag)
34112 if (CS%id_v_predia > 0) call post_data(CS%id_v_predia, v, CS%diag)
34212 if (CS%id_h_predia > 0) call post_data(CS%id_h_predia, h, CS%diag)
34312 if (CS%id_T_predia > 0) call post_data(CS%id_T_predia, tv%T, CS%diag)
34412 if (CS%id_S_predia > 0) call post_data(CS%id_S_predia, tv%S, CS%diag)
34512 if (CS%id_e_predia > 0) then
346 !$omp target update to(h)
347 !$omp target enter data map(alloc: eta)
3480 call find_eta(h, tv, G, GV, US, eta, dZref=G%Z_ref)
349 !$omp target exit data map(from: eta)
3500 call post_data(CS%id_e_predia, eta, CS%diag)
351 endif
352
353 ! Save a copy of the initial state if stochastic perturbations are active.
35412 if (stoch_CS%do_sppt) then
3550 allocate(h_in(G%isd:G%ied, G%jsd:G%jed, GV%ke)) ; h_in(:,:,:) = h(:,:,:)
3560 allocate(t_in(G%isd:G%ied, G%jsd:G%jed, GV%ke)) ; t_in(:,:,:) = tv%T(:,:,:)
3570 allocate(s_in(G%isd:G%ied, G%jsd:G%jed, GV%ke)) ; s_in(:,:,:) = tv%S(:,:,:)
358 endif
359
36012 if (CS%debug) then
3610 call MOM_state_chksum("Start of diabatic ", u, v, h, G, GV, US, haloshift=0)
3620 call MOM_forcing_chksum("Start of diabatic", fluxes, G, US, haloshift=0)
363 endif
36412 if (CS%debugConservation) call MOM_state_stats('Start of diabatic', u, v, h, tv%T, tv%S, G, GV, US)
365
36612 if (CS%debug_energy_req) &
3670 call diapyc_energy_req_test(h, dt, tv, G, GV, US, CS%diapyc_en_rec_CSp)
368
36912 call cpu_clock_begin(id_clock_set_diffusivity)
37012 call set_BBL_TKE(u, v, h, tv, fluxes, visc, G, GV, US, CS%set_diff_CSp, OBC=OBC)
37112 call cpu_clock_end(id_clock_set_diffusivity)
372
373 ! Frazil formation keeps the temperature above the freezing point.
374 ! make_frazil is deliberately called at both the beginning and at
375 ! the end of the diabatic processes.
37612 if (associated(tv%T) .AND. associated(tv%frazil)) then
377 ! For frazil diagnostic, the first call covers the first half of the time step
37812 call enable_averages(0.5*dt, Time_end - real_to_time(0.5*dt, unscale=US%T_to_s), CS%diag)
37912 if (CS%frazil_tendency_diag) then
3800 do k=1,nz ; do j=js,je ; do i=is,ie
3810 temp_diag(i,j,k) = tv%T(i,j,k)
382 enddo ; enddo ; enddo
383 endif
384
38512 if (associated(fluxes%p_surf_full)) then
3860 call make_frazil(h, tv, G, GV, US, CS%diabatic_aux_CSp, fluxes%p_surf_full, halo=CS%halo_TS_diff)
387 else
38812 call make_frazil(h, tv, G, GV, US, CS%diabatic_aux_CSp, halo=CS%halo_TS_diff)
389 endif
39012 if (showCallTree) call callTree_waypoint("done with 1st make_frazil (diabatic)")
391
39212 if (CS%frazil_tendency_diag) then
3930 call diagnose_frazil_tendency(tv, h, temp_diag, 0.5*dt, G, GV, US, CS)
3940 if (CS%id_frazil_h > 0) call post_data(CS%id_frazil_h, h, CS%diag)
395 endif
39612 call disable_averaging(CS%diag)
397 endif ! associated(tv%T) .AND. associated(tv%frazil)
39812 if (CS%debugConservation) call MOM_state_stats('1st make_frazil', u, v, h, tv%T, tv%S, G, GV, US)
399
40012 if (CS%use_int_tides) then
401 ! This block provides an interface for the unresolved low-mode internal tide module.
402 call set_int_tide_input(u, v, h, tv, fluxes, CS%int_tide_input, dt, G, GV, US, &
4030 CS%int_tide_input_CSp)
404
405 call propagate_int_tide(h, tv, CS%int_tide_input%Nb, CS%int_tide_input%Rho_bot, dt, &
4060 G, GV, US, CS%int_tide_input_CSp, CS%int_tide_CSp)
407
4080 if (showCallTree) call callTree_waypoint("done with propagate_int_tide (diabatic)")
409 endif ! end CS%use_int_tides
410
41112 if (CS%useALEalgorithm .and. CS%use_legacy_diabatic) then
412 call diabatic_ALE_legacy(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, &
41312 G, GV, US, CS, stoch_CS, Waves)
4140 elseif (CS%useALEalgorithm) then
415 call diabatic_ALE(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, &
4160 G, GV, US, CS, stoch_CS, Waves)
417 else
418 call layered_diabatic(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, &
4190 G, GV, US, CS, Waves)
420 endif
421
42212 call cpu_clock_begin(id_clock_pass)
42312 if (associated(visc%sfc_buoy_flx)) &
42412 call pass_var(visc%sfc_buoy_flx, G%domain, halo=1, complete=.not.associated(visc%MLD))
42512 if (associated(visc%h_ML)) &
42612 call pass_var(visc%h_ML, G%Domain, halo=1, complete=.not.associated(visc%MLD))
42712 if (associated(visc%MLD)) &
42812 call pass_var(visc%MLD, G%Domain, halo=1, complete=.true.)
42912 if (associated(visc%Kv_shear)) &
43012 call pass_var(visc%Kv_shear, G%Domain, To_All+Omit_Corners, halo=1)
43112 call cpu_clock_end(id_clock_pass)
432
43312 call disable_averaging(CS%diag)
434 ! Frazil formation keeps temperature above the freezing point.
435 ! make_frazil is deliberately called at both the beginning and at
436 ! the end of the diabatic processes.
43712 if (associated(tv%T) .AND. associated(tv%frazil)) then
43812 call enable_averages(0.5*dt, Time_end, CS%diag)
43912 if (CS%frazil_tendency_diag) then
4400 do k=1,nz ; do j=js,je ; do i=is,ie
4410 temp_diag(i,j,k) = tv%T(i,j,k)
442 enddo ; enddo ; enddo
443 endif
444
44512 if (associated(fluxes%p_surf_full)) then
4460 call make_frazil(h, tv, G, GV, US, CS%diabatic_aux_CSp, fluxes%p_surf_full)
447 else
44812 call make_frazil(h, tv, G, GV, US, CS%diabatic_aux_CSp)
449 endif
450
45112 if (CS%frazil_tendency_diag) then
4520 call diagnose_frazil_tendency(tv, h, temp_diag, 0.5*dt, G, GV, US, CS)
4530 if (CS%id_frazil_h > 0 ) call post_data(CS%id_frazil_h, h, CS%diag)
454 endif
455
45612 if (showCallTree) call callTree_waypoint("done with 2nd make_frazil (diabatic)")
45712 if (CS%debugConservation) call MOM_state_stats('2nd make_frazil', u, v, h, tv%T, tv%S, G, GV, US)
45812 call disable_averaging(CS%diag)
459
460 endif ! endif for frazil
461
46212 if (stoch_CS%do_sppt) then
463 ! perturb diabatic tendencies.
464 ! These stochastic perturbations do not conserve heat, salt or mass.
4650 do k=1,nz ; do j=js,je ; do i=is,ie
4660 h(i,j,k) = max(h_in(i,j,k) + (h(i,j,k)-h_in(i,j,k)) * stoch_CS%sppt_wts(i,j), GV%Angstrom_H)
4670 tv%S(i,j,k) = max(s_in(i,j,k) + (tv%S(i,j,k)-s_in(i,j,k)) * stoch_CS%sppt_wts(i,j), 0.0)
468 enddo ; enddo ; enddo
469 ! now that we have updated thickness and salinity, calculate freeing point
4700 H_to_RL2_T2 = GV%H_to_RZ * GV%g_Earth
4710 do j=js,je
4720 ps(:) = 0.0
4730 if (associated(fluxes%p_surf)) then
4740 do i=is,ie
4750 ps(i) = fluxes%p_surf(i,j)
476 enddo
477 endif
478
4790 do i=is,ie
4800 pressure(i,1) = ps(i) + (0.5*H_to_RL2_T2)*h(i,j,1)
481 enddo
4820 do k=2,nz ; do i=is,ie
483 pressure(i,k) = pressure(i,k-1) + &
4840 (0.5*H_to_RL2_T2) * (h(i,j,k) + h(i,j,k-1))
485 enddo ; enddo
4860 do k=1,nz
487 call calculate_TFreeze(tv%S(is:ie,j,k), pressure(is:ie,k), T_freeze(is:ie), &
4880 tv%eqn_of_state)
4890 do i=is,ie
4900 tv%T(i,j,k) = max(t_in(i,j,k) + (tv%T(i,j,k)-t_in(i,j,k)) * stoch_CS%sppt_wts(i,j), T_freeze(i))
491 enddo
492 enddo
493 enddo
494
4950 deallocate(h_in, t_in, s_in)
496 endif
497
498 ! Diagnose mixed layer depths.
49912 call enable_averages(dt, Time_end, CS%diag)
50012 if (CS%id_MLD_003 > 0 .or. CS%id_subMLN2 > 0 .or. CS%id_mlotstsq > 0) then
501 call diagnoseMLDbyDensityDifference(CS%id_MLD_003, h, tv, 0.03*US%kg_m3_to_R, G, GV, US, CS%diag, &
502 CS%ref_h_mld, CS%id_MLD_003_zr, CS%id_MLD_003_rr, &
5030 id_N2subML=CS%id_subMLN2, id_MLDsq=CS%id_mlotstsq, dz_subML=CS%dz_subML_N2)
504 endif
50512 if (CS%id_MLD_0125 > 0) then
506 call diagnoseMLDbyDensityDifference(CS%id_MLD_0125, h, tv, 0.125*US%kg_m3_to_R, G, GV, US, CS%diag, &
5070 ref_H_MLD=0.0, id_ref_z=-1, id_ref_rho=-1)
508 endif
50912 if (CS%id_MLD_user > 0) then
510 call diagnoseMLDbyDensityDifference(CS%id_MLD_user, h, tv, CS%MLDdensityDifference, G, GV, US, CS%diag, &
5110 ref_H_MLD=0.0, id_ref_z=-1, id_ref_rho=-1)
512 endif
51312 if ((CS%id_MLD_EN1 > 0) .or. (CS%id_MLD_EN2 > 0) .or. (CS%id_MLD_EN3 > 0)) then
514 ! Surface Mixed Layer diagnostic
515 call diagnoseMLDbyEnergy((/CS%id_MLD_EN1, CS%id_MLD_EN2, CS%id_MLD_EN3/), h, tv, G, GV, US, CS%MLD_En_vals, &
5160 (/1,nz/), CS%diag, OM4_iteration=CS%use_OM4_MLD_En_iter)
517 endif
51812 if ((CS%id_BMLD_EN1 > 0) .or. (CS%id_BMLD_EN2 > 0) .or. (CS%id_BMLD_EN3 > 0)) then
519 ! Bottom Mixed Layer diagnostic
520 call diagnoseMLDbyEnergy((/CS%id_BMLD_EN1, CS%id_BMLD_EN2, CS%id_BMLD_EN3/), h, tv, G, GV, US, CS%BMLD_En_vals, &
5210 (/nz,1/), CS%diag, OM4_iteration=.false.)
522 endif
52312 if (stoch_CS%do_sppt .and. stoch_CS%id_sppt_wts > 0) &
5240 call post_data(stoch_CS%id_sppt_wts, stoch_CS%sppt_wts, CS%diag)
525
52612 call disable_averaging(CS%diag)
527
52812 if (CS%debugConservation) call MOM_state_stats('leaving diabatic', u, v, h, tv%T, tv%S, G, GV, US)
529
53012end subroutine diabatic
531
532
533!> Applies diabatic forcing and diapycnal mixing of temperature, salinity and other tracers for use
534!! with an ALE algorithm. This version uses an older set of algorithms compared with diabatic_ALE.
53512subroutine diabatic_ALE_legacy(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, &
536 G, GV, US, CS, stoch_CS, Waves)
537 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
538 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
539 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
540 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
541 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
542 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
543 type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
544 !! unused have NULL ptrs
545 real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: BLD !< Active mixed layer depth [Z ~> m]
546 type(forcing), intent(inout) :: fluxes !< points to forcing fields
547 !! unused fields have NULL ptrs
548 type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities,
549 !! BBL properties and related fields
550 type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum
551 !! equations, to enable the later derived
552 !! diagnostics, like energy budgets
553 type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
554 real, intent(in) :: dt !< time increment [T ~> s]
555 type(time_type), intent(in) :: Time_end !< Time at the end of the interval
556 type(diabatic_CS), pointer :: CS !< module control structure
557 type(stochastic_CS), pointer :: stoch_CS !< stochastic control structure
558 type(Wave_parameters_CS), pointer :: Waves !< Surface gravity waves
559
560 ! local variables
561 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: &
56224 h_orig, & ! Initial layer thicknesses [H ~> m or kg m-2]
56324 dz, & ! The vertical distance between interfaces around a layer [Z ~> m]
56424 dSV_dT, & ! The partial derivative of specific volume with temperature [R-1 C-1 ~> m3 kg-1 degC-1]
56524 dSV_dS, & ! The partial derivative of specific volume with salinity [R-1 S-1 ~> m3 kg-1 ppt-1].
56624 cTKE, & ! convective TKE requirements for each layer [R Z3 T-2 ~> J m-2].
56724 u_h, & ! Zonal velocities interpolated to thickness points [L T-1 ~> m s-1]
56824 v_h, & ! Meridional velocities interpolated to thickness points [L T-1 ~> m s-1]
56924 temp_diag, & ! Diagnostic array of previous temperatures [C ~> degC]
57024 saln_diag ! Diagnostic array of previous salinity [S ~> ppt]
571
572 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: &
57324 ent_s, & ! The diffusive coupling across interfaces within one time step for
574 ! salinity and passive tracers [H ~> m or kg m-2]
57524 ent_t, & ! The diffusive coupling across interfaces within one time step for
576 ! temperature [H ~> m or kg m-2]
57724 Kd_int, & ! diapycnal diffusivity of interfaces [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
57824 Kd_heat, & ! diapycnal diffusivity of heat [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
57924 Kd_salt, & ! diapycnal diffusivity of salt and passive tracers [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
58024 Kd_extra_T , & ! The extra diffusivity of temperature due to double diffusion relative to
581 ! Kd_int [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
58224 Kd_extra_S , & ! The extra diffusivity of salinity due to double diffusion relative to
583 ! Kd_int [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
58424 Kd_ePBL, & ! test array of diapycnal diffusivities at interfaces [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
58524 KPP_NLTheat, & ! KPP non-local transport for heat [nondim]
58624 KPP_NLTscalar, & ! KPP non-local transport for scalars [nondim]
58724 KPP_buoy_flux, & ! KPP forcing buoyancy flux [L2 T-3 ~> m2 s-3]
58824 Tdif_flx, & ! diffusive diapycnal heat flux across interfaces [C H T-1 ~> degC m s-1 or degC kg m-2 s-1]
58924 Sdif_flx, & ! diffusive diapycnal salt flux across interfaces [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
59024 N2_salt, & !< Salinity contribution to squared buoyancy frequency at interfaces [T-2 ~> s-2]
59124 N2_temp !< Temperature contribution to squared buoyancy frequency at interfaces [T-2 ~> s-2]
592
593 real, dimension(SZI_(G),SZJ_(G)) :: &
59424 U_star, & ! The friction velocity [Z T-1 ~> m s-1].
59524 KPP_temp_flux, & ! KPP effective temperature flux [C H T-1 ~> degC m s-1 or degC kg m-2 s-1]
59624 KPP_salt_flux, & ! KPP effective salt flux [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
59724 SkinBuoyFlux, & ! 2d surface buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL
59824 BBL_BuoyFlux ! 2d bottom buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL
599
600 real, dimension(SZI_(G)) :: &
60124 p_i ,& ! Pressure at the interface [R L2 T-2 ~> Pa]
60224 T_i, & ! Temperature at the interface [C ~> degC]
60324 S_i, & ! Salinity at the interface [S ~> ppt]
60424 drhodS, & ! Local change in density w.r.t. salinity using model EOS & state [R C-1 ~> kg m-3 ppt-1]
60524 drhodT, & ! Local change in density w.r.t. temperature using model EOS & state [R C-1 ~> kg m-3 degC-1]
60624 dSpV_dT, & ! Partial derivative of specific volume with temperature [R-1 C-1 ~> m3 kg-1 degC-1]
60724 dSpV_dS ! Partial derivative of specific volume with salinity [R-1 S-1 ~> m3 kg-1 ppt-1]
608
609 logical, dimension(SZI_(G)) :: &
61024 in_boundary ! True if there are no massive layers below, where massive is defined as
611 ! sufficiently thick that the no-flux boundary conditions have not restricted
612 ! the entrainment - usually sqrt(Kd*dt).
613
614 real :: h_neglect ! A thickness that is so small it is usually lost
615 ! in roundoff and can be neglected [H ~> m or kg m-2]
616 real :: dz_neglect ! A vertical distance that is so small it is usually lost
617 ! in roundoff and can be neglected [Z ~> m]
618 real :: dz_neglect2 ! dz_neglect^2 [Z2 ~> m2]
619 real :: add_ent ! Entrainment that needs to be added when mixing tracers [H ~> m or kg m-2]
620 real :: I_dzval ! The inverse of the thicknesses averaged to interfaces [Z-1 ~> m-1]
621 real :: I_h ! The inverse of the thicknesses averaged to interfaces [H-1 ~> m-1 or m2 kg-1]
622 real :: Tr_ea_BBL ! The diffusive tracer thickness in the BBL that is
623 ! coupled to the bottom within a timestep [H ~> m or kg m-2]
624 real :: Kd_add_here ! An added diffusivity [H Z T-1 ~> m2 s-1 or kg m-1 s-1].
62524 real :: htot(SZIB_(G)) ! The summed thickness from the bottom [H ~> m or kg m-2].
626
627 real :: Ent_int ! The diffusive entrainment rate at an interface [H ~> m or kg m-2]
628 real :: Idt ! The inverse time step [T-1 ~> s-1]
629 real :: g_Rho0 ! G_Earth/Rho0 [H T-2 R-1 ~> m4 s-2 kg-1 or m s-2]
630 real :: H_to_pres ! A conversion factor from thicknesses to pressure [R L2 T-2 H-1 ~> Pa m-1 or Pa m2 kg-1]
631 real :: alt_H_to_pres! A conversion factor from thicknesses to pressure w/ alternative scaling [R Z T-2 ~> Pa m-1]
632 logical :: nonBous ! True if not using the Boussinesq approximation
633
634 integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
635
636 logical :: showCallTree ! If true, show the call tree
637 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
638
63912 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
64012 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
64112 dz_neglect = GV%dZ_subroundoff ; dz_neglect2 = dz_neglect*dz_neglect
64212 h_neglect = GV%H_subroundoff
643
64412 nonBous = .not.(GV%Boussinesq .or. GV%semi_Boussinesq)
64512 g_Rho0 = GV%g_Earth_Z_T2 / GV%H_to_RZ
64612 H_to_pres = GV%H_to_RZ * GV%g_Earth
64712 alt_H_to_pres = H_to_pres * US%L_to_Z**2 * GV%Z_to_H
648
64916001964 Kd_heat(:,:,:) = 0.0 ; Kd_salt(:,:,:) = 0.0
650
65112 showCallTree = callTree_showQuery()
65212 if (showCallTree) call callTree_enter("diabatic_ALE_legacy(), MOM_diabatic_driver.F90")
653
654 ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep
65512 call enable_averages(dt, Time_end, CS%diag)
656
65712 if (CS%Use_KdWork_diag) call Allocate_VBF_CS(G, GV, CS%VBF)
658
65912 if (CS%use_geothermal) then
66012 call cpu_clock_begin(id_clock_geothermal)
66112 call geothermal_in_place(h, tv, dt, G, GV, US, CS%geothermal, BBL_BuoyFlux, halo=CS%halo_TS_diff)
66212 call cpu_clock_end(id_clock_geothermal)
66312 if (showCallTree) call callTree_waypoint("geothermal (diabatic)")
66412 if (CS%debugConservation) call MOM_state_stats('geothermal', u, v, h, tv%T, tv%S, G, GV, US)
665 endif
666
667 ! Whenever thickness changes let the diag manager know, target grids
668 ! for vertical remapping may need to be regenerated.
66912 call diag_update_remap_grids(CS%diag)
670
671 ! Set_pen_shortwave estimates the optical properties of the water column.
672 ! It will need to be modified later to include information about the
673 ! biological properties and layer thicknesses.
67412 if (associated(CS%optics)) &
67512 call set_pen_shortwave(CS%optics, fluxes, G, GV, US, CS%diabatic_aux_CSp, CS%opacity, CS%tracer_flow_CSp)
676
67712 if (CS%debug) call MOM_state_chksum("before find_uv_at_h", u, v, h, G, GV, US, haloshift=0)
678
67912 if (CS%use_kappa_shear .or. CS%use_CVMix_shear) then
68012 if (CS%use_geothermal) then
68112 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US, zero_mix=.true.)
682 else
6830 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US)
684 endif
68512 if (showCallTree) call callTree_waypoint("done with find_uv_at_h (diabatic)")
686 endif
687
68812 call cpu_clock_begin(id_clock_set_diffusivity)
689 ! Sets: Kd_int, Kd_extra_T, Kd_extra_S and visc%TKE_turb
690 ! Also changes: visc%Kd_shear, visc%Kv_shear and visc%Kv_slow
69112 if (CS%debug) &
6920 call MOM_state_chksum("before set_diffusivity", u, v, h, G, GV, US, haloshift=CS%halo_TS_diff)
69312 if (CS%double_diffuse) then
694 call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, &
6950 CS%set_diff_CSp, CS%VBF, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S)
696 else
697 call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, &
69812 CS%set_diff_CSp, CS%VBF)
699 endif
70012 call cpu_clock_end(id_clock_set_diffusivity)
70112 if (showCallTree) call callTree_waypoint("done with set_diffusivity (diabatic)")
702
703
70412 if (CS%debug) then
7050 call MOM_state_chksum("after set_diffusivity ", u, v, h, G, GV, US, haloshift=0)
7060 call MOM_forcing_chksum("after set_diffusivity ", fluxes, G, US, haloshift=0)
7070 call MOM_thermovar_chksum("after set_diffusivity ", tv, G, US)
7080 call hchksum(Kd_Int, "after set_diffusivity Kd_Int", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
709 endif
710
711 ! Set diffusivities for heat and salt separately
71212 if (CS%useKPP) then
713 ! Add contribution from double diffusion
7140 if (CS%double_diffuse) then
715 !$OMP parallel do default(shared)
7160 do K=1,nz+1 ; do j=js,je ; do i=is,ie
7170 Kd_salt(i,j,K) = Kd_int(i,j,K) + Kd_extra_S(i,j,K)
7180 Kd_heat(i,j,K) = Kd_int(i,j,K) + Kd_extra_T(i,j,K)
719 enddo ; enddo ; enddo
720 else
721 !$OMP parallel do default(shared)
7220 do K=1,nz+1 ; do j=js,je ; do i=is,ie
7230 Kd_salt(i,j,K) = Kd_int(i,j,K)
7240 Kd_heat(i,j,K) = Kd_int(i,j,K)
725 enddo ; enddo ; enddo
726 endif
727
7280 if (CS%debug) then
7290 call hchksum(Kd_heat, "after set_diffusivity Kd_heat", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
7300 call hchksum(Kd_salt, "after set_diffusivity Kd_salt", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
731 endif
732
7330 call cpu_clock_begin(id_clock_kpp)
734 ! total vertical viscosity in the interior is represented via visc%Kv_shear
735
736 ! NOTE: The following do not require initialization, but their checksums do
737 ! require initialization, and past versions were initialized to zero.
7380 KPP_NLTheat(:,:,:) = 0.
7390 KPP_NLTscalar(:,:,:) = 0.
7400 KPP_buoy_flux(:,:,:) = 0.
7410 KPP_temp_flux(:,:) = 0.
7420 KPP_salt_flux(:,:) = 0.
743
744 ! KPP needs the surface buoyancy flux but does not update state variables.
745 ! We could make this call higher up to avoid a repeat unpacking of the surface fluxes.
746 ! Sets: KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux
747 ! NOTE: KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux are returned as rates (i.e. stuff per second)
748 ! unlike other instances where the fluxes are integrated in time over a time-step.
749 call calculateBuoyancyFlux2d(G, GV, US, fluxes, CS%optics, h, tv%T, tv%S, tv, &
7500 KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux)
751
752 ! Determine the friction velocity, perhaps using the evovling surface density.
7530 call find_ustar(fluxes, tv, U_star, G, GV, US)
754
755 ! The KPP scheme calculates boundary layer diffusivities and non-local transport.
7560 if ( associated(fluxes%lamult) ) then
757 call KPP_compute_BLD(CS%KPP_CSp, G, GV, US, h, tv%T, tv%S, u, v, tv, &
7580 U_star, KPP_buoy_flux, Waves=Waves, lamult=fluxes%lamult)
759
760 call KPP_calculate(CS%KPP_CSp, G, GV, US, h, tv, U_star, KPP_buoy_flux, Kd_heat, &
7610 Kd_salt, visc%Kv_shear, KPP_NLTheat, KPP_NLTscalar, Waves=Waves, lamult=fluxes%lamult)
762 else
763 call KPP_compute_BLD(CS%KPP_CSp, G, GV, US, h, tv%T, tv%S, u, v, tv, &
7640 U_star, KPP_buoy_flux, Waves=Waves)
765
766 call KPP_calculate(CS%KPP_CSp, G, GV, US, h, tv, U_star, KPP_buoy_flux, Kd_heat, &
7670 Kd_salt, visc%Kv_shear, KPP_NLTheat, KPP_NLTscalar, Waves=Waves)
768 endif
769
7700 call KPP_get_BLD(CS%KPP_CSp, BLD(:,:), G, US)
771 ! If visc%MLD or visc%h_ML exist, copy KPP's BLD into them with appropriate conversions.
7720 if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV)
7730 if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:)
7740 if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = KPP_buoy_flux(:,:,1)
775
7760 if (.not.CS%KPPisPassive) then
777 !$OMP parallel do default(shared)
7780 do K=1,nz+1 ; do j=js,je ; do i=is,ie
7790 Kd_int(i,j,K) = min( Kd_salt(i,j,K), Kd_heat(i,j,K) )
780 enddo ; enddo ; enddo
7810 if (CS%double_diffuse) then
782 !$OMP parallel do default(shared)
7830 do K=1,nz+1 ; do j=js,je ; do i=is,ie
7840 Kd_extra_S(i,j,K) = (Kd_salt(i,j,K) - Kd_int(i,j,K))
7850 Kd_extra_T(i,j,K) = (Kd_heat(i,j,K) - Kd_int(i,j,K))
786 enddo ; enddo ; enddo
787 endif
788 endif ! not passive
789
7900 if (showCallTree) call callTree_waypoint("done with KPP_calculate (diabatic)")
7910 if (CS%debug) then
7920 call MOM_state_chksum("after KPP", u, v, h, G, GV, US, haloshift=0)
7930 call MOM_forcing_chksum("after KPP", fluxes, G, US, haloshift=0)
7940 call MOM_thermovar_chksum("after KPP", tv, G, US)
7950 call hchksum(Kd_heat, "after KPP Kd_heat", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
7960 call hchksum(Kd_salt, "after KPP Kd_salt", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
797 call hchksum(KPP_temp_flux, "before KPP_applyNLT netHeat", G%HI, haloshift=0, &
7980 unscale=US%C_to_degC*GV%H_to_m*US%s_to_T)
799 call hchksum(KPP_salt_flux, "before KPP_applyNLT netSalt", G%HI, haloshift=0, &
8000 unscale=US%S_to_ppt*GV%H_to_m*US%s_to_T)
8010 call hchksum(KPP_NLTheat, "before KPP_applyNLT NLTheat", G%HI, haloshift=0)
8020 call hchksum(KPP_NLTscalar, "before KPP_applyNLT NLTscalar", G%HI, haloshift=0)
803 endif
804 ! Apply non-local transport of heat and salt
805 ! Changes: tv%T, tv%S
806 call KPP_NonLocalTransport_temp(CS%KPP_CSp, G, GV, h, KPP_NLTheat, KPP_temp_flux, &
8070 dt, tv%tr_T, tv%T, tv%C_p)
808 call KPP_NonLocalTransport_saln(CS%KPP_CSp, G, GV, h, KPP_NLTscalar, KPP_salt_flux, &
8090 dt, tv%tr_S, tv%S)
8100 call cpu_clock_end(id_clock_kpp)
8110 if (showCallTree) call callTree_waypoint("done with KPP_applyNonLocalTransport (diabatic)")
8120 if (CS%debugConservation) call MOM_state_stats('KPP_applyNonLocalTransport', u, v, h, tv%T, tv%S, G, GV, US)
813
8140 if (CS%debug) then
8150 call MOM_state_chksum("after KPP_applyNLT ", u, v, h, G, GV, US, haloshift=0)
8160 call MOM_forcing_chksum("after KPP_applyNLT ", fluxes, G, US, haloshift=0)
8170 call MOM_thermovar_chksum("after KPP_applyNLT ", tv, G, US)
818 endif
819 endif ! endif for KPP
820
821 ! This is the "old" method for applying differential diffusion.
822 ! Changes: tv%T, tv%S
82312 if (CS%double_diffuse .and. associated(tv%T)) then
824
8250 call cpu_clock_begin(id_clock_differential_diff)
8260 call differential_diffuse_T_S(h, tv%T, tv%S, Kd_extra_T, Kd_extra_S, tv, dt, G, GV)
8270 call cpu_clock_end(id_clock_differential_diff)
828
8290 if (showCallTree) call callTree_waypoint("done with differential_diffuse_T_S (diabatic)")
8300 if (CS%debugConservation) call MOM_state_stats('differential_diffuse_T_S', u, v, h, tv%T, tv%S, G, GV, US)
831
832 ! increment heat and salt diffusivity.
833 ! CS%useKPP==.true. already has extra_T and extra_S included
8340 if (.not. CS%useKPP) then
835 !$OMP parallel do default(shared)
8360 do K=2,nz ; do j=js,je ; do i=is,ie
8370 Kd_heat(i,j,K) = Kd_heat(i,j,K) + Kd_extra_T(i,j,K)
8380 Kd_salt(i,j,K) = Kd_salt(i,j,K) + Kd_extra_S(i,j,K)
839 enddo ; enddo ; enddo
840 endif
841
842 endif
843
844 ! Calculate vertical mixing due to convection (computed via CVMix)
84512 if (CS%use_CVMix_conv) then
846 ! Increment vertical diffusion and viscosity due to convection
8470 call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv, BLD, Kd_int, visc%Kv_shear)
848 endif
849
850 ! Find the vertical distances across layers.
85112 call thickness_to_dz(h, tv, dz, G, GV, US)
852
853 ! This block sets ent_t and ent_s from h and Kd_int.
85487132 do j=js,je ; do i=is,ie
85586400 ent_s(i,j,1) = 0.0 ; ent_s(i,j,nz+1) = 0.0
85687120 ent_t(i,j,1) = 0.0 ; ent_t(i,j,nz+1) = 0.0
857 enddo ; enddo
858 !$OMP parallel do default(shared) private(I_dzval)
8596447780 do K=2,nz ; do j=js,je ; do i=is,ie
8606393600 I_dzval = 1.0 / (dz_neglect + 0.5*(dz(i,j,k-1) + dz(i,j,k)))
8616393600 ent_s(i,j,K) = dt * I_dzval * Kd_int(i,j,K)
8626446880 ent_t(i,j,K) = ent_s(i,j,K)
863 enddo ; enddo ; enddo
86412 if (showCallTree) call callTree_waypoint("done setting ent_s and ent_t from Kd_int (diabatic)")
865
86612 if (CS%debug) then
8670 call MOM_forcing_chksum("after calc_entrain ", fluxes, G, US, haloshift=0)
8680 call MOM_thermovar_chksum("after calc_entrain ", tv, G, US)
8690 call MOM_state_chksum("after calc_entrain ", u, v, h, G, GV, US, haloshift=0)
8700 call hchksum(ent_s, "after calc_entrain ent_s", G%HI, haloshift=0, unscale=GV%H_to_MKS)
871 endif
872
873 ! Save fields before boundary forcing is applied for tendency diagnostics
8746534912 do k=1,nz ; do j=js,je ; do i=is,ie
8756534000 h_orig(i,j,k) = h(i,j,k)
876 enddo ; enddo ; enddo
87712 if (CS%boundary_forcing_tendency_diag) then
8780 do k=1,nz ; do j=js,je ; do i=is,ie
8790 temp_diag(i,j,k) = tv%T(i,j,k)
8800 saln_diag(i,j,k) = tv%S(i,j,k)
881 enddo ; enddo ; enddo
882 endif
883
884 ! Apply forcing
885 ! Changes made to following fields: h, tv%T and tv%S.
88612 call cpu_clock_begin(id_clock_remap)
887
88812 if (CS%use_energetic_PBL) then
889
890105276 skinbuoyflux(:,:) = 0.0
891 call applyBoundaryFluxesInOut(CS%diabatic_aux_CSp, G, GV, US, dt, fluxes, CS%optics, &
892 optics_nbands(CS%optics), h, tv, CS%aggregate_FW_forcing, CS%evap_CFL_limit, &
89312 CS%minimum_forcing_depth, cTKE, dSV_dT, dSV_dS, SkinBuoyFlux=SkinBuoyFlux, MLD_h=visc%h_ML)
894
89512 if (CS%debug) then
8960 call hchksum(ent_t, "after applyBoundaryFluxes ent_t", G%HI, haloshift=0, unscale=GV%H_to_mks)
8970 call hchksum(ent_s, "after applyBoundaryFluxes ent_s", G%HI, haloshift=0, unscale=GV%H_to_mks)
898 call hchksum(cTKE, "after applyBoundaryFluxes cTKE", G%HI, haloshift=0, &
8990 unscale=US%RZ3_T3_to_W_m2*US%T_to_s)
900 call hchksum(dSV_dT, "after applyBoundaryFluxes dSV_dT", G%HI, haloshift=0, &
9010 unscale=US%kg_m3_to_R*US%degC_to_C)
902 call hchksum(dSV_dS, "after applyBoundaryFluxes dSV_dS", G%HI, haloshift=0, &
9030 unscale=US%kg_m3_to_R*US%ppt_to_S)
9040 call hchksum(h, "after applyBoundaryFluxes h", G%HI, haloshift=0, unscale=GV%H_to_mks)
9050 call hchksum(tv%T, "after applyBoundaryFluxes tv%T", G%HI, haloshift=0, unscale=US%C_to_degC)
9060 call hchksum(tv%S, "after applyBoundaryFluxes tv%S", G%HI, haloshift=0, unscale=US%S_to_ppt)
907 call hchksum(SkinBuoyFlux, "after applyBdryFlux SkinBuoyFlux", G%HI, haloshift=0, &
9080 unscale=US%Z_to_m**2*US%s_to_T**3)
909 endif
910
91112 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US)
912 call energetic_PBL(h, u_h, v_h, tv, fluxes, visc, dt, Kd_ePBL, G, GV, US, &
91312 CS%ePBL, stoch_CS, dSV_dT, dSV_dS, cTKE, SkinBuoyFlux, BBL_BuoyFlux, waves=waves)
914
91512 call energetic_PBL_get_MLD(CS%ePBL, BLD(:,:), G, US)
916 ! If visc%MLD or visc%h_ML exist, copy ePBL's BLD into them with appropriate conversions.
91712 if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV)
918105276 if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:)
919105276 if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = SkinBuoyFlux(:,:)
920
921 ! Find the vertical distances across layers, which may have been modified by the net surface flux
92212 call thickness_to_dz(h, tv, dz, G, GV, US)
923
924 ! Augment the diffusivities and viscosity due to those diagnosed in energetic_PBL.
9256447780 do K=2,nz ; do j=js,je ; do i=is,ie
9266393600 if (CS%ePBL_is_additive) then
9270 Kd_add_here = Kd_ePBL(i,j,K)
9280 visc%Kv_shear(i,j,K) = visc%Kv_shear(i,j,K) + CS%ePBL_Prandtl*Kd_ePBL(i,j,K)
929 else
9306393600 Kd_add_here = max(Kd_ePBL(i,j,K) - visc%Kd_shear(i,j,K), 0.0)
9316393600 visc%Kv_shear(i,j,K) = max(visc%Kv_shear(i,j,K), CS%ePBL_Prandtl*Kd_ePBL(i,j,K))
932 endif
933
9346393600 Ent_int = Kd_add_here * dt / (0.5*(dz(i,j,k-1) + dz(i,j,k)) + dz_neglect)
9356393600 ent_s(i,j,K) = ent_s(i,j,K) + Ent_int
9366393600 Kd_int(i,j,K) = Kd_int(i,j,K) + Kd_add_here
937
938 ! for diagnostics
9396393600 Kd_heat(i,j,K) = Kd_heat(i,j,K) + Kd_int(i,j,K)
9406446880 Kd_salt(i,j,K) = Kd_salt(i,j,K) + Kd_int(i,j,K)
941
942 enddo ; enddo ; enddo
943
94412 if (CS%debug) then
9450 call hchksum(ent_t, "after ePBL ent_t", G%HI, haloshift=0, unscale=GV%H_to_MKS)
9460 call hchksum(ent_s, "after ePBL ent_s", G%HI, haloshift=0, unscale=GV%H_to_MKS)
9470 call hchksum(Kd_ePBL, "after ePBL Kd_ePBL", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
948 endif
949
950 else
951 call applyBoundaryFluxesInOut(CS%diabatic_aux_CSp, G, GV, US, dt, fluxes, CS%optics, &
952 optics_nbands(CS%optics), h, tv, CS%aggregate_FW_forcing, &
9530 CS%evap_CFL_limit, CS%minimum_forcing_depth, MLD_h=visc%h_ML)
954
955 ! Find the vertical distances across layers, which may have been modified by the net surface flux
9560 call thickness_to_dz(h, tv, dz, G, GV, US)
957
958 endif ! endif for CS%use_energetic_PBL
959
960 ! diagnose the tendencies due to boundary forcing
961 ! At this point, the diagnostic grids have not been updated since the call to the boundary layer scheme
962 ! so all tendency diagnostics need to be posted on h_orig, and grids rebuilt afterwards
96312 if (CS%boundary_forcing_tendency_diag) then
9640 call diagnose_boundary_forcing_tendency(tv, h, temp_diag, saln_diag, h_orig, dt, G, GV, US, CS)
9650 if (CS%id_boundary_forcing_h > 0) call post_data(CS%id_boundary_forcing_h, h, CS%diag, alt_h=h_orig)
966 endif
967 ! Boundary fluxes may have changed T, S, and h
96812 call diag_update_remap_grids(CS%diag)
96912 call cpu_clock_end(id_clock_remap)
97012 if (CS%debug) then
9710 call MOM_forcing_chksum("after applyBoundaryFluxes ", fluxes, G, US, haloshift=0)
9720 call MOM_thermovar_chksum("after applyBoundaryFluxes ", tv, G, US)
9730 call MOM_state_chksum("after applyBoundaryFluxes ", u, v, h, G, GV, US, haloshift=0)
974 endif
97512 if (showCallTree) call callTree_waypoint("done with applyBoundaryFluxes (diabatic)")
97612 if (CS%debugConservation) call MOM_state_stats('applyBoundaryFluxes', u, v, h, tv%T, tv%S, G, GV, US)
977
97812 if (CS%debug) then
9790 call MOM_state_chksum("after negative check ", u, v, h, G, GV, US, haloshift=0)
9800 call MOM_forcing_chksum("after negative check ", fluxes, G, US, haloshift=0)
9810 call MOM_thermovar_chksum("after negative check ", tv, G, US)
982 endif
98312 if (showCallTree) call callTree_waypoint("done with h=ea-eb (diabatic)")
98412 if (CS%debugConservation) call MOM_state_stats('h=ea-eb', u, v, h, tv%T, tv%S, G, GV, US)
985
986 ! calculate change in temperature & salinity due to dia-coordinate surface diffusion
98712 if (associated(tv%T)) then
988
98912 if (CS%debug) then
9900 call hchksum(ent_t, "before triDiagTS ent_t ", G%HI, haloshift=0, unscale=GV%H_to_MKS)
9910 call hchksum(ent_s, "before triDiagTS ent_s ", G%HI, haloshift=0, unscale=GV%H_to_MKS)
992 endif
993
99412 call cpu_clock_begin(id_clock_tridiag)
995 ! Keep salinity from falling below a small but positive threshold.
996 ! This constraint is needed for SIS1 ice model, which can extract
997 ! more salt than is present in the ocean. SIS2 does not suffer
998 ! from this limitation, in which case we can let salinity=0 and still
999 ! have salt conserved with SIS2 ice. So for SIS2, we can run with
1000 ! BOUND_SALINITY=False in MOM.F90.
100112 if (associated(tv%S) .and. associated(tv%salt_deficit)) &
10020 call adjust_salt(h, tv, G, GV, CS%diabatic_aux_CSp)
1003
100412 if (CS%diabatic_diff_tendency_diag) then
10050 do k=1,nz ; do j=js,je ; do i=is,ie
10060 temp_diag(i,j,k) = tv%T(i,j,k)
10070 saln_diag(i,j,k) = tv%S(i,j,k)
1008 enddo ; enddo ; enddo
1009 endif
1010
1011 ! Changes T and S via the tridiagonal solver; no change to h
10126534912 do k=1,nz ; do j=js,je ; do i=is,ie
10136534000 ent_t(i,j,K) = ent_s(i,j,K) ; ent_t(i,j,K+1) = ent_s(i,j,K+1)
1014 enddo ; enddo ; enddo
101512 if (CS%tracer_tridiag) then
10160 call tracer_vertdiff_Eulerian(h, ent_t, dt, tv%T, G, GV)
10170 call tracer_vertdiff_Eulerian(h, ent_s, dt, tv%S, G, GV)
1018 else
101912 call triDiagTS_Eulerian(G, GV, is, ie, js, je, h, ent_s, tv%T, tv%S)
1020 endif
1021
1022 ! diagnose temperature, salinity, heat, and salt tendencies
102312 if (CS%diabatic_diff_tendency_diag) then
10240 call diagnose_diabatic_diff_tendency(tv, h, temp_diag, saln_diag, dt, G, GV, US, CS)
10250 if (CS%id_diabatic_diff_h > 0) call post_data(CS%id_diabatic_diff_h, h, CS%diag, alt_h=h)
1026 endif
1027
102812 call cpu_clock_end(id_clock_tridiag)
1029
103012 if (showCallTree) call callTree_waypoint("done with triDiagTS (diabatic)")
1031
1032 endif ! endif corresponding to if (associated(tv%T))
1033
103412 if (CS%debugConservation) call MOM_state_stats('triDiagTS', u, v, h, tv%T, tv%S, G, GV, US)
1035
103612 if (CS%debug) then
10370 call MOM_state_chksum("after mixed layer ", u, v, h, G, GV, US, haloshift=0)
10380 call MOM_thermovar_chksum("after mixed layer ", tv, G, US)
1039 endif
1040
1041 ! Whenever thickness changes let the diag manager know, as the
1042 ! target grids for vertical remapping may need to be regenerated.
104312 call diag_update_remap_grids(CS%diag)
1044
1045 ! Set diffusivities for VBF diagnostics if enabled
104612 if (CS%use_energetic_PBL .and. associated(CS%VBF%Kd_ePBL)) CS%VBF%Kd_ePBL(:,:,:) = Kd_ePBL(:,:,:)
104712 if (associated(CS%VBF%Kd_salt)) CS%VBF%Kd_temp(:,:,:) = Kd_heat(:,:,:)
104812 if (associated(CS%VBF%Kd_temp)) CS%VBF%Kd_salt(:,:,:) = Kd_salt(:,:,:)
1049
1050
1051 ! Diagnose the diapycnal diffusivities and other related quantities.
105212 if (CS%id_Kd_int > 0) call post_data(CS%id_Kd_int, Kd_int, CS%diag)
105312 if (CS%id_Kd_heat > 0) call post_data(CS%id_Kd_heat, Kd_heat, CS%diag)
105412 if (CS%id_Kd_salt > 0) call post_data(CS%id_Kd_salt, Kd_salt, CS%diag)
105512 if (CS%id_Kd_ePBL > 0) call post_data(CS%id_Kd_ePBL, Kd_ePBL, CS%diag)
1056
105712 if (CS%id_ea > 0) call post_data(CS%id_ea, ent_s(:,:,1:nz), CS%diag)
105812 if (CS%id_eb > 0) call post_data(CS%id_eb, ent_s(:,:,2:nz+1), CS%diag)
105912 if (CS%id_ea_t > 0) call post_data(CS%id_ea_t, ent_t(:,:,1:nz), CS%diag)
106012 if (CS%id_eb_t > 0) call post_data(CS%id_eb_t, ent_t(:,:,2:nz+1), CS%diag)
106112 if (CS%id_ea_s > 0) call post_data(CS%id_ea_s, ent_s(:,:,1:nz), CS%diag)
106212 if (CS%id_eb_s > 0) call post_data(CS%id_eb_s, ent_s(:,:,2:nz+1), CS%diag)
106312 Idt = 1.0 / dt
106412 if (CS%id_Tdif > 0) then
10650 do j=js,je ; do i=is,ie
10660 Tdif_flx(i,j,1) = 0.0 ; Tdif_flx(i,j,nz+1) = 0.0
1067 enddo ; enddo
1068 !$OMP parallel do default(shared)
10690 do K=2,nz ; do j=js,je ; do i=is,ie
10700 Tdif_flx(i,j,K) = (Idt * ent_t(i,j,K)) * (tv%T(i,j,k-1) - tv%T(i,j,k))
1071 enddo ; enddo ; enddo
10720 if (CS%id_Tdif > 0) call post_data(CS%id_Tdif, Tdif_flx, CS%diag)
1073 endif
107412 if (CS%id_Sdif > 0) then
10750 do j=js,je ; do i=is,ie
10760 Sdif_flx(i,j,1) = 0.0 ; Sdif_flx(i,j,nz+1) = 0.0
1077 enddo ; enddo
1078 !$OMP parallel do default(shared)
10790 do K=2,nz ; do j=js,je ; do i=is,ie
10800 Sdif_flx(i,j,K) = (Idt * ent_s(i,j,K)) * (tv%S(i,j,k-1) - tv%S(i,j,k))
1081 enddo ; enddo ; enddo
10820 if (CS%id_Sdif > 0) call post_data(CS%id_Sdif, Sdif_flx, CS%diag)
1083 endif
1084
108512 if (CS%Use_KdWork_diag .or. CS%Use_N2_diag) then
10860 N2_salt(:,:,:) = 0.0
10870 N2_temp(:,:,:) = 0.0
1088 !Compute N2 and don't mask negatives here
10890 EOSdom(:) = EOS_domain(G%HI)
10900 if (nonBous) then
1091 !$OMP parallel do default(shared)
10920 do j=js,je
10930 if (associated(tv%p_surf)) then
10940 do i=is,ie ; p_i(i) = tv%p_surf(i,j) ; enddo
1095 else
10960 do i=is,ie ; p_i(i) = 0.0 ; enddo
1097 endif
10980 do K=2,nz
10990 do i=is,ie
11000 p_i(i) = p_i(i) + H_to_pres * h(i,j,k-1)
1101 enddo
11020 T_i = 0.5*(tv%T(:,j,k-1)+tv%T(:,j,k))
11030 S_i = 0.5*(tv%S(:,j,k-1)+tv%S(:,j,k))
11040 call calculate_specific_vol_derivs(T_i, S_i, p_i, dSpV_dT, dSpV_dS, tv%eqn_of_state, EOSdom)
11050 do i=is,ie
11060 I_dzval = 1.0 / (dz_neglect + 0.5*(dz(i,j,k-1) + dz(i,j,k)))
11070 N2_salt(i,j,K) = (tv%S(i,j,k-1) - tv%S(i,j,k)) * (dSpv_dS(i) * (alt_H_to_pres * I_dzval))
11080 N2_temp(i,j,K) = (tv%T(i,j,k-1) - tv%T(i,j,k)) * (dSpV_dT(i) * (alt_H_to_pres * I_dzval))
1109 enddo
1110 enddo
1111 enddo
1112 else
1113 !$OMP parallel do default(shared)
11140 do j=js,je
11150 if (associated(tv%p_surf)) then
11160 do i=is,ie ; p_i(i) = tv%p_surf(i,j) ; enddo
1117 else
11180 do i=is,ie ; p_i(i) = 0.0 ; enddo
1119 endif
11200 do K=2,nz
11210 do i=is,ie
11220 p_i(i) = p_i(i) + H_to_pres* h(i,j,k-1)
1123 enddo
11240 T_i = 0.5*(tv%T(:,j,k-1)+tv%T(:,j,k))
11250 S_i = 0.5*(tv%S(:,j,k-1)+tv%S(:,j,k))
11260 call calculate_density_derivs(T_i, S_i, p_i, dRhodT, dRhodS, tv%eqn_of_state, EOSdom)
11270 do i=is,ie
11280 I_h = 1.0 / (h_neglect + 0.5*(h(i,j,k-1) + h(i,j,k)))
11290 N2_salt(i,j,K) = -(tv%S(i,j,k-1) - tv%S(i,j,k)) * (dRhodS(i) * (g_rho0 * I_h))
11300 N2_temp(i,j,K) = -(tv%T(i,j,k-1) - tv%T(i,j,k)) * (dRhodT(i) * (g_rho0 * I_h))
1131 enddo
1132 enddo
1133 enddo
1134 endif
11350 if (CS%id_N2_dd>0) call post_data(CS%id_N2_dd, N2_salt(:,:,:)+N2_temp(:,:,:), CS%diag)
11360 if (CS%id_N2_salt_dd>0) call post_data(CS%id_N2_salt_dd, N2_salt, CS%diag)
11370 if (CS%id_N2_temp_dd>0) call post_data(CS%id_N2_temp_dd, N2_temp, CS%diag)
1138
11390 if (CS%Use_KdWork_diag) then
11400 call KdWork_diagnostics(G,GV,US,CS%diag,CS%VBF,N2_salt,N2_temp,dz)
1141 endif
1142
11430 call deallocate_VBF_CS(CS%VBF)
1144
1145 endif
1146
1147 ! mixing of passive tracers from massless boundary layers to interior
114812 call cpu_clock_begin(id_clock_tracers)
1149
115012 if (CS%mix_boundary_tracer_ALE) then
11510 Tr_ea_BBL = sqrt(dt * CS%Kd_BBL_tr)
1152
1153 !$OMP parallel do default(shared) private(htot,in_boundary,add_ent)
11540 do j=js,je
11550 do i=is,ie
11560 htot(i) = 0.0
11570 in_boundary(i) = (G%mask2dT(i,j) > 0.0)
1158 enddo
11590 do k=nz,2,-1 ; do i=is,ie
11600 if (in_boundary(i)) then
11610 htot(i) = htot(i) + h(i,j,k)
1162 ! If diapycnal mixing has been suppressed because this is a massless
1163 ! layer near the bottom, add some mixing of tracers between these
1164 ! layers. This flux is based on the harmonic mean of the two
1165 ! thicknesses, as this corresponds pretty closely (to within
1166 ! differences in the density jumps between layers) with what is done
1167 ! in the calculation of the fluxes in the first place. Kd_min_tr
1168 ! should be much less than the values that have been set in Kd_int,
1169 ! perhaps a molecular diffusivity.
1170 add_ent = ((dt * CS%Kd_min_tr)) * &
1171 ((dz(i,j,k-1)+dz(i,j,k)+dz_neglect) / (dz(i,j,k-1)*dz(i,j,k)+dz_neglect2)) - &
11720 0.5*(ent_s(i,j,K) + ent_s(i,j,K))
11730 if (htot(i) < Tr_ea_BBL) then
11740 add_ent = max(0.0, add_ent, (Tr_ea_BBL - htot(i)) - ent_s(i,j,K))
11750 elseif (add_ent < 0.0) then
11760 add_ent = 0.0 ; in_boundary(i) = .false.
1177 endif
1178
11790 ent_s(i,j,K) = ent_s(i,j,K) + add_ent
1180 endif
1181
11820 if (CS%double_diffuse) then ; if (Kd_extra_S(i,j,k) > 0.0) then
1183 add_ent = (dt * Kd_extra_S(i,j,k)) / &
11840 (0.5 * (dz(i,j,k-1) + dz(i,j,k)) + dz_neglect)
11850 ent_s(i,j,K) = ent_s(i,j,K) + add_ent
1186 endif ; endif
1187 enddo ; enddo
1188
1189 enddo
119012 elseif (CS%double_diffuse .and. .not.CS%mix_boundary_tracers) then ! extra diffusivity for passive tracers
1191 !$OMP parallel do default(shared) private(add_ent)
11920 do k=nz,2,-1 ; do j=js,je ; do i=is,ie
11930 if (Kd_extra_S(i,j,k) > 0.0) then
1194 add_ent = (dt * Kd_extra_S(i,j,k)) / &
11950 (0.5 * (dz(i,j,k-1) + dz(i,j,k)) + dz_neglect)
1196 else
11970 add_ent = 0.0
1198 endif
11990 ent_s(i,j,K) = ent_s(i,j,K) + add_ent
1200 enddo ; enddo ; enddo
1201 endif ! (CS%mix_boundary_tracers)
1202
1203 ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1204 call call_tracer_column_fns(h_orig, h, ent_s(:,:,1:nz), ent_s(:,:,2:nz+1), fluxes, BLD, dt, &
1205 G, GV, US, tv, CS%optics, CS%tracer_flow_CSp, CS%debug, &
1206 KPP_CSp=CS%KPP_CSp, &
1207 nonLocalTrans=KPP_NLTscalar, &
1208 evap_CFL_limit=CS%evap_CFL_limit, &
120912 minimum_forcing_depth=CS%minimum_forcing_depth, h_BL=visc%h_ML)
1210
121112 call cpu_clock_end(id_clock_tracers)
1212
1213 ! Apply ALE sponge
121412 if (CS%use_sponge .and. associated(CS%ALE_sponge_CSp)) then
12150 call cpu_clock_begin(id_clock_sponge)
12160 call apply_ALE_sponge(h, tv, dt, G, GV, US, CS%ALE_sponge_CSp, CS%Time)
12170 call cpu_clock_end(id_clock_sponge)
12180 if (CS%debug) then
12190 call MOM_state_chksum("apply_sponge ", u, v, h, G, GV, US, haloshift=0)
12200 call MOM_thermovar_chksum("apply_sponge ", tv, G, US)
1221 endif
1222 endif ! CS%use_sponge
1223
1224 ! Apply data assimilation incremental update -oda_incupd-
122512 if (CS%use_oda_incupd .and. associated(CS%oda_incupd_CSp)) then
12260 call MOM_mesg("Starting ODA_INCUPD legacy ", 5)
12270 call cpu_clock_begin(id_clock_oda_incupd)
12280 call apply_oda_incupd(h, tv, u, v, dt, G, GV, US, CS%oda_incupd_CSp)
12290 call cpu_clock_end(id_clock_oda_incupd)
12300 if (CS%debug) then
12310 call MOM_state_chksum("apply_oda_incupd ", u, v, h, G, GV, US, haloshift=0)
12320 call MOM_thermovar_chksum("apply_oda_incupd ", tv, G, US)
1233 endif
1234 endif ! CS%use_oda_incupd
1235
1236
1237
123812 call disable_averaging(CS%diag)
1239
124012 if (showCallTree) call callTree_leave("diabatic_ALE_legacy()")
1241
124212end subroutine diabatic_ALE_legacy
1243
1244
1245!> This subroutine imposes the diapycnal mass fluxes and the
1246!! accompanying diapycnal advection of momentum and tracers.
12470subroutine diabatic_ALE(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, &
1248 G, GV, US, CS, stoch_CS, Waves)
1249 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1250 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
1251 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1252 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
1253 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
1254 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
1255 type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
1256 !! unused have NULL ptrs
1257 real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: BLD !< Active mixed layer depth [Z ~> m]
1258 type(forcing), intent(inout) :: fluxes !< points to forcing fields
1259 !! unused fields have NULL ptrs
1260 type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities,
1261 !! BBL properties and related fields
1262 type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum
1263 !! equations, to enable the later derived
1264 !! diagnostics, like energy budgets
1265 type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
1266 real, intent(in) :: dt !< time increment [T ~> s]
1267 type(time_type), intent(in) :: Time_end !< Time at the end of the interval
1268 type(diabatic_CS), pointer :: CS !< module control structure
1269 type(stochastic_CS), pointer :: stoch_CS !< stochastic control structure
1270 type(Wave_parameters_CS), pointer :: Waves !< Surface gravity waves
1271
1272 ! local variables
1273 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: &
12740 h_orig, & ! Initial layer thicknesses [H ~> m or kg m-2]
12750 dz, & ! The vertical distance between interfaces around a layer [Z ~> m]
12760 dSV_dT, & ! The partial derivative of specific volume with temperature [R-1 C-1 ~> m3 kg-1 degC-1]
12770 dSV_dS, & ! The partial derivative of specific volume with salinity [R-1 S-1 ~> m3 kg-1 ppt-1].
12780 cTKE, & ! convective TKE requirements for each layer [R Z3 T-2 ~> J m-2].
12790 u_h, & ! Zonal velocities interpolated to thickness points [L T-1 ~> m s-1]
12800 v_h, & ! Meridional velocities interpolated to thickness points [L T-1 ~> m s-1]
12810 temp_diag, & ! Diagnostic array of previous temperatures [C ~> degC]
12820 saln_diag ! Diagnostic array of previous salinity [S ~> ppt]
1283
1284 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: &
12850 ent_s, & ! The diffusive coupling across interfaces within one time step for
1286 ! salinity and passive tracers [H ~> m or kg m-2]
12870 ent_t, & ! The diffusive coupling across interfaces within one time step for
1288 ! temperature [H ~> m or kg m-2]
12890 Kd_heat, & ! diapycnal diffusivity of heat or the smaller of the diapycnal diffusivities of
1290 ! heat and salt [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
12910 Kd_salt, & ! diapycnal diffusivity of salt and passive tracers [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
12920 Kd_extra_T , & ! The extra diffusivity of temperature due to double diffusion relative to
1293 ! Kd_int returned from set_diffusivity [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
12940 Kd_extra_S , & ! The extra diffusivity of salinity due to double diffusion relative to
1295 ! Kd_int returned from set_diffusivity [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
12960 Kd_ePBL, & ! boundary layer or convective diapycnal diffusivities at interfaces [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
12970 KPP_NLTheat, & ! KPP non-local transport for heat [nondim]
12980 KPP_NLTscalar, & ! KPP non-local transport for scalars [nondim]
12990 KPP_buoy_flux, & ! KPP forcing buoyancy flux [L2 T-3 ~> m2 s-3]
13000 Tdif_flx, & ! diffusive diapycnal heat flux across interfaces [C H T-1 ~> degC m s-1 or degC kg m-2 s-1]
13010 Sdif_flx, & ! diffusive diapycnal salt flux across interfaces [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
13020 N2_salt, & !< Salinity contribution to squared buoyancy frequency at interfaces [T-2 ~> s-2]
13030 N2_temp !< Temperature contribution to squared buoyancy frequency at interfaces [T-2 ~> s-2]
1304
1305 real, dimension(SZI_(G),SZJ_(G)) :: &
13060 U_star, & ! The friction velocity [Z T-1 ~> m s-1].
13070 KPP_temp_flux, & ! KPP effective temperature flux [C H T-1 ~> degC m s-1 or degC kg m-2 s-1]
13080 KPP_salt_flux, & ! KPP effective salt flux [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
13090 SkinBuoyFlux, & ! 2d surface buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL
13100 BBL_BuoyFlux ! 2d bottom buoyancy flux [Z2 T-3 ~> m2 s-3], used by ePBL
1311
1312 logical, dimension(SZI_(G)) :: &
13130 in_boundary ! True if there are no massive layers below, where massive is defined as
1314 ! sufficiently thick that the no-flux boundary conditions have not restricted
1315 ! the entrainment - usually sqrt(Kd*dt).
1316
1317 real, dimension(SZI_(G)) :: &
13180 p_i ,& ! Pressure at the interface [R L2 T-2 ~> Pa]
13190 T_i, & ! Temperature at the interface [C ~> degC]
13200 S_i, & ! Salinity at the interface [S ~> ppt]
13210 drhodS, & ! Local change in density w.r.t. salinity using model EOS & state [R C-1 ~> kg m-3 ppt-1]
13220 drhodT, & ! Local change in density w.r.t. temperature using model EOS & state [R C-1 ~> kg m-3 degC-1]
13230 dSpV_dT, & ! Partial derivative of specific volume with temperature [R-1 C-1 ~> m3 kg-1 degC-1]
13240 dSpV_dS ! Partial derivative of specific volume with salinity [R-1 S-1 ~> m3 kg-1 ppt-1]
1325
1326 real :: h_neglect ! A thickness that is so small it is usually lost
1327 ! in roundoff and can be neglected [H ~> m or kg m-2]
1328 real :: dz_neglect ! A vertical distance that is so small it is usually lost
1329 ! in roundoff and can be neglected [Z ~> m]
1330 real :: dz_neglect2 ! dz_neglect^2 [Z2 ~> m2]
1331 real :: add_ent ! Entrainment that needs to be added when mixing tracers [H ~> m or kg m-2]
1332 real :: I_dzval ! The inverse of the thicknesses averaged to interfaces [Z-1 ~> m-1]
1333 real :: I_h ! The inverse of the thicknesses averaged to interfaces [H-1 ~> m-1 or m2 kg-1]
1334 real :: Tr_ea_BBL ! The diffusive tracer thickness in the BBL that is
1335 ! coupled to the bottom within a timestep [H ~> m or kg m-2]
13360 real :: htot(SZIB_(G)) ! The summed thickness from the bottom [H ~> m or kg m-2].
1337 real :: Kd_add_here ! An added diffusivity [H Z T-1 ~> m2 s-1 or kg m-1 s-1].
1338 real :: Idt ! The inverse time step [T-1 ~> s-1]
1339 real :: g_Rho0 ! G_Earth/Rho0 [H T-2 R-1 ~> m4 s-2 kg-1 or m s-2]
1340 real :: H_to_pres ! A conversion factor from thicknesses to pressure [R L2 T-2 H-1 ~> Pa m-1 or Pa m2 kg-1]
1341 real :: alt_H_to_pres! A conversion factor from thicknesses to pressure w/ alternative scaling [R Z T-2 ~> Pa m-1]
1342 logical :: nonBous ! True if not using the Boussinesq approximation
1343
1344 integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
1345
1346 logical :: showCallTree ! If true, show the call tree
1347 integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, Isq, Ieq, Jsq, Jeq, nz
1348
13490 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
13500 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
13510 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
13520 dz_neglect = GV%dZ_subroundoff ; dz_neglect2 = dz_neglect*dz_neglect
13530 h_neglect = GV%H_subroundoff
1354
13550 nonBous = .not.(GV%Boussinesq .or. GV%semi_Boussinesq)
13560 g_Rho0 = GV%g_Earth_Z_T2 / GV%H_to_RZ
13570 H_to_pres = GV%H_to_RZ * GV%g_Earth
13580 alt_H_to_pres = H_to_pres * US%L_to_Z**2 * GV%Z_to_H
1359
13600 Kd_heat(:,:,:) = 0.0 ; Kd_salt(:,:,:) = 0.0
13610 ent_s(:,:,:) = 0.0 ; ent_t(:,:,:) = 0.0
1362
13630 showCallTree = callTree_showQuery()
13640 if (showCallTree) call callTree_enter("diabatic_ALE(), MOM_diabatic_driver.F90")
1365
13660 if (.not. (CS%useALEalgorithm)) call MOM_error(FATAL, "MOM_diabatic_driver: "// &
13670 "The ALE algorithm must be enabled when using MOM_diabatic_driver.")
1368
1369 ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep
13700 call enable_averages(dt, Time_end, CS%diag)
1371
13720 if (CS%Use_KdWork_diag) call Allocate_VBF_CS(G, GV, CS%VBF)
1373
13740 if (CS%use_geothermal) then
13750 call cpu_clock_begin(id_clock_geothermal)
13760 call geothermal_in_place(h, tv, dt, G, GV, US, CS%geothermal, BBL_buoyflux, halo=CS%halo_TS_diff)
13770 call cpu_clock_end(id_clock_geothermal)
13780 if (showCallTree) call callTree_waypoint("geothermal (diabatic)")
13790 if (CS%debugConservation) call MOM_state_stats('geothermal', u, v, h, tv%T, tv%S, G, GV, US)
1380 endif
1381
1382 ! Whenever thickness changes let the diag manager know, target grids
1383 ! for vertical remapping may need to be regenerated.
13840 call diag_update_remap_grids(CS%diag)
1385
1386 ! Set_pen_shortwave estimates the optical properties of the water column.
1387 ! It will need to be modified later to include information about the
1388 ! biological properties and layer thicknesses.
13890 if (associated(CS%optics)) &
13900 call set_pen_shortwave(CS%optics, fluxes, G, GV, US, CS%diabatic_aux_CSp, CS%opacity, CS%tracer_flow_CSp)
1391
13920 if (CS%debug) call MOM_state_chksum("before find_uv_at_h", u, v, h, G, GV, US, haloshift=0)
1393
13940 if (CS%use_kappa_shear .or. CS%use_CVMix_shear) then
13950 if (CS%use_geothermal) then
13960 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US, zero_mix=.true.)
1397 else
13980 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US)
1399 endif
14000 if (showCallTree) call callTree_waypoint("done with find_uv_at_h (diabatic)")
1401 endif
1402
14030 call cpu_clock_begin(id_clock_set_diffusivity)
1404 ! Sets: Kd_heat, Kd_extra_T, Kd_extra_S and visc%TKE_turb
1405 ! Also changes: visc%Kd_shear, visc%Kv_shear and visc%Kv_slow
14060 if (CS%debug) &
14070 call MOM_state_chksum("before set_diffusivity", u, v, h, G, GV, US, haloshift=CS%halo_TS_diff)
14080 if (CS%double_diffuse) then
1409 call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_heat, G, GV, US, &
14100 CS%set_diff_CSp, CS%VBF, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S)
1411 else
1412 call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_heat, G, GV, US, &
14130 CS%set_diff_CSp, CS%VBF)
1414 endif
14150 call cpu_clock_end(id_clock_set_diffusivity)
14160 if (showCallTree) call callTree_waypoint("done with set_diffusivity (diabatic)")
1417
14180 if (CS%debug) then
14190 call MOM_state_chksum("after set_diffusivity ", u, v, h, G, GV, US, haloshift=0)
14200 call MOM_forcing_chksum("after set_diffusivity ", fluxes, G, US, haloshift=0)
14210 call MOM_thermovar_chksum("after set_diffusivity ", tv, G, US)
14220 call hchksum(Kd_heat, "after set_diffusivity Kd_heat", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
1423 endif
1424
1425 ! Set diffusivities for heat and salt separately, and possibly change the meaning of Kd_heat.
14260 if (CS%double_diffuse) then
1427 ! Add contributions from double diffusion
1428 !$OMP parallel do default(shared)
14290 do K=1,nz+1 ; do j=js,je ; do i=is,ie
14300 Kd_salt(i,j,K) = Kd_heat(i,j,K) + Kd_extra_S(i,j,K)
14310 Kd_heat(i,j,K) = Kd_heat(i,j,K) + Kd_extra_T(i,j,K)
1432 enddo ; enddo ; enddo
1433 else
1434 !$OMP parallel do default(shared)
14350 do K=1,nz+1 ; do j=js,je ; do i=is,ie
14360 Kd_salt(i,j,K) = Kd_heat(i,j,K)
1437 enddo ; enddo ; enddo
1438 endif
1439
14400 if (CS%debug) then
14410 call hchksum(Kd_heat, "after double diffuse Kd_heat", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
14420 call hchksum(Kd_salt, "after double diffuse Kd_salt", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
1443 endif
1444
14450 if (CS%useKPP) then
14460 call cpu_clock_begin(id_clock_kpp)
1447 ! total vertical viscosity in the interior is represented via visc%Kv_shear
14480 do k=1,nz+1 ; do j=js,je ; do i=is,ie
14490 visc%Kv_shear(i,j,k) = visc%Kv_shear(i,j,k) + visc%Kv_slow(i,j,k)
1450 enddo ; enddo ; enddo
1451
1452 ! NOTE: The following do not require initialization, but their checksums do
1453 ! require initialization, and past versions were initialized to zero.
14540 KPP_NLTheat(:,:,:) = 0.
14550 KPP_NLTscalar(:,:,:) = 0.
14560 KPP_buoy_flux(:,:,:) = 0.
14570 KPP_temp_flux(:,:) = 0.
14580 KPP_salt_flux(:,:) = 0.
1459
1460 ! KPP needs the surface buoyancy flux but does not update state variables.
1461 ! We could make this call higher up to avoid a repeat unpacking of the surface fluxes.
1462 ! Sets: KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux
1463 ! NOTE: KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux are returned as rates (i.e. stuff per second)
1464 ! unlike other instances where the fluxes are integrated in time over a time-step.
1465 call calculateBuoyancyFlux2d(G, GV, US, fluxes, CS%optics, h, tv%T, tv%S, tv, &
14660 KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux)
1467
1468 ! Determine the friction velocity, perhaps using the evovling surface density.
14690 call find_ustar(fluxes, tv, U_star, G, GV, US)
1470
1471 ! The KPP scheme calculates boundary layer diffusivities and non-local transport.
14720 if ( associated(fluxes%lamult) ) then
1473 call KPP_compute_BLD(CS%KPP_CSp, G, GV, US, h, tv%T, tv%S, u, v, tv, &
14740 U_star, KPP_buoy_flux, Waves=Waves, lamult=fluxes%lamult)
1475
1476 call KPP_calculate(CS%KPP_CSp, G, GV, US, h, tv, U_star, KPP_buoy_flux, Kd_heat, &
14770 Kd_salt, visc%Kv_shear, KPP_NLTheat, KPP_NLTscalar, Waves=Waves, lamult=fluxes%lamult)
1478 else
1479 call KPP_compute_BLD(CS%KPP_CSp, G, GV, US, h, tv%T, tv%S, u, v, tv, &
14800 U_star, KPP_buoy_flux, Waves=Waves)
1481
1482 call KPP_calculate(CS%KPP_CSp, G, GV, US, h, tv, U_star, KPP_buoy_flux, Kd_heat, &
14830 Kd_salt, visc%Kv_shear, KPP_NLTheat, KPP_NLTscalar, Waves=Waves)
1484 endif
1485
14860 call KPP_get_BLD(CS%KPP_CSp, BLD(:,:), G, US)
1487 ! If visc%MLD or visc%h_ML exist, copy KPP's BLD into them with appropriate conversions.
14880 if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV)
14890 if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:)
14900 if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = KPP_buoy_flux(:,:,1)
1491
14920 if (showCallTree) call callTree_waypoint("done with KPP_calculate (diabatic)")
14930 if (CS%debug) then
14940 call MOM_state_chksum("after KPP", u, v, h, G, GV, US, haloshift=0)
14950 call MOM_forcing_chksum("after KPP", fluxes, G, US, haloshift=0)
14960 call MOM_thermovar_chksum("after KPP", tv, G, US)
14970 call hchksum(Kd_heat, "after KPP Kd_heat", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
14980 call hchksum(Kd_salt, "after KPP Kd_salt", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
1499 call hchksum(KPP_temp_flux, "before KPP_applyNLT netHeat", G%HI, haloshift=0, &
15000 unscale=US%C_to_degC*GV%H_to_m*US%s_to_T)
1501 call hchksum(KPP_salt_flux, "before KPP_applyNLT netSalt", G%HI, haloshift=0, &
15020 unscale=US%S_to_ppt*GV%H_to_m*US%s_to_T)
15030 call hchksum(KPP_NLTheat, "before KPP_applyNLT NLTheat", G%HI, haloshift=0)
15040 call hchksum(KPP_NLTscalar, "before KPP_applyNLT NLTscalar", G%HI, haloshift=0)
1505 endif
1506 ! Apply non-local transport of heat and salt
1507 ! Changes: tv%T, tv%S
1508 call KPP_NonLocalTransport_temp(CS%KPP_CSp, G, GV, h, KPP_NLTheat, KPP_temp_flux, &
15090 dt, tv%tr_T, tv%T, tv%C_p)
1510 call KPP_NonLocalTransport_saln(CS%KPP_CSp, G, GV, h, KPP_NLTscalar, KPP_salt_flux, &
15110 dt, tv%tr_S, tv%S)
15120 call cpu_clock_end(id_clock_kpp)
15130 if (showCallTree) call callTree_waypoint("done with KPP_applyNonLocalTransport (diabatic)")
15140 if (CS%debugConservation) call MOM_state_stats('KPP_applyNonLocalTransport', u, v, h, tv%T, tv%S, G, GV, US)
1515
15160 if (CS%debug) then
15170 call MOM_state_chksum("after KPP_applyNLT ", u, v, h, G, GV, US, haloshift=0)
15180 call MOM_forcing_chksum("after KPP_applyNLT ", fluxes, G, US, haloshift=0)
15190 call MOM_thermovar_chksum("after KPP_applyNLT ", tv, G, US)
1520 endif
1521 endif ! endif for KPP
1522
1523 ! Calculate vertical mixing due to convection (computed via CVMix)
15240 if (CS%use_CVMix_conv) then
1525 ! Increment vertical diffusion and viscosity due to convection
15260 call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv, BLD, Kd_heat, visc%Kv_shear, Kd_aux=Kd_salt)
1527 endif
1528
1529 ! Save fields before boundary forcing is applied for tendency diagnostics
15300 do k=1,nz ; do j=js,je ; do i=is,ie
15310 h_orig(i,j,k) = h(i,j,k)
1532 enddo ; enddo ; enddo
15330 if (CS%boundary_forcing_tendency_diag) then
15340 do k=1,nz ; do j=js,je ; do i=is,ie
15350 temp_diag(i,j,k) = tv%T(i,j,k)
15360 saln_diag(i,j,k) = tv%S(i,j,k)
1537 enddo ; enddo ; enddo
1538 endif
1539
1540 ! Apply forcing
1541 ! Changes made to following fields: h, tv%T and tv%S.
15420 call cpu_clock_begin(id_clock_remap)
1543
15440 if (CS%use_energetic_PBL) then
1545
15460 skinbuoyflux(:,:) = 0.0
1547 call applyBoundaryFluxesInOut(CS%diabatic_aux_CSp, G, GV, US, dt, fluxes, CS%optics, &
1548 optics_nbands(CS%optics), h, tv, CS%aggregate_FW_forcing, CS%evap_CFL_limit, &
15490 CS%minimum_forcing_depth, cTKE, dSV_dT, dSV_dS, SkinBuoyFlux=SkinBuoyFlux, MLD_h=visc%h_ML)
1550
15510 if (CS%debug) then
15520 call hchksum(ent_t, "after applyBoundaryFluxes ent_t", G%HI, haloshift=0, unscale=GV%H_to_MKS)
15530 call hchksum(ent_s, "after applyBoundaryFluxes ent_s", G%HI, haloshift=0, unscale=GV%H_to_MKS)
1554 call hchksum(cTKE, "after applyBoundaryFluxes cTKE", G%HI, haloshift=0, &
15550 unscale=US%RZ3_T3_to_W_m2*US%T_to_s)
1556 call hchksum(dSV_dT, "after applyBoundaryFluxes dSV_dT", G%HI, haloshift=0, &
15570 unscale=US%kg_m3_to_R*US%degC_to_C)
1558 call hchksum(dSV_dS, "after applyBoundaryFluxes dSV_dS", G%HI, haloshift=0, &
15590 unscale=US%kg_m3_to_R*US%ppt_to_S)
1560 endif
1561
15620 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US)
1563 call energetic_PBL(h, u_h, v_h, tv, fluxes, visc, dt, Kd_ePBL, G, GV, US, &
15640 CS%ePBL, stoch_CS, dSV_dT, dSV_dS, cTKE, SkinBuoyFlux, BBL_BuoyFlux, waves=waves)
1565
15660 call energetic_PBL_get_MLD(CS%ePBL, BLD(:,:), G, US)
1567 ! If visc%MLD or visc%h_ML exist, copy ePBL's BLD into them with appropriate conversions.
15680 if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV)
15690 if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:)
15700 if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = SkinBuoyFlux(:,:)
1571
1572 ! Augment the diffusivities and viscosity due to those diagnosed in energetic_PBL.
15730 do K=2,nz ; do j=js,je ; do i=is,ie
15740 if (CS%ePBL_is_additive) then
15750 Kd_add_here = Kd_ePBL(i,j,K)
15760 visc%Kv_shear(i,j,K) = visc%Kv_shear(i,j,K) + CS%ePBL_Prandtl*Kd_ePBL(i,j,K)
1577 else
15780 Kd_add_here = max(Kd_ePBL(i,j,K) - visc%Kd_shear(i,j,K), 0.0)
15790 visc%Kv_shear(i,j,K) = max(visc%Kv_shear(i,j,K), CS%ePBL_Prandtl*Kd_ePBL(i,j,K))
1580 endif
1581
15820 Kd_heat(i,j,K) = Kd_heat(i,j,K) + Kd_add_here
15830 Kd_salt(i,j,K) = Kd_salt(i,j,K) + Kd_add_here
1584 enddo ; enddo ; enddo
1585
15860 if (CS%debug) then
15870 call hchksum(ent_t, "after ePBL ent_t", G%HI, haloshift=0, unscale=GV%H_to_MKS)
15880 call hchksum(ent_s, "after ePBL ent_s", G%HI, haloshift=0, unscale=GV%H_to_MKS)
15890 call hchksum(Kd_ePBL, "after ePBL Kd_ePBL", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
1590 endif
1591
1592 else
1593 call applyBoundaryFluxesInOut(CS%diabatic_aux_CSp, G, GV, US, dt, fluxes, CS%optics, &
1594 optics_nbands(CS%optics), h, tv, CS%aggregate_FW_forcing, &
15950 CS%evap_CFL_limit, CS%minimum_forcing_depth, MLD_h=visc%h_ML)
1596
1597 endif ! endif for CS%use_energetic_PBL
1598
1599 ! diagnose the tendencies due to boundary forcing
1600 ! At this point, the diagnostic grids have not been updated since the call to the boundary layer scheme
1601 ! so all tendency diagnostics need to be posted on h_orig, and grids rebuilt afterwards
16020 if (CS%boundary_forcing_tendency_diag) then
16030 call diagnose_boundary_forcing_tendency(tv, h, temp_diag, saln_diag, h_orig, dt, G, GV, US, CS)
16040 if (CS%id_boundary_forcing_h > 0) call post_data(CS%id_boundary_forcing_h, h, CS%diag, alt_h=h_orig)
1605 endif
1606 ! Boundary fluxes may have changed T, S, and h
16070 call diag_update_remap_grids(CS%diag)
16080 call cpu_clock_end(id_clock_remap)
16090 if (CS%debug) then
16100 call MOM_forcing_chksum("after applyBoundaryFluxes ", fluxes, G, US, haloshift=0)
16110 call MOM_thermovar_chksum("after applyBoundaryFluxes ", tv, G, US)
16120 call MOM_state_chksum("after applyBoundaryFluxes ", u, v, h, G, GV, US, haloshift=0)
1613 endif
16140 if (showCallTree) call callTree_waypoint("done with applyBoundaryFluxes (diabatic)")
16150 if (CS%debugConservation) call MOM_state_stats('applyBoundaryFluxes', u, v, h, tv%T, tv%S, G, GV, US)
1616
16170 if (showCallTree) call callTree_waypoint("done with h=ea-eb (diabatic)")
16180 if (CS%debugConservation) call MOM_state_stats('h=ea-eb', u, v, h, tv%T, tv%S, G, GV, US)
1619
1620 ! calculate change in temperature & salinity due to dia-coordinate surface diffusion
16210 if (associated(tv%T)) then
1622
16230 if (CS%debug) then
16240 call hchksum(ent_t, "before triDiagTS ent_t ", G%HI, haloshift=0, unscale=GV%H_to_MKS)
16250 call hchksum(ent_s, "before triDiagTS ent_s ", G%HI, haloshift=0, unscale=GV%H_to_MKS)
1626 endif
1627
16280 call cpu_clock_begin(id_clock_tridiag)
1629 ! Keep salinity from falling below a small but positive threshold.
1630 ! This constraint is needed for SIS1 ice model, which can extract
1631 ! more salt than is present in the ocean. SIS2 does not suffer
1632 ! from this limitation, in which case we can let salinity=0 and still
1633 ! have salt conserved with SIS2 ice. So for SIS2, we can run with
1634 ! BOUND_SALINITY=False in MOM.F90.
16350 if (associated(tv%S) .and. associated(tv%salt_deficit)) &
16360 call adjust_salt(h, tv, G, GV, CS%diabatic_aux_CSp)
1637
16380 if (CS%diabatic_diff_tendency_diag) then
16390 do k=1,nz ; do j=js,je ; do i=is,ie
16400 temp_diag(i,j,k) = tv%T(i,j,k)
16410 saln_diag(i,j,k) = tv%S(i,j,k)
1642 enddo ; enddo ; enddo
1643 endif
1644
1645 ! Find the vertical distances across layers, which may have been modified by the net surface flux
16460 call thickness_to_dz(h, tv, dz, G, GV, US)
1647
1648 ! set ent_t=dt*Kd_heat/h_int and est_s=dt*Kd_salt/h_int on interfaces for use in the tridiagonal solver.
16490 do j=js,je ; do i=is,ie
16500 ent_t(i,j,1) = 0. ; ent_t(i,j,nz+1) = 0.
16510 ent_s(i,j,1) = 0. ; ent_s(i,j,nz+1) = 0.
1652 enddo ; enddo
1653
1654 !$OMP parallel do default(shared) private(I_dzval)
16550 do K=2,nz ; do j=js,je ; do i=is,ie
16560 I_dzval = 1.0 / (dz_neglect + 0.5*(dz(i,j,k-1) + dz(i,j,k)))
16570 ent_t(i,j,K) = dt * I_dzval * Kd_heat(i,j,k)
16580 ent_s(i,j,K) = dt * I_dzval * Kd_salt(i,j,k)
1659 enddo ; enddo ; enddo
16600 if (showCallTree) call callTree_waypoint("done setting ent_t and ent_t from Kd_heat and " //&
16610 "Kd_salt (diabatic_ALE)")
1662
1663 ! Changes T and S via the tridiagonal solver; no change to h
16640 call tracer_vertdiff_Eulerian(h, ent_t, dt, tv%T, G, GV)
16650 call tracer_vertdiff_Eulerian(h, ent_s, dt, tv%S, G, GV)
1666
1667 ! In ALE-mode, layer thicknesses do not change. Therefore, we can use h below
16680 if (CS%diabatic_diff_tendency_diag) then
16690 call diagnose_diabatic_diff_tendency(tv, h, temp_diag, saln_diag, dt, G, GV, US, CS)
1670 endif
16710 call cpu_clock_end(id_clock_tridiag)
1672
16730 if (showCallTree) call callTree_waypoint("done with triDiagTS (diabatic)")
1674
1675 endif ! endif corresponding to if (associated(tv%T))
1676
16770 if (CS%debugConservation) call MOM_state_stats('triDiagTS', u, v, h, tv%T, tv%S, G, GV, US)
1678
16790 if (CS%debug) then
16800 call MOM_state_chksum("after mixed layer ", u, v, h, G, GV, US, haloshift=0)
16810 call MOM_thermovar_chksum("after mixed layer ", tv, G, US)
1682 endif
1683
1684 ! Whenever thickness changes let the diag manager know, as the
1685 ! target grids for vertical remapping may need to be regenerated.
16860 call diag_update_remap_grids(CS%diag)
1687
1688 ! Set diffusivities for VBF diagnostics if enabled
16890 if (CS%use_energetic_PBL .and. associated(CS%VBF%Kd_ePBL)) CS%VBF%Kd_ePBL(:,:,:) = Kd_ePBL(:,:,:)
16900 if (associated(CS%VBF%Kd_salt)) CS%VBF%Kd_temp(:,:,:) = Kd_heat(:,:,:)
16910 if (associated(CS%VBF%Kd_temp)) CS%VBF%Kd_salt(:,:,:) = Kd_salt(:,:,:)
1692
1693 ! Diagnose the diapycnal diffusivities and other related quantities.
16940 if (CS%id_Kd_heat > 0) call post_data(CS%id_Kd_heat, Kd_heat, CS%diag)
16950 if (CS%id_Kd_salt > 0) call post_data(CS%id_Kd_salt, Kd_salt, CS%diag)
16960 if (CS%id_Kd_ePBL > 0) call post_data(CS%id_Kd_ePBL, Kd_ePBL, CS%diag)
16970 if (CS%id_Kd_int > 0) then
16980 if (CS%double_diffuse .or. CS%useKPP) then
1699 ! Using this as a work array might cause confusion.
17000 do K=1,nz ; do j=js,je ; do i=is,ie
17010 Kd_heat(i,j,k) = min(Kd_heat(i,j,k), Kd_salt(i,j,k))
1702 enddo ; enddo ; enddo
1703 endif
17040 call post_data(CS%id_Kd_int, Kd_heat, CS%diag)
1705 endif
1706
17070 if (CS%id_ea_t > 0) call post_data(CS%id_ea_t, ent_t(:,:,1:nz), CS%diag)
17080 if (CS%id_eb_t > 0) call post_data(CS%id_eb_t, ent_t(:,:,2:nz+1), CS%diag)
17090 if (CS%id_ea_s > 0) call post_data(CS%id_ea_s, ent_s(:,:,1:nz), CS%diag)
17100 if (CS%id_eb_s > 0) call post_data(CS%id_eb_s, ent_s(:,:,2:nz+1), CS%diag)
1711
17120 Idt = 1.0 / dt
17130 if (CS%id_Tdif > 0) then
17140 do j=js,je ; do i=is,ie
17150 Tdif_flx(i,j,1) = 0.0 ; Tdif_flx(i,j,nz+1) = 0.0
1716 enddo ; enddo
1717 !$OMP parallel do default(shared)
17180 do K=2,nz ; do j=js,je ; do i=is,ie
17190 Tdif_flx(i,j,K) = (Idt * ent_t(i,j,K)) * (tv%T(i,j,k-1) - tv%T(i,j,k))
1720 enddo ; enddo ; enddo
17210 if (CS%id_Tdif > 0) call post_data(CS%id_Tdif, Tdif_flx, CS%diag)
1722 endif
17230 if (CS%id_Sdif > 0) then
17240 do j=js,je ; do i=is,ie
17250 Sdif_flx(i,j,1) = 0.0 ; Sdif_flx(i,j,nz+1) = 0.0
1726 enddo ; enddo
1727 !$OMP parallel do default(shared)
17280 do K=2,nz ; do j=js,je ; do i=is,ie
17290 Sdif_flx(i,j,K) = (Idt * ent_s(i,j,K)) * (tv%S(i,j,k-1) - tv%S(i,j,k))
1730 enddo ; enddo ; enddo
17310 if (CS%id_Sdif > 0) call post_data(CS%id_Sdif, Sdif_flx, CS%diag)
1732 endif
1733
17340 if (CS%Use_KdWork_diag .or. CS%Use_N2_diag) then
17350 N2_salt(:,:,:) = 0.0
17360 N2_temp(:,:,:) = 0.0
1737 !Compute N2 and don't mask negatives here
17380 EOSdom(:) = EOS_domain(G%HI)
17390 if (nonBous) then
1740 !$OMP parallel do default(shared)
17410 do j=js,je
17420 if (associated(tv%p_surf)) then
17430 do i=is,ie ; p_i(i) = tv%p_surf(i,j) ; enddo
1744 else
17450 do i=is,ie ; p_i(i) = 0.0 ; enddo
1746 endif
17470 do K=2,nz
17480 do i=is,ie
17490 p_i(i) = p_i(i) + H_to_pres * h(i,j,k-1)
1750 enddo
17510 T_i = 0.5*(tv%T(:,j,k-1)+tv%T(:,j,k))
17520 S_i = 0.5*(tv%S(:,j,k-1)+tv%S(:,j,k))
17530 call calculate_specific_vol_derivs(T_i, S_i, p_i, dSpV_dT, dSpV_dS, tv%eqn_of_state, EOSdom)
17540 do i=is,ie
17550 I_dzval = 1.0 / (dz_neglect + 0.5*(dz(i,j,k-1) + dz(i,j,k)))
17560 N2_salt(i,j,K) = (tv%S(i,j,k-1) - tv%S(i,j,k)) * (dSpv_dS(i) * (alt_H_to_pres * I_dzval))
17570 N2_temp(i,j,K) = (tv%T(i,j,k-1) - tv%T(i,j,k)) * (dSpV_dT(i) * (alt_H_to_pres * I_dzval))
1758 enddo
1759 enddo
1760 enddo
1761 else
1762 !$OMP parallel do default(shared)
17630 do j=js,je
17640 if (associated(tv%p_surf)) then
17650 do i=is,ie ; p_i(i) = tv%p_surf(i,j) ; enddo
1766 else
17670 do i=is,ie ; p_i(i) = 0.0 ; enddo
1768 endif
17690 do K=2,nz
17700 do i=is,ie
17710 p_i(i) = p_i(i) + H_to_pres* h(i,j,k-1)
1772 enddo
17730 T_i = 0.5*(tv%T(:,j,k-1)+tv%T(:,j,k))
17740 S_i = 0.5*(tv%S(:,j,k-1)+tv%S(:,j,k))
17750 call calculate_density_derivs(T_i, S_i, p_i, dRhodT, dRhodS, tv%eqn_of_state, EOSdom)
17760 do i=is,ie
17770 I_h = 1.0 / (h_neglect + 0.5*(h(i,j,k-1) + h(i,j,k)))
17780 N2_salt(i,j,K) = -(tv%S(i,j,k-1) - tv%S(i,j,k)) * (dRhodS(i) * (g_rho0 * I_h))
17790 N2_temp(i,j,K) = -(tv%T(i,j,k-1) - tv%T(i,j,k)) * (dRhodT(i) * (g_rho0 * I_h))
1780 enddo
1781 enddo
1782 enddo
1783 endif
17840 if (CS%id_N2_dd>0) call post_data(CS%id_N2_dd, N2_salt(:,:,:)+N2_temp(:,:,:), CS%diag)
17850 if (CS%id_N2_salt_dd>0) call post_data(CS%id_N2_salt_dd, N2_salt, CS%diag)
17860 if (CS%id_N2_temp_dd>0) call post_data(CS%id_N2_temp_dd, N2_temp, CS%diag)
1787
17880 if (CS%Use_KdWork_diag) then
17890 call KdWork_diagnostics(G,GV,US,CS%diag,CS%VBF,N2_salt,N2_temp,dz)
1790 endif
1791
17920 call deallocate_VBF_CS(CS%VBF)
1793
1794 endif
1795
1796 ! mixing of passive tracers from massless boundary layers to interior
17970 call cpu_clock_begin(id_clock_tracers)
1798
17990 if (CS%mix_boundary_tracer_ALE) then
18000 Tr_ea_BBL = sqrt(dt * CS%Kd_BBL_tr)
1801 !$OMP parallel do default(shared) private(htot,in_boundary,add_ent)
18020 do j=js,je
18030 do i=is,ie
18040 htot(i) = 0.0
18050 in_boundary(i) = (G%mask2dT(i,j) > 0.0)
1806 enddo
18070 do k=nz,2,-1 ; do i=is,ie
18080 if (in_boundary(i)) then
18090 htot(i) = htot(i) + h(i,j,k)
1810 ! If diapycnal mixing has been suppressed because this is a massless layer near the
1811 ! bottom, add some mixing of tracers between these layers. This flux is based on the
1812 ! harmonic mean of the two thicknesses, following what is done in layered mode. Kd_min_tr
1813 ! should be much less than the values in Kd_salt, perhaps a molecular diffusivity.
1814 add_ent = (dt * CS%Kd_min_tr) * &
1815 ((dz(i,j,k-1)+dz(i,j,k) + dz_neglect) / (dz(i,j,k-1)*dz(i,j,k) + dz_neglect2)) - &
18160 ent_s(i,j,K)
18170 if (htot(i) < Tr_ea_BBL) then
18180 add_ent = max(0.0, add_ent, (Tr_ea_BBL - htot(i)) - ent_s(i,j,K))
18190 elseif (add_ent < 0.0) then
18200 add_ent = 0.0 ; in_boundary(i) = .false.
1821 endif
1822
18230 ent_s(i,j,K) = ent_s(i,j,K) + add_ent
1824 endif
1825 enddo ; enddo
1826 enddo
1827 endif ! (CS%mix_boundary_tracer_ALE)
1828
1829 ! For passive tracers, the changes in thickness due to boundary fluxes has yet to be applied
1830 call call_tracer_column_fns(h_orig, h, ent_s(:,:,1:nz), ent_s(:,:,2:nz+1), fluxes, BLD, dt, &
1831 G, GV, US, tv, CS%optics, CS%tracer_flow_CSp, CS%debug, &
1832 KPP_CSp=CS%KPP_CSp, &
1833 nonLocalTrans=KPP_NLTscalar, &
1834 evap_CFL_limit=CS%evap_CFL_limit, &
18350 minimum_forcing_depth=CS%minimum_forcing_depth, h_BL=visc%h_ML)
1836
18370 call cpu_clock_end(id_clock_tracers)
1838
1839 ! Apply ALE sponge
18400 if (CS%use_sponge .and. associated(CS%ALE_sponge_CSp)) then
18410 call cpu_clock_begin(id_clock_sponge)
18420 call apply_ALE_sponge(h, tv, dt, G, GV, US, CS%ALE_sponge_CSp, CS%Time)
18430 call cpu_clock_end(id_clock_sponge)
18440 if (CS%debug) then
18450 call MOM_state_chksum("apply_sponge ", u, v, h, G, GV, US, haloshift=0)
18460 call MOM_thermovar_chksum("apply_sponge ", tv, G, US)
1847 endif
1848 endif ! CS%use_sponge
1849
1850 ! Apply data assimilation incremental update -oda_incupd-
18510 if (CS%use_oda_incupd .and. associated(CS%oda_incupd_CSp)) then
18520 call MOM_mesg("Starting ODA_INCUPD ", 5)
18530 call cpu_clock_begin(id_clock_oda_incupd)
18540 call apply_oda_incupd(h, tv, u, v, dt, G, GV, US, CS%oda_incupd_CSp)
18550 call cpu_clock_end(id_clock_oda_incupd)
18560 if (CS%debug) then
18570 call MOM_state_chksum("apply_oda_incupd ", u, v, h, G, GV, US, haloshift=0)
18580 call MOM_thermovar_chksum("apply_oda_incupd ", tv, G, US)
1859 endif
1860 endif ! CS%use_oda_incupd
1861
1862
18630 call cpu_clock_begin(id_clock_pass)
1864 ! visc%Kv_slow is not in the group pass because it has larger vertical extent.
18650 if (associated(visc%Kv_slow)) &
18660 call pass_var(visc%Kv_slow, G%Domain, To_All+Omit_Corners, halo=1)
18670 call cpu_clock_end(id_clock_pass)
1868
18690 call disable_averaging(CS%diag)
1870
18710 if (showCallTree) call callTree_leave("diabatic_ALE()")
1872
18730end subroutine diabatic_ALE
1874
1875!> Imposes the diapycnal mass fluxes and the accompanying diapycnal advection of momentum and tracers
1876!! using the original MOM6 algorithms.
18770subroutine layered_diabatic(u, v, h, tv, BLD, fluxes, visc, ADp, CDp, dt, Time_end, &
1878 G, GV, US, CS, Waves)
1879 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1880 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
1881 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1882 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
1883 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
1884 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< thickness [H ~> m or kg m-2]
1885 type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
1886 !! unused have NULL ptrs
1887 real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: BLD !< Active mixed layer depth [Z ~> m]
1888 type(forcing), intent(inout) :: fluxes !< points to forcing fields
1889 !! unused fields have NULL ptrs
1890 type(vertvisc_type), intent(inout) :: visc !< Structure with vertical viscosities,
1891 !! BBL properties and related fields
1892 type(accel_diag_ptrs), intent(inout) :: ADp !< Points to accelerations in momentum
1893 !! equations, to enable the later derived
1894 !! diagnostics, like energy budgets
1895 type(cont_diag_ptrs), intent(inout) :: CDp !< points to terms in continuity equations
1896 real, intent(in) :: dt !< time increment [T ~> s]
1897 type(time_type), intent(in) :: Time_end !< Time at the end of the interval
1898 type(diabatic_CS), pointer :: CS !< module control structure
1899 type(Wave_parameters_CS), pointer :: Waves !< Surface gravity waves
1900
1901 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: &
19020 ea, & ! amount of fluid entrained from the layer above within
1903 ! one time step [H ~> m or kg m-2]
19040 eb, & ! amount of fluid entrained from the layer below within
1905 ! one time step [H ~> m or kg m-2]
19060 Kd_lay, & ! diapycnal diffusivity of layers [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
19070 h_orig, & ! initial layer thicknesses [H ~> m or kg m-2]
19080 dz, & ! The vertical distance between interfaces around a layer [Z ~> m]
19090 hold, & ! layer thickness before diapycnal entrainment, and later the initial
1910 ! layer thicknesses (if a mixed layer is used) [H ~> m or kg m-2]
19110 dz_old, & ! The initial vertical distance between interfaces around a layer
1912 ! or the distance before entrainment [Z ~> m]
19130 u_h, & ! Zonal velocities at thickness points after entrainment [L T-1 ~> m s-1]
19140 v_h, & ! Meridional velocities at thickness points after entrainment [L T-1 ~> m s-1]
19150 temp_diag, & ! Diagnostic array of previous temperatures [C ~> degC]
19160 saln_diag ! Diagnostic array of previous salinity [S ~> ppt]
1917 real, dimension(SZI_(G),SZJ_(G)) :: &
19180 h_MLD, & ! Active mixed layer thickness [H ~> m or kg m-2].
19190 U_star, & ! The friction velocity [Z T-1 ~> m s-1].
19200 KPP_temp_flux, & ! KPP effective temperature flux [C H T-1 ~> degC m s-1 or degC kg m-2 s-1]
19210 KPP_salt_flux, & ! KPP effective salt flux [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
19220 Rcv_ml ! Coordinate density of mixed layer [R ~> kg m-3], used for applying sponges
1923
1924 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), target :: &
1925 ! These are targets so that the space can be shared with eaml & ebml.
19260 eatr, & ! The equivalent of ea for tracers, which differs from ea in that it tends to
1927 ! homogenize tracers in massless layers near the boundaries [H ~> m or kg m-2]
19280 ebtr ! The equivalent of eb for tracers, which differs from eb in that it tends to
1929 ! homogenize tracers in massless layers near the boundaries [H ~> m or kg m-2]
1930
1931 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: &
19320 Kd_int, & ! diapycnal diffusivity of interfaces [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
19330 Kd_heat, & ! diapycnal diffusivity of heat [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
19340 Kd_salt, & ! diapycnal diffusivity of salt and passive tracers [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
19350 Kd_extra_T , & ! The extra diffusivity of temperature due to double diffusion relative to
1936 ! Kd_int [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
19370 Kd_extra_S , & ! The extra diffusivity of salinity due to double diffusion relative to
1938 ! Kd_int [H Z T-1 ~> m2 s-1 or kg m-1 s-1]
19390 KPP_NLTheat, & ! KPP non-local transport for heat [nondim]
19400 KPP_NLTscalar, & ! KPP non-local transport for scalars [nondim]
19410 KPP_buoy_flux, & ! KPP forcing buoyancy flux [L2 T-3 ~> m2 s-3]
19420 Tdif_flx, & ! diffusive diapycnal heat flux across interfaces [C H T-1 ~> degC m s-1 or degC kg m-2 s-1]
19430 Tadv_flx, & ! advective diapycnal heat flux across interfaces [C H T-1 ~> degC m s-1 or degC kg m-2 s-1]
19440 Sdif_flx, & ! diffusive diapycnal salt flux across interfaces [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
19450 Sadv_flx ! advective diapycnal salt flux across interfaces [S H T-1 ~> ppt m s-1 or ppt kg m-2 s-1]
1946
1947 ! The following 3 variables are only used with a bulk mixed layer.
1948 real, pointer, dimension(:,:,:) :: &
19490 eaml, & ! The equivalent of ea due to mixed layer processes [H ~> m or kg m-2].
19500 ebml ! The equivalent of eb due to mixed layer processes [H ~> m or kg m-2].
1951 ! eaml and ebml are pointers to eatr and ebtr so as to reuse the memory as
1952 ! the arrays are not needed at the same time.
1953
19540 integer :: kb(SZI_(G),SZJ_(G)) ! index of the lightest layer denser
1955 ! than the buffer layer [nondim]
1956
19570 real :: p_ref_cv(SZI_(G)) ! Reference pressure for the potential density that defines the
1958 ! coordinate variable, set to P_Ref [R L2 T-2 ~> Pa].
1959
19600 logical :: in_boundary(SZI_(G)) ! True if there are no massive layers below,
1961 ! where massive is defined as sufficiently thick that
1962 ! the no-flux boundary conditions have not restricted
1963 ! the entrainment - usually sqrt(Kd*dt).
1964
1965 real :: h_neglect ! A thickness that is so small it is usually lost
1966 ! in roundoff and can be neglected [H ~> m or kg m-2]
1967 real :: dz_neglect ! A vertical distance that is so small it is usually lost
1968 ! in roundoff and can be neglected [Z ~> m]
1969 real :: dz_neglect2 ! dz_neglect^2 [Z2 ~> m2]
1970 real :: net_ent ! The net of ea-eb at an interface [H ~> m or kg m-2]
1971 real :: add_ent ! Entrainment that needs to be added when mixing tracers [H ~> m or kg m-2]
1972 real :: eaval ! eaval is 2*ea at velocity grid points [H ~> m or kg m-2]
1973 real :: hval ! hval is 2*h at velocity grid points [H ~> m or kg m-2]
1974 real :: h_tr ! h_tr is h at tracer points with a tiny thickness
1975 ! added to ensure positive definiteness [H ~> m or kg m-2]
1976 real :: Tr_ea_BBL ! The diffusive tracer thickness in the BBL that is
1977 ! coupled to the bottom within a timestep [H ~> m or kg m-2]
1978
19790 real :: htot(SZIB_(G)) ! The summed thickness from the bottom [H ~> m or kg m-2].
19800 real :: b1(SZIB_(G)) ! A variable used by the tridiagonal solver [H-1 ~> m-1 or m2 kg-1]
1981 real :: b_denom_1 ! The first term in the denominator of b1 [H ~> m or kg m-2]
19820 real :: d1(SZIB_(G)) ! A variable used by the tridiagonal solver [nondim]
19830 real :: c1(SZIB_(G),SZK_(GV)) ! A variable used by the tridiagonal solver [nondim]
1984
1985 real :: dt_mix ! The amount of time over which to apply mixing [T ~> s]
1986 real :: Idt ! The inverse time step [T-1 ~> s-1]
1987
1988 integer :: dir_flag ! An integer encoding the directions in which to do halo updates.
1989 logical :: showCallTree ! If true, show the call tree
1990 integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
1991 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, nkmb, halo
1992
19930 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
19940 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
19950 nkmb = GV%nk_rho_varies
19960 h_neglect = GV%H_subroundoff
19970 dz_neglect = GV%dZ_subroundoff ; dz_neglect2 = dz_neglect*dz_neglect
19980 Kd_heat(:,:,:) = 0.0 ; Kd_salt(:,:,:) = 0.0
1999
20000 showCallTree = callTree_showQuery()
20010 if (showCallTree) call callTree_enter("layered_diabatic(), MOM_diabatic_driver.F90")
2002
2003 ! set equivalence between the same bits of memory for these arrays
20040 eaml => eatr ; ebml => ebtr
2005
2006 ! For all other diabatic subroutines, the averaging window should be the entire diabatic timestep
20070 call enable_averages(dt, Time_end, CS%diag)
2008
20090 if ((CS%ML_mix_first > 0.0) .or. CS%use_geothermal) then
20100 halo = CS%halo_TS_diff
2011 !$OMP parallel do default(shared)
20120 do k=1,nz ; do j=js-halo,je+halo ; do i=is-halo,ie+halo
20130 h_orig(i,j,k) = h(i,j,k) ; eaml(i,j,k) = 0.0 ; ebml(i,j,k) = 0.0
2014 enddo ; enddo ; enddo
2015 endif
2016
20170 if (CS%use_geothermal) then
20180 call cpu_clock_begin(id_clock_geothermal)
20190 call geothermal_entraining(h, tv, dt, eaml, ebml, G, GV, US, CS%geothermal, halo=CS%halo_TS_diff)
20200 call cpu_clock_end(id_clock_geothermal)
20210 if (showCallTree) call callTree_waypoint("geothermal (diabatic)")
20220 if (CS%debugConservation) call MOM_state_stats('geothermal', u, v, h, tv%T, tv%S, G, GV, US)
2023 endif
2024
2025 ! Whenever thickness changes let the diag manager know, target grids
2026 ! for vertical remapping may need to be regenerated.
20270 call diag_update_remap_grids(CS%diag)
2028
2029 ! Set_pen_shortwave estimates the optical properties of the water column.
2030 ! It will need to be modified later to include information about the
2031 ! biological properties and layer thicknesses.
20320 if (associated(CS%optics)) &
20330 call set_pen_shortwave(CS%optics, fluxes, G, GV, US, CS%diabatic_aux_CSp, CS%opacity, CS%tracer_flow_CSp)
2034
20350 if (CS%use_bulkmixedlayer) then
20360 if (CS%debug) call MOM_forcing_chksum("Before mixedlayer", fluxes, G, US, haloshift=0)
2037
20380 if (CS%ML_mix_first > 0.0) then
2039! This subroutine
2040! (1) Cools the mixed layer.
2041! (2) Performs convective adjustment by mixed layer entrainment.
2042! (3) Heats the mixed layer and causes it to detrain to
2043! Monin-Obukhov depth or minimum mixed layer depth.
2044! (4) Uses any remaining TKE to drive mixed layer entrainment.
2045! (5) Possibly splits buffer layer into two isopycnal layers (when using isopycnal coordinate)
20460 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US)
2047
20480 call cpu_clock_begin(id_clock_mixedlayer)
20490 if (CS%ML_mix_first < 1.0) then
2050 ! Changes: h, tv%T, tv%S, eaml and ebml (G is also inout???)
2051 call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt*CS%ML_mix_first, &
2052 eaml, ebml, G, GV, US, CS%bulkmixedlayer, CS%optics, &
20530 BLD, h_MLD, CS%aggregate_FW_forcing, dt, last_call=.false.)
2054 else
2055 ! Changes: h, tv%T, tv%S, eaml and ebml (G is also inout???)
2056 call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt, eaml, ebml, &
2057 G, GV, US, CS%bulkmixedlayer, CS%optics, &
20580 BLD, h_MLD, CS%aggregate_FW_forcing, dt, last_call=.true.)
20590 if (associated(visc%h_ML)) visc%h_ML(:,:) = h_MLD(:,:)
20600 if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:)
2061 endif
2062
2063 ! Keep salinity from falling below a small but positive threshold.
2064 ! This constraint is needed for SIS1 ice model, which can extract
2065 ! more salt than is present in the ocean. SIS2 does not suffer
2066 ! from this limitation, in which case we can let salinity=0 and still
2067 ! have salt conserved with SIS2 ice. So for SIS2, we can run with
2068 ! BOUND_SALINITY=False in MOM.F90.
20690 if (associated(tv%S) .and. associated(tv%salt_deficit)) &
20700 call adjust_salt(h, tv, G, GV, CS%diabatic_aux_CSp)
20710 call cpu_clock_end(id_clock_mixedlayer)
20720 if (CS%debug) then
20730 call MOM_state_chksum("After mixedlayer ", u, v, h, G, GV, US, haloshift=0)
20740 call MOM_forcing_chksum("After mixedlayer", fluxes, G, US, haloshift=0)
2075 endif
20760 if (showCallTree) call callTree_waypoint("done with 1st bulkmixedlayer (diabatic)")
20770 if (CS%debugConservation) call MOM_state_stats('1st bulkmixedlayer', u, v, h, tv%T, tv%S, G, GV, US)
2078 endif
2079 endif
2080
20810 if (CS%debug) &
20820 call MOM_state_chksum("before find_uv_at_h", u, v, h, G, GV, US, haloshift=0)
20830 if (CS%use_kappa_shear .or. CS%use_CVMix_shear) then
20840 if ((CS%ML_mix_first > 0.0) .or. CS%use_geothermal) then
20850 call find_uv_at_h(u, v, h_orig, u_h, v_h, G, GV, US, eaml, ebml)
20860 if (CS%debug) then
20870 call hchksum(eaml, "after find_uv_at_h eaml", G%HI, unscale=GV%H_to_MKS)
20880 call hchksum(ebml, "after find_uv_at_h ebml", G%HI, unscale=GV%H_to_MKS)
2089 endif
2090 else
20910 call find_uv_at_h(u, v, h, u_h, v_h, G, GV, US)
2092 endif
20930 if (showCallTree) call callTree_waypoint("done with find_uv_at_h (diabatic)")
2094 endif
2095
20960 call cpu_clock_begin(id_clock_set_diffusivity)
2097 ! Sets: Kd_lay, Kd_int, Kd_extra_T, Kd_extra_S and visc%TKE_turb
2098 ! Also changes: visc%Kd_shear and visc%Kv_shear
20990 if ((CS%halo_TS_diff > 0) .and. (CS%ML_mix_first > 0.0)) then
21000 if (associated(tv%T)) call pass_var(tv%T, G%Domain, halo=CS%halo_TS_diff, complete=.false.)
21010 if (associated(tv%S)) call pass_var(tv%S, G%Domain, halo=CS%halo_TS_diff, complete=.false.)
21020 call pass_var(h, G%domain, halo=CS%halo_TS_diff, complete=.true.)
2103 endif
2104
2105 ! Update derived thermodynamic quantities.
21060 if ((CS%ML_mix_first > 0.0) .and. allocated(tv%SpV_avg)) then
21070 call calc_derived_thermo(tv, h, G, GV, US, halo=CS%halo_TS_diff)
2108 endif
2109
21100 if (CS%debug) &
21110 call MOM_state_chksum("before set_diffusivity", u, v, h, G, GV, US, haloshift=CS%halo_TS_diff)
21120 if (CS%double_diffuse) then
2113 call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, &
21140 CS%set_diff_CSp, CS%VBF, Kd_lay=Kd_lay, Kd_extra_T=Kd_extra_T, Kd_extra_S=Kd_extra_S)
2115 else
2116 call set_diffusivity(u, v, h, u_h, v_h, tv, fluxes, CS%optics, visc, dt, Kd_int, G, GV, US, &
21170 CS%set_diff_CSp, CS%VBF, Kd_lay=Kd_lay)
2118 endif
21190 call cpu_clock_end(id_clock_set_diffusivity)
21200 if (showCallTree) call callTree_waypoint("done with set_diffusivity (diabatic)")
2121
21220 if (CS%debug) then
21230 call MOM_state_chksum("after set_diffusivity ", u, v, h, G, GV, US, haloshift=0)
21240 call MOM_forcing_chksum("after set_diffusivity ", fluxes, G, US, haloshift=0)
21250 call MOM_thermovar_chksum("after set_diffusivity ", tv, G, US)
21260 call hchksum(Kd_lay, "after set_diffusivity Kd_lay", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
21270 call hchksum(Kd_Int, "after set_diffusivity Kd_Int", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
2128 endif
2129
2130
21310 if (CS%useKPP) then
21320 call cpu_clock_begin(id_clock_kpp)
2133
2134 ! NOTE: The following do not require initialization, but their checksums do
2135 ! require initialization, and past versions were initialized to zero.
21360 KPP_NLTheat(:,:,:) = 0.
21370 KPP_NLTscalar(:,:,:) = 0.
21380 KPP_buoy_flux(:,:,:) = 0.
21390 KPP_temp_flux(:,:) = 0.
21400 KPP_salt_flux(:,:) = 0.
2141
2142 ! KPP needs the surface buoyancy flux but does not update state variables.
2143 ! We could make this call higher up to avoid a repeat unpacking of the surface fluxes.
2144 ! Sets: KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux
2145 ! NOTE: KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux are returned as rates (i.e. stuff per second)
2146 ! unlike other instances where the fluxes are integrated in time over a time-step.
2147 call calculateBuoyancyFlux2d(G, GV, US, fluxes, CS%optics, h, tv%T, tv%S, tv, &
21480 KPP_buoy_flux, KPP_temp_flux, KPP_salt_flux)
2149 ! The KPP scheme calculates boundary layer diffusivities and non-local transport.
2150
2151 ! Set diffusivities for heat and salt separately
2152
21530 if (CS%double_diffuse) then
2154 ! Add contribution from double diffusion
2155 !$OMP parallel do default(shared)
21560 do K=1,nz+1 ; do j=js,je ; do i=is,ie
21570 Kd_salt(i,j,K) = Kd_int(i,j,K) + Kd_extra_S(i,j,K)
21580 Kd_heat(i,j,K) = Kd_int(i,j,K) + Kd_extra_T(i,j,K)
2159 enddo ; enddo ; enddo
2160 else
2161 !$OMP parallel do default(shared)
21620 do K=1,nz+1 ; do j=js,je ; do i=is,ie
21630 Kd_salt(i,j,K) = Kd_int(i,j,K)
21640 Kd_heat(i,j,K) = Kd_int(i,j,K)
2165 enddo ; enddo ; enddo
2166 endif
2167
2168 ! Determine the friction velocity, perhaps using the evovling surface density.
21690 call find_ustar(fluxes, tv, U_star, G, GV, US)
2170
21710 if ( associated(fluxes%lamult) ) then
2172 call KPP_compute_BLD(CS%KPP_CSp, G, GV, US, h, tv%T, tv%S, u, v, tv, &
21730 U_star, KPP_buoy_flux, Waves=Waves, lamult=fluxes%lamult)
2174
2175 call KPP_calculate(CS%KPP_CSp, G, GV, US, h, tv, U_star, KPP_buoy_flux, Kd_heat, &
21760 Kd_salt, visc%Kv_shear, KPP_NLTheat, KPP_NLTscalar, Waves=Waves, lamult=fluxes%lamult)
2177 else
2178 call KPP_compute_BLD(CS%KPP_CSp, G, GV, US, h, tv%T, tv%S, u, v, tv, &
21790 U_star, KPP_buoy_flux, Waves=Waves)
2180
2181 call KPP_calculate(CS%KPP_CSp, G, GV, US, h, tv, U_star, KPP_buoy_flux, Kd_heat, &
21820 Kd_salt, visc%Kv_shear, KPP_NLTheat, KPP_NLTscalar, Waves=Waves)
2183 endif
2184
21850 call KPP_get_BLD(CS%KPP_CSp, BLD(:,:), G, US)
2186 ! If visc%MLD or visc%h_ML exist, copy KPP's BLD into them with appropriate conversions.
21870 if (associated(visc%h_ML)) call convert_MLD_to_ML_thickness(BLD, h, visc%h_ML, tv, G, GV)
21880 if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:)
21890 if (associated(visc%sfc_buoy_flx)) visc%sfc_buoy_flx(:,:) = KPP_buoy_flux(:,:,1)
2190
21910 if (.not. CS%KPPisPassive) then
2192 !$OMP parallel do default(shared)
21930 do k=1,nz+1 ; do j=js,je ; do i=is,ie
21940 Kd_int(i,j,K) = min( Kd_salt(i,j,k), Kd_heat(i,j,k) )
2195 enddo ; enddo ; enddo
21960 if (CS%double_diffuse) then
2197 !$OMP parallel do default(shared)
21980 do k=1,nz+1 ; do j=js,je ; do i=is,ie
21990 Kd_extra_S(i,j,k) = (Kd_salt(i,j,k) - Kd_int(i,j,K))
22000 Kd_extra_T(i,j,k) = (Kd_heat(i,j,k) - Kd_int(i,j,K))
2201 enddo ; enddo ; enddo
2202 endif
2203 endif ! not passive
2204
22050 call cpu_clock_end(id_clock_kpp)
22060 if (showCallTree) call callTree_waypoint("done with KPP_calculate (diabatic)")
22070 if (CS%debug) then
22080 call MOM_state_chksum("after KPP", u, v, h, G, GV, US, haloshift=0)
22090 call MOM_forcing_chksum("after KPP", fluxes, G, US, haloshift=0)
22100 call MOM_thermovar_chksum("after KPP", tv, G, US)
22110 call hchksum(Kd_lay, "after KPP Kd_lay", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
22120 call hchksum(Kd_Int, "after KPP Kd_Int", G%HI, haloshift=0, unscale=GV%HZ_T_to_m2_s)
2213 endif
2214 endif ! endif for KPP
2215
2216 ! Add vertical diff./visc. due to convection (computed via CVMix)
22170 if (CS%use_CVMix_conv) then
22180 call calculate_CVMix_conv(h, tv, G, GV, US, CS%CVMix_conv, BLD, Kd_int, visc%Kv_shear)
2219 endif
2220
22210 if (CS%useKPP) then
22220 call cpu_clock_begin(id_clock_kpp)
22230 if (CS%debug) then
2224 call hchksum(KPP_temp_flux, "before KPP_applyNLT netHeat", G%HI, haloshift=0, &
22250 unscale=US%C_to_degC*GV%H_to_m*US%s_to_T)
2226 call hchksum(KPP_salt_flux, "before KPP_applyNLT netSalt", G%HI, haloshift=0, &
22270 unscale=US%S_to_ppt*GV%H_to_m*US%s_to_T)
22280 call hchksum(KPP_NLTheat, "before KPP_applyNLT NLTheat", G%HI, haloshift=0)
22290 call hchksum(KPP_NLTscalar, "before KPP_applyNLT NLTscalar", G%HI, haloshift=0)
2230 endif
2231 ! Apply non-local transport of heat and salt
2232 ! Changes: tv%T, tv%S
2233 call KPP_NonLocalTransport_temp(CS%KPP_CSp, G, GV, h, KPP_NLTheat, KPP_temp_flux, &
22340 dt, tv%tr_T, tv%T, tv%C_p)
2235 call KPP_NonLocalTransport_saln(CS%KPP_CSp, G, GV, h, KPP_NLTscalar, KPP_salt_flux, &
22360 dt, tv%tr_S, tv%S)
22370 call cpu_clock_end(id_clock_kpp)
22380 if (showCallTree) call callTree_waypoint("done with KPP_applyNonLocalTransport (diabatic)")
22390 if (CS%debugConservation) call MOM_state_stats('KPP_applyNonLocalTransport', u, v, h, tv%T, tv%S, G, GV, US)
2240
22410 if (CS%debug) then
22420 call MOM_state_chksum("after KPP_applyNLT ", u, v, h, G, GV, US, haloshift=0)
22430 call MOM_forcing_chksum("after KPP_applyNLT ", fluxes, G, US, haloshift=0)
22440 call MOM_thermovar_chksum("after KPP_applyNLT ", tv, G, US)
2245 endif
2246 endif ! endif for KPP
2247
2248 ! Differential diffusion done here.
2249 ! Changes: tv%T, tv%S
22500 if (CS%double_diffuse .and. associated(tv%T)) then
2251
22520 call cpu_clock_begin(id_clock_differential_diff)
22530 call differential_diffuse_T_S(h, tv%T, tv%S, Kd_extra_T, Kd_extra_S, tv, dt, G, GV)
22540 call cpu_clock_end(id_clock_differential_diff)
22550 if (showCallTree) call callTree_waypoint("done with differential_diffuse_T_S (diabatic)")
22560 if (CS%debugConservation) call MOM_state_stats('differential_diffuse_T_S', u, v, h, tv%T, tv%S, G, GV, US)
2257
2258 ! increment heat and salt diffusivity.
2259 ! CS%useKPP==.true. already has extra_T and extra_S included
22600 if (.not. CS%useKPP) then
2261 !$OMP parallel do default(shared)
22620 do K=2,nz ; do j=js,je ; do i=is,ie
22630 Kd_heat(i,j,K) = Kd_heat(i,j,K) + Kd_extra_T(i,j,K)
22640 Kd_salt(i,j,K) = Kd_salt(i,j,K) + Kd_extra_S(i,j,K)
2265 enddo ; enddo ; enddo
2266 endif
2267
2268 endif
2269
2270 ! Calculate layer entrainments and detrainments from diffusivities and differences between
2271 ! layer and target densities (i.e. do remapping as well as diffusion).
22720 call cpu_clock_begin(id_clock_entrain)
2273 ! Calculate appropriately limited diapycnal mass fluxes to account
2274 ! for diapycnal diffusion and advection. Sets: ea, eb. Changes: kb
2275 call Entrainment_diffusive(h, tv, fluxes, dt, G, GV, US, CS%entrain_diffusive, &
22760 ea, eb, kb, Kd_lay=Kd_lay, Kd_int=Kd_int)
22770 call cpu_clock_end(id_clock_entrain)
22780 if (showCallTree) call callTree_waypoint("done with Entrainment_diffusive (diabatic)")
2279
22800 if (CS%debug) then
22810 call MOM_forcing_chksum("after calc_entrain ", fluxes, G, US, haloshift=0)
22820 call MOM_thermovar_chksum("after calc_entrain ", tv, G, US)
22830 call MOM_state_chksum("after calc_entrain ", u, v, h, G, GV, US, haloshift=0)
22840 call hchksum(ea, "after calc_entrain ea", G%HI, haloshift=0, unscale=GV%H_to_MKS)
22850 call hchksum(eb, "after calc_entrain eb", G%HI, haloshift=0, unscale=GV%H_to_MKS)
2286 endif
2287
2288 ! Save fields before boundary forcing is applied for tendency diagnostics
22890 if (CS%boundary_forcing_tendency_diag) then
22900 do k=1,nz ; do j=js,je ; do i=is,ie
22910 temp_diag(i,j,k) = tv%T(i,j,k)
22920 saln_diag(i,j,k) = tv%S(i,j,k)
2293 enddo ; enddo ; enddo
2294 endif
2295
2296 ! Update h according to divergence of the difference between
2297 ! ea and eb. We keep a record of the original h in hold.
2298 ! In the following, the checks for negative values are to guard
2299 ! against instances where entrainment drives a layer to
2300 ! negative thickness. This situation will never happen if
2301 ! enough iterations are permitted in Calculate_Entrainment.
2302 ! Even if too few iterations are allowed, it is still guarded
2303 ! against. In other words the checks are probably unnecessary.
2304 !$OMP parallel do default(shared)
23050 do j=js,je
23060 do i=is,ie
23070 hold(i,j,1) = h(i,j,1)
23080 h(i,j,1) = h(i,j,1) + (eb(i,j,1) - ea(i,j,2))
23090 hold(i,j,nz) = h(i,j,nz)
23100 h(i,j,nz) = h(i,j,nz) + (ea(i,j,nz) - eb(i,j,nz-1))
23110 if (h(i,j,1) <= 0.0) then
23120 h(i,j,1) = GV%Angstrom_H
2313 endif
23140 if (h(i,j,nz) <= 0.0) then
23150 h(i,j,nz) = GV%Angstrom_H
2316 endif
2317 enddo
23180 do k=2,nz-1 ; do i=is,ie
23190 hold(i,j,k) = h(i,j,k)
2320 h(i,j,k) = h(i,j,k) + ((ea(i,j,k) - eb(i,j,k-1)) + &
23210 (eb(i,j,k) - ea(i,j,k+1)))
23220 if (h(i,j,k) <= 0.0) then
23230 h(i,j,k) = GV%Angstrom_H
2324 endif
2325 enddo ; enddo
2326 enddo
2327 ! Checks for negative thickness may have changed layer thicknesses
23280 call diag_update_remap_grids(CS%diag)
2329
23300 if (CS%debug) then
23310 call MOM_state_chksum("after negative check ", u, v, h, G, GV, US, haloshift=0)
23320 call MOM_forcing_chksum("after negative check ", fluxes, G, US, haloshift=0)
23330 call MOM_thermovar_chksum("after negative check ", tv, G, US)
2334 endif
23350 if (showCallTree) call callTree_waypoint("done with h=ea-eb (diabatic)")
23360 if (CS%debugConservation) call MOM_state_stats('h=ea-eb', u, v, h, tv%T, tv%S, G, GV, US)
2337
2338 ! Here, T and S are updated according to ea and eb.
2339 ! If using the bulk mixed layer, T and S are also updated
2340 ! by surface fluxes (in fluxes%*).
2341 ! This is a very long block.
23420 if (CS%use_bulkmixedlayer) then
2343
23440 if (associated(tv%T)) then
23450 call cpu_clock_begin(id_clock_tridiag)
2346 ! Temperature and salinity (as state variables) are treated
2347 ! differently from other tracers to insure massless layers that
2348 ! are lighter than the mixed layer have temperatures and salinities
2349 ! that correspond to their prescribed densities.
23500 if (CS%massless_match_targets) then
2351 !$OMP parallel do default (shared) private(h_tr,b1,d1,c1,b_denom_1)
23520 do j=js,je
23530 do i=is,ie
23540 h_tr = hold(i,j,1) + h_neglect
23550 b1(i) = 1.0 / (h_tr + eb(i,j,1))
23560 d1(i) = h_tr * b1(i)
23570 tv%T(i,j,1) = b1(i) * (h_tr*tv%T(i,j,1))
23580 tv%S(i,j,1) = b1(i) * (h_tr*tv%S(i,j,1))
2359 enddo
23600 do k=2,nkmb ; do i=is,ie
23610 c1(i,k) = eb(i,j,k-1) * b1(i)
23620 h_tr = hold(i,j,k) + h_neglect
23630 b_denom_1 = h_tr + d1(i)*ea(i,j,k)
23640 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
23650 if (k<nkmb) d1(i) = b_denom_1 * b1(i)
23660 tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,k-1))
23670 tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,k-1))
2368 enddo ; enddo
2369
23700 do k=nkmb+1,nz ; do i=is,ie
23710 if (k == kb(i,j)) then
23720 c1(i,k) = eb(i,j,k-1) * b1(i)
2373 d1(i) = (((eb(i,j,nkmb)-eb(i,j,k-1)) + hold(i,j,nkmb) + h_neglect) + &
23740 d1(i)*ea(i,j,nkmb)) * b1(i)
23750 h_tr = hold(i,j,k) + h_neglect
23760 b_denom_1 = h_tr + d1(i)*ea(i,j,k)
23770 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
23780 d1(i) = b_denom_1 * b1(i)
23790 tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,nkmb))
23800 tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,nkmb))
23810 elseif (k > kb(i,j)) then
23820 c1(i,k) = eb(i,j,k-1) * b1(i)
23830 h_tr = hold(i,j,k) + h_neglect
23840 b_denom_1 = h_tr + d1(i)*ea(i,j,k)
23850 b1(i) = 1.0 / (b_denom_1 + eb(i,j,k))
23860 d1(i) = b_denom_1 * b1(i)
23870 tv%T(i,j,k) = b1(i) * (h_tr*tv%T(i,j,k) + ea(i,j,k)*tv%T(i,j,k-1))
23880 tv%S(i,j,k) = b1(i) * (h_tr*tv%S(i,j,k) + ea(i,j,k)*tv%S(i,j,k-1))
23890 elseif (eb(i,j,k) < eb(i,j,k-1)) then ! (note that k < kb(i,j))
2390 ! The bottommost buffer layer might entrain all the mass from some
2391 ! of the interior layers that are thin and lighter in the coordinate
2392 ! density than that buffer layer. The T and S of these newly
2393 ! massless interior layers are unchanged.
23940 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)
23950 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)
2396 endif
2397 enddo ; enddo
2398
23990 do k=nz-1,nkmb,-1 ; do i=is,ie
24000 if (k >= kb(i,j)) then
24010 tv%T(i,j,k) = tv%T(i,j,k) + c1(i,k+1)*tv%T(i,j,k+1)
24020 tv%S(i,j,k) = tv%S(i,j,k) + c1(i,k+1)*tv%S(i,j,k+1)
2403 endif
2404 enddo ; enddo
24050 do i=is,ie ; if (kb(i,j) <= nz) then
24060 tv%T(i,j,nkmb) = tv%T(i,j,nkmb) + c1(i,kb(i,j))*tv%T(i,j,kb(i,j))
24070 tv%S(i,j,nkmb) = tv%S(i,j,nkmb) + c1(i,kb(i,j))*tv%S(i,j,kb(i,j))
2408 endif ; enddo
24090 do k=nkmb-1,1,-1 ; do i=is,ie
24100 tv%T(i,j,k) = tv%T(i,j,k) + c1(i,k+1)*tv%T(i,j,k+1)
24110 tv%S(i,j,k) = tv%S(i,j,k) + c1(i,k+1)*tv%S(i,j,k+1)
2412 enddo ; enddo
2413 enddo ! end of j loop
2414 else ! .not. massless_match_targets
2415 ! This simpler form allows T & S to be too dense for the layers
2416 ! between the buffer layers and the interior.
2417 ! Changes: T, S
24180 if (CS%tracer_tridiag) then
24190 call tracer_vertdiff(hold, ea, eb, dt, tv%T, G, GV)
24200 call tracer_vertdiff(hold, ea, eb, dt, tv%S, G, GV)
2421 else
24220 call triDiagTS(G, GV, is, ie, js, je, hold, ea, eb, tv%T, tv%S)
2423 endif
2424 endif ! massless_match_targets
24250 call cpu_clock_end(id_clock_tridiag)
2426
2427 endif ! endif for associated(T)
24280 if (CS%debugConservation) call MOM_state_stats('BML tridiag', u, v, h, tv%T, tv%S, G, GV, US)
2429
24300 if ((CS%ML_mix_first > 0.0) .or. CS%use_geothermal) then
2431 ! The mixed layer code has already been called, but there is some needed
2432 ! bookkeeping.
2433 !$OMP parallel do default(shared)
24340 do k=1,nz ; do j=js,je ; do i=is,ie
24350 hold(i,j,k) = h_orig(i,j,k)
24360 ea(i,j,k) = ea(i,j,k) + eaml(i,j,k)
24370 eb(i,j,k) = eb(i,j,k) + ebml(i,j,k)
2438 enddo ; enddo ; enddo
24390 if (CS%debug) then
24400 call hchksum(ea, "after ea = ea + eaml", G%HI, haloshift=0, unscale=GV%H_to_MKS)
24410 call hchksum(eb, "after eb = eb + ebml", G%HI, haloshift=0, unscale=GV%H_to_MKS)
2442 endif
2443 endif
2444
24450 if (CS%ML_mix_first < 1.0) then
2446 ! Call the mixed layer code now, perhaps for a second time.
2447 ! This subroutine (1) Cools the mixed layer.
2448 ! (2) Performs convective adjustment by mixed layer entrainment.
2449 ! (3) Heats the mixed layer and causes it to detrain to
2450 ! Monin-Obukhov depth or minimum mixed layer depth.
2451 ! (4) Uses any remaining TKE to drive mixed layer entrainment.
2452 ! (5) Possibly splits the buffer layer into two isopycnal layers.
2453
24540 call find_uv_at_h(u, v, hold, u_h, v_h, G, GV, US, ea, eb)
24550 if (CS%debug) call MOM_state_chksum("find_uv_at_h1 ", u, v, h, G, GV, US, haloshift=0)
2456
24570 dt_mix = min(dt, dt*(1.0 - CS%ML_mix_first))
24580 call cpu_clock_begin(id_clock_mixedlayer)
2459 ! Changes: h, tv%T, tv%S, ea and eb (G is also inout???)
2460 call bulkmixedlayer(h, u_h, v_h, tv, fluxes, dt_mix, ea, eb, &
2461 G, GV, US, CS%bulkmixedlayer, CS%optics, &
24620 BLD, h_MLD, CS%aggregate_FW_forcing, dt, last_call=.true.)
24630 if (associated(visc%h_ML)) visc%h_ML(:,:) = h_MLD(:,:)
24640 if (associated(visc%MLD)) visc%MLD(:,:) = BLD(:,:)
2465
2466 ! Keep salinity from falling below a small but positive threshold.
2467 ! This constraint is needed for SIS1 ice model, which can extract
2468 ! more salt than is present in the ocean. SIS2 does not suffer
2469 ! from this limitation, in which case we can let salinity=0 and still
2470 ! have salt conserved with SIS2 ice. So for SIS2, we can run with
2471 ! BOUND_SALINITY=False in MOM.F90.
24720 if (associated(tv%S) .and. associated(tv%salt_deficit)) &
24730 call adjust_salt(h, tv, G, GV, CS%diabatic_aux_CSp)
2474
24750 call cpu_clock_end(id_clock_mixedlayer)
24760 if (showCallTree) call callTree_waypoint("done with 2nd bulkmixedlayer (diabatic)")
24770 if (CS%debugConservation) call MOM_state_stats('2nd bulkmixedlayer', u, v, h, tv%T, tv%S, G, GV, US)
2478 endif
2479
2480 else ! following block for when NOT using BULKMIXEDLAYER
2481
2482 ! calculate change in temperature & salinity due to dia-coordinate surface diffusion
24830 if (associated(tv%T)) then
2484
24850 if (CS%debug) then
24860 call hchksum(ea, "before triDiagTS ea ", G%HI, haloshift=0, unscale=GV%H_to_MKS)
24870 call hchksum(eb, "before triDiagTS eb ", G%HI, haloshift=0, unscale=GV%H_to_MKS)
2488 endif
24890 call cpu_clock_begin(id_clock_tridiag)
2490
2491 ! Keep salinity from falling below a small but positive threshold.
2492 ! This constraint is needed for SIS1 ice model, which can extract
2493 ! more salt than is present in the ocean. SIS2 does not suffer
2494 ! from this limitation, in which case we can let salinity=0 and still
2495 ! have salt conserved with SIS2 ice. So for SIS2, we can run with
2496 ! BOUND_SALINITY=False in MOM.F90.
24970 if (associated(tv%S) .and. associated(tv%salt_deficit)) &
24980 call adjust_salt(h, tv, G, GV, CS%diabatic_aux_CSp)
2499
25000 if (CS%diabatic_diff_tendency_diag) then
25010 do k=1,nz ; do j=js,je ; do i=is,ie
25020 temp_diag(i,j,k) = tv%T(i,j,k)
25030 saln_diag(i,j,k) = tv%S(i,j,k)
2504 enddo ; enddo ; enddo
2505 endif
2506
2507 ! Changes T and S via the tridiagonal solver; no change to h
25080 if (CS%tracer_tridiag) then
25090 call tracer_vertdiff(hold, ea, eb, dt, tv%T, G, GV)
25100 call tracer_vertdiff(hold, ea, eb, dt, tv%S, G, GV)
2511 else
25120 call triDiagTS(G, GV, is, ie, js, je, hold, ea, eb, tv%T, tv%S)
2513 endif
2514
2515 ! diagnose temperature, salinity, heat, and salt tendencies
2516 ! Note: hold here refers to the thicknesses from before the dual-entrainment when using
2517 ! the bulk mixed layer scheme, so tendencies should be posted on hold.
25180 if (CS%diabatic_diff_tendency_diag) then
25190 call diagnose_diabatic_diff_tendency(tv, hold, temp_diag, saln_diag, dt, G, GV, US, CS)
25200 if (CS%id_diabatic_diff_h > 0) call post_data(CS%id_diabatic_diff_h, hold, CS%diag, alt_h=hold)
2521 endif
2522
25230 call cpu_clock_end(id_clock_tridiag)
25240 if (showCallTree) call callTree_waypoint("done with triDiagTS (diabatic)")
2525
2526 endif ! endif corresponding to if (associated(tv%T))
25270 if (CS%debugConservation) call MOM_state_stats('triDiagTS', u, v, h, tv%T, tv%S, G, GV, US)
2528
2529 endif ! endif for the BULKMIXEDLAYER block
2530
25310 if (CS%debug) then
25320 call MOM_state_chksum("after mixed layer ", u, v, h, G, GV, US, haloshift=0)
25330 call MOM_thermovar_chksum("after mixed layer ", tv, G, US)
25340 call hchksum(ea, "after mixed layer ea", G%HI, unscale=GV%H_to_MKS)
25350 call hchksum(eb, "after mixed layer eb", G%HI, unscale=GV%H_to_MKS)
2536 endif
2537
25380 call cpu_clock_begin(id_clock_remap)
25390 call regularize_layers(h, tv, dt, ea, eb, G, GV, US, CS%regularize_layers)
25400 call cpu_clock_end(id_clock_remap)
25410 if (showCallTree) call callTree_waypoint("done with regularize_layers (diabatic)")
25420 if (CS%debugConservation) call MOM_state_stats('regularize_layers', u, v, h, tv%T, tv%S, G, GV, US)
2543
2544 ! Whenever thickness changes let the diag manager know, as the
2545 ! target grids for vertical remapping may need to be regenerated.
25460 if (associated(ADp%du_dt_dia) .or. associated(ADp%dv_dt_dia)) &
2547 ! Remapped d[uv]dt_dia require east/north halo updates of h
25480 call pass_var(h, G%domain, To_West+To_South+Omit_Corners, halo=1)
25490 call diag_update_remap_grids(CS%diag)
2550
2551 ! diagnostics
25520 Idt = 1.0 / dt
25530 if ((CS%id_Tdif > 0) .or. (CS%id_Tadv > 0)) then
25540 do j=js,je ; do i=is,ie
25550 Tdif_flx(i,j,1) = 0.0 ; Tdif_flx(i,j,nz+1) = 0.0
25560 Tadv_flx(i,j,1) = 0.0 ; Tadv_flx(i,j,nz+1) = 0.0
2557 enddo ; enddo
2558 !$OMP parallel do default(shared)
25590 do K=2,nz ; do j=js,je ; do i=is,ie
2560 Tdif_flx(i,j,K) = (Idt * 0.5*(ea(i,j,k) + eb(i,j,k-1))) * &
25610 (tv%T(i,j,k-1) - tv%T(i,j,k))
2562 Tadv_flx(i,j,K) = (Idt * (ea(i,j,k) - eb(i,j,k-1))) * &
25630 0.5*(tv%T(i,j,k-1) + tv%T(i,j,k))
2564 enddo ; enddo ; enddo
2565 endif
25660 if ((CS%id_Sdif > 0) .or. (CS%id_Sadv > 0)) then
25670 do j=js,je ; do i=is,ie
25680 Sdif_flx(i,j,1) = 0.0 ; Sdif_flx(i,j,nz+1) = 0.0
25690 Sadv_flx(i,j,1) = 0.0 ; Sadv_flx(i,j,nz+1) = 0.0
2570 enddo ; enddo
2571 !$OMP parallel do default(shared)
25720 do K=2,nz ; do j=js,je ; do i=is,ie
2573 Sdif_flx(i,j,K) = (Idt * 0.5*(ea(i,j,k) + eb(i,j,k-1))) * &
25740 (tv%S(i,j,k-1) - tv%S(i,j,k))
2575 Sadv_flx(i,j,K) = (Idt * (ea(i,j,k) - eb(i,j,k-1))) * &
25760 0.5*(tv%S(i,j,k-1) + tv%S(i,j,k))
2577 enddo ; enddo ; enddo
2578 endif
2579
2580 ! mixing of passive tracers from massless boundary layers to interior
25810 call cpu_clock_begin(id_clock_tracers)
2582
2583 ! Find the vertical distances across layers.
25840 if (CS%mix_boundary_tracers .or. CS%double_diffuse) &
25850 call thickness_to_dz(h, tv, dz, G, GV, US)
25860 if (CS%double_diffuse) &
25870 call thickness_to_dz(hold, tv, dz_old, G, GV, US)
2588
25890 if (CS%mix_boundary_tracers) then
25900 Tr_ea_BBL = sqrt(dt * CS%Kd_BBL_tr)
2591 !$OMP parallel do default(shared) private(htot,in_boundary,add_ent)
25920 do j=js,je
25930 do i=is,ie
25940 ebtr(i,j,nz) = eb(i,j,nz)
25950 htot(i) = 0.0
25960 in_boundary(i) = (G%mask2dT(i,j) > 0.0)
2597 enddo
25980 do k=nz,2,-1 ; do i=is,ie
25990 if (in_boundary(i)) then
26000 htot(i) = htot(i) + h(i,j,k)
2601 ! If diapycnal mixing has been suppressed because this is a massless
2602 ! layer near the bottom, add some mixing of tracers between these
2603 ! layers. This flux is based on the harmonic mean of the two
2604 ! thicknesses, as this corresponds pretty closely (to within
2605 ! differences in the density jumps between layers) with what is done
2606 ! in the calculation of the fluxes in the first place. Kd_min_tr
2607 ! should be much less than the values that have been set in Kd_lay,
2608 ! perhaps a molecular diffusivity.
2609 add_ent = (dt * CS%Kd_min_tr) * &
2610 ((dz(i,j,k-1) + dz(i,j,k) + dz_neglect) / &
2611 (dz(i,j,k-1)*dz(i,j,k) + dz_neglect2)) - &
26120 0.5*(ea(i,j,k) + eb(i,j,k-1))
26130 if (htot(i) < Tr_ea_BBL) then
2614 add_ent = max(0.0, add_ent, &
26150 (Tr_ea_BBL - htot(i)) - min(ea(i,j,k), eb(i,j,k-1)))
26160 elseif (add_ent < 0.0) then
26170 add_ent = 0.0 ; in_boundary(i) = .false.
2618 endif
2619
26200 ebtr(i,j,k-1) = eb(i,j,k-1) + add_ent
26210 eatr(i,j,k) = ea(i,j,k) + add_ent
2622 else
26230 ebtr(i,j,k-1) = eb(i,j,k-1) ; eatr(i,j,k) = ea(i,j,k)
2624 endif
26250 if (CS%double_diffuse) then ; if (Kd_extra_S(i,j,K) > 0.0) then
2626 add_ent = (dt * Kd_extra_S(i,j,K)) / &
26270 (0.25 * ((dz(i,j,k-1) + dz(i,j,k)) + (dz_old(i,j,k-1) + dz_old(i,j,k))) + dz_neglect)
26280 ebtr(i,j,k-1) = ebtr(i,j,k-1) + add_ent
26290 eatr(i,j,k) = eatr(i,j,k) + add_ent
2630 endif ; endif
2631 enddo ; enddo
26320 do i=is,ie ; eatr(i,j,1) = ea(i,j,1) ; enddo
2633
2634 enddo
2635
2636 call call_tracer_column_fns(hold, h, eatr, ebtr, fluxes, BLD, dt, G, GV, US, tv, &
2637 CS%optics, CS%tracer_flow_CSp, CS%debug, &
26380 KPP_CSp=CS%KPP_CSp, nonLocalTrans=KPP_NLTscalar, h_BL=visc%h_ML)
2639
26400 elseif (CS%double_diffuse) then ! extra diffusivity for passive tracers
2641
26420 do j=js,je ; do i=is,ie
26430 ebtr(i,j,nz) = eb(i,j,nz) ; eatr(i,j,1) = ea(i,j,1)
2644 enddo ; enddo
2645 !$OMP parallel do default(shared) private(add_ent)
26460 do k=nz,2,-1 ; do j=js,je ; do i=is,ie
26470 if (Kd_extra_S(i,j,K) > 0.0) then
2648 add_ent = (dt * Kd_extra_S(i,j,K)) / &
26490 (0.25 * ((dz(i,j,k-1) + dz(i,j,k)) + (dz_old(i,j,k-1) + dz_old(i,j,k))) + dz_neglect)
2650 else
26510 add_ent = 0.0
2652 endif
26530 ebtr(i,j,k-1) = eb(i,j,k-1) + add_ent
26540 eatr(i,j,k) = ea(i,j,k) + add_ent
2655 enddo ; enddo ; enddo
2656
2657 call call_tracer_column_fns(hold, h, eatr, ebtr, fluxes, BLD, dt, G, GV, US, tv, &
2658 CS%optics, CS%tracer_flow_CSp, CS%debug, &
26590 KPP_CSp=CS%KPP_CSp, nonLocalTrans=KPP_NLTscalar, h_BL=visc%h_ML)
2660
2661 else
2662 call call_tracer_column_fns(hold, h, ea, eb, fluxes, BLD, dt, G, GV, US, tv, &
2663 CS%optics, CS%tracer_flow_CSp, CS%debug, &
26640 KPP_CSp=CS%KPP_CSp, nonLocalTrans=KPP_NLTscalar, h_BL=visc%h_ML)
2665
2666 endif ! (CS%mix_boundary_tracers)
2667
26680 call cpu_clock_end(id_clock_tracers)
2669
2670 ! sponges
26710 if (CS%use_sponge) then
26720 call cpu_clock_begin(id_clock_sponge)
2673 ! Layer mode sponge
26740 if (CS%use_bulkmixedlayer .and. associated(tv%eqn_of_state)) then
26750 do i=is,ie ; p_ref_cv(i) = tv%P_Ref ; enddo
26760 EOSdom(:) = EOS_domain(G%HI)
2677 !$OMP parallel do default(shared)
26780 do j=js,je
2679 call calculate_density(tv%T(:,j,1), tv%S(:,j,1), p_ref_cv, Rcv_ml(:,j), &
26800 tv%eqn_of_state, EOSdom)
2681 enddo
26820 call apply_sponge(h, tv, dt, G, GV, US, ea, eb, CS%sponge_CSp, Rcv_ml)
2683 else
26840 call apply_sponge(h, tv, dt, G, GV, US, ea, eb, CS%sponge_CSp)
2685 endif
26860 call cpu_clock_end(id_clock_sponge)
26870 if (CS%debug) then
26880 call MOM_state_chksum("apply_sponge ", u, v, h, G, GV, US, haloshift=0)
26890 call MOM_thermovar_chksum("apply_sponge ", tv, G, US)
2690 endif
2691 endif ! CS%use_sponge
2692
2693 ! Apply data assimilation incremental update -oda_incupd-
26940 if (CS%use_oda_incupd .and. associated(CS%oda_incupd_CSp)) then
26950 call cpu_clock_begin(id_clock_oda_incupd)
26960 call apply_oda_incupd(h, tv, u, v, dt, G, GV, US, CS%oda_incupd_CSp)
26970 call cpu_clock_end(id_clock_oda_incupd)
26980 if (CS%debug) then
26990 call MOM_state_chksum("apply_oda_incupd ", u, v, h, G, GV, US, haloshift=0)
27000 call MOM_thermovar_chksum("apply_oda_incupd ", tv, G, US)
2701 endif
2702 endif ! CS%use_oda_incupd
2703
2704
2705
2706! Save the diapycnal mass fluxes as a diagnostic field.
27070 if (associated(CDp%diapyc_vel)) then
2708 !$OMP parallel do default(shared)
27090 do j=js,je
27100 do K=2,nz ; do i=is,ie
27110 CDp%diapyc_vel(i,j,K) = Idt * (ea(i,j,k) - eb(i,j,k-1))
2712 enddo ; enddo
27130 do i=is,ie
27140 CDp%diapyc_vel(i,j,1) = 0.0
27150 CDp%diapyc_vel(i,j,nz+1) = 0.0
2716 enddo
2717 enddo
2718 endif
2719
2720! For momentum, it is only the net flux that homogenizes within
2721! the mixed layer. Vertical viscosity that is proportional to the
2722! mixed layer turbulence is applied elsewhere.
27230 if (CS%use_bulkmixedlayer) then
27240 if (CS%debug) then
27250 call hchksum(ea, "before net flux rearrangement ea", G%HI, unscale=GV%H_to_MKS)
27260 call hchksum(eb, "before net flux rearrangement eb", G%HI, unscale=GV%H_to_MKS)
2727 endif
2728 !$OMP parallel do default(shared) private(net_ent)
27290 do j=js,je
27300 do K=2,GV%nkml ; do i=is,ie
27310 net_ent = ea(i,j,k) - eb(i,j,k-1)
27320 ea(i,j,k) = max(net_ent, 0.0)
27330 eb(i,j,k-1) = max(-net_ent, 0.0)
2734 enddo ; enddo
2735 enddo
27360 if (CS%debug) then
27370 call hchksum(ea, "after net flux rearrangement ea", G%HI, unscale=GV%H_to_MKS)
27380 call hchksum(eb, "after net flux rearrangement eb", G%HI, unscale=GV%H_to_MKS)
2739 endif
2740 endif
2741
2742! Initialize halo regions of ea, eb, and hold to default values.
2743 !$OMP parallel do default(shared)
27440 do k=1,nz
27450 do i=is-1,ie+1
27460 hold(i,js-1,k) = GV%Angstrom_H ; ea(i,js-1,k) = 0.0 ; eb(i,js-1,k) = 0.0
27470 hold(i,je+1,k) = GV%Angstrom_H ; ea(i,je+1,k) = 0.0 ; eb(i,je+1,k) = 0.0
2748 enddo
27490 do j=js,je
27500 hold(is-1,j,k) = GV%Angstrom_H ; ea(is-1,j,k) = 0.0 ; eb(is-1,j,k) = 0.0
27510 hold(ie+1,j,k) = GV%Angstrom_H ; ea(ie+1,j,k) = 0.0 ; eb(ie+1,j,k) = 0.0
2752 enddo
2753 enddo
2754
27550 call cpu_clock_begin(id_clock_pass)
27560 if (G%symmetric) then ; dir_flag = To_All+Omit_Corners
27570 else ; dir_flag = To_West+To_South+Omit_Corners ; endif
27580 call create_group_pass(CS%pass_hold_eb_ea, hold, G%Domain, dir_flag, halo=1)
27590 call create_group_pass(CS%pass_hold_eb_ea, eb, G%Domain, dir_flag, halo=1)
27600 call create_group_pass(CS%pass_hold_eb_ea, ea, G%Domain, dir_flag, halo=1)
27610 call do_group_pass(CS%pass_hold_eb_ea, G%Domain)
27620 call cpu_clock_end(id_clock_pass)
2763
2764 ! Use a tridiagonal solver to determine effect of the diapycnal
2765 ! advection on velocity field. It is assumed that water leaves
2766 ! or enters the ocean with the surface velocity.
27670 if (CS%debug) then
27680 call MOM_state_chksum("before u/v tridiag ", u, v, h, G, GV, US, haloshift=0)
27690 call hchksum(ea, "before u/v tridiag ea", G%HI, unscale=GV%H_to_MKS)
27700 call hchksum(eb, "before u/v tridiag eb", G%HI, unscale=GV%H_to_MKS)
27710 call hchksum(hold, "before u/v tridiag hold", G%HI, unscale=GV%H_to_MKS)
2772 endif
27730 call cpu_clock_begin(id_clock_tridiag)
2774
2775 !$OMP parallel do default(shared) private(hval,b1,d1,c1,eaval)
27760 do j=js,je
27770 do I=Isq,Ieq
27780 if (associated(ADp%du_dt_dia)) ADp%du_dt_dia(I,j,1) = u(I,j,1)
27790 hval = (hold(i,j,1) + hold(i+1,j,1)) + (ea(i,j,1) + ea(i+1,j,1)) + h_neglect
27800 b1(I) = 1.0 / (hval + (eb(i,j,1) + eb(i+1,j,1)))
27810 d1(I) = hval * b1(I)
27820 u(I,j,1) = b1(I) * (hval * u(I,j,1))
2783 enddo
27840 do k=2,nz ; do I=Isq,Ieq
27850 if (associated(ADp%du_dt_dia)) ADp%du_dt_dia(I,j,k) = u(I,j,k)
27860 c1(I,k) = (eb(i,j,k-1)+eb(i+1,j,k-1)) * b1(I)
27870 eaval = ea(i,j,k) + ea(i+1,j,k)
27880 hval = hold(i,j,k) + hold(i+1,j,k) + h_neglect
27890 b1(I) = 1.0 / ((eb(i,j,k) + eb(i+1,j,k)) + (hval + d1(I)*eaval))
27900 d1(I) = (hval + d1(I)*eaval) * b1(I)
27910 u(I,j,k) = (hval*u(I,j,k) + eaval*u(I,j,k-1))*b1(I)
2792 enddo ; enddo
27930 do k=nz-1,1,-1 ; do I=Isq,Ieq
27940 u(I,j,k) = u(I,j,k) + c1(I,k+1)*u(I,j,k+1)
27950 if (associated(ADp%du_dt_dia)) &
27960 ADp%du_dt_dia(I,j,k) = (u(I,j,k) - ADp%du_dt_dia(I,j,k)) * Idt
2797 enddo ; enddo
27980 if (associated(ADp%du_dt_dia)) then
27990 do I=Isq,Ieq
28000 ADp%du_dt_dia(I,j,nz) = (u(I,j,nz)-ADp%du_dt_dia(I,j,nz)) * Idt
2801 enddo
2802 endif
2803 enddo
28040 if (CS%debug) then
28050 call MOM_state_chksum("aft 1st loop tridiag ", u, v, h, G, GV, US, haloshift=0)
2806 endif
2807 !$OMP parallel do default(shared) private(hval,b1,d1,c1,eaval)
28080 do J=Jsq,Jeq
28090 do i=is,ie
28100 if (associated(ADp%dv_dt_dia)) ADp%dv_dt_dia(i,J,1) = v(i,J,1)
28110 hval = (hold(i,j,1) + hold(i,j+1,1)) + (ea(i,j,1) + ea(i,j+1,1)) + h_neglect
28120 b1(i) = 1.0 / (hval + (eb(i,j,1) + eb(i,j+1,1)))
28130 d1(I) = hval * b1(I)
28140 v(i,J,1) = b1(i) * (hval * v(i,J,1))
2815 enddo
28160 do k=2,nz ; do i=is,ie
28170 if (associated(ADp%dv_dt_dia)) ADp%dv_dt_dia(i,J,k) = v(i,J,k)
28180 c1(i,k) = (eb(i,j,k-1)+eb(i,j+1,k-1)) * b1(i)
28190 eaval = ea(i,j,k) + ea(i,j+1,k)
28200 hval = hold(i,j,k) + hold(i,j+1,k) + h_neglect
28210 b1(i) = 1.0 / ((eb(i,j,k) + eb(i,j+1,k)) + (hval + d1(i)*eaval))
28220 d1(i) = (hval + d1(i)*eaval) * b1(i)
28230 v(i,J,k) = (hval*v(i,J,k) + eaval*v(i,J,k-1))*b1(i)
2824 enddo ; enddo
28250 do k=nz-1,1,-1 ; do i=is,ie
28260 v(i,J,k) = v(i,J,k) + c1(i,k+1)*v(i,J,k+1)
28270 if (associated(ADp%dv_dt_dia)) &
28280 ADp%dv_dt_dia(i,J,k) = (v(i,J,k) - ADp%dv_dt_dia(i,J,k)) * Idt
2829 enddo ; enddo
28300 if (associated(ADp%dv_dt_dia)) then
28310 do i=is,ie
28320 ADp%dv_dt_dia(i,J,nz) = (v(i,J,nz)-ADp%dv_dt_dia(i,J,nz)) * Idt
2833 enddo
2834 endif
2835 enddo
28360 call cpu_clock_end(id_clock_tridiag)
28370 if (CS%debug) then
28380 call MOM_state_chksum("after u/v tridiag ", u, v, h, G, GV, US, haloshift=0)
2839 endif
2840
2841 ! Diagnose the diapycnal diffusivities and other related quantities.
28420 if (CS%id_Kd_int > 0) call post_data(CS%id_Kd_int, Kd_int, CS%diag)
28430 if (CS%id_Kd_heat > 0) call post_data(CS%id_Kd_heat, Kd_heat, CS%diag)
28440 if (CS%id_Kd_salt > 0) call post_data(CS%id_Kd_salt, Kd_salt, CS%diag)
2845
28460 if (CS%id_ea > 0) call post_data(CS%id_ea, ea, CS%diag)
28470 if (CS%id_eb > 0) call post_data(CS%id_eb, eb, CS%diag)
2848
28490 if (CS%id_dudt_dia > 0) call post_data(CS%id_dudt_dia, ADp%du_dt_dia, CS%diag)
28500 if (CS%id_dvdt_dia > 0) call post_data(CS%id_dvdt_dia, ADp%dv_dt_dia, CS%diag)
28510 if (CS%id_wd > 0) call post_data(CS%id_wd, CDp%diapyc_vel, CS%diag)
2852
28530 if (CS%id_Tdif > 0) call post_data(CS%id_Tdif, Tdif_flx, CS%diag)
28540 if (CS%id_Tadv > 0) call post_data(CS%id_Tadv, Tadv_flx, CS%diag)
28550 if (CS%id_Sdif > 0) call post_data(CS%id_Sdif, Sdif_flx, CS%diag)
28560 if (CS%id_Sadv > 0) call post_data(CS%id_Sadv, Sadv_flx, CS%diag)
2857
2858 ! Diagnostics for thickness-weighted vertically averaged diapycnal accelerations
28590 if (CS%id_hf_dudt_dia_2d > 0) &
28600 call post_product_sum_u(CS%id_hf_dudt_dia_2d, ADp%du_dt_dia, ADp%diag_hfrac_u, G, nz, CS%diag)
28610 if (CS%id_hf_dvdt_dia_2d > 0) &
28620 call post_product_sum_v(CS%id_hf_dvdt_dia_2d, ADp%dv_dt_dia, ADp%diag_hfrac_v, G, nz, CS%diag)
2863
28640 call disable_averaging(CS%diag)
2865
28660 if (showCallTree) call callTree_leave("layered_diabatic()")
2867
28680end subroutine layered_diabatic
2869
2870!> Returns pointers or values of members within the diabatic_CS type. For extensibility,
2871!! each returned argument is an optional argument
287225subroutine extract_diabatic_member(CS, opacity_CSp, optics_CSp, evap_CFL_limit, minimum_forcing_depth, &
2873 KPP_CSp, energetic_PBL_CSp, diabatic_aux_CSp, diabatic_halo, use_KPP)
2874 type(diabatic_CS), target, intent(in) :: CS !< module control structure
2875 ! All output arguments are optional
2876 type(opacity_CS), optional, pointer :: opacity_CSp !< A pointer to be set to the opacity control structure
2877 type(optics_type), optional, pointer :: optics_CSp !< A pointer to be set to the optics control structure
2878 type(KPP_CS), optional, pointer :: KPP_CSp !< A pointer to be set to the KPP CS
2879 type(energetic_PBL_CS), optional, pointer :: energetic_PBL_CSp !< A pointer to be set to the ePBL CS
2880 real, optional, intent( out) :: evap_CFL_limit !<The largest fraction of a layer that can be
2881 !! evaporated in one time-step [nondim].
2882 real, optional, intent( out) :: minimum_forcing_depth !< The smallest depth over which heat
2883 !! and freshwater fluxes are applied [H ~> m or kg m-2].
2884 type(diabatic_aux_CS), optional, pointer :: diabatic_aux_CSp !< A pointer to be set to the diabatic_aux
2885 !! control structure
2886 integer, optional, intent( out) :: diabatic_halo !< The halo size where the diabatic algorithms
2887 !! assume thermodynamics properties are valid.
2888 logical, optional, intent( out) :: use_KPP !< If true, diabatic is using KPP vertical mixing
2889
2890 ! Pointers to control structures
289125 if (present(opacity_CSp)) opacity_CSp => CS%opacity
289225 if (present(optics_CSp)) optics_CSp => CS%optics
289325 if (present(KPP_CSp)) KPP_CSp => CS%KPP_CSp
289425 if (present(energetic_PBL_CSp) .and. CS%use_energetic_PBL) energetic_PBL_CSp => CS%ePBL
289525 if (present(diabatic_aux_CSp)) diabatic_aux_CSp => CS%diabatic_aux_CSp
2896
2897 ! Constants within diabatic_CS
289825 if (present(evap_CFL_limit)) evap_CFL_limit = CS%evap_CFL_limit
289925 if (present(minimum_forcing_depth)) minimum_forcing_depth = CS%minimum_forcing_depth
290025 if (present(diabatic_halo)) diabatic_halo = CS%halo_diabatic
290125 if (present(use_KPP)) use_KPP = CS%use_KPP
290225end subroutine extract_diabatic_member
2903
2904!> Routine called for adiabatic physics
29050subroutine adiabatic(h, tv, fluxes, dt, G, GV, US, CS)
2906 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
2907 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
2908 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
2909 intent(inout) :: h !< thickness [H ~> m or kg m-2]
2910 type(thermo_var_ptrs), intent(inout) :: tv !< points to thermodynamic fields
2911 type(forcing), intent(inout) :: fluxes !< boundary fluxes
2912 real, intent(in) :: dt !< time step [T ~> s]
2913 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2914 type(diabatic_CS), pointer :: CS !< module control structure
2915
29160 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: zeros ! An array of zeros with units of [H ~> m or kg m-2]
2917
29180 zeros(:,:,:) = 0.0
2919
2920 call call_tracer_column_fns(h, h, zeros, zeros, fluxes, zeros(:,:,1), dt, G, GV, US, tv, &
29210 CS%optics, CS%tracer_flow_CSp, CS%debug)
2922
29230end subroutine adiabatic
2924
2925
2926!> This routine diagnoses tendencies from application of diabatic diffusion
2927!! using ALE algorithm. Note that layer thickness is not altered by
2928!! diabatic diffusion.
29290subroutine diagnose_diabatic_diff_tendency(tv, h, temp_old, saln_old, dt, G, GV, US, CS)
2930 type(ocean_grid_type), intent(in) :: G !< ocean grid structure
2931 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
2932 type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
2933 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< thickness [H ~> m or kg m-2]
2934 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: temp_old !< temperature prior to diabatic
2935 !! physics [C ~> degC]
2936 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: saln_old !< salinity prior to diabatic physics [S ~> ppt]
2937 real, intent(in) :: dt !< time step [T ~> s]
2938 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2939 type(diabatic_CS), pointer :: CS !< module control structure
2940
2941 ! Local variables
29420 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: work_3d ! A 3-d work array for diagnostics [various]
29430 real, dimension(SZI_(G),SZJ_(G)) :: work_2d ! A 2-d work array for diagnostics [various]
2944 real :: Idt ! The inverse of the timestep [T-1 ~> s-1]
2945 integer :: i, j, k, is, ie, js, je, nz
2946 logical :: do_saln_tend ! Calculate salinity-based tendency diagnostics
2947
29480 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
29490 Idt = 0.0 ; if (dt > 0.0) Idt = 1. / dt
29500 work_3d(:,:,:) = 0.0
29510 work_2d(:,:) = 0.0
2952
2953
2954 ! temperature tendency
29550 do k=1,nz ; do j=js,je ; do i=is,ie
29560 work_3d(i,j,k) = (tv%T(i,j,k)-temp_old(i,j,k))*Idt
2957 enddo ; enddo ; enddo
29580 if (CS%id_diabatic_diff_temp_tend > 0) then
29590 call post_data(CS%id_diabatic_diff_temp_tend, work_3d, CS%diag, alt_h=h)
2960 endif
2961
2962 ! heat tendency
29630 if (CS%id_diabatic_diff_heat_tend > 0 .or. CS%id_diabatic_diff_heat_tend_2d > 0) then
29640 do k=1,nz ; do j=js,je ; do i=is,ie
29650 work_3d(i,j,k) = h(i,j,k)*GV%H_to_RZ * tv%C_p * work_3d(i,j,k)
2966 enddo ; enddo ; enddo
29670 if (CS%id_diabatic_diff_heat_tend > 0) then
29680 call post_data(CS%id_diabatic_diff_heat_tend, work_3d, CS%diag, alt_h=h)
2969 endif
29700 if (CS%id_diabatic_diff_heat_tend_2d > 0) then
29710 work_2d(:,:) = 0.0
29720 do k=1,nz ; do j=js,je ; do i=is,ie
29730 work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
2974 enddo ; enddo ; enddo
29750 call post_data(CS%id_diabatic_diff_heat_tend_2d, work_2d, CS%diag)
2976 endif
2977 endif
2978
2979 ! salinity tendency
2980 do_saln_tend = CS%id_diabatic_diff_saln_tend > 0 &
2981 .or. CS%id_diabatic_diff_salt_tend > 0 &
29820 .or. CS%id_diabatic_diff_salt_tend_2d > 0
2983
29840 if (do_saln_tend) then
29850 do k=1,nz ; do j=js,je ; do i=is,ie
29860 work_3d(i,j,k) = (tv%S(i,j,k) - saln_old(i,j,k)) * Idt
2987 enddo ; enddo ; enddo
2988
29890 if (CS%id_diabatic_diff_saln_tend > 0) &
29900 call post_data(CS%id_diabatic_diff_saln_tend, work_3d, CS%diag, alt_h=h)
2991
2992 ! salt tendency
29930 if (CS%id_diabatic_diff_salt_tend > 0 .or. CS%id_diabatic_diff_salt_tend_2d > 0) then
29940 do k=1,nz ; do j=js,je ; do i=is,ie
29950 work_3d(i,j,k) = h(i,j,k) * work_3d(i,j,k)
2996 enddo ; enddo ; enddo
29970 if (CS%id_diabatic_diff_salt_tend > 0) then
29980 call post_data(CS%id_diabatic_diff_salt_tend, work_3d, CS%diag, alt_h=h)
2999 endif
30000 if (CS%id_diabatic_diff_salt_tend_2d > 0) then
30010 work_2d(:,:) = 0.0
30020 do k=1,nz ; do j=js,je ; do i=is,ie
30030 work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
3004 enddo ; enddo ; enddo
30050 call post_data(CS%id_diabatic_diff_salt_tend_2d, work_2d, CS%diag)
3006 endif
3007 endif
3008 endif
3009
30100end subroutine diagnose_diabatic_diff_tendency
3011
3012
3013!> This routine diagnoses tendencies from application of boundary fluxes.
3014!! These impacts are generally 3d, in particular for penetrative shortwave.
3015!! Other fluxes contribute 3d in cases when the layers vanish or are very thin,
3016!! in which case we distribute the flux into k > 1 layers.
30170subroutine diagnose_boundary_forcing_tendency(tv, h, temp_old, saln_old, h_old, &
3018 dt, G, GV, US, CS)
3019 type(ocean_grid_type), intent(in) :: G !< ocean grid structure
3020 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
3021 type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
3022 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
3023 intent(in) :: h !< thickness after boundary flux application [H ~> m or kg m-2]
3024 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
3025 intent(in) :: temp_old !< temperature prior to boundary flux application [C ~> degC]
3026 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
3027 intent(in) :: saln_old !< salinity prior to boundary flux application [S ~> ppt]
3028 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
3029 intent(in) :: h_old !< thickness prior to boundary flux application [H ~> m or kg m-2]
3030 real, intent(in) :: dt !< time step [T ~> s]
3031 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
3032 type(diabatic_CS), pointer :: CS !< module control structure
3033
3034 ! Local variables
30350 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: work_3d ! A 3-d work array for diagnostics [various]
30360 real, dimension(SZI_(G),SZJ_(G)) :: work_2d ! A 2-d work array for diagnostics [various]
3037 real :: Idt ! The inverse of the timestep [T-1 ~> s-1]
3038 integer :: i, j, k, is, ie, js, je, nz
3039
30400 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
30410 Idt = 0.0 ; if (dt > 0.0) Idt = 1. / dt
30420 work_3d(:,:,:) = 0.0
30430 work_2d(:,:) = 0.0
3044
3045 ! Thickness tendency
30460 if (CS%id_boundary_forcing_h_tendency > 0) then
30470 do k=1,nz ; do j=js,je ; do i=is,ie
30480 work_3d(i,j,k) = (h(i,j,k) - h_old(i,j,k))*Idt
3049 enddo ; enddo ; enddo
30500 call post_data(CS%id_boundary_forcing_h_tendency, work_3d, CS%diag, alt_h=h_old)
3051 endif
3052
3053 ! temperature tendency
30540 if (CS%id_boundary_forcing_temp_tend > 0) then
30550 do k=1,nz ; do j=js,je ; do i=is,ie
30560 work_3d(i,j,k) = (tv%T(i,j,k)-temp_old(i,j,k))*Idt
3057 enddo ; enddo ; enddo
30580 call post_data(CS%id_boundary_forcing_temp_tend, work_3d, CS%diag, alt_h=h_old)
3059 endif
3060
3061 ! heat tendency
30620 if (CS%id_boundary_forcing_heat_tend > 0 .or. CS%id_boundary_forcing_heat_tend_2d > 0) then
30630 do k=1,nz ; do j=js,je ; do i=is,ie
30640 work_3d(i,j,k) = GV%H_to_RZ * tv%C_p * Idt * (h(i,j,k) * tv%T(i,j,k) - h_old(i,j,k) * temp_old(i,j,k))
3065 enddo ; enddo ; enddo
30660 if (CS%id_boundary_forcing_heat_tend > 0) then
30670 call post_data(CS%id_boundary_forcing_heat_tend, work_3d, CS%diag, alt_h=h_old)
3068 endif
30690 if (CS%id_boundary_forcing_heat_tend_2d > 0) then
30700 work_2d(:,:) = 0.0
30710 do k=1,nz ; do j=js,je ; do i=is,ie
30720 work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
3073 enddo ; enddo ; enddo
30740 call post_data(CS%id_boundary_forcing_heat_tend_2d, work_2d, CS%diag)
3075 endif
3076 endif
3077
3078 ! salinity tendency
30790 if (CS%id_boundary_forcing_saln_tend > 0) then
30800 do k=1,nz ; do j=js,je ; do i=is,ie
30810 work_3d(i,j,k) = (tv%S(i,j,k)-saln_old(i,j,k))*Idt
3082 enddo ; enddo ; enddo
30830 call post_data(CS%id_boundary_forcing_saln_tend, work_3d, CS%diag, alt_h=h_old)
3084 endif
3085
3086 ! salt tendency
30870 if (CS%id_boundary_forcing_salt_tend > 0 .or. CS%id_boundary_forcing_salt_tend_2d > 0) then
30880 do k=1,nz ; do j=js,je ; do i=is,ie
30890 work_3d(i,j,k) = Idt * (h(i,j,k) * tv%S(i,j,k) - h_old(i,j,k) * saln_old(i,j,k))
3090 enddo ; enddo ; enddo
30910 if (CS%id_boundary_forcing_salt_tend > 0) then
30920 call post_data(CS%id_boundary_forcing_salt_tend, work_3d, CS%diag, alt_h=h_old)
3093 endif
30940 if (CS%id_boundary_forcing_salt_tend_2d > 0) then
30950 work_2d(:,:) = 0.0
30960 do k=1,nz ; do j=js,je ; do i=is,ie
30970 work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
3098 enddo ; enddo ; enddo
30990 call post_data(CS%id_boundary_forcing_salt_tend_2d, work_2d, CS%diag)
3100 endif
3101 endif
3102
31030end subroutine diagnose_boundary_forcing_tendency
3104
3105
3106!> This routine diagnoses tendencies for temperature and heat from frazil formation.
3107!! This routine is called twice from within subroutine diabatic; at start and at
3108!! end of the diabatic processes. The impacts from frazil are generally a function
3109!! of depth. Hence, when checking heat budget, be sure to remove HFSIFRAZIL from HFDS in k=1.
31100subroutine diagnose_frazil_tendency(tv, h, temp_old, dt, G, GV, US, CS)
3111 type(ocean_grid_type), intent(in) :: G !< ocean grid structure
3112 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
3113 type(thermo_var_ptrs), intent(in) :: tv !< points to updated thermodynamic fields
3114 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< thickness [H ~> m or kg m-2]
3115 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: temp_old !< temperature prior to frazil formation [C ~> degC]
3116 real, intent(in) :: dt !< time step [T ~> s]
3117 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
3118 type(diabatic_CS), pointer :: CS !< module control structure
3119
31200 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: work_3d ! A 3-d work array for diagnostics [various]
31210 real, dimension(SZI_(G),SZJ_(G)) :: work_2d ! A 2-d work array for diagnostics [various]
3122 real :: Idt ! The inverse of the timestep [T-1 ~> s-1]
3123 integer :: i, j, k, is, ie, js, je, nz
3124
31250 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
31260 Idt = 0.0 ; if (dt > 0.0) Idt = 1. / dt
3127
3128 ! temperature tendency
31290 if (CS%id_frazil_temp_tend > 0) then
31300 do k=1,nz ; do j=js,je ; do i=is,ie
31310 work_3d(i,j,k) = Idt * (tv%T(i,j,k)-temp_old(i,j,k))
3132 enddo ; enddo ; enddo
31330 call post_data(CS%id_frazil_temp_tend, work_3d, CS%diag)
3134 endif
3135
3136 ! heat tendency
31370 if (CS%id_frazil_heat_tend > 0 .or. CS%id_frazil_heat_tend_2d > 0) then
31380 do k=1,nz ; do j=js,je ; do i=is,ie
31390 work_3d(i,j,k) = GV%H_to_RZ * tv%C_p * h(i,j,k) * Idt * (tv%T(i,j,k)-temp_old(i,j,k))
3140 enddo ; enddo ; enddo
31410 if (CS%id_frazil_heat_tend > 0) call post_data(CS%id_frazil_heat_tend, work_3d, CS%diag)
3142
3143 ! As a consistency check, we must have
3144 ! FRAZIL_HEAT_TENDENCY_2d = HFSIFRAZIL
31450 if (CS%id_frazil_heat_tend_2d > 0) then
31460 work_2d(:,:) = 0.0
31470 do k=1,nz ; do j=js,je ; do i=is,ie
31480 work_2d(i,j) = work_2d(i,j) + work_3d(i,j,k)
3149 enddo ; enddo ; enddo
31500 call post_data(CS%id_frazil_heat_tend_2d, work_2d, CS%diag)
3151 endif
3152 endif
3153
31540end subroutine diagnose_frazil_tendency
3155
3156
3157!> A simplified version of diabatic_driver_init that will allow
3158!! tracer column functions to be called without allowing any
3159!! of the diabatic processes to be used.
31600subroutine adiabatic_driver_init(Time, G, param_file, diag, CS, &
3161 tracer_flow_CSp)
3162 type(time_type), intent(in) :: Time !< current model time
3163 type(ocean_grid_type), intent(in) :: G !< model grid structure
3164 type(param_file_type), intent(in) :: param_file !< the file to parse for parameter values
3165 type(diag_ctrl), target, intent(inout) :: diag !< regulates diagnostic output
3166 type(diabatic_CS), pointer :: CS !< module control structure
3167 type(tracer_flow_control_CS), pointer :: tracer_flow_CSp !< pointer to control structure of the
3168 !! tracer flow control module
3169
3170 ! This "include" declares and sets the variable "version".
3171# include "version_variable.h"
3172 character(len=40) :: mdl = "MOM_diabatic_driver" ! This module's name.
3173
31740 if (associated(CS)) then
3175 call MOM_error(WARNING, "adiabatic_driver_init called with an "// &
31760 "associated control structure.")
31770 return
31780 else ; allocate(CS) ; endif
3179
31800 CS%diag => diag
31810 if (associated(tracer_flow_CSp)) CS%tracer_flow_CSp => tracer_flow_CSp
3182
3183 ! Set default, read and log parameters
3184 call log_version(param_file, mdl, version, &
31850 "The following parameters are used for diabatic processes.")
3186
3187 ! Check for any subsidiary parameters that are inconsistent with the adiabatic mode.
3188 call get_param(param_file, mdl, "SPONGE", CS%use_sponge, &
3189 "If true, sponges may be applied anywhere in the domain. "//&
3190 "The exact location and properties of those sponges are "//&
3191 "specified via calls to initialize_sponge and possibly "//&
31920 "set_up_sponge_field.", default=.false., do_not_log=.true.)
3193 call get_param(param_file, mdl, "ENERGETICS_SFC_PBL", CS%use_energetic_PBL, &
3194 "If true, use an implied energetics planetary boundary "//&
3195 "layer scheme to determine the diffusivity and viscosity "//&
31960 "in the surface boundary layer.", default=.false., do_not_log=.true.)
3197 call get_param(param_file, mdl, "USE_KPP", CS%use_KPP, &
3198 "If true, turns on the [CVMix] KPP scheme of Large et al., 1994, "//&
3199 "to calculate diffusivities and non-local transport in the OBL.", &
32000 default=.false., do_not_log=.true.)
3201
32020 if (CS%use_sponge) call MOM_error(WARNING, &
32030 "When ADIABATIC = True, it is inconsistent to set SPONGE = True.")
32040 if (CS%use_energetic_PBL) call MOM_error(WARNING, &
32050 "When ADIABATIC = True, it is inconsistent to set ENERGETICS_SFC_PBL = True.")
32060 if (CS%use_KPP) call MOM_error(WARNING, &
32070 "When ADIABATIC = True, it is inconsistent to set USE_KPP = True.")
3208
32090 if (CS%use_sponge .or. CS%use_energetic_PBL .or. CS%use_KPP) &
32100 call MOM_error(FATAL, "adiabatic_driver_init is aborting due to inconsistent parameter settings.")
3211
3212end subroutine adiabatic_driver_init
3213
3214
3215!> This routine initializes the diabatic driver module.
32161subroutine diabatic_driver_init(Time, G, GV, US, param_file, useALEalgorithm, diag, &
3217 ADp, CDp, CS, tracer_flow_CSp, sponge_CSp, &
3218 ALE_sponge_CSp, oda_incupd_CSp, int_tide_CSp)
3219 type(time_type), target :: Time !< model time
3220 type(ocean_grid_type), intent(inout) :: G !< model grid structure
3221 type(verticalGrid_type), intent(in) :: GV !< model vertical grid structure
3222 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
3223 type(param_file_type), intent(in) :: param_file !< file to parse for parameter values
3224 logical, intent(in) :: useALEalgorithm !< logical for whether to use ALE remapping
3225 type(diag_ctrl), target, intent(inout) :: diag !< structure to regulate diagnostic output
3226 type(accel_diag_ptrs), intent(inout) :: ADp !< pointers to accelerations in momentum equations,
3227 !! to enable diagnostics, like energy budgets
3228 type(cont_diag_ptrs), intent(inout) :: CDp !< pointers to terms in continuity equations
3229 type(diabatic_CS), pointer :: CS !< module control structure
3230 type(tracer_flow_control_CS), pointer :: tracer_flow_CSp !< pointer to control structure of the
3231 !! tracer flow control module
3232 type(sponge_CS), pointer :: sponge_CSp !< pointer to the sponge module control structure
3233 type(ALE_sponge_CS), pointer :: ALE_sponge_CSp !< pointer to the ALE sponge module control structure
3234 type(oda_incupd_CS), pointer :: oda_incupd_CSp !< pointer to the ocean data assimilation incremental
3235 !! update module control structure
3236 type(int_tide_CS), pointer :: int_tide_CSp !< pointer to the internal tide structure
3237
3238 ! Local variables
3239 real :: Kd ! A diffusivity used in the default for other tracer diffusivities [Z2 T-1 ~> m2 s-1]
3240 logical :: use_temperature
3241 character(len=20) :: EN1, EN2, EN3
3242
3243 ! This "include" declares and sets the variable "version".
3244# include "version_variable.h"
3245 character(len=40) :: mdl = "MOM_diabatic_driver" ! This module's name.
3246 character(len=48) :: thickness_units
3247 logical :: physical_OBL_scheme
3248 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, nz, nbands
32491 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed ; nz = GV%ke
32501 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
3251
32521 CS%initialized = .true.
3253
32541 CS%diag => diag
32551 CS%Time => Time
3256
32571 if (associated(tracer_flow_CSp)) CS%tracer_flow_CSp => tracer_flow_CSp
32581 if (associated(sponge_CSp)) CS%sponge_CSp => sponge_CSp
32591 if (associated(ALE_sponge_CSp)) CS%ALE_sponge_CSp => ALE_sponge_CSp
32601 if (associated(oda_incupd_CSp)) CS%oda_incupd_CSp => oda_incupd_CSp
32611 if (associated(int_tide_CSp)) CS%int_tide_CSp => int_tide_CSp
3262
32631 CS%useALEalgorithm = useALEalgorithm
32641 CS%use_bulkmixedlayer = (GV%nkml > 0)
3265
3266 ! Set default, read and log parameters
3267 call log_version(param_file, mdl, version, &
3268 "The following parameters are used for diabatic processes.", &
32691 log_to_all=.true., debugging=.true.)
3270 call get_param(param_file, mdl, "USE_LEGACY_DIABATIC_DRIVER", CS%use_legacy_diabatic, &
3271 "If true, use a legacy version of the diabatic subroutine. "//&
3272 "This is temporary and is needed to avoid change in answers.", &
32731 default=.true.)
3274 call get_param(param_file, mdl, "SPONGE", CS%use_sponge, &
3275 "If true, sponges may be applied anywhere in the domain. "//&
3276 "The exact location and properties of those sponges are "//&
3277 "specified via calls to initialize_sponge and possibly "//&
32781 "set_up_sponge_field.", default=.false.)
3279 call get_param(param_file, mdl, "ODA_INCUPD", CS%use_oda_incupd, &
3280 "If true, oda incremental updates will be applied "//&
32811 "everywhere in the domain.", default=.false.)
3282 call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", use_temperature, &
3283 "If true, temperature and salinity are used as state "//&
32841 "variables.", default=.true.)
3285 call get_param(param_file, mdl, "ENERGETICS_SFC_PBL", CS%use_energetic_PBL, &
3286 "If true, use an implied energetics planetary boundary "//&
3287 "layer scheme to determine the diffusivity and viscosity "//&
32881 "in the surface boundary layer.", default=.false.)
3289 call get_param(param_file, mdl, "EPBL_IS_ADDITIVE", CS%ePBL_is_additive, &
3290 "If true, the diffusivity from ePBL is added to all "//&
3291 "other diffusivities. Otherwise, the larger of kappa-shear "//&
32921 "and ePBL diffusivities are used.", default=.true.)
3293 call get_param(param_file, mdl, "PRANDTL_EPBL", CS%ePBL_Prandtl, &
3294 "The Prandtl number used by ePBL to convert vertical diffusivities into "//&
32951 "viscosities.", default=1.0, units="nondim", do_not_log=.not.CS%use_energetic_PBL)
3296 call get_param(param_file, mdl, "USE_KPP", CS%use_KPP, &
3297 "If true, turns on the [CVMix] KPP scheme of Large et al., 1994, "//&
3298 "to calculate diffusivities and non-local transport in the OBL.", &
32991 default=.false., do_not_log=.true.)
33001 CS%use_CVMix_ddiff = CVMix_ddiff_is_used(param_file)
3301
33021 CS%use_kappa_shear = kappa_shear_is_used(param_file)
33031 CS%use_CVMix_shear = CVMix_shear_is_used(param_file)
3304
33051 if (CS%use_bulkmixedlayer) then
3306 call get_param(param_file, mdl, "ML_MIX_FIRST", CS%ML_mix_first, &
3307 "The fraction of the mixed layer mixing that is applied "//&
3308 "before interior diapycnal mixing. 0 by default.", &
33090 units="nondim", default=0.0)
33100 call get_param(param_file, mdl, "NKBL", CS%nkbl, default=2, do_not_log=.true.)
3311 else
33121 CS%ML_mix_first = 0.0
3313 endif
33141 if (use_temperature) then
3315 call get_param(param_file, mdl, "DO_GEOTHERMAL", CS%use_geothermal, &
33161 "If true, apply geothermal heating.", default=.false.)
3317 else
33180 CS%use_geothermal = .false.
3319 endif
3320 call get_param(param_file, mdl, "INTERNAL_TIDES", CS%use_int_tides, &
3321 "If true, use the code that advances a separate set of "//&
33221 "equations for the internal tide energy density.", default=.false.)
3323
3324 call get_param(param_file, mdl, "MASSLESS_MATCH_TARGETS", CS%massless_match_targets, &
3325 "If true, the temperature and salinity of massless layers "//&
3326 "are kept consistent with their target densities. "//&
3327 "Otherwise the properties of massless layers evolve "//&
3328 "diffusively to match massive neighboring layers.", &
33291 default=.true.)
3330
3331 call get_param(param_file, mdl, "AGGREGATE_FW_FORCING", CS%aggregate_FW_forcing, &
3332 "If true, the net incoming and outgoing fresh water fluxes are combined "//&
3333 "and applied as either incoming or outgoing depending on the sign of the net. "//&
3334 "If false, the net incoming fresh water flux is added to the model and "//&
3335 "thereafter the net outgoing is removed from the topmost non-vanished "//&
33361 "layers of the updated state.", default=.true.)
3337
3338 call get_param(param_file, mdl, "DEBUG", CS%debug, &
3339 "If true, write out verbose debugging data.", &
33401 default=.false., debuggingParam=.true.)
3341 call get_param(param_file, mdl, "DEBUG_CONSERVATION", CS%debugConservation, &
3342 "If true, monitor conservation and extrema.", &
33431 default=.false., debuggingParam=.true.)
3344
3345 call get_param(param_file, mdl, "DEBUG_ENERGY_REQ", CS%debug_energy_req, &
33461 "If true, debug the energy requirements.", default=.false., do_not_log=.true.)
3347 call get_param(param_file, mdl, "MIX_BOUNDARY_TRACERS", CS%mix_boundary_tracers, &
3348 "If true, mix the passive tracers in massless layers at "//&
3349 "the bottom into the interior as though a diffusivity of "//&
33501 "KD_MIN_TR were operating.", default=.true.)
3351 call get_param(param_file, mdl, "MIX_BOUNDARY_TRACER_ALE", CS%mix_boundary_tracer_ALE, &
3352 "If true and in ALE mode, mix the passive tracers in massless layers at "//&
3353 "the bottom into the interior as though a diffusivity of "//&
33541 "KD_MIN_TR were operating.", default=.false., do_not_log=.not.CS%useALEalgorithm)
3355
33561 if (CS%mix_boundary_tracers .or. CS%mix_boundary_tracer_ALE) then
33571 call get_param(param_file, mdl, "KD", Kd, units="m2 s-1", default=0.0, scale=US%m2_s_to_Z2_T)
3358 call get_param(param_file, mdl, "KD_MIN_TR", CS%Kd_min_tr, &
3359 "A minimal diffusivity that should always be applied to "//&
3360 "tracers, especially in massless layers near the bottom. "//&
3361 "The default is 0.1*KD.", &
33621 units="m2 s-1", default=0.1*Kd*US%Z2_T_to_m2_s, scale=GV%m2_s_to_HZ_T)
3363 call get_param(param_file, mdl, "KD_BBL_TR", CS%Kd_BBL_tr, &
3364 "A bottom boundary layer tracer diffusivity that will "//&
3365 "allow for explicitly specified bottom fluxes. The "//&
3366 "entrainment at the bottom is at least sqrt(Kd_BBL_tr*dt) "//&
3367 "over the same distance.", &
33681 units="m2 s-1", default=0., scale=GV%m2_s_to_HZ_T*(US%Z_to_m*GV%m_to_H))
3369 ! The scaling factor here is usually equivalent to GV%m2_s_to_HZ_T*GV%Z_to_H.
3370 endif
3371
3372 call get_param(param_file, mdl, "TRACER_TRIDIAG", CS%tracer_tridiag, &
3373 "If true, use the passive tracer tridiagonal solver for T and S", &
33741 default=.false.)
3375
3376 call get_param(param_file, mdl, "MINIMUM_FORCING_DEPTH", CS%minimum_forcing_depth, &
3377 "The smallest depth over which forcing can be applied. This "//&
3378 "only takes effect when near-surface layers become thin "//&
3379 "relative to this scale, in which case the forcing tendencies "//&
3380 "scaled down by distributing the forcing over this depth scale.", &
33811 units="m", default=0.001, scale=GV%m_to_H)
3382 call get_param(param_file, mdl, "EVAP_CFL_LIMIT", CS%evap_CFL_limit, &
3383 "The largest fraction of a layer than can be lost to forcing "//&
3384 "(e.g. evaporation, sea-ice formation) in one time-step. The unused "//&
3385 "mass loss is passed down through the column.", &
33861 units="nondim", default=0.8)
3387
33881 if (CS%use_energetic_PBL .and. .not.CS%useALEalgorithm) &
3389 call MOM_error(FATAL, "diabatic_driver_init: "//&
33900 "ENERGETICS_SFC_PBL = True is only coded to work when USE_REGRIDDING = True.")
3391
3392 ! Register all available diagnostics for this module.
33931 thickness_units = get_thickness_units(GV)
3394
3395 CS%id_ea_t = register_diag_field('ocean_model', 'ea_t', diag%axesTL, Time, &
33961 'Layer (heat) entrainment from above per timestep', 'm', conversion=GV%H_to_m)
3397 CS%id_eb_t = register_diag_field('ocean_model', 'eb_t', diag%axesTL, Time, &
33981 'Layer (heat) entrainment from below per timestep', 'm', conversion=GV%H_to_m)
3399 CS%id_ea_s = register_diag_field('ocean_model', 'ea_s', diag%axesTL, Time, &
34001 'Layer (salt) entrainment from above per timestep', 'm', conversion=GV%H_to_m)
3401 CS%id_eb_s = register_diag_field('ocean_model', 'eb_s', diag%axesTL, Time, &
34021 'Layer (salt) entrainment from below per timestep', 'm', conversion=GV%H_to_m)
3403 ! used by layer diabatic
3404 CS%id_ea = register_diag_field('ocean_model', 'ea', diag%axesTL, Time, &
34051 'Layer entrainment from above per timestep', 'm', conversion=GV%H_to_m)
3406 CS%id_eb = register_diag_field('ocean_model', 'eb', diag%axesTL, Time, &
34071 'Layer entrainment from below per timestep', 'm', conversion=GV%H_to_m)
34081 if (.not.CS%useALEalgorithm) then
3409 CS%id_wd = register_diag_field('ocean_model', 'wd', diag%axesTi, Time, &
34100 'Diapycnal velocity', 'm s-1', conversion=GV%H_to_m*US%s_to_T)
34110 if (CS%id_wd > 0) call safe_alloc_ptr(CDp%diapyc_vel,isd,ied,jsd,jed,nz+1)
3412
3413 CS%id_dudt_dia = register_diag_field('ocean_model', 'dudt_dia', diag%axesCuL, Time, &
34140 'Zonal Acceleration from Diapycnal Mixing', 'm s-2', conversion=US%L_T2_to_m_s2)
3415 CS%id_dvdt_dia = register_diag_field('ocean_model', 'dvdt_dia', diag%axesCvL, Time, &
34160 'Meridional Acceleration from Diapycnal Mixing', 'm s-2', conversion=US%L_T2_to_m_s2)
3417
3418 CS%id_hf_dudt_dia_2d = register_diag_field('ocean_model', 'hf_dudt_dia_2d', diag%axesCu1, Time, &
3419 'Depth-sum Fractional Thickness-weighted Zonal Acceleration from Diapycnal Mixing', &
34200 'm s-2', conversion=US%L_T2_to_m_s2)
34210 if (CS%id_hf_dudt_dia_2d > 0) call safe_alloc_ptr(ADp%diag_hfrac_u,IsdB,IedB,jsd,jed,nz)
3422
3423 CS%id_hf_dvdt_dia_2d = register_diag_field('ocean_model', 'hf_dvdt_dia_2d', diag%axesCv1, Time, &
3424 'Depth-sum Fractional Thickness-weighted Meridional Acceleration from Diapycnal Mixing', &
34250 'm s-2', conversion=US%L_T2_to_m_s2)
34260 if (CS%id_hf_dvdt_dia_2d > 0) call safe_alloc_ptr(ADp%diag_hfrac_v,isd,ied,JsdB,JedB,nz)
3427
34280 if ((CS%id_dudt_dia > 0) .or. (CS%id_hf_dudt_dia_2d > 0)) &
34290 call safe_alloc_ptr(ADp%du_dt_dia,IsdB,IedB,jsd,jed,nz)
34300 if ((CS%id_dvdt_dia > 0) .or. (CS%id_hf_dvdt_dia_2d > 0)) &
34310 call safe_alloc_ptr(ADp%dv_dt_dia,isd,ied,JsdB,JedB,nz)
3432 endif
3433
34341 if (use_temperature) then
3435 CS%id_Tdif = register_diag_field('ocean_model',"Tflx_dia_diff", diag%axesTi, &
3436 Time, "Diffusive diapycnal temperature flux across interfaces", &
34371 units="degC m s-1", conversion=US%C_to_degC*GV%H_to_m*US%s_to_T)
34381 if (.not.CS%useALEalgorithm) then
3439 CS%id_Tadv = register_diag_field('ocean_model',"Tflx_dia_adv", diag%axesTi, &
3440 Time, "Advective diapycnal temperature flux across interfaces", &
34410 units="degC m s-1", conversion=US%C_to_degC*GV%H_to_m*US%s_to_T)
3442 endif
3443 CS%id_Sdif = register_diag_field('ocean_model',"Sflx_dia_diff", diag%axesTi, &
3444 Time, "Diffusive diapycnal salnity flux across interfaces", &
34451 units="psu m s-1", conversion=US%S_to_ppt*GV%H_to_m*US%s_to_T)
34461 if (.not.CS%useALEalgorithm) then
3447 CS%id_Sadv = register_diag_field('ocean_model',"Sflx_dia_adv", diag%axesTi, &
3448 Time, "Advective diapycnal salnity flux across interfaces", &
34490 units="psu m s-1", conversion=US%S_to_ppt*GV%H_to_m*US%s_to_T)
3450 endif
3451
3452 CS%id_N2_dd = register_diag_field('ocean_model',"N2_diabatic", diag%axesTi, &
3453 Time, "Squared buoyancy frequency diagnosed after diffusion applied in thermodynamic timestep.", &
34541 "s-2", conversion=US%s_to_T**2)
3455 CS%id_N2_temp_dd = register_diag_field('ocean_model',"N2_temp_diabatic", diag%axesTi, &
3456 Time, "Squared buoyancy frequency due to temperature stratification diagnosed after diffusion applied "//&
34571 "in thermodynamic timestep.", "s-2", conversion=US%s_to_T**2)
3458 CS%id_N2_salt_dd = register_diag_field('ocean_model',"N2_salt_diabatic", diag%axesTi, &
3459 Time, "Squared buoyancy frequency due to salinity stratification diagnosed after diffusion applied "//&
34601 "in thermodynamic timestep.", "s-2", conversion=US%s_to_T**2)
34611 if (CS%id_N2_dd>0 .or. CS%id_N2_temp_dd>0 .or. CS%id_N2_salt_dd>0) CS%Use_N2_diag = .true.
3462
3463 CS%id_MLD_003 = register_diag_field('ocean_model', 'MLD_003', diag%axesT1, Time, &
3464 'Mixed layer depth (delta rho = 0.03)', units='m', conversion=US%Z_to_m, &
3465 cmor_field_name='mlotst', cmor_long_name='Ocean Mixed Layer Thickness Defined by Sigma T', &
34661 cmor_standard_name='ocean_mixed_layer_thickness_defined_by_sigma_t')
3467 CS%id_mlotstsq = register_diag_field('ocean_model', 'mlotstsq', diag%axesT1, Time, &
3468 long_name='Square of Ocean Mixed Layer Thickness Defined by Sigma T', &
3469 standard_name='square_of_ocean_mixed_layer_thickness_defined_by_sigma_t', &
34701 units='m2', conversion=US%Z_to_m**2)
3471 CS%id_MLD_0125 = register_diag_field('ocean_model', 'MLD_0125', diag%axesT1, Time, &
34721 'Mixed layer depth (delta rho = 0.125)', 'm', conversion=US%Z_to_m)
3473 call get_param(param_file, mdl, "MLD_EN_VALS", CS%MLD_En_vals, &
3474 "The energy values used to compute MLDs. If not set (or all set to 0.), the "//&
3475 "default will overwrite to 25., 2500., 250000.", units='J/m2', &
34761 defaults=(/25., 2500., 250000./), scale=US%W_m2_to_RZ3_T3*US%s_to_T)
34771 write(EN1,'(F10.2)') CS%MLD_En_vals(1)*US%RZ3_T3_to_W_m2*US%T_to_s
34781 write(EN2,'(F10.2)') CS%MLD_En_vals(2)*US%RZ3_T3_to_W_m2*US%T_to_s
34791 write(EN3,'(F10.2)') CS%MLD_En_vals(3)*US%RZ3_T3_to_W_m2*US%T_to_s
3480 CS%id_MLD_EN1 = register_diag_field('ocean_model', 'MLD_EN1', diag%axesT1, Time, &
3481 'Mixed layer depth for energy value set to '//trim(EN1)//' J/m2 (Energy set by 1st MLD_EN_VALS)', &
34821 units='m', conversion=US%Z_to_m)
3483 CS%id_MLD_EN2 = register_diag_field('ocean_model', 'MLD_EN2', diag%axesT1, Time, &
3484 'Mixed layer depth for energy value set to '//trim(EN2)//' J/m2 (Energy set by 2nd MLD_EN_VALS)', &
34851 units='m', conversion=US%Z_to_m)
3486 CS%id_MLD_EN3 = register_diag_field('ocean_model', 'MLD_EN3', diag%axesT1, Time, &
3487 'Mixed layer depth for energy value set to '//trim(EN3)//' J/m2 (Energy set by 3rd MLD_EN_VALS)', &
34881 units='m', conversion=US%Z_to_m)
3489 call get_param(param_file, mdl, "BMLD_EN_VALS", CS%BMLD_En_vals, &
3490 "The energy values used to compute Bottom MLDs. If not set (or all set to 0.), the "//&
3491 "default will overwrite to 25., 2500., 250000.", units='J/m2', &
34921 defaults=(/25., 2500., 250000./), scale=US%W_m2_to_RZ3_T3*US%s_to_T)
34931 write(EN1,'(F10.2)') CS%BMLD_En_vals(1)*US%RZ3_T3_to_W_m2*US%T_to_s
34941 write(EN2,'(F10.2)') CS%BMLD_En_vals(2)*US%RZ3_T3_to_W_m2*US%T_to_s
34951 write(EN3,'(F10.2)') CS%BMLD_En_vals(3)*US%RZ3_T3_to_W_m2*US%T_to_s
3496 CS%id_BMLD_EN1 = register_diag_field('ocean_model', 'BMLD_EN1', diag%axesT1, Time, &
3497 'Bottom mixed layer depth for energy value set to '//trim(EN1)//' J/m2 (Energy set by 1st MLD_EN_VALS)', &
34981 units='m', conversion=US%Z_to_m)
3499 CS%id_BMLD_EN2 = register_diag_field('ocean_model', 'BMLD_EN2', diag%axesT1, Time, &
3500 'Bottom mixed layer depth for energy value set to '//trim(EN2)//' J/m2 (Energy set by 2nd MLD_EN_VALS)', &
35011 units='m', conversion=US%Z_to_m)
3502 CS%id_BMLD_EN3 = register_diag_field('ocean_model', 'BMLD_EN3', diag%axesT1, Time, &
3503 'Bottom mixed layer depth for energy value set to '//trim(EN3)//' J/m2 (Energy set by 3rd MLD_EN_VALS)', &
35041 units='m', conversion=US%Z_to_m)
3505 if ((CS%id_MLD_EN1>0).or. (CS%id_MLD_EN2>0).or. (CS%id_MLD_EN3>0).or. &
35061 (CS%id_BMLD_EN1>0).or.(CS%id_BMLD_EN2>0).or.(CS%id_BMLD_EN3>0)) then
3507 call get_param(param_file, mdl, "USE_OM4_MLD_EN_ITER", CS%use_OM4_MLD_En_iter, &
3508 "If true, uses an older set of iteration coefficients in computing the PE based "//&
3509 "surface MLD to reproduce OM4 era models. False uses an updated (general) method.",&
35100 default=.true.)
3511 endif
3512 CS%id_subMLN2 = register_diag_field('ocean_model', 'subML_N2', diag%axesT1, Time, &
35131 'Squared buoyancy frequency below mixed layer', units='s-2', conversion=US%s_to_T**2)
3514 CS%id_MLD_user = register_diag_field('ocean_model', 'MLD_user', diag%axesT1, Time, &
35151 'Mixed layer depth (used defined)', units='m', conversion=US%Z_to_m)
35161 if (CS%id_MLD_003 > 0) then
3517 call get_param(param_file, mdl, "HREF_FOR_MLD", CS%ref_h_mld, &
3518 "Reference depth used to calculate the potential density used to find the mixed layer depth "//&
35190 "based on a delta rho = 0.03 kg/m3.", units='m', default=0.0, scale=US%m_to_Z)
3520 CS%id_MLD_003_zr = register_diag_field('ocean_model', 'MLD_003_refZ', diag%axesT1, Time, &
35210 'Depth of reference density for MLD (delta rho = 0.03)', units='m', conversion=US%Z_to_m)
3522 CS%id_MLD_003_rr = register_diag_field('ocean_model', 'MLD_003_refRho', diag%axesT1, Time, &
35230 'Reference density for MLD (delta rho = 0.03)', units='kg/m3', conversion=US%R_to_kg_m3)
3524 endif
3525 endif
3526
35271 call KdWork_init(Time, G,GV,US,diag,CS%VBF,CS%Use_KdWork_diag)
35281 if (CS%Use_KdWork_diag.and.(.not.useALEalgorithm)) &
35290 call MOM_error(WARNING,"The KdWork diagnostics are not fully implemented for use in layer mode.")
35301 if (CS%Use_KdWork_diag.and.(CS%use_legacy_diabatic)) &
35310 call MOM_error(WARNING,"The KdWork diagnostics are only approximate with the legacy diabatic driver.")
3532
3533 call get_param(param_file, mdl, "DIAG_MLD_DENSITY_DIFF", CS%MLDdensityDifference, &
3534 "The density difference used to determine a diagnostic mixed "//&
3535 "layer depth, MLD_user, following the definition of Levitus 1982. "//&
3536 "The MLD is the depth at which the density is larger than the "//&
3537 "surface density by the specified amount.", &
35381 units='kg/m3', default=0.1, scale=US%kg_m3_to_R)
3539 call get_param(param_file, mdl, "DIAG_DEPTH_SUBML_N2", CS%dz_subML_N2, &
3540 "The distance over which to calculate a diagnostic of the "//&
3541 "stratification at the base of the mixed layer.", &
35421 units='m', default=50.0, scale=US%m_to_Z)
3543
3544 ! diagnostics for values prior to diabatic and prior to ALE
3545 CS%id_u_predia = register_diag_field('ocean_model', 'u_predia', diag%axesCuL, Time, &
35461 'Zonal velocity before diabatic forcing', 'm s-1', conversion=US%L_T_to_m_s)
3547 CS%id_v_predia = register_diag_field('ocean_model', 'v_predia', diag%axesCvL, Time, &
35481 'Meridional velocity before diabatic forcing', 'm s-1', conversion=US%L_T_to_m_s)
3549 CS%id_h_predia = register_diag_field('ocean_model', 'h_predia', diag%axesTL, Time, &
3550 'Layer Thickness before diabatic forcing', &
35511 trim(thickness_units), conversion=GV%H_to_MKS, v_extensive=.true.)
3552 CS%id_e_predia = register_diag_field('ocean_model', 'e_predia', diag%axesTi, Time, &
35531 'Interface Heights before diabatic forcing', 'm', conversion=US%Z_to_m)
35541 if (use_temperature) then
3555 CS%id_T_predia = register_diag_field('ocean_model', 'temp_predia', diag%axesTL, Time, &
35561 'Potential Temperature', 'degC', conversion=US%C_to_degC)
3557 CS%id_S_predia = register_diag_field('ocean_model', 'salt_predia', diag%axesTL, Time, &
35581 'Salinity', 'PSU', conversion=US%S_to_ppt)
3559 endif
3560
3561 CS%id_Kd_int = register_diag_field('ocean_model', 'Kd_interface', diag%axesTi, Time, &
35621 'Total diapycnal diffusivity at interfaces', 'm2 s-1', conversion=GV%HZ_T_to_m2_s)
35631 if (CS%use_energetic_PBL) then
3564 CS%id_Kd_ePBL = register_diag_field('ocean_model', 'Kd_ePBL', diag%axesTi, Time, &
35651 'ePBL diapycnal diffusivity at interfaces', 'm2 s-1', conversion=GV%HZ_T_to_m2_s)
3566 endif
3567
3568 CS%id_Kd_heat = register_diag_field('ocean_model', 'Kd_heat', diag%axesTi, Time, &
3569 'Total diapycnal diffusivity for heat at interfaces', 'm2 s-1', conversion=GV%HZ_T_to_m2_s, &
3570 cmor_field_name='difvho', &
3571 cmor_standard_name='ocean_vertical_heat_diffusivity', &
35721 cmor_long_name='Ocean vertical heat diffusivity')
3573 CS%id_Kd_salt = register_diag_field('ocean_model', 'Kd_salt', diag%axesTi, Time, &
3574 'Total diapycnal diffusivity for salt at interfaces', 'm2 s-1', conversion=GV%HZ_T_to_m2_s, &
3575 cmor_field_name='difvso', &
3576 cmor_standard_name='ocean_vertical_salt_diffusivity', &
35771 cmor_long_name='Ocean vertical salt diffusivity')
3578
3579 ! CS%useKPP is set to True if KPP-scheme is to be used, False otherwise.
3580 ! KPP_init() allocated CS%KPP_Csp and also sets CS%KPPisPassive
35811 CS%useKPP = KPP_init(param_file, G, GV, US, diag, Time, CS%KPP_CSp, passive=CS%KPPisPassive)
3582
3583 ! Diagnostics for tendencies of temperature and salinity due to diabatic processes,
3584 ! available only for ALE algorithm.
3585 ! Diagnostics for tendencies of temperature and heat due to frazil
3586 CS%id_diabatic_diff_h = register_diag_field('ocean_model', 'diabatic_diff_h', diag%axesTL, Time, &
3587 'Cell thickness used during diabatic diffusion', &
35881 thickness_units, conversion=GV%H_to_MKS, v_extensive=.true.)
3589
35901 if (CS%useALEalgorithm) then
3591 CS%id_diabatic_diff_temp_tend = register_diag_field('ocean_model', &
3592 'diabatic_diff_temp_tendency', diag%axesTL, Time, &
35931 'Diabatic diffusion temperature tendency', 'degC s-1', conversion=US%C_to_degC*US%s_to_T)
35941 if (CS%id_diabatic_diff_temp_tend > 0) then
35950 CS%diabatic_diff_tendency_diag = .true.
3596 endif
3597
3598 CS%id_diabatic_diff_saln_tend = register_diag_field('ocean_model',&
3599 'diabatic_diff_saln_tendency', diag%axesTL, Time, &
36001 'Diabatic diffusion salinity tendency', 'psu s-1', conversion=US%S_to_ppt*US%s_to_T)
36011 if (CS%id_diabatic_diff_saln_tend > 0) then
36020 CS%diabatic_diff_tendency_diag = .true.
3603 endif
3604
3605 CS%id_diabatic_diff_heat_tend = register_diag_field('ocean_model', &
3606 'diabatic_heat_tendency', diag%axesTL, Time, &
3607 'Diabatic diffusion heat tendency', &
3608 'W m-2', conversion=US%QRZ_T_to_W_m2, cmor_field_name='opottempdiff', &
3609 cmor_standard_name='tendency_of_sea_water_potential_temperature_expressed_as_heat_content_'// &
3610 'due_to_parameterized_dianeutral_mixing', &
3611 cmor_long_name='Tendency of sea water potential temperature expressed as heat content '// &
3612 'due to parameterized dianeutral mixing', &
36131 v_extensive=.true.)
36141 if (CS%id_diabatic_diff_heat_tend > 0) then
36150 CS%diabatic_diff_tendency_diag = .true.
3616 endif
3617
3618 CS%id_diabatic_diff_salt_tend = register_diag_field('ocean_model', &
3619 'diabatic_salt_tendency', diag%axesTL, Time, &
3620 'Diabatic diffusion of salt tendency', &
3621 'kg m-2 s-1', conversion=US%S_to_ppt*0.001*GV%H_to_RZ*US%RZ_T_to_kg_m2s, &
3622 cmor_field_name='osaltdiff', &
3623 cmor_standard_name='tendency_of_sea_water_salinity_expressed_as_salt_content_'// &
3624 'due_to_parameterized_dianeutral_mixing', &
3625 cmor_long_name='Tendency of sea water salinity expressed as salt content '// &
3626 'due to parameterized dianeutral mixing', &
36271 v_extensive=.true.)
36281 if (CS%id_diabatic_diff_salt_tend > 0) then
36290 CS%diabatic_diff_tendency_diag = .true.
3630 endif
3631
3632 ! This diagnostic should equal to roundoff if all is working well.
3633 CS%id_diabatic_diff_heat_tend_2d = register_diag_field('ocean_model', &
3634 'diabatic_heat_tendency_2d', diag%axesT1, Time, &
3635 'Depth integrated diabatic diffusion heat tendency', &
3636 'W m-2', conversion=US%QRZ_T_to_W_m2, cmor_field_name='opottempdiff_2d', &
3637 cmor_standard_name='tendency_of_sea_water_potential_temperature_expressed_as_heat_content_'//&
3638 'due_to_parameterized_dianeutral_mixing_depth_integrated', &
3639 cmor_long_name='Tendency of sea water potential temperature expressed as heat content '//&
36401 'due to parameterized dianeutral mixing depth integrated')
36411 if (CS%id_diabatic_diff_heat_tend_2d > 0) then
36420 CS%diabatic_diff_tendency_diag = .true.
3643 endif
3644
3645 ! This diagnostic should equal to roundoff if all is working well.
3646 CS%id_diabatic_diff_salt_tend_2d = register_diag_field('ocean_model', &
3647 'diabatic_salt_tendency_2d', diag%axesT1, Time, &
3648 'Depth integrated diabatic diffusion salt tendency', &
3649 'kg m-2 s-1', conversion=US%S_to_ppt*0.001*GV%H_to_RZ*US%RZ_T_to_kg_m2s, &
3650 cmor_field_name='osaltdiff_2d', &
3651 cmor_standard_name='tendency_of_sea_water_salinity_expressed_as_salt_content_'// &
3652 'due_to_parameterized_dianeutral_mixing_depth_integrated', &
3653 cmor_long_name='Tendency of sea water salinity expressed as salt content '// &
36541 'due to parameterized dianeutral mixing depth integrated')
36551 if (CS%id_diabatic_diff_salt_tend_2d > 0) then
36560 CS%diabatic_diff_tendency_diag = .true.
3657 endif
3658
3659 ! Diagnostics for tendencies of thickness temperature and salinity due to boundary forcing,
3660 ! available only for ALE algorithm.
3661 ! Diagnostics for tendencies of temperature and heat due to frazil
3662 CS%id_boundary_forcing_h = register_diag_field('ocean_model', 'boundary_forcing_h', diag%axesTL, Time, &
3663 'Cell thickness after applying boundary forcing', &
36641 thickness_units, conversion=GV%H_to_MKS, v_extensive=.true.)
3665 CS%id_boundary_forcing_h_tendency = register_diag_field('ocean_model', &
3666 'boundary_forcing_h_tendency', diag%axesTL, Time, &
3667 'Cell thickness tendency due to boundary forcing', &
36681 trim(thickness_units)//" s-1", conversion=GV%H_to_MKS*US%s_to_T, v_extensive=.true.)
36691 if (CS%id_boundary_forcing_h_tendency > 0) then
36700 CS%boundary_forcing_tendency_diag = .true.
3671 endif
3672
3673 CS%id_boundary_forcing_temp_tend = register_diag_field('ocean_model',&
3674 'boundary_forcing_temp_tendency', diag%axesTL, Time, &
36751 'Boundary forcing temperature tendency', 'degC s-1', conversion=US%C_to_degC*US%s_to_T)
36761 if (CS%id_boundary_forcing_temp_tend > 0) then
36770 CS%boundary_forcing_tendency_diag = .true.
3678 endif
3679
3680 CS%id_boundary_forcing_saln_tend = register_diag_field('ocean_model',&
3681 'boundary_forcing_saln_tendency', diag%axesTL, Time, &
36821 'Boundary forcing saln tendency', 'psu s-1', conversion=US%S_to_ppt*US%s_to_T)
36831 if (CS%id_boundary_forcing_saln_tend > 0) then
36840 CS%boundary_forcing_tendency_diag = .true.
3685 endif
3686
3687 CS%id_boundary_forcing_heat_tend = register_diag_field('ocean_model',&
3688 'boundary_forcing_heat_tendency', diag%axesTL, Time, &
3689 'Boundary forcing heat tendency', &
36901 'W m-2', conversion=US%QRZ_T_to_W_m2, v_extensive=.true.)
36911 if (CS%id_boundary_forcing_heat_tend > 0) then
36920 CS%boundary_forcing_tendency_diag = .true.
3693 endif
3694
3695 CS%id_boundary_forcing_salt_tend = register_diag_field('ocean_model',&
3696 'boundary_forcing_salt_tendency', diag%axesTL, Time, &
3697 'Boundary forcing salt tendency', &
3698 'kg m-2 s-1', conversion=US%S_to_ppt*0.001*GV%H_to_RZ*US%RZ_T_to_kg_m2s, &
36991 v_extensive = .true.)
37001 if (CS%id_boundary_forcing_salt_tend > 0) then
37010 CS%boundary_forcing_tendency_diag = .true.
3702 endif
3703
3704 ! This diagnostic should equal to surface heat flux if all is working well.
3705 CS%id_boundary_forcing_heat_tend_2d = register_diag_field('ocean_model',&
3706 'boundary_forcing_heat_tendency_2d', diag%axesT1, Time, &
3707 'Depth integrated boundary forcing of ocean heat', &
37081 'W m-2', conversion=US%QRZ_T_to_W_m2)
37091 if (CS%id_boundary_forcing_heat_tend_2d > 0) then
37100 CS%boundary_forcing_tendency_diag = .true.
3711 endif
3712
3713 ! This diagnostic should equal to surface salt flux if all is working well.
3714 CS%id_boundary_forcing_salt_tend_2d = register_diag_field('ocean_model',&
3715 'boundary_forcing_salt_tendency_2d', diag%axesT1, Time, &
3716 'Depth integrated boundary forcing of ocean salt', &
37171 'kg m-2 s-1', conversion=US%S_to_ppt*0.001*GV%H_to_RZ*US%RZ_T_to_kg_m2s)
37181 if (CS%id_boundary_forcing_salt_tend_2d > 0) then
37190 CS%boundary_forcing_tendency_diag = .true.
3720 endif
3721 endif
3722
3723 ! diagnostics for tendencies of temp and heat due to frazil
3724 CS%id_frazil_h = register_diag_field('ocean_model', 'frazil_h', diag%axesTL, Time, &
3725 long_name='Cell Thickness', standard_name='cell_thickness', &
37261 units=thickness_units, conversion=GV%H_to_MKS, v_extensive=.true.)
3727
3728 ! diagnostic for tendency of temp due to frazil
3729 CS%id_frazil_temp_tend = register_diag_field('ocean_model',&
3730 'frazil_temp_tendency', diag%axesTL, Time, &
37311 'Temperature tendency due to frazil formation', 'degC s-1', conversion=US%C_to_degC*US%s_to_T)
37321 if (CS%id_frazil_temp_tend > 0) then
37330 CS%frazil_tendency_diag = .true.
3734 endif
3735
3736 ! diagnostic for tendency of heat due to frazil
3737 CS%id_frazil_heat_tend = register_diag_field('ocean_model',&
3738 'frazil_heat_tendency', diag%axesTL, Time, &
3739 'Heat tendency due to frazil formation', &
37401 'W m-2', conversion=US%QRZ_T_to_W_m2, v_extensive=.true.)
37411 if (CS%id_frazil_heat_tend > 0) then
37420 CS%frazil_tendency_diag = .true.
3743 endif
3744
3745 ! If all is working properly, this diagnostic should equal to hfsifrazil.
3746 CS%id_frazil_heat_tend_2d = register_diag_field('ocean_model',&
3747 'frazil_heat_tendency_2d', diag%axesT1, Time, &
3748 'Depth integrated heat tendency due to frazil formation', &
37491 'W m-2', conversion=US%QRZ_T_to_W_m2)
37501 if (CS%id_frazil_heat_tend_2d > 0) then
37510 CS%frazil_tendency_diag = .true.
3752 endif
3753
3754 ! CS%use_CVMix_conv is set to True if CVMix convection will be used, otherwise it is False.
37551 CS%use_CVMix_conv = CVMix_conv_init(Time, G, GV, US, param_file, diag, CS%CVMix_conv)
3756
3757 call entrain_diffusive_init(Time, G, GV, US, param_file, diag, CS%entrain_diffusive, &
37581 just_read_params=CS%useALEalgorithm)
3759
3760 ! initialize the geothermal heating module
37611 if (CS%use_geothermal) &
37621 call geothermal_init(Time, G, GV, US, param_file, diag, CS%geothermal, useALEalgorithm)
3763
3764 ! initialize module for internal tide induced mixing
37651 if (CS%use_int_tides) then
3766 call int_tide_input_init(Time, G, GV, US, param_file, diag, CS%int_tide_input_CSp, &
37670 CS%int_tide_input)
37680 call internal_tides_init(Time, G, GV, US, param_file, diag, int_tide_CSp)
3769 endif
3770
3771 !if (associated(int_tide_CSp)) CS%int_tide_CSp => int_tide_CSp
3772
37731 physical_OBL_scheme = (CS%use_bulkmixedlayer .or. CS%use_KPP .or. CS%use_energetic_PBL)
3774 ! initialize module for setting diffusivities
3775 call set_diffusivity_init(Time, G, GV, US, param_file, diag, CS%set_diff_CSp, CS%int_tide_CSp, &
3776 halo_TS=CS%halo_TS_diff, double_diffuse=CS%double_diffuse, &
37771 physical_OBL_scheme=physical_OBL_scheme)
3778
37791 CS%halo_diabatic = CS%halo_TS_diff
37801 if (CS%use_int_tides) CS%halo_diabatic = max(CS%halo_TS_diff, 2)
3781
37821 if (CS%useKPP .and. (CS%double_diffuse .and. .not.CS%use_CVMix_ddiff)) &
3783 call MOM_error(FATAL, 'diabatic_driver_init: DOUBLE_DIFFUSION (old method) does not work '//&
37840 'with KPP. Please set DOUBLE_DIFFUSION=False and USE_CVMIX_DDIFF=True.')
3785
3786 ! set up the clocks for this module
37871 id_clock_entrain = cpu_clock_id('(Ocean diabatic entrain)', grain=CLOCK_MODULE)
37881 if (CS%use_bulkmixedlayer) &
37890 id_clock_mixedlayer = cpu_clock_id('(Ocean mixed layer)', grain=CLOCK_MODULE)
37901 id_clock_remap = cpu_clock_id('(Ocean vert remap)', grain=CLOCK_MODULE)
37911 if (CS%use_geothermal) &
37921 id_clock_geothermal = cpu_clock_id('(Ocean geothermal)', grain=CLOCK_ROUTINE)
37931 id_clock_set_diffusivity = cpu_clock_id('(Ocean set_diffusivity)', grain=CLOCK_MODULE)
37941 id_clock_kpp = cpu_clock_id('(Ocean KPP)', grain=CLOCK_MODULE)
37951 id_clock_tracers = cpu_clock_id('(Ocean tracer_columns)', grain=CLOCK_MODULE_DRIVER+5)
37961 if (CS%use_sponge) &
37970 id_clock_sponge = cpu_clock_id('(Ocean sponges)', grain=CLOCK_MODULE)
37981 if (CS%use_oda_incupd) &
37990 id_clock_oda_incupd = cpu_clock_id('(Ocean inc. update data assimilation)', grain=CLOCK_MODULE)
38001 id_clock_tridiag = cpu_clock_id('(Ocean diabatic tridiag)', grain=CLOCK_ROUTINE)
38011 id_clock_pass = cpu_clock_id('(Ocean diabatic message passing)', grain=CLOCK_ROUTINE)
38021 id_clock_differential_diff = -1 ; if (CS%double_diffuse .and. .not.CS%use_CVMix_ddiff) &
38030 id_clock_differential_diff = cpu_clock_id('(Ocean differential diffusion)', grain=CLOCK_ROUTINE)
3804
3805 ! initialize the auxiliary diabatic driver module
3806 call diabatic_aux_init(Time, G, GV, US, param_file, diag, CS%diabatic_aux_CSp, &
38071 CS%useALEalgorithm, CS%use_energetic_PBL)
3808
3809 ! initialize the boundary layer modules
38101 if (CS%use_bulkmixedlayer) &
38110 call bulkmixedlayer_init(Time, G, GV, US, param_file, diag, CS%bulkmixedlayer)
38121 if (CS%use_energetic_PBL) &
38131 call energetic_PBL_init(Time, G, GV, US, param_file, diag, CS%ePBL)
3814
38151 call regularize_layers_init(Time, G, GV, param_file, diag, CS%regularize_layers)
3816
38171 if (CS%debug_energy_req) &
38180 call diapyc_energy_req_init(Time, G, GV, US, param_file, diag, CS%diapyc_en_rec_CSp)
3819
3820 ! obtain information about the number of bands for penetrative shortwave
38211 if (use_temperature) then
38221 call get_param(param_file, mdl, "PEN_SW_NBANDS", nbands, default=1)
38231 if (nbands > 0) then
38241 allocate(CS%optics)
38251 call opacity_init(Time, G, GV, US, param_file, diag, CS%opacity, CS%optics)
3826 endif
3827 endif
3828
3829 ! Initialize the diagnostic grid storage
38301 call diag_grid_storage_init(CS%diag_grids_prev, G, GV, diag)
3831
38321end subroutine diabatic_driver_init
3833
3834!> Routine to register restarts, pass-through to children modules
38351subroutine register_diabatic_restarts(G, GV, US, param_file, int_tide_CSp, restart_CSp, CS)
3836 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
3837 type(verticalGrid_type), intent(in) :: GV !< The ocean's vertical grid structure
3838 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
3839 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
3840 type(int_tide_CS), pointer :: int_tide_CSp !< Internal tide control structure
3841 type(MOM_restart_CS), pointer :: restart_CSp !< MOM restart control structure
3842 type(diabatic_CS), pointer :: CS !< module control structure
3843
3844 logical :: use_int_tides
3845
38461 if (associated(CS)) then
3847 call MOM_error(WARNING, "diabatic_driver_init called with an "// &
38480 "associated control structure.")
38490 return
3850 else
38511 allocate(CS)
3852 endif
3853
38541 use_int_tides=.false.
3855
38561 call read_param(param_file, "INTERNAL_TIDES", use_int_tides)
3857
38581 if (use_int_tides) then
38590 call register_int_tide_restarts(G, GV, US, param_file, int_tide_CSp, restart_CSp)
3860 endif
3861
38621 call register_KPP_restarts(G, param_file, restart_CSp, CS%KPP_CSp)
3863
3864end subroutine register_diabatic_restarts
3865
3866!> Routine to close the diabatic driver module
38671subroutine diabatic_driver_end(CS)
3868 type(diabatic_CS), intent(inout) :: CS !< module control structure
3869
38701 if (associated(CS%VBF)) then
38711 call KdWork_end(CS%VBF)
3872 endif
3873
38741 if (associated(CS%optics)) then
38751 call opacity_end(CS%opacity, CS%optics)
38761 deallocate(CS%optics)
3877 endif
3878
38791 if (CS%debug_energy_req) &
38800 call diapyc_energy_req_end(CS%diapyc_en_rec_CSp)
3881
38821 if (CS%use_energetic_PBL) &
38831 call energetic_PBL_end(CS%ePBL)
3884
38851 call diabatic_aux_end(CS%diabatic_aux_CSp)
3886
38871 call set_diffusivity_end(CS%set_diff_CSp)
3888
38891 deallocate(CS%set_diff_CSp)
3890
38911 if (CS%use_geothermal) &
38921 call geothermal_end(CS%geothermal)
3893
38941 if (CS%useKPP) &
38950 call KPP_end(CS%KPP_CSp)
3896
3897 ! GMM, the following is commented out because arrays in
3898 ! CS%diag_grids_prev are neither pointers or allocatables
3899 ! and, therefore, cannot be deallocated.
3900
3901 !call diag_grid_storage_end(CS%diag_grids_prev)
39021end subroutine diabatic_driver_end
3903
3904
3905!> \namespace mom_diabatic_driver
3906!!
3907!! By Robert Hallberg, Alistair Adcroft, and Stephen Griffies
3908!!
3909!! This program contains the subroutine that, along with the
3910!! subroutines that it calls, implements diapycnal mass and momentum
3911!! fluxes and a bulk mixed layer. The diapycnal diffusion can be
3912!! used without the bulk mixed layer.
3913!!
3914!! \section section_diabatic Outline of MOM diabatic
3915!!
3916!! * diabatic first determines the (diffusive) diapycnal mass fluxes
3917!! based on the convergence of the buoyancy fluxes within each layer.
3918!!
3919!! * The dual-stream entrainment scheme of MacDougall and Dewar (JPO,
3920!! 1997) is used for combined diapycnal advection and diffusion,
3921!! calculated implicitly and potentially with the Richardson number
3922!! dependent mixing, as described by Hallberg (MWR, 2000).
3923!!
3924!! * Diapycnal advection is the residual of diapycnal diffusion,
3925!! so the fully implicit upwind differencing scheme that is used is
3926!! entirely appropriate.
3927!!
3928!! * The downward buoyancy flux in each layer is determined from
3929!! an implicit calculation based on the previously
3930!! calculated flux of the layer above and an estimated flux in the
3931!! layer below. This flux is subject to the following conditions:
3932!! (1) the flux in the top and bottom layers are set by the boundary
3933!! conditions, and (2) no layer may be driven below a minimal thickness.
3934!! If there is a bulk mixed layer, the buffer layer is treated
3935!! as a fixed density layer with vanishingly small diffusivity.
3936!!
3937!! diabatic takes 5 arguments: the two velocities (u and v), the
3938!! thicknesses (h), a structure containing the forcing fields, and
3939!! the length of time over which to act (dt). The velocities and
3940!! thickness are taken as inputs and modified within the subroutine.
3941!! There is no limit on the time step.
3942
39430end module MOM_diabatic_driver