← back to index

src/core/MOM.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!> The central module of the MOM6 ocean model
6module MOM
7
8! Infrastructure modules
9use MOM_array_transform, only : rotate_array, rotate_vector
10use MOM_debugging, only : MOM_debugging_init, hchksum, uvchksum, totalTandS
11use MOM_debugging, only : check_redundant, query_debugging_checks
12use MOM_checksum_packages, only : MOM_thermo_chksum, MOM_state_chksum
13use MOM_checksum_packages, only : MOM_accel_chksum, MOM_surface_chksum
14use MOM_coms, only : num_PEs
15use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
16use MOM_cpu_clock, only : CLOCK_COMPONENT, CLOCK_SUBCOMPONENT
17use MOM_cpu_clock, only : CLOCK_MODULE_DRIVER, CLOCK_MODULE, CLOCK_ROUTINE
18use MOM_diag_mediator, only : diag_mediator_init, enable_averaging, enable_averages
19use MOM_diag_mediator, only : diag_mediator_infrastructure_init
20use MOM_diag_mediator, only : diag_set_state_ptrs, diag_update_remap_grids
21use MOM_diag_mediator, only : disable_averaging, post_data, safe_alloc_ptr
22use MOM_diag_mediator, only : register_diag_field, register_cell_measure
23use MOM_diag_mediator, only : set_axes_info, diag_ctrl, diag_masks_set
24use MOM_diag_mediator, only : set_masks_for_axes
25use MOM_diag_mediator, only : diag_grid_storage, diag_grid_storage_init
26use MOM_diag_mediator, only : diag_save_grids, diag_restore_grids
27use MOM_diag_mediator, only : diag_copy_storage_to_diag, diag_copy_diag_to_storage
28use MOM_domains, only : MOM_domains_init, MOM_domain_type
29use MOM_domains, only : sum_across_PEs, pass_var, pass_vector
30use MOM_domains, only : clone_MOM_domain, deallocate_MOM_domain
31use MOM_domains, only : To_North, To_East, To_South, To_West
32use MOM_domains, only : To_All, Omit_corners, CGRID_NE, SCALAR_PAIR
33use MOM_domains, only : create_group_pass, do_group_pass, group_pass_type
34use MOM_domains, only : start_group_pass, complete_group_pass, Omit_Corners
35use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING, is_root_pe
36use MOM_error_handler, only : MOM_set_verbosity, callTree_showQuery
37use MOM_error_handler, only : callTree_enter, callTree_leave, callTree_waypoint
38use MOM_file_parser, only : read_param, get_param, log_version, param_file_type
39use MOM_forcing_type, only : forcing, mech_forcing, find_ustar
40use MOM_forcing_type, only : MOM_forcing_chksum, MOM_mech_forcing_chksum
41use MOM_get_input, only : Get_MOM_Input, directories
42use MOM_io, only : MOM_io_init, vardesc, var_desc
43use MOM_io, only : slasher, file_exists, MOM_read_data
44use MOM_obsolete_params, only : find_obsolete_params
45use MOM_restart, only : register_restart_field, register_restart_pair, save_restart
46use MOM_restart, only : query_initialized, set_initialized, restart_registry_lock
47use MOM_restart, only : restart_init, is_new_run, determine_is_new_run, MOM_restart_CS
48use MOM_spatial_means, only : global_mass_integral
49use MOM_time_manager, only : time_type, real_to_time, operator(+)
50use MOM_time_manager, only : operator(-), operator(>), operator(*), operator(/)
51use MOM_time_manager, only : operator(>=), operator(==), increment_date
52use MOM_unit_tests, only : unit_tests
53
54! MOM core modules
55use MOM_ALE, only : ALE_init, ALE_end, ALE_regrid, ALE_CS, adjustGridForIntegrity
56use MOM_ALE, only : ALE_getCoordinate, ALE_getCoordinateUnits, ALE_writeCoordinateFile
57use MOM_ALE, only : ALE_updateVerticalGridType, ALE_remap_init_conds, pre_ALE_adjustments
58use MOM_ALE, only : ALE_remap_tracers, ALE_remap_velocities
59use MOM_ALE, only : ALE_remap_set_h_vel, ALE_remap_set_h_vel_via_dz
60use MOM_ALE, only : ALE_update_regrid_weights, pre_ALE_diagnostics, ALE_register_diags
61use MOM_ALE, only : ALE_set_extrap_boundaries
62use MOM_ALE_sponge, only : rotate_ALE_sponge, update_ALE_sponge_field
63use MOM_barotropic, only : Barotropic_CS
64use MOM_boundary_update, only : call_OBC_register, OBC_register_end, update_OBC_CS
65use MOM_check_scaling, only : check_MOM6_scaling_factors
66use MOM_coord_initialization, only : MOM_initialize_coord, write_vertgrid_file
67use MOM_diabatic_driver, only : diabatic, diabatic_driver_init, diabatic_CS, extract_diabatic_member
68use MOM_diabatic_driver, only : adiabatic, adiabatic_driver_init, diabatic_driver_end
69use MOM_diabatic_driver, only : register_diabatic_restarts
70use MOM_stochastics, only : stochastics_init, update_stochastics, stochastic_CS, apply_skeb
71use MOM_diagnostics, only : calculate_diagnostic_fields, MOM_diagnostics_init
72use MOM_diagnostics, only : register_transport_diags, post_transport_diagnostics
73use MOM_diagnostics, only : register_surface_diags, write_static_fields
74use MOM_diagnostics, only : post_surface_dyn_diags, post_surface_thermo_diags
75use MOM_diagnostics, only : diagnostics_CS, surface_diag_IDs, transport_diag_IDs
76use MOM_diagnostics, only : MOM_diagnostics_end
77use MOM_dynamics_unsplit, only : step_MOM_dyn_unsplit, register_restarts_dyn_unsplit
78use MOM_dynamics_unsplit, only : initialize_dyn_unsplit, end_dyn_unsplit
79use MOM_dynamics_unsplit, only : MOM_dyn_unsplit_CS
80use MOM_dynamics_split_RK2, only : step_MOM_dyn_split_RK2, register_restarts_dyn_split_RK2
81use MOM_dynamics_split_RK2, only : initialize_dyn_split_RK2, end_dyn_split_RK2
82use MOM_dynamics_split_RK2, only : MOM_dyn_split_RK2_CS, remap_dyn_split_rk2_aux_vars
83use MOM_dynamics_split_RK2, only : init_dyn_split_RK2_diabatic
84use MOM_dynamics_split_RK2b, only : step_MOM_dyn_split_RK2b, register_restarts_dyn_split_RK2b
85use MOM_dynamics_split_RK2b, only : initialize_dyn_split_RK2b, end_dyn_split_RK2b
86use MOM_dynamics_split_RK2b, only : MOM_dyn_split_RK2b_CS, remap_dyn_split_RK2b_aux_vars
87use MOM_dynamics_unsplit_RK2, only : step_MOM_dyn_unsplit_RK2, register_restarts_dyn_unsplit_RK2
88use MOM_dynamics_unsplit_RK2, only : initialize_dyn_unsplit_RK2, end_dyn_unsplit_RK2
89use MOM_dynamics_unsplit_RK2, only : MOM_dyn_unsplit_RK2_CS
90use MOM_dyn_horgrid, only : dyn_horgrid_type, create_dyn_horgrid, destroy_dyn_horgrid
91use MOM_dyn_horgrid, only : rotate_dyn_horgrid
92use MOM_EOS, only : EOS_init, calculate_density, calculate_TFreeze, EOS_domain
93use MOM_fixed_initialization, only : MOM_initialize_fixed
94use MOM_forcing_type, only : allocate_forcing_type, allocate_mech_forcing
95use MOM_forcing_type, only : deallocate_mech_forcing, deallocate_forcing_type
96use MOM_forcing_type, only : rotate_forcing, rotate_mech_forcing
97use MOM_forcing_type, only : copy_common_forcing_fields, set_derived_forcing_fields
98use MOM_forcing_type, only : homogenize_forcing, homogenize_mech_forcing
99use MOM_grid, only : ocean_grid_type, MOM_grid_init, MOM_grid_end
100use MOM_grid, only : set_first_direction
101use MOM_harmonic_analysis, only : HA_accum, harmonic_analysis_CS
102use MOM_hor_index, only : hor_index_type, hor_index_init
103use MOM_hor_index, only : rotate_hor_index
104use MOM_interface_heights, only : find_eta, calc_derived_thermo, thickness_to_dz
105use MOM_interface_filter, only : interface_filter, interface_filter_init, interface_filter_end
106use MOM_interface_filter, only : interface_filter_CS
107use MOM_internal_tides, only : int_tide_CS
108use MOM_kappa_shear, only : kappa_shear_at_vertex
109use MOM_lateral_mixing_coeffs, only : calc_slope_functions, VarMix_init, VarMix_end
110use MOM_lateral_mixing_coeffs, only : calc_resoln_function, calc_depth_function, VarMix_CS
111use MOM_MEKE, only : MEKE_alloc_register_restart, step_forward_MEKE
112use MOM_MEKE, only : MEKE_CS, MEKE_init, MEKE_end
113use MOM_MEKE_types, only : MEKE_type
114use MOM_mixed_layer_restrat, only : mixedlayer_restrat, mixedlayer_restrat_init, mixedlayer_restrat_CS
115use MOM_mixed_layer_restrat, only : mixedlayer_restrat_register_restarts
116use MOM_obsolete_diagnostics, only : register_obsolete_diagnostics
117use MOM_open_boundary, only : ocean_OBC_type, open_boundary_end
118use MOM_open_boundary, only : register_temp_salt_segments, update_segment_tracer_reservoirs
119use MOM_open_boundary, only : read_OBC_segment_data, initialize_OBC_segment_reservoirs
120use MOM_open_boundary, only : setup_OBC_tracer_reservoirs
121use MOM_open_boundary, only : setup_OBC_thickness_reservoirs
122use MOM_open_boundary, only : open_boundary_register_restarts, remap_OBC_fields
123use MOM_open_boundary, only : open_boundary_setup_vert, initialize_segment_data
124use MOM_open_boundary, only : update_OBC_segment_data, rotate_OBC_config
125use MOM_open_boundary, only : open_boundary_halo_update, write_OBC_info, chksum_OBC_segments
126use MOM_open_boundary, only : segment_thickness_reservoir_init
127use MOM_porous_barriers, only : porous_widths_layer, porous_widths_interface, porous_barriers_init
128use MOM_porous_barriers, only : porous_barrier_CS
129use MOM_set_visc, only : set_viscous_BBL, set_viscous_ML, set_visc_CS
130use MOM_set_visc, only : set_visc_register_restarts, remap_vertvisc_aux_vars
131use MOM_set_visc, only : set_visc_init, set_visc_end
132use MOM_shared_initialization, only : write_ocean_geometry_file
133use MOM_sponge, only : init_sponge_diags, sponge_CS
134use MOM_state_initialization, only : MOM_initialize_state, MOM_initialize_OBCs
135use MOM_stoch_eos, only : MOM_stoch_eos_init, MOM_stoch_eos_run, MOM_stoch_eos_CS
136use MOM_stoch_eos, only : stoch_EOS_register_restarts, post_stoch_EOS_diags, mom_calc_varT
137use MOM_sum_output, only : write_energy, accumulate_net_input
138use MOM_sum_output, only : MOM_sum_output_init, MOM_sum_output_end
139use MOM_sum_output, only : sum_output_CS
140use MOM_ALE_sponge, only : init_ALE_sponge_diags, ALE_sponge_CS
141use MOM_thickness_diffuse, only : thickness_diffuse, thickness_diffuse_init
142use MOM_thickness_diffuse, only : thickness_diffuse_end, thickness_diffuse_CS
143use MOM_tracer_advect, only : advect_tracer, tracer_advect_init
144use MOM_tracer_advect, only : tracer_advect_end, tracer_advect_CS
145use MOM_tracer_hor_diff, only : tracer_hordiff, tracer_hor_diff_init
146use MOM_tracer_hor_diff, only : tracer_hor_diff_end, tracer_hor_diff_CS
147use MOM_tracer_registry, only : tracer_registry_type, register_tracer, tracer_registry_init
148use MOM_tracer_registry, only : register_tracer_diagnostics, post_tracer_diagnostics_at_sync
149use MOM_tracer_registry, only : post_tracer_transport_diagnostics, MOM_tracer_chksum
150use MOM_tracer_registry, only : preALE_tracer_diagnostics, postALE_tracer_diagnostics
151use MOM_tracer_registry, only : lock_tracer_registry, tracer_registry_end
152use MOM_tracer_flow_control, only : call_tracer_register, tracer_flow_control_CS
153use MOM_tracer_flow_control, only : tracer_flow_control_init, call_tracer_surface_state
154use MOM_tracer_flow_control, only : tracer_flow_control_end, call_tracer_register_obc_segments
155use MOM_transcribe_grid, only : copy_dyngrid_to_MOM_grid, copy_MOM_grid_to_dyngrid
156use MOM_unit_scaling, only : unit_scale_type, unit_scaling_init, unit_scaling_end
157use MOM_variables, only : surface, allocate_surface_state, deallocate_surface_state
158use MOM_variables, only : thermo_var_ptrs, vertvisc_type, porous_barrier_type
159use MOM_variables, only : accel_diag_ptrs, cont_diag_ptrs, ocean_internal_state
160use MOM_variables, only : rotate_surface_state
161use MOM_verticalGrid, only : verticalGrid_type, verticalGridInit, verticalGridEnd
162use MOM_verticalGrid, only : get_thickness_units, get_flux_units, get_tr_flux_units
163use MOM_wave_interface, only : wave_parameters_CS, waves_end, waves_register_restarts
164use MOM_wave_interface, only : Update_Stokes_Drift
165
166! Database client used for machine-learning interface
167use MOM_database_comms, only : dbcomms_CS_type, database_comms_init, dbclient_type
168
169! ODA modules
170use MOM_oda_driver_mod, only : ODA_CS, oda, init_oda, oda_end
171use MOM_oda_driver_mod, only : set_prior_tracer, set_analysis_time, apply_oda_tracer_increments
172use MOM_oda_incupd, only : oda_incupd_CS, init_oda_incupd_diags
173
174! Offline modules
175use MOM_offline_main, only : offline_transport_CS, offline_transport_init, update_offline_fields
176use MOM_offline_main, only : insert_offline_main, extract_offline_main, post_offline_convergence_diags
177use MOM_offline_main, only : register_diags_offline_transport, offline_advection_ale
178use MOM_offline_main, only : offline_redistribute_residual, offline_diabatic_ale
179use MOM_offline_main, only : offline_fw_fluxes_into_ocean, offline_fw_fluxes_out_ocean
180use MOM_offline_main, only : offline_advection_layer, offline_transport_end
181use MOM_ice_shelf, only : ice_shelf_CS, ice_shelf_query, initialize_ice_shelf
182use MOM_particles_mod, only : particles, particles_init, particles_run, particles_save_restart, particles_end
183use MOM_particles_mod, only : particles_to_k_space, particles_to_z_space
184implicit none ; private
185
186#include <MOM_memory.h>
187
188! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
189! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
190! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
191! vary with the Boussinesq approximation, the Boussinesq variant is given first.
192
193!> A structure with diagnostic IDs of the state variables
194type MOM_diag_IDs
195 !>@{ 3-d state field diagnostic IDs
196 integer :: id_u = -1, id_v = -1, id_h = -1
197 !>@}
198 !> 2-d state field diagnostic ID
199 integer :: id_ssh_inst = -1
200end type MOM_diag_IDs
201
202!> Control structure for the MOM module, including the variables that describe
203!! the state of the ocean.
204type, public :: MOM_control_struct ; private
205 real ALLOCABLE_, dimension(NIMEM_,NJMEM_,NKMEM_) :: &
206 h, & !< layer thickness [H ~> m or kg m-2]
207 T, & !< potential temperature [C ~> degC]
208 S !< salinity [S ~> ppt]
209 real ALLOCABLE_, dimension(NIMEMB_PTR_,NJMEM_,NKMEM_) :: &
210 u, & !< zonal velocity component [L T-1 ~> m s-1]
211 uh, & !< uh = u * h * dy at u grid points [H L2 T-1 ~> m3 s-1 or kg s-1]
212 uhtr !< accumulated zonal thickness fluxes to advect tracers [H L2 ~> m3 or kg]
213 real ALLOCABLE_, dimension(NIMEM_,NJMEMB_PTR_,NKMEM_) :: &
214 v, & !< meridional velocity [L T-1 ~> m s-1]
215 vh, & !< vh = v * h * dx at v grid points [H L2 T-1 ~> m3 s-1 or kg s-1]
216 vhtr !< accumulated meridional thickness fluxes to advect tracers [H L2 ~> m3 or kg]
217 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: ssh_rint
218 !< A running time integral of the sea surface height [T Z ~> s m].
219 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: ave_ssh_ibc
220 !< time-averaged (over a forcing time step) sea surface height
221 !! with a correction for the inverse barometer [Z ~> m]
222 real ALLOCABLE_, dimension(NIMEM_,NJMEM_) :: eta_av_bc
223 !< free surface height or column mass time averaged over the last
224 !! baroclinic dynamics time step [H ~> m or kg m-2]
225 real, dimension(:,:), pointer :: Hml => NULL()
226 !< active mixed layer depth, or 0 if there is no boundary layer scheme [Z ~> m]
227 real :: time_in_cycle !< The running time of the current time-stepping cycle
228 !! in calls that step the dynamics, and also the length of
229 !! the time integral of ssh_rint [T ~> s].
230 real :: time_in_thermo_cycle !< The running time of the current time-stepping
231 !! cycle in calls that step the thermodynamics [T ~> s].
232
233 type(ocean_grid_type), allocatable :: G_in !< Input grid metric
234 type(ocean_grid_type), pointer :: G => NULL() !< Model grid metric
235 logical :: rotate_index = .false. !< True if index map is rotated
236 logical :: homogenize_forcings = .false. !< True if all inputs are homogenized
237 logical :: update_ustar = .false. !< True to update ustar from homogenized tau
238 logical :: vertex_shear = .false. !< True if vertex shear is on
239
240 type(verticalGrid_type), pointer :: &
241 GV => NULL() !< structure containing vertical grid info
242 type(unit_scale_type), pointer :: &
243 US => NULL() !< structure containing various unit conversion factors
244 type(thermo_var_ptrs), allocatable :: tv
245 !< structure containing pointers to available thermodynamic fields
246 real :: t_dyn_rel_adv !< The time of the dynamics relative to tracer advection and lateral mixing
247 !! [T ~> s], or equivalently the elapsed time since advectively updating the
248 !! tracers. t_dyn_rel_adv is invariably positive and may span multiple coupling timesteps.
249 integer :: n_dyn_steps_in_adv !< The number of dynamics time steps that contributed to uhtr
250 !! and vhtr since the last time tracer advection occured.
251 real :: t_dyn_rel_thermo !< The time of the dynamics relative to diabatic processes and remapping
252 !! [T ~> s]. t_dyn_rel_thermo can be negative or positive depending on whether
253 !! the diabatic processes are applied before or after the dynamics and may span
254 !! multiple coupling timesteps.
255 real :: t_dyn_rel_diag !< The time of the diagnostics relative to diabatic processes and remapping
256 !! [T ~> s]. t_dyn_rel_diag is always positive, since the diagnostics must lag.
257 logical :: preadv_h_stored = .false. !< If true, the thicknesses from before the advective cycle
258 !! have been stored for use in diagnostics.
259
260 type(diag_ctrl) :: diag !< structure to regulate diagnostic output timing
261 type(vertvisc_type), allocatable :: visc
262 !< structure containing vertical viscosities, bottom drag viscosities, and related fields
263 type(MEKE_type) :: MEKE !< Fields related to the Mesoscale Eddy Kinetic Energy
264 logical :: adiabatic !< If true, there are no diapycnal mass fluxes, and no calls
265 !! to routines to calculate or apply diapycnal fluxes.
266 logical :: diabatic_first !< If true, apply diabatic and thermodynamic processes before time
267 !! stepping the dynamics.
268 logical :: use_ALE_algorithm !< If true, use the ALE algorithm rather than layered
269 !! isopycnal/stacked shallow water mode. This logical is set by calling the
270 !! function useRegridding() from the MOM_regridding module.
271 logical :: remap_aux_vars !< If true, apply ALE remapping to all of the auxiliary 3-D
272 !! variables that are needed to reproduce across restarts,
273 !! similarly to what is done with the primary state variables.
274 logical :: remap_uv_using_old_alg !< If true, use the old "remapping via a delta z" method for
275 !! velocities. If false, remap between two grids described by thicknesses.
276
277 type(MOM_stoch_eos_CS) :: stoch_eos_CS !< structure containing random pattern for stoch EOS
278 logical :: alternate_first_direction !< If true, alternate whether the x- or y-direction
279 !! updates occur first in directionally split parts of the calculation.
280 real :: first_dir_restart = -1.0 !< A real copy of G%first_direction for use in restart files [nondim]
281 logical :: offline_tracer_mode = .false.
282 !< If true, step_offline() is called instead of step_MOM().
283 !! This is intended for running MOM6 in offline tracer mode
284 logical :: MEKE_in_dynamics !< If .true. (default), MEKE is called in the dynamics routine otherwise
285 !! it is called during the tracer dynamics
286
287 type(time_type), pointer :: Time !< pointer to the ocean clock
288 real :: dt !< (baroclinic) dynamics time step [T ~> s]
289 real :: dt_therm !< diabatic time step [T ~> s]
290 real :: dt_tr_adv !< tracer advection time step [T ~> s]
291 logical :: thermo_spans_coupling !< If true, thermodynamic and tracer time
292 !! steps can span multiple coupled time steps.
293 logical :: tradv_spans_coupling !< If true, thermodynamic and tracer time
294 integer :: nstep_tot = 0 !< The total number of dynamic timesteps taken
295 !! so far in this run segment
296 logical :: count_calls = .false. !< If true, count the calls to step_MOM, rather than the
297 !! number of dynamics steps in nstep_tot
298 logical :: debug !< If true, write verbose checksums for debugging purposes.
299 logical :: debug_OBCs !< If true, write verbose OBC values for debugging purposes.
300 integer :: ntrunc !< number u,v truncations since last call to write_energy
301
302 integer :: cont_stencil !< The stencil for thickness from the continuity solver.
303 integer :: dyn_h_stencil !< The stencil for thickness for the dynamics based on
304 !! the continuity solver and Coriolis schemes.
305 ! These elements are used to control the dynamics updates.
306 logical :: do_dynamics !< If false, does not call step_MOM_dyn_*. This is an
307 !! undocumented run-time flag that is fragile.
308 logical :: split !< If true, use the split time stepping scheme.
309 logical :: use_alt_split !< If true, use a version of the split explicit time stepping
310 !! scheme that exchanges velocities with step_MOM that have the
311 !! average barotropic phase over a baroclinic timestep rather
312 !! than the instantaneous barotropic phase.
313 logical :: use_RK2 !< If true, use RK2 instead of RK3 in unsplit mode
314 !! (i.e., no split between barotropic and baroclinic).
315 logical :: interface_filter !< If true, apply an interface height filter immediately
316 !! after any calls to thickness_diffuse.
317 logical :: thickness_diffuse !< If true, diffuse interface height w/ a diffusivity KHTH.
318 logical :: thickness_diffuse_first !< If true, diffuse thickness before dynamics.
319 logical :: interface_filter_dt_bug !< If true, uses the wrong time interval in
320 !! calls to interface_filter and thickness_diffuse.
321 logical :: mixedlayer_restrat !< If true, use submesoscale mixed layer restratifying scheme.
322 logical :: useMEKE !< If true, call the MEKE parameterization.
323 logical :: use_stochastic_EOS !< If true, use the stochastic EOS parameterizations.
324 logical :: useWaves !< If true, update Stokes drift
325 real :: dtbt_reset_period !< The time interval between dynamic recalculation of the
326 !! barotropic time step [T ~> s]. If this is negative dtbt is never
327 !! calculated, and if it is 0, dtbt is calculated every step.
328 type(time_type) :: dtbt_reset_interval !< A time_time representation of dtbt_reset_period.
329 type(time_type) :: dtbt_reset_time !< The next time DTBT should be calculated.
330 real :: dt_obc_seg_period !< The time interval between OBC segment updates for OBGC
331 !! tracers [T ~> s], or a negative value if the segment
332 !! data are time-invarant, or zero to update the OBGC
333 !! segment data with every call to update_OBC_segment_data.
334 type(time_type) :: dt_obc_seg_interval !< A time_time representation of dt_obc_seg_period.
335 type(time_type) :: dt_obc_seg_time !< The next time OBC segment update is applied to OBGC tracers.
336
337 real, dimension(:,:), pointer :: frac_shelf_h => NULL() !< fraction of total area occupied
338 !! by ice shelf [nondim]
339 real, dimension(:,:), pointer :: mass_shelf => NULL() !< Mass of ice shelf [R Z ~> kg m-2]
340 type(accel_diag_ptrs), allocatable :: ADp !< structure containing pointers to accelerations,
341 !! for derived diagnostics (e.g., energy budgets)
342 type(cont_diag_ptrs) :: CDp !< structure containing pointers to continuity equation
343 !! terms, for derived diagnostics (e.g., energy budgets)
344 real, dimension(:,:,:), pointer :: &
345 u_prev => NULL(), & !< previous value of u stored for diagnostics [L T-1 ~> m s-1]
346 v_prev => NULL() !< previous value of v stored for diagnostics [L T-1 ~> m s-1]
347
348 logical :: interp_p_surf !< If true, linearly interpolate surface pressure
349 !! over the coupling time step, using specified value
350 !! at the end of the coupling step. False by default.
351 logical :: p_surf_prev_set !< If true, p_surf_prev has been properly set from
352 !! a previous time-step or the ocean restart file.
353 !! This is only valid when interp_p_surf is true.
354 real, dimension(:,:), pointer :: &
355 p_surf_prev => NULL(), & !< surface pressure [R L2 T-2 ~> Pa] at end previous call to step_MOM
356 p_surf_begin => NULL(), & !< surface pressure [R L2 T-2 ~> Pa] at start of step_MOM_dyn_...
357 p_surf_end => NULL() !< surface pressure [R L2 T-2 ~> Pa] at end of step_MOM_dyn_...
358
359 ! Variables needed to reach between start and finish phases of initialization
360 logical :: write_IC !< If true, then the initial conditions will be written to file
361 character(len=120) :: IC_file !< A file into which the initial conditions are
362 !! written in a new run if SAVE_INITIAL_CONDS is true.
363
364 logical :: calc_rho_for_sea_lev !< If true, calculate rho to convert pressure to sea level
365
366 ! These elements are used to control the calculation and error checking of the surface state
367 real :: Hmix !< Diagnostic mixed layer thickness over which to
368 !! average surface tracer properties when a bulk
369 !! mixed layer is not used [H ~> m or kg m-2], or a negative value
370 !! if a bulk mixed layer is being used.
371 real :: HFrz !< If HFrz > 0, the nominal depth over which melt potential is computed
372 !! [H ~> m or kg m-2]. The actual depth over which melt potential is
373 !! computed is min(HFrz, OBLD), where OBLD is the boundary layer depth.
374 !! If HFrz <= 0 (default), melt potential will not be computed.
375 real :: Hmix_UV !< Depth scale over which to average surface flow to
376 !! feedback to the coupler/driver [H ~> m or kg m-2] when
377 !! bulk mixed layer is not used, or a negative value
378 !! if a bulk mixed layer is being used.
379 logical :: check_bad_sfc_vals !< If true, scan surface state for ridiculous values.
380 real :: bad_val_ssh_max !< Maximum SSH before triggering bad value message [Z ~> m]
381 real :: bad_val_sst_max !< Maximum SST before triggering bad value message [C ~> degC]
382 real :: bad_val_sst_min !< Minimum SST before triggering bad value message [C ~> degC]
383 real :: bad_val_sss_max !< Maximum SSS before triggering bad value message [S ~> ppt]
384 real :: bad_val_col_thick !< Minimum column thickness before triggering bad value message [Z ~> m]
385 integer :: answer_date !< The vintage of the expressions for the surface properties. Values
386 !! below 20190101 recover the answers from the end of 2018, while
387 !! higher values use more appropriate expressions that differ at
388 !! roundoff for non-Boussinesq cases.
389 logical :: use_particles !< Turns on the particles package
390 logical :: use_uh_particles !< particles are advected by uh/h
391 logical :: uh_particles_bug !< If true, uses an inconsistent timestep for particle advection
392 logical :: use_dbclient !< Turns on the database client used for ML inference/analysis
393 character(len=10) :: particle_type !< Particle types include: surface(default), profiling and sail drone.
394
395 type(MOM_diag_IDs) :: IDs !< Handles used for diagnostics.
396 type(transport_diag_IDs) :: transport_IDs !< Handles used for transport diagnostics.
397 type(surface_diag_IDs) :: sfc_IDs !< Handles used for surface diagnostics.
398 type(diag_grid_storage) :: diag_pre_sync !< The grid (thicknesses) before remapping
399 type(diag_grid_storage) :: diag_pre_dyn !< The grid (thicknesses) before dynamics
400
401 ! The remainder of this type provides pointers to child module control structures.
402
403 type(MOM_dyn_unsplit_CS), pointer :: dyn_unsplit_CSp => NULL()
404 !< Pointer to the control structure used for the unsplit dynamics
405 type(MOM_dyn_unsplit_RK2_CS), pointer :: dyn_unsplit_RK2_CSp => NULL()
406 !< Pointer to the control structure used for the unsplit RK2 dynamics
407 type(MOM_dyn_split_RK2_CS), pointer :: dyn_split_RK2_CSp => NULL()
408 !< Pointer to the control structure used for the mode-split RK2 dynamics
409 type(MOM_dyn_split_RK2b_CS), pointer :: dyn_split_RK2b_CSp => NULL()
410 !< Pointer to the control structure used for an alternate version of the mode-split RK2 dynamics
411 type(harmonic_analysis_CS), pointer :: HA_CSp => NULL()
412 !< Pointer to the control structure for harmonic analysis
413 type(thickness_diffuse_CS) :: thickness_diffuse_CSp
414 !< Pointer to the control structure used for the isopycnal height diffusive transport.
415 !! This is also common referred to as Gent-McWilliams diffusion
416 type(interface_filter_CS) :: interface_filter_CSp
417 !< Control structure used for the interface height smoothing operator.
418 type(mixedlayer_restrat_CS) :: mixedlayer_restrat_CSp
419 !< Pointer to the control structure used for the mixed layer restratification
420 type(set_visc_CS), allocatable :: set_visc_CSp
421 !< Control structure used to set viscosities
422 type(diabatic_CS), pointer :: diabatic_CSp => NULL()
423 !< Pointer to the control structure for the diabatic driver
424 type(MEKE_CS) :: MEKE_CSp
425 !< Pointer to the control structure for the MEKE updates
426 type(VarMix_CS), allocatable :: VarMix
427 !< Control structure for the variable mixing module
428 type(tracer_registry_type), pointer :: tracer_Reg => NULL()
429 !< Pointer to the MOM tracer registry
430 type(tracer_advect_CS), pointer :: tracer_adv_CSp => NULL()
431 !< Pointer to the MOM tracer advection control structure
432 type(tracer_hor_diff_CS), pointer :: tracer_diff_CSp => NULL()
433 !< Pointer to the MOM along-isopycnal tracer diffusion control structure
434 type(tracer_flow_control_CS), pointer :: tracer_flow_CSp => NULL()
435 !< Pointer to the control structure that orchestrates the calling of tracer packages
436 ! Although update_OBC_CS is not used directly outside of initialization, other modules
437 ! set pointers to this type, so it should be kept for the duration of the run.
438 type(update_OBC_CS), pointer :: update_OBC_CSp => NULL()
439 !< Pointer to the control structure for updating open boundary condition properties
440 type(ocean_OBC_type), pointer :: OBC => NULL()
441 !< Pointer to the MOM open boundary condition type
442 type(sponge_CS), pointer :: sponge_CSp => NULL()
443 !< Pointer to the layered-mode sponge control structure
444 type(ALE_sponge_CS), pointer :: ALE_sponge_CSp => NULL()
445 !< Pointer to the ALE-mode sponge control structure
446 type(oda_incupd_CS), pointer :: oda_incupd_CSp => NULL()
447 !< Pointer to the oda incremental update control structure
448 type(int_tide_CS), pointer :: int_tide_CSp => NULL()
449 !< Pointer to the internal tides control structure
450 type(ALE_CS), pointer :: ALE_CSp => NULL()
451 !< Pointer to the Arbitrary Lagrangian Eulerian (ALE) vertical coordinate control structure
452
453 ! Pointers to control structures used for diagnostics
454 type(sum_output_CS), pointer :: sum_output_CSp => NULL()
455 !< Pointer to the globally summed output control structure
456 type(diagnostics_CS) :: diagnostics_CSp
457 !< Pointer to the MOM diagnostics control structure
458 type(offline_transport_CS), pointer :: offline_CSp => NULL()
459 !< Pointer to the offline tracer transport control structure
460 type(porous_barrier_CS) :: por_bar_CS
461 !< Control structure for porous barrier
462
463 logical :: ensemble_ocean !< if true, this run is part of a
464 !! larger ensemble for the purpose of data assimilation
465 !! or statistical analysis.
466 type(ODA_CS), pointer :: odaCS => NULL() !< a pointer to the control structure for handling
467 !! ensemble model state vectors and data assimilation
468 !! increments and priors
469 type(dbcomms_CS_type) :: dbcomms_CS !< Control structure for database client used for online ML/AI
470 logical :: use_porbar !< If true, use porous barrier to constrain the widths and face areas
471 !! at the edges of the grid cells.
472 type(porous_barrier_type) :: pbv !< porous barrier fractional cell metrics
473 type(particles), pointer :: particles => NULL() !<Lagrangian particles
474 type(stochastic_CS), pointer :: stoch_CS => NULL() !< a pointer to the stochastics control structure
475 type(MOM_restart_CS), pointer :: restart_CS => NULL()
476 !< Pointer to MOM's restart control structure
477end type MOM_control_struct
478
479public initialize_MOM, finish_MOM_initialization, MOM_end
480public step_MOM, step_offline
481public extract_surface_state, get_ocean_stocks
482public get_MOM_state_elements, MOM_state_is_synchronized
483public allocate_surface_state, deallocate_surface_state
484public save_MOM_restart
485
486!>@{ CPU time clock IDs
487integer :: id_clock_ocean
488integer :: id_clock_dynamics
489integer :: id_clock_thermo
490integer :: id_clock_MOM_end
491integer :: id_clock_remap
492integer :: id_clock_tracer
493integer :: id_clock_diabatic
494integer :: id_clock_adiabatic
495integer :: id_clock_continuity ! also in dynamics s/r
496integer :: id_clock_thick_diff
497integer :: id_clock_int_filter
498integer :: id_clock_BBL_visc
499integer :: id_clock_ml_restrat
500integer :: id_clock_diagnostics
501integer :: id_clock_Z_diag
502integer :: id_clock_init
503integer :: id_clock_MOM_init
504integer :: id_clock_pass ! also in dynamics d/r
505integer :: id_clock_pass_init ! also in dynamics d/r
506integer :: id_clock_ALE
507integer :: id_clock_other
508integer :: id_clock_offline_tracer
509integer :: id_clock_save_restart
510integer :: id_clock_unit_tests
511integer :: id_clock_stoch
512integer :: id_clock_varT
513!>@}
514
515contains
516
517!> This subroutine orchestrates the time stepping of MOM. The adiabatic
518!! dynamics are stepped by calls to one of the step_MOM_dyn_...routines.
519!! The action of lateral processes on tracers occur in calls to
520!! advect_tracer and tracer_hordiff. Vertical mixing and possibly remapping
521!! occur inside of diabatic.
52212subroutine step_MOM(forces_in, fluxes_in, sfc_state, Time_start, time_int_in, CS, &
523 Waves, do_dynamics, do_thermodynamics, start_cycle, &
524 end_cycle, cycle_length, reset_therm)
525 type(mech_forcing), target, intent(inout) :: forces_in !< A structure with the driving mechanical forces
526 type(forcing), target, intent(inout) :: fluxes_in !< A structure with pointers to themodynamic,
527 !! tracer and mass exchange forcing fields
528 type(surface), target, intent(inout) :: sfc_state !< surface ocean state
529 type(time_type), intent(in) :: Time_start !< starting time of a segment, as a time type
530 real, intent(in) :: time_int_in !< time interval covered by this run segment [T ~> s].
531 type(MOM_control_struct), intent(inout), target :: CS !< control structure from initialize_MOM
532 type(Wave_parameters_CS), &
533 optional, pointer :: Waves !< An optional pointer to a wave property CS
534 logical, optional, intent(in) :: do_dynamics !< Present and false, do not do updates due
535 !! to the dynamics.
536 logical, optional, intent(in) :: do_thermodynamics !< Present and false, do not do updates due
537 !! to the thermodynamics or remapping.
538 logical, optional, intent(in) :: start_cycle !< This indicates whether this call is to be
539 !! treated as the first call to step_MOM in a
540 !! time-stepping cycle; missing is like true.
541 logical, optional, intent(in) :: end_cycle !< This indicates whether this call is to be
542 !! treated as the last call to step_MOM in a
543 !! time-stepping cycle; missing is like true.
544 real, optional, intent(in) :: cycle_length !< The amount of time in a coupled time
545 !! stepping cycle [T ~> s].
546 logical, optional, intent(in) :: reset_therm !< This indicates whether the running sums of
547 !! thermodynamic quantities should be reset.
548 !! If missing, this is like start_cycle.
549
550 ! local variables
551 type(ocean_grid_type), pointer :: G => NULL() ! pointer to a structure containing
552 ! metrics and related information
553 type(ocean_grid_type), pointer :: G_in => NULL() ! Input grid metric
554 type(verticalGrid_type), pointer :: GV => NULL() ! Pointer to the vertical grid structure
555 type(unit_scale_type), pointer :: US => NULL() ! Pointer to a structure containing
556 ! various unit conversion factors
557 integer :: ntstep ! number of time steps between diabatic forcing updates
558 integer :: ntastep ! number of time steps between tracer advection updates
559 integer :: n_max ! number of steps to take in this call
560 integer :: halo_sz, dynamics_stencil
561
562 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz, n
563 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
564
565 real :: time_interval ! time interval covered by this run segment [T ~> s].
566 real :: dt ! baroclinic time step [T ~> s]
567 real :: dtdia ! time step for diabatic processes [T ~> s]
568 real :: dt_tr_adv ! time step for tracer advection [T ~> s]
569 real :: dt_therm ! a limited and quantized version of CS%dt_therm [T ~> s]
570 real :: dt_tradv_here ! a further limited value of dt_tr_adv [T ~> s]
571
572 real :: wt_end, wt_beg ! Fractional weights of the future pressure at the end
573 ! and beginning of the current time step [nondim]
574 real :: bbl_time_int ! The amount of time over which the calculated BBL
575 ! properties will apply, for use in diagnostics, or 0
576 ! if it is not to be calculated anew [T ~> s].
577 real :: rel_time = 0.0 ! relative time since start of this call [T ~> s].
578
579 logical :: do_advection ! If true, do tracer advection.
580 logical :: do_diabatic ! If true, do diabatic update.
581 logical :: thermo_does_span_coupling ! If true,thermodynamic (diabatic) forcing spans
582 ! multiple coupling timesteps.
583 logical :: tradv_does_span_coupling ! If true, tracer advection spans
584 ! multiple coupling timesteps.
585 logical :: do_dyn ! If true, dynamics are updated with this call.
586 logical :: do_thermo ! If true, thermodynamics and remapping may be applied with this call.
587 logical :: debug_redundant ! If true, check redundant values on PE boundaries when debugging.
588 logical :: nonblocking_p_surf_update ! A flag to indicate whether surface properties
589 ! can use nonblocking halo updates
590 logical :: cycle_start ! If true, do calculations that are only done at the start of
591 ! a stepping cycle (whatever that may mean).
592 logical :: cycle_end ! If true, do calculations and diagnostics that are only done at
593 ! the end of a stepping cycle (whatever that may mean).
594 logical :: therm_reset ! If true, reset running sums of thermodynamic quantities.
595 real :: cycle_time ! The length of the coupled time-stepping cycle [T ~> s].
596 real, dimension(SZI_(CS%G),SZJ_(CS%G)) :: &
59724 U_star ! The wind friction velocity, calculated using the Boussinesq reference density or
598 ! the time-evolving surface density in non-Boussinesq mode [Z T-1 ~> m s-1]
599 real, dimension(SZI_(CS%G),SZJ_(CS%G)) :: &
60024 ssh ! sea surface height, which may be based on eta_av [Z ~> m]
601 real, dimension(SZI_(CS%G),SZJ_(CS%G),SZK_(CS%GV)) :: &
60224 dz ! Vertical distance across layers [Z ~> m]
603
604 real, dimension(:,:,:), pointer :: &
605 u => NULL(), & ! u : zonal velocity component [L T-1 ~> m s-1]
606 v => NULL(), & ! v : meridional velocity component [L T-1 ~> m s-1]
607 h => NULL() ! h : layer thickness [H ~> m or kg m-2]
608 real, dimension(:,:), pointer :: &
609 p_surf => NULL() ! A pointer to the ocean surface pressure [R L2 T-2 ~> Pa].
610 real :: I_wt_ssh ! The inverse of the time weights [T-1 ~> s-1]
611
612 type(time_type) :: Time_local, end_time_thermo
613 type(time_type) :: Time_end_diag ! End time of a diagnostic segment, as a time type
614
615 type(group_pass_type) :: pass_tau_ustar_psurf
616 logical :: showCallTree
617
618 ! External forcing fields on the model index map
619 type(mech_forcing), pointer :: forces ! Mechanical forcing
620 type(forcing), pointer :: fluxes ! Boundary fluxes
621 type(surface), pointer :: sfc_state_diag ! Surface boundary fields
622 integer :: turns ! Number of quarter turns from input to model indexing
623
62412 G => CS%G ; G_in => CS%G_in ; GV => CS%GV ; US => CS%US
62512 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
62612 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
62712 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
62812 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
62912 u => CS%u ; v => CS%v ; h => CS%h
630
63112 time_interval = time_int_in
6320 do_dyn = .true. ; if (present(do_dynamics)) do_dyn = do_dynamics
63312 do_thermo = .true. ; if (present(do_thermodynamics)) do_thermo = do_thermodynamics
63412 if (.not.(do_dyn .or. do_thermo)) call MOM_error(FATAL,"Step_MOM: "//&
6350 "Both do_dynamics and do_thermodynamics are false, which makes no sense.")
63612 cycle_start = .true. ; if (present(start_cycle)) cycle_start = start_cycle
63712 cycle_end = .true. ; if (present(end_cycle)) cycle_end = end_cycle
63812 cycle_time = time_interval ; if (present(cycle_length)) cycle_time = cycle_length
63912 therm_reset = cycle_start ; if (present(reset_therm)) therm_reset = reset_therm
640
64112 call cpu_clock_begin(id_clock_ocean)
64212 call cpu_clock_begin(id_clock_other)
643
64412 if (CS%debug) then
645 !$omp target update from(u, v, h)
6460 call query_debugging_checks(do_redundant=debug_redundant)
6470 call MOM_state_chksum("Beginning of step_MOM ", u, v, h, CS%uh, CS%vh, G, GV, US)
648 endif
649
65012 showCallTree = callTree_showQuery()
65112 if (showCallTree) call callTree_enter("step_MOM(), MOM.F90")
652
653 ! Rotate the forces from G_in to G
65412 if (CS%rotate_index) then
6550 turns = G%HI%turns
6560 allocate(forces)
6570 call allocate_mech_forcing(forces_in, G, forces)
6580 call rotate_mech_forcing(forces_in, turns, forces)
659
6600 allocate(fluxes)
6610 call allocate_forcing_type(fluxes_in, G, fluxes, turns=turns)
6620 call rotate_forcing(fluxes_in, fluxes, turns)
663 else
66412 forces => forces_in
66512 fluxes => fluxes_in
666 endif
667
668 ! Homogenize the forces
66912 if (CS%homogenize_forcings) then
670 ! Homogenize all forcing and fluxes fields.
6710 call homogenize_mech_forcing(forces, G, US, GV%Rho0, CS%update_ustar)
672 ! Note the following computes the mean ustar as the mean of ustar rather than
673 ! ustar of the mean of tau.
6740 call homogenize_forcing(fluxes, G, GV, US)
6750 if (CS%update_ustar) then
676 ! These calls corrects the ustar values
6770 call copy_common_forcing_fields(forces, fluxes, G)
6780 call set_derived_forcing_fields(forces, fluxes, G, US, GV%Rho0)
679 endif
680 endif
681 !$omp target enter data map(to: forces, forces%taux, forces%tauy, forces%ustar)
682
683 ! This will be replaced later with the pressures from forces or fluxes if they are available.
684105276 if (associated(CS%tv%p_surf)) CS%tv%p_surf(:,:) = 0.0
685
686 ! First determine the time step that is consistent with this call and an
687 ! integer fraction of time_interval.
68812 if (do_dyn) then
68912 n_max = 1
69012 if (time_interval > CS%dt) n_max = ceiling(time_interval/CS%dt - 0.001)
691
69212 dt = time_interval / real(n_max)
693 thermo_does_span_coupling = (CS%thermo_spans_coupling .and. &
69412 (CS%dt_therm > 1.5*cycle_time))
695 tradv_does_span_coupling = (CS%tradv_spans_coupling .and. &
69612 (CS%dt_tr_adv > 1.5*cycle_time))
69712 if (thermo_does_span_coupling) then
698 ! Set dt_therm to be an integer multiple of the coupling time step.
6990 dt_therm = cycle_time * floor(CS%dt_therm / cycle_time + 0.001)
7000 ntstep = floor(dt_therm/dt + 0.001)
70112 elseif (.not.do_thermo) then
7020 dt_therm = CS%dt_therm
7030 if (present(cycle_length)) dt_therm = min(CS%dt_therm, cycle_length)
7040 ntstep = 1 ! ntstep is initialized to avoid an error in a secondary logical test,
705 ! but the nonzero value of ntstep does not matter when do_thermo is false.
706 else
70712 ntstep = MAX(1, MIN(n_max, floor(CS%dt_therm/dt + 0.001)))
70812 dt_therm = dt*ntstep
709 endif
71012 if (tradv_does_span_coupling) then
711 ! Set dt_tr_adv to be an integer multiple of the coupling time step.
7120 dt_tr_adv = cycle_time * floor(CS%dt_tr_adv / cycle_time + 0.001)
7130 ntastep = floor(dt_tr_adv/dt + 0.001)
71412 elseif (.not.do_thermo) then
7150 dt_tr_adv = CS%dt_tr_adv
7160 if (present(cycle_length)) dt_tr_adv = min(CS%dt_tr_adv, cycle_length)
717 ! ntastep is not used.
718 else
71912 ntastep = MAX(1, MIN(n_max, floor(CS%dt_tr_adv/dt + 0.001)))
72012 dt_tr_adv = dt*ntastep
721 endif
722
723 !---------- Initiate group halo pass of the forcing fields
72412 call cpu_clock_begin(id_clock_pass)
725 ! Halo updates for surface pressure need to be completed before calling calc_resoln_function
726 ! among other routines if the surface pressure is used in the equation of state.
727 nonblocking_p_surf_update = G%nonblocking_updates .and. &
728 .not.(associated(CS%tv%p_surf) .and. associated(forces%p_surf) .and. &
72912 allocated(CS%tv%SpV_avg) .and. associated(CS%tv%T))
73012 if (.not.associated(forces%taux) .or. .not.associated(forces%tauy)) &
7310 call MOM_error(FATAL,'step_MOM:forces%taux,tauy not associated')
73212 call create_group_pass(pass_tau_ustar_psurf, forces%taux, forces%tauy, G%Domain)
73312 if (associated(forces%ustar)) &
73412 call create_group_pass(pass_tau_ustar_psurf, forces%ustar, G%Domain)
73512 if (associated(forces%tau_mag)) &
73612 call create_group_pass(pass_tau_ustar_psurf, forces%tau_mag, G%Domain)
73712 if (associated(forces%p_surf)) &
73812 call create_group_pass(pass_tau_ustar_psurf, forces%p_surf, G%Domain)
73912 if (nonblocking_p_surf_update) then
7400 call start_group_pass(pass_tau_ustar_psurf, G%Domain)
741 else
74212 call do_group_pass(pass_tau_ustar_psurf, G%Domain, omp_offload=.true.)
743 endif
74412 call cpu_clock_end(id_clock_pass)
745
74612 if (associated(forces%p_surf)) p_surf => forces%p_surf
74712 if (.not.associated(forces%p_surf)) CS%interp_p_surf = .false.
74812 if (associated(CS%tv%p_surf) .and. associated(forces%p_surf)) then
749105276 do j=jsd,jed ; do i=isd,ied ; CS%tv%p_surf(i,j) = forces%p_surf(i,j) ; enddo ; enddo
750
75112 if (allocated(CS%tv%SpV_avg) .and. associated(CS%tv%T)) then
752 !$omp target update from(h)
753 ! The internal ocean state depends on the surface pressues, so update SpV_avg.
7540 dynamics_stencil = min(3, G%Domain%nihalo, G%Domain%njhalo)
7550 call calc_derived_thermo(CS%tv, h, G, GV, US, halo=dynamics_stencil, debug=CS%debug)
756 endif
757 endif
758
759 else
760 ! This step only updates the thermodynamics so setting timesteps is simpler.
7610 n_max = 1
7620 if ((time_interval > CS%dt_therm) .and. (CS%dt_therm > 0.0)) &
7630 n_max = ceiling(time_interval/CS%dt_therm - 0.001)
764
7650 dt = time_interval / real(n_max)
7660 dt_therm = dt ; ntstep = 1
767
7680 if (CS%UseWaves .and. associated(fluxes%ustar)) &
7690 call pass_var(fluxes%ustar, G%Domain, clock=id_clock_pass, halo=1)
7700 if (CS%UseWaves .and. associated(fluxes%tau_mag)) &
7710 call pass_var(fluxes%tau_mag, G%Domain, clock=id_clock_pass, halo=1)
772
7730 if (associated(fluxes%p_surf)) p_surf => fluxes%p_surf
7740 if (associated(CS%tv%p_surf) .and. associated(fluxes%p_surf)) then
7750 do j=js,je ; do i=is,ie ; CS%tv%p_surf(i,j) = fluxes%p_surf(i,j) ; enddo ; enddo
7760 if (allocated(CS%tv%SpV_avg)) then
777 !$omp target update from(h)
7780 call pass_var(CS%tv%p_surf, G%Domain, clock=id_clock_pass)
779 ! The internal ocean state depends on the surface pressues, so update SpV_avg.
7800 call extract_diabatic_member(CS%diabatic_CSp, diabatic_halo=halo_sz)
7810 halo_sz = max(halo_sz, 1)
7820 call calc_derived_thermo(CS%tv, h, G, GV, US, halo=halo_sz, debug=CS%debug)
783 endif
784 endif
785 endif
786
78712 if (therm_reset) then
78812 CS%time_in_thermo_cycle = 0.0
78912 if (associated(CS%tv%frazil)) then
790105276 CS%tv%frazil(:,:) = 0.0
79112 CS%tv%frazil_was_reset = .true.
792 endif
79312 if (associated(CS%tv%salt_deficit)) CS%tv%salt_deficit(:,:) = 0.0
794105276 if (associated(CS%tv%TempxPmE)) CS%tv%TempxPmE(:,:) = 0.0
795105276 if (associated(CS%tv%internal_heat)) CS%tv%internal_heat(:,:) = 0.0
796 endif
797
79812 if (cycle_start) then
79912 CS%time_in_cycle = 0.0
80012 do concurrent (j=js:je, i=is:ie)
80187852 CS%ssh_rint(i,j) = 0.
802 enddo
803
80412 if (CS%VarMix%use_variable_mixing) then
80512 Time_end_diag = Time_start + real_to_time(cycle_time, unscale=US%T_to_s)
80612 call enable_averages(cycle_time, Time_end_diag, CS%diag)
80712 call calc_resoln_function(h, CS%tv, G, GV, US, CS%VarMix, CS%MEKE, CS%OBC, dt)
80812 call calc_depth_function(G, CS%VarMix)
80912 call disable_averaging(CS%diag)
810 endif
811 endif
812 ! advance the random pattern if stochastic physics is active
81312 if (CS%stoch_CS%do_sppt .OR. CS%stoch_CS%pert_epbl .OR. CS%stoch_CS%do_skeb) &
8140 call update_stochastics(CS%stoch_CS)
815
81612 if (do_dyn) then
81712 if (nonblocking_p_surf_update) &
8180 call complete_group_pass(pass_tau_ustar_psurf, G%Domain, clock=id_clock_pass)
819
82012 if (CS%interp_p_surf) then
8210 if (.not.associated(CS%p_surf_end)) allocate(CS%p_surf_end(isd:ied,jsd:jed))
8220 if (.not.associated(CS%p_surf_begin)) allocate(CS%p_surf_begin(isd:ied,jsd:jed))
8230 if (.not.CS%p_surf_prev_set) then
8240 do j=jsd,jed ; do i=isd,ied
8250 CS%p_surf_prev(i,j) = forces%p_surf(i,j)
826 enddo ; enddo
8270 CS%p_surf_prev_set = .true.
828 endif
829 else
83012 CS%p_surf_end => forces%p_surf
831 endif
83212 if (CS%UseWaves) then
833 ! Update wave information, which is presently kept static over each call to step_mom
834 !$omp target update from(h)
8350 Time_end_diag = Time_start + real_to_time(time_interval, unscale=US%T_to_s)
8360 call enable_averages(time_interval, Time_end_diag, CS%diag)
8370 call find_ustar(forces, CS%tv, U_star, G, GV, US, halo=1)
8380 call thickness_to_dz(h, CS%tv, dz, G, GV, US, halo_size=1)
8390 call Update_Stokes_Drift(G, GV, US, Waves, dz, U_star, time_interval, do_dyn)
8400 call disable_averaging(CS%diag)
841 endif
842 else ! not do_dyn.
8430 if (CS%UseWaves) then ! Diagnostics are not enabled in this call.
844 !$omp target update from(h)
8450 call find_ustar(fluxes, CS%tv, U_star, G, GV, US, halo=1)
8460 call thickness_to_dz(h, CS%tv, dz, G, GV, US, halo_size=1)
8470 call Update_Stokes_Drift(G, GV, US, Waves, dz, U_star, time_interval, do_dyn)
848 endif
849 endif
850
85112 if (CS%debug) then
852 !$omp target update from(u, v, h)
8530 if (cycle_start) &
8540 call MOM_state_chksum("Before steps ", u, v, h, CS%uh, CS%vh, G, GV, US)
8550 if (cycle_start .and. debug_redundant) &
8560 call check_redundant("Before steps ", u, v, G, unscale=US%L_T_to_m_s)
8570 if (do_dyn) call MOM_mech_forcing_chksum("Before steps", forces, G, US, haloshift=0)
8580 if (do_dyn .and. debug_redundant) &
859 call check_redundant("Before steps ", forces%taux, forces%tauy, G, &
8600 unscale=US%RZ_T_to_kg_m2s*US%L_T_to_m_s)
861 endif
86212 call cpu_clock_end(id_clock_other)
863
86412 rel_time = 0.0
865
866 ! TODO: This appears safe to remove but needs verification.
867 !**!$omp target update to(u, v, h, CS%uhtr, CS%vhtr)
868
86936 do n=1,n_max
87024 rel_time = rel_time + dt ! The relative time at the end of the step.
871 ! Set the universally visible time to the middle of the time step.
87224 CS%Time = Time_start + real_to_time(rel_time - 0.5*dt, unscale=US%T_to_s)
873 ! Set the local time to the end of the time step.
87424 Time_local = Time_start + real_to_time(rel_time, unscale=US%T_to_s)
875
87624 if (showCallTree) call callTree_enter("DT cycles (step_MOM) n=",n)
877
878 ! Update the vertically extensive diagnostic grids so that they are
879 ! referenced to the beginning timestep
88024 call diag_update_remap_grids(CS%diag, update_intensive = .false., update_extensive = .true. )
881
882 !===========================================================================
883 ! This is the first place where the diabatic processes and remapping could occur.
88424 if (CS%diabatic_first .and. (CS%t_dyn_rel_adv==0.0) .and. do_thermo) then ! do thermodynamics.
8850 if (.not.do_dyn) then
8860 dtdia = dt
8870 elseif (thermo_does_span_coupling) then
8880 dtdia = dt_therm
8890 if ((fluxes%dt_buoy_accum > 0.0) .and. (dtdia > time_interval) .and. &
890 (abs(fluxes%dt_buoy_accum - dtdia) > 1e-6*dtdia)) then
891 call MOM_error(FATAL, "step_MOM: Mismatch between long thermodynamic "//&
8920 "timestep and time over which buoyancy fluxes have been accumulated.")
893 endif
894 call MOM_error(FATAL, "MOM is not yet set up to have restarts that work "//&
8950 "with THERMO_SPANS_COUPLING and DIABATIC_FIRST.")
896 else
8970 dtdia = dt*min(ntstep,n_max-(n-1))
898 endif
899
9000 end_time_thermo = Time_local
9010 if (dtdia > dt) then
902 ! If necessary, temporarily reset CS%Time to the center of the period covered
903 ! by the call to step_MOM_thermo, noting that they begin at the same time.
9040 CS%Time = CS%Time + real_to_time(0.5*(dtdia-dt), unscale=US%T_to_s)
905 ! The end-time of the diagnostic interval needs to be set ahead if there
906 ! are multiple dynamic time steps worth of thermodynamics applied here.
9070 end_time_thermo = Time_local + real_to_time(dtdia-dt, unscale=US%T_to_s)
908 endif
909
910 ! Apply diabatic forcing, do mixing, and regrid.
911 call step_MOM_thermo(CS, G, GV, US, u, v, h, CS%tv, fluxes, dtdia, &
9120 end_time_thermo, .true., Waves=Waves)
913
9140 if ( CS%use_ALE_algorithm ) then
915 !$omp target update from(u, v, h)
9160 call ALE_regridding_and_remapping(CS, G, GV, US, u, v, h, CS%tv, dtdia, Time_local)
917 !$omp target update to(u, v, h)
918 endif
919
9200 call post_diabatic_halo_updates(CS, G, GV, US, u, v, h, CS%tv)
921
9220 CS%time_in_thermo_cycle = CS%time_in_thermo_cycle + dtdia
923
924 ! The diabatic processes are now ahead of the dynamics by dtdia.
9250 CS%t_dyn_rel_thermo = -dtdia
9260 if (showCallTree) call callTree_waypoint("finished diabatic_first (step_MOM)")
927
9280 if (dtdia > dt) & ! Reset CS%Time to its previous value.
9290 CS%Time = Time_start + real_to_time(rel_time - 0.5*dt, unscale=US%T_to_s)
930 endif ! end of block "(CS%diabatic_first .and. (CS%t_dyn_rel_adv==0.0))"
931
93224 if (do_dyn) then
933 ! Store pre-dynamics thicknesses for proper diagnostic remapping for transports or
934 ! advective tendencies. If there are more than one dynamics steps per advective
935 ! step (i.e DT_THERM > DT), this needs to be stored at the first dynamics call.
93624 if (.not.CS%preadv_h_stored .and. (CS%t_dyn_rel_adv == 0.)) then
937 !$omp target update from(h)
93812 call diag_copy_diag_to_storage(CS%diag_pre_dyn, h, CS%diag)
93912 CS%preadv_h_stored = .true.
940 endif
941
942 ! The pre-dynamics velocities might be stored for debugging truncations.
94324 if (associated(CS%u_prev) .and. associated(CS%v_prev)) then
944 !$omp target update from(u, v)
9450 do k=1,nz ; do j=jsd,jed ; do I=IsdB,IedB
9460 CS%u_prev(I,j,k) = u(I,j,k)
947 enddo ; enddo ; enddo
9480 do k=1,nz ; do J=JsdB,JedB ; do i=isd,ied
9490 CS%v_prev(I,j,k) = v(i,J,k)
950 enddo ; enddo ; enddo
951 endif
952
95324 if (CS%interface_filter_dt_bug) then
9540 dt_tradv_here = dt_therm
9550 if (do_thermo .and. do_dyn .and. .not.thermo_does_span_coupling) &
9560 dt_tradv_here = dt*min(ntstep, n_max-n+1)
957 else
95824 dt_tradv_here = dt_tr_adv
95924 if (do_thermo .and. do_dyn .and. .not.tradv_does_span_coupling) &
96024 dt_tradv_here = dt*min(ntstep, n_max-n+1)
961 endif
962
963 ! Indicate whether the bottom boundary layer properties need to be
964 ! recalculated, and if so for how long an interval they are valid.
96524 bbl_time_int = 0.0
96624 if (do_thermo) then
96724 if ((CS%t_dyn_rel_adv == 0.0) .or. (n==1)) &
96812 bbl_time_int = max(dt, min(dt_therm - CS%t_dyn_rel_adv, dt*(1+n_max-n)) )
969 else
9700 if ((CS%t_dyn_rel_adv == 0.0) .or. ((n==1) .and. cycle_start)) &
9710 bbl_time_int = min(dt_therm, cycle_time)
972 endif
973
97424 if (CS%interp_p_surf) then
9750 wt_end = real(n) / real(n_max)
9760 wt_beg = real(n-1) / real(n_max)
9770 do j=jsd,jed ; do i=isd,ied
978 CS%p_surf_end(i,j) = wt_end * forces%p_surf(i,j) + &
9790 (1.0-wt_end) * CS%p_surf_prev(i,j)
980 CS%p_surf_begin(i,j) = wt_beg * forces%p_surf(i,j) + &
9810 (1.0-wt_beg) * CS%p_surf_prev(i,j)
982 enddo ; enddo
983 endif
984
985 call step_MOM_dynamics(forces, CS%p_surf_begin, CS%p_surf_end, dt, &
986 dt_tradv_here, bbl_time_int, CS, &
98724 Time_local, Waves=Waves)
988
989 !===========================================================================
990 ! This is the start of the tracer advection part of the algorithm.
99124 if (tradv_does_span_coupling .or. .not.do_thermo) then
992 do_advection = ((CS%t_dyn_rel_adv + 0.5*dt > dt_tr_adv) .or. &
9930 (CS%t_dyn_rel_thermo + 0.5*dt > dt_therm))
994 else
99524 do_advection = ((MOD(n,ntastep) == 0) .or. (n==n_max))
996 endif
997
99824 if (do_advection) then ! Do advective transport and lateral tracer mixing.
99912 call step_MOM_tracer_dyn(CS, G, GV, US, h, Time_local)
100012 if (CS%diabatic_first .and. abs(CS%t_dyn_rel_thermo) > 1e-6*dt) call MOM_error(FATAL, &
1001 "step_MOM: Mismatch between the dynamics and diabatic times "//&
10020 "with DIABATIC_FIRST.")
1003 endif
1004 endif ! end of (do_dyn)
1005
1006 !===========================================================================
1007 ! This is the second place where the diabatic processes and remapping could occur.
100824 if (thermo_does_span_coupling .or. .not.do_dyn) then
10090 do_diabatic = (do_thermo .and. (CS%t_dyn_rel_thermo + 0.5*dt > dt_therm))
1010 else
101124 do_diabatic = (do_thermo .and. ((MOD(n,ntstep) == 0) .or. (n==n_max)))
1012 endif
1013
101424 if ((CS%t_dyn_rel_adv==0.0) .and. (.not.CS%diabatic_first) .and. do_diabatic) then
101512 dtdia = CS%t_dyn_rel_thermo
1016 ! If the MOM6 dynamic and thermodynamic time stepping is being orchestrated
1017 ! by the coupler, the value of diabatic_first does not matter.
101812 if ((CS%t_dyn_rel_thermo==0.0) .and. .not.do_dyn) dtdia = dt
1019
102012 if (CS%thermo_spans_coupling .and. (CS%dt_therm > 1.5*cycle_time) .and. &
1021 (abs(dt_therm - dtdia) > 1e-6*dt_therm)) then
1022 call MOM_error(FATAL, "step_MOM: Mismatch between dt_therm and dtdia "//&
10230 "before call to diabatic.")
1024 endif
1025
1026 ! If necessary, temporarily reset CS%Time to the center of the period covered
1027 ! by the call to step_MOM_thermo, noting that they end at the same time.
102812 if (dtdia > dt) &
102912 CS%Time = CS%Time - real_to_time(0.5*(dtdia-dt), unscale=US%T_to_s)
1030
1031 ! Apply diabatic forcing, do mixing, and regrid.
1032 call step_MOM_thermo(CS, G, GV, US, u, v, h, CS%tv, fluxes, dtdia, &
103312 Time_local, .false., Waves=Waves)
1034
103512 if ( CS%use_ALE_algorithm ) then
1036 !$omp target update from(u, v, h)
103712 call ALE_regridding_and_remapping(CS, G, GV, US, u, v, h, CS%tv, dtdia, Time_local)
1038 !$omp target update to(u, v, h)
1039 endif
1040
1041 ! UMW NOTE: These transfers are needed to prevent excessive transfers in the group
1042 ! updates within this subroutine
1043 !$omp target enter data map(to: CS%tv, CS%tv%T, CS%tv%S)
104412 call post_diabatic_halo_updates(CS, G, GV, US, u, v, h, CS%tv)
1045 !$omp target exit data map(from: CS%tv%T, CS%tv%S)
1046 !$omp target exit data map(release: CS%tv)
1047
104812 CS%time_in_thermo_cycle = CS%time_in_thermo_cycle + dtdia
1049
105012 if ((CS%t_dyn_rel_thermo==0.0) .and. .not.do_dyn) then
1051 ! The diabatic processes are now ahead of the dynamics by dtdia.
10520 CS%t_dyn_rel_thermo = -dtdia
1053 else ! The diabatic processes and the dynamics are synchronized.
105412 CS%t_dyn_rel_thermo = 0.0
1055 endif
1056
1057 ! Reset CS%Time to its previous value.
105812 if (dtdia > dt) &
105912 CS%Time = Time_start + real_to_time(rel_time - 0.5*dt, unscale=US%T_to_s)
1060 endif
1061
106224 if (do_dyn) then
1063 !$omp target enter data map(alloc: ssh)
106424 call cpu_clock_begin(id_clock_dynamics)
1065 ! Determining the time-average sea surface height is part of the algorithm.
1066 ! This may be eta_av if Boussinesq, or need to be diagnosed if not.
106724 CS%time_in_cycle = CS%time_in_cycle + dt
1068 !$omp target enter data map(to: CS%eta_av_bc)
106924 call find_eta(h, CS%tv, G, GV, US, ssh, eta_bt=CS%eta_av_bc, dZref=G%Z_ref)
1070 !$omp target exit data map(release: CS%eta_av_bc)
1071
107224 do concurrent (j=js:je, i=is:ie)
1073175704 CS%ssh_rint(i,j) = CS%ssh_rint(i,j) + dt * ssh(i,j)
1074 enddo
1075
107624 if (CS%IDs%id_ssh_inst > 0) then
1077 !$omp target update from(ssh)
10780 call enable_averages(dt, Time_local, CS%diag)
10790 call post_data(CS%IDs%id_ssh_inst, ssh, CS%diag)
10800 call disable_averaging(CS%diag)
1081 endif
108224 call cpu_clock_end(id_clock_dynamics)
1083
1084 !$omp target exit data map(delete: ssh)
1085 endif
1086
1087 !===========================================================================
1088 ! Calculate diagnostics at the end of the time step if the state is self-consistent.
108924 if (MOM_state_is_synchronized(CS)) then
1090 !### Perhaps this should be if (CS%t_dyn_rel_thermo == 0.0)
1091 !$omp target update from(u, v, h, CS%uhtr, CS%vhtr)
109212 call cpu_clock_begin(id_clock_other) ; call cpu_clock_begin(id_clock_diagnostics)
1093 ! Diagnostics that require the complete state to be up-to-date can be calculated.
1094
109512 call enable_averages(CS%t_dyn_rel_diag, Time_local, CS%diag)
1096 call calculate_diagnostic_fields(u, v, h, CS%uh, CS%vh, CS%tv, CS%ADp, &
1097 CS%CDp, p_surf, CS%t_dyn_rel_diag, CS%diag_pre_sync,&
109812 G, GV, US, CS%diagnostics_CSp)
109912 call post_tracer_diagnostics_at_sync(CS%Tracer_reg, h, CS%diag_pre_sync, CS%diag, G, GV, CS%t_dyn_rel_diag)
110012 call diag_copy_diag_to_storage(CS%diag_pre_sync, h, CS%diag)
110112 if (showCallTree) call callTree_waypoint("finished calculate_diagnostic_fields (step_MOM)")
110212 call disable_averaging(CS%diag)
110312 CS%t_dyn_rel_diag = 0.0
1104
110512 call cpu_clock_end(id_clock_diagnostics) ; call cpu_clock_end(id_clock_other)
1106 endif
1107
110824 if (do_dyn .and. .not.CS%count_calls) CS%nstep_tot = CS%nstep_tot + 1
110936 if (showCallTree) call callTree_leave("DT cycles (step_MOM)")
1110 enddo
1111
1112 ! TODO: This appears safe to remove but needs verification.
1113 !**!$omp target update from(u, v, h, CS%uhtr, CS%vhtr)
1114
111512 if (CS%count_calls .and. cycle_start) CS%nstep_tot = CS%nstep_tot + 1
1116
111712 call cpu_clock_begin(id_clock_other)
1118
111912 if (CS%time_in_cycle > 0.0) then
1120 !$omp target enter data map(alloc: ssh)
1121
112212 I_wt_ssh = 1.0/CS%time_in_cycle
112312 do concurrent (j=js:je, i=is:ie)
112486400 ssh(i,j) = CS%ssh_rint(i,j) * I_wt_ssh
112587852 CS%ave_ssh_ibc(i,j) = ssh(i,j)
1126 enddo
1127
112812 if (associated(CS%HA_CSp)) then
1129 !$omp target update from(ssh)
11300 call HA_accum('ssh', ssh, Time_local, G, CS%HA_CSp)
1131 endif
1132
113312 if (do_dyn) then
1134 call adjust_ssh_for_p_atm(CS%tv, G, GV, US, CS%ave_ssh_ibc, forces%p_surf_SSH, &
113512 CS%calc_rho_for_sea_lev)
11360 elseif (do_thermo) then
1137 call adjust_ssh_for_p_atm(CS%tv, G, GV, US, CS%ave_ssh_ibc, fluxes%p_surf_SSH, &
11380 CS%calc_rho_for_sea_lev)
1139 endif
1140 !$omp target exit data map(delete: ssh)
1141 endif
1142
114312 if (do_dyn .and. CS%interp_p_surf) then ; do j=jsd,jed ; do i=isd,ied
11440 CS%p_surf_prev(i,j) = forces%p_surf(i,j)
1145 enddo ; enddo ; endif
1146
114712 if (CS%ensemble_ocean) then
1148 ! store ensemble vector in odaCS
11490 call set_prior_tracer(CS%Time, G, GV, CS%h, CS%tv, CS%odaCS)
1150 ! call DA interface
11510 call oda(CS%Time,CS%odaCS)
1152 ! update the time for the next analysis step if needed
11530 call set_analysis_time(CS%Time,CS%odaCS)
1154 endif
1155
115612 if (showCallTree) call callTree_waypoint("calling extract_surface_state (step_MOM)")
1157 ! NOTE: sfc_state uses input indexing, since it is also used by drivers.
115812 call extract_surface_state(CS, sfc_state)
1159
1160 ! Do diagnostics that only occur at the end of a complete forcing step.
116112 if (cycle_end) then
116212 if (showCallTree) call callTree_waypoint("Do cycle end diagnostics (step_MOM)")
116312 if (CS%rotate_index) then
11640 allocate(sfc_state_diag)
11650 call rotate_surface_state(sfc_state, sfc_state_diag, G, turns)
1166 else
116712 sfc_state_diag => sfc_state
1168 endif
1169
117012 call cpu_clock_begin(id_clock_diagnostics)
1171
1172 !$omp target update from(ssh) &
1173 !$omp if (CS%time_in_cycle > 0. .or. CS%time_in_thermo_cycle > 0.)
1174
117512 if (CS%time_in_cycle > 0.0) then
117612 call enable_averages(CS%time_in_cycle, Time_local, CS%diag)
117712 call post_surface_dyn_diags(CS%sfc_IDs, G, CS%diag, sfc_state_diag, ssh)
1178 endif
1179
118012 if (CS%time_in_thermo_cycle > 0.0) then
1181 !$omp target update from(CS%ave_ssh_ibc)
118212 call enable_averages(CS%time_in_thermo_cycle, Time_local, CS%diag)
1183 call post_surface_thermo_diags(CS%sfc_IDs, G, GV, US, CS%diag, CS%time_in_thermo_cycle, &
118412 sfc_state_diag, CS%tv, ssh, CS%ave_ssh_ibc)
1185 endif
1186
1187 !$omp target exit data map(delete: ssh) &
1188 !$omp if (CS%time_in_cycle > 0. .or. CS%time_in_thermo_cycle > 0.)
1189
119012 call disable_averaging(CS%diag)
119112 call cpu_clock_end(id_clock_diagnostics)
119212 if (CS%rotate_index) then
11930 call deallocate_surface_state(sfc_state_diag)
1194 endif
119512 if (showCallTree) call callTree_waypoint("Done with end cycle diagnostics (step_MOM)")
1196 endif
1197
1198 ! Accumulate the surface fluxes for assessing conservation
119912 if (do_thermo .and. fluxes%fluxes_used) &
1200 call accumulate_net_input(fluxes, sfc_state, CS%tv, fluxes%dt_buoy_accum, &
120112 G, US, CS%sum_output_CSp)
1202
120312 if (MOM_state_is_synchronized(CS)) then
1204 call write_energy(CS%u, CS%v, CS%h, CS%tv, Time_local, CS%nstep_tot, &
1205 G, GV, US, CS%sum_output_CSp, CS%tracer_flow_CSp, &
120612 dt_forcing=real_to_time(time_interval, unscale=US%T_to_s) )
1207 endif
120812 call cpu_clock_end(id_clock_other)
1209
1210 ! De-rotate fluxes and copy back to the input, since they can be changed.
121112 if (CS%rotate_index) then
12120 call rotate_forcing(fluxes, fluxes_in, -turns)
12130 call rotate_mech_forcing(forces, -turns, forces_in)
12140 call deallocate_mech_forcing(forces)
12150 deallocate(forces)
12160 call deallocate_forcing_type(fluxes)
12170 deallocate(fluxes)
1218 endif
1219
122012 if (showCallTree) call callTree_leave("step_MOM()")
122112 call cpu_clock_end(id_clock_ocean)
1222
122312end subroutine step_MOM
1224
1225!> Time step the ocean dynamics, including the momentum and continuity equations
122624subroutine step_MOM_dynamics(forces, p_surf_begin, p_surf_end, dt, dt_tr_adv, &
1227 bbl_time_int, CS, Time_local, Waves)
1228 type(mech_forcing), intent(in) :: forces !< A structure with the driving mechanical forces
1229 real, dimension(:,:), pointer :: p_surf_begin !< A pointer (perhaps NULL) to the surface
1230 !! pressure at the beginning of this dynamic
1231 !! step, intent in [R L2 T-2 ~> Pa].
1232 real, dimension(:,:), pointer :: p_surf_end !< A pointer (perhaps NULL) to the surface
1233 !! pressure at the end of this dynamic step,
1234 !! intent in [R L2 T-2 ~> Pa].
1235 real, intent(in) :: dt !< time interval covered by this call [T ~> s].
1236 real, intent(in) :: dt_tr_adv !< time interval covered by any updates that may
1237 !! span multiple dynamics steps [T ~> s].
1238 real, intent(in) :: bbl_time_int !< time interval over which updates to the
1239 !! bottom boundary layer properties will apply [T ~> s],
1240 !! or zero not to update the properties.
1241 type(MOM_control_struct), intent(inout), target :: CS !< control structure from initialize_MOM
1242 type(time_type), intent(in) :: Time_local !< End time of a segment, as a time type
1243 type(wave_parameters_CS), &
1244 optional, pointer :: Waves !< Container for wave related parameters; the
1245 !! fields in Waves are intent in here.
1246
1247 ! local variables
1248 type(ocean_grid_type), pointer :: G => NULL() ! pointer to a structure containing
1249 ! metrics and related information
1250 type(verticalGrid_type), pointer :: GV => NULL() ! Pointer to the vertical grid structure
1251 type(unit_scale_type), pointer :: US => NULL() ! Pointer to a structure containing
1252 ! various unit conversion factors
1253 type(MOM_diag_IDs), pointer :: IDs => NULL() ! A structure with the diagnostic IDs.
1254 real, dimension(:,:,:), pointer :: &
1255 u => NULL(), & ! u : zonal velocity component [L T-1 ~> m s-1]
1256 v => NULL(), & ! v : meridional velocity component [L T-1 ~> m s-1]
1257 h => NULL() ! h : layer thickness [H ~> m or kg m-2]
1258
1259 type(time_type) :: Time_end_diag ! End time of a diagnostic segment, as a time type
1260 logical :: calc_dtbt ! Indicates whether the dynamically adjusted
1261 ! barotropic time step needs to be updated.
1262 logical :: showCallTree
1263
1264 integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
1265 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
1266
126724 G => CS%G ; GV => CS%GV ; US => CS%US ; IDs => CS%IDs
126824 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
126924 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
127024 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
127124 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
127224 u => CS%u ; v => CS%v ; h => CS%h
127324 showCallTree = callTree_showQuery()
1274
127524 call cpu_clock_begin(id_clock_dynamics)
1276
127724 call cpu_clock_begin(id_clock_stoch)
127824 if (CS%use_stochastic_EOS) call MOM_stoch_eos_run(G, u, v, dt, Time_local, CS%stoch_eos_CS)
127924 call cpu_clock_end(id_clock_stoch)
1280
128124 call cpu_clock_begin(id_clock_varT)
128224 if (CS%use_stochastic_EOS) then
12830 call MOM_calc_varT(G, GV, US, h, CS%tv, CS%stoch_eos_CS, dt)
12840 if (associated(CS%tv%varT)) call pass_var(CS%tv%varT, G%Domain, clock=id_clock_pass, halo=1)
1285 endif
128624 call cpu_clock_end(id_clock_varT)
1287
128824 if ((CS%t_dyn_rel_adv == 0.0) .and. CS%thickness_diffuse_first .and. &
1289 (CS%thickness_diffuse .or. CS%interface_filter)) then
1290
129112 Time_end_diag = Time_local + real_to_time(dt_tr_adv - dt, unscale=US%T_to_s)
129212 call enable_averages(dt_tr_adv, Time_end_diag, CS%diag)
129312 if (CS%thickness_diffuse) then
1294 !$omp target update from(h, CS%uhtr, CS%vhtr)
129512 call cpu_clock_begin(id_clock_thick_diff)
1296
129712 if (CS%VarMix%use_variable_mixing) &
129812 call calc_slope_functions(h, CS%tv, dt, G, GV, US, CS%VarMix, OBC=CS%OBC)
1299
1300 call thickness_diffuse(h, CS%uhtr, CS%vhtr, CS%tv, dt_tr_adv, G, GV, US, &
1301 CS%MEKE, CS%VarMix, CS%CDp, CS%thickness_diffuse_CSp, &
130212 CS%stoch_CS)
1303
130412 call cpu_clock_end(id_clock_thick_diff)
130512 call pass_var(h, G%Domain, clock=id_clock_pass, halo=CS%dyn_h_stencil)
1306 !$omp target update to(h, CS%uhtr, CS%vhtr)
130712 if (showCallTree) call callTree_waypoint("finished thickness_diffuse_first (step_MOM)")
1308 endif
1309
131012 if (CS%interface_filter) then
1311 !$omp target update from(h, CS%uhtr, CS%vhtr)
13120 if (allocated(CS%tv%SpV_avg)) call pass_var(CS%tv%SpV_avg, G%Domain, clock=id_clock_pass)
13130 CS%tv%valid_SpV_halo = min(G%Domain%nihalo, G%Domain%njhalo)
13140 call cpu_clock_begin(id_clock_int_filter)
1315 call interface_filter(h, CS%uhtr, CS%vhtr, CS%tv, dt_tr_adv, G, GV, US, &
13160 CS%CDp, CS%interface_filter_CSp)
13170 call cpu_clock_end(id_clock_int_filter)
13180 call pass_var(h, G%Domain, clock=id_clock_pass, halo=CS%dyn_h_stencil)
1319 !$omp target update to(h, CS%uhtr, CS%vhtr)
13200 if (showCallTree) call callTree_waypoint("finished interface_filter_first (step_MOM)")
1321 endif
1322
132312 call disable_averaging(CS%diag)
1324 ! Whenever thickness changes let the diag manager know, target grids
1325 ! for vertical remapping may need to be regenerated.
132612 call diag_update_remap_grids(CS%diag)
1327 endif
1328
1329 ! Update porous barrier fractional cell metrics
133024 if (CS%use_porbar) then
1331 !$omp target update from(h)
13320 call enable_averages(dt, Time_local, CS%diag)
13330 call porous_widths_layer(h, CS%tv, G, GV, US, CS%pbv, CS%por_bar_CS)
13340 call disable_averaging(CS%diag)
1335 call pass_vector(CS%pbv%por_face_areaU, CS%pbv%por_face_areaV, &
13360 G%Domain, direction=To_All+SCALAR_PAIR, clock=id_clock_pass, halo=CS%cont_stencil)
1337 !$omp target update to(CS%pbv%por_face_areaU, CS%pbv%por_face_areaV)
1338 endif
1339
1340 ! The bottom boundary layer properties need to be recalculated.
134124 if (bbl_time_int > 0.0) then
134212 Time_end_diag = Time_local + real_to_time(bbl_time_int - dt, unscale=US%T_to_s)
134312 call enable_averages(bbl_time_int, Time_end_diag, CS%diag)
1344 ! Calculate the BBL properties and store them inside visc (u,h).
134512 call cpu_clock_begin(id_clock_BBL_visc)
134612 call set_viscous_BBL(CS%u, CS%v, CS%h, CS%tv, CS%visc, G, GV, US, CS%set_visc_CSp, CS%pbv)
134712 call cpu_clock_end(id_clock_BBL_visc)
134812 if (showCallTree) call callTree_wayPoint("done with set_viscous_BBL (step_MOM)")
134912 call disable_averaging(CS%diag)
1350 endif
1351
1352 !OBC segment data update for some fields can be less frequent than others
135324 if (associated(CS%OBC)) then
13540 CS%OBC%update_OBC_seg_data = .false.
13550 if (CS%dt_obc_seg_period == 0.0) CS%OBC%update_OBC_seg_data = .true.
13560 if (CS%dt_obc_seg_period > 0.0) then
13570 if (Time_local >= CS%dt_obc_seg_time) then
13580 CS%OBC%update_OBC_seg_data = .true.
13590 CS%dt_obc_seg_time = CS%dt_obc_seg_time + CS%dt_obc_seg_interval
1360 endif
1361 endif
1362 endif
1363 ! if (CS%debug_OBCs .and. associated(CS%OBC)) call chksum_OBC_segments(CS%OBC, G, GV, US, 3)
1364
136524 if (CS%do_dynamics .and. CS%split) then !--------------------------- start SPLIT
1366 ! This section uses a split time stepping scheme for the dynamic equations,
1367 ! basically the stacked shallow water equations with viscosity.
1368
136924 calc_dtbt = .false.
137024 if (CS%dtbt_reset_period == 0.0) calc_dtbt = .true.
137124 if (CS%dtbt_reset_period > 0.0) then
137224 if (Time_local >= CS%dtbt_reset_time) then !### Change >= to > here.
137313 calc_dtbt = .true.
137413 CS%dtbt_reset_time = CS%dtbt_reset_time + CS%dtbt_reset_interval
1375 endif
1376 endif
1377
137824 if (CS%use_alt_split) then
1379 !$omp target update from(u, v, h, CS%uhtr, CS%vhtr)
1380 !$omp target update from(CS%visc%bbl_thick_u, CS%visc%bbl_thick_v)
1381 !$omp target update from(CS%visc%kv_bbl_u, CS%visc%kv_bbl_v)
1382 call step_MOM_dyn_split_RK2b(u, v, h, CS%tv, CS%visc, Time_local, dt, forces, &
1383 p_surf_begin, p_surf_end, CS%uh, CS%vh, CS%uhtr, CS%vhtr, &
1384 CS%eta_av_bc, G, GV, US, CS%dyn_split_RK2b_CSp, calc_dtbt, CS%VarMix, &
13850 CS%MEKE, CS%thickness_diffuse_CSp, CS%pbv, waves=waves)
1386 !$omp target update to(u, v, h, CS%uhtr, CS%vhtr)
1387 else
1388 call step_MOM_dyn_split_RK2(u, v, h, CS%tv, CS%visc, Time_local, dt, forces, &
1389 p_surf_begin, p_surf_end, CS%uh, CS%vh, CS%uhtr, CS%vhtr, &
1390 CS%eta_av_bc, G, GV, US, CS%dyn_split_RK2_CSp, calc_dtbt, CS%VarMix, &
139124 CS%MEKE, CS%thickness_diffuse_CSp, CS%pbv, CS%stoch_CS, waves=waves)
1392 ! TODO: uh, vh, CS%eta_av_bc ?
1393 endif
1394
139524 if (showCallTree) call callTree_waypoint("finished step_MOM_dyn_split (step_MOM)")
1396
13970 elseif (CS%do_dynamics) then ! ------------------------------------ not SPLIT
1398 ! This section uses an unsplit stepping scheme for the dynamic
1399 ! equations; basically the stacked shallow water equations with viscosity.
1400 ! Because the time step is limited by CFL restrictions on the external
1401 ! gravity waves, the unsplit is usually much less efficient that the split
1402 ! approaches. But because of its simplicity, the unsplit method is very
1403 ! useful for debugging purposes.
1404
14050 if (CS%use_RK2) then
1406 !$omp target update from(u, v, h, CS%uhtr, CS%vhtr)
1407 !$omp target update from(CS%visc%bbl_thick_u, CS%visc%bbl_thick_v)
1408 !$omp target update from(CS%visc%kv_bbl_u, CS%visc%kv_bbl_v)
1409 call step_MOM_dyn_unsplit_RK2(u, v, h, CS%tv, CS%visc, Time_local, dt, forces, &
1410 p_surf_begin, p_surf_end, CS%uh, CS%vh, CS%uhtr, CS%vhtr, &
1411 CS%eta_av_bc, G, GV, US, CS%dyn_unsplit_RK2_CSp, CS%VarMix, CS%MEKE, CS%pbv, &
14120 CS%stoch_CS)
1413 !$omp target update to(u, v, h, CS%uhtr, CS%vhtr)
1414 else
1415 !$omp target update from(u, v, h, CS%uhtr, CS%vhtr)
1416 !$omp target update from(CS%visc%bbl_thick_u, CS%visc%bbl_thick_v)
1417 !$omp target update from(CS%visc%kv_bbl_u, CS%visc%kv_bbl_v)
1418 call step_MOM_dyn_unsplit(u, v, h, CS%tv, CS%visc, Time_local, dt, forces, &
1419 p_surf_begin, p_surf_end, CS%uh, CS%vh, CS%uhtr, CS%vhtr, &
1420 CS%eta_av_bc, G, GV, US, CS%dyn_unsplit_CSp, CS%VarMix, CS%MEKE, CS%pbv, &
14210 CS%stoch_CS, Waves=Waves)
1422 !$omp target update to(u, v, h, CS%uhtr, CS%vhtr)
1423 endif
1424
14250 if (showCallTree) call callTree_waypoint("finished step_MOM_dyn_unsplit (step_MOM)")
1426 endif
1427
142824 if (CS%use_particles .and. CS%do_dynamics .and. (.not. CS%use_uh_particles)) then
14290 if (CS%thickness_diffuse_first) call MOM_error(WARNING,"particles_run: "//&
1430 "Thickness_diffuse_first is true and use_uh_particles is false. "//&
14310 "This is usually a bad combination.")
1432 ! Run particles using unweighted velocity
1433 !$omp target update from(u, v, h)
1434 call particles_run(CS%particles, Time_local, CS%u, CS%v, CS%h, &
14350 CS%tv, dt, CS%use_uh_particles)
14360 call particles_to_z_space(CS%particles, h)
1437 endif
1438
1439 ! Update the model's current to reflect wind-wave growth
144024 if (Waves%Stokes_DDT .and. (.not.Waves%Passive_Stokes_DDT)) then
1441 !$omp target update from(u, v)
14420 do J=jsq,jeq ; do i=is,ie
14430 v(i,J,:) = v(i,J,:) + Waves%ddt_us_y(i,J,:)*dt
1444 enddo ; enddo
14450 do j=js,je ; do I=isq,ieq
14460 u(I,j,:) = u(I,j,:) + Waves%ddt_us_x(I,j,:)*dt
1447 enddo ; enddo
14480 call pass_vector(u, v, G%Domain)
1449 !$omp target update to(u, v)
1450 endif
1451 ! Added an additional output to track Stokes drift time tendency.
1452 ! It is mostly for debugging, and perhaps doesn't need to hang
1453 ! around permanently.
145424 if (Waves%Stokes_DDT .and. (Waves%id_3dstokes_y_from_ddt>0)) then
14550 do J=jsq,jeq ; do i=is,ie
14560 Waves%us_y_from_ddt(i,J,:) = Waves%us_y_from_ddt(i,J,:) + Waves%ddt_us_y(i,J,:)*dt
1457 enddo ; enddo
1458 endif
145924 if (Waves%Stokes_DDT .and. (Waves%id_3dstokes_x_from_ddt>0)) then
14600 do j=js,je ; do I=isq,ieq
14610 Waves%us_x_from_ddt(I,j,:) = Waves%us_x_from_ddt(I,j,:) + Waves%ddt_us_x(I,j,:)*dt
1462 enddo ; enddo
1463 endif
1464
146524 if ((CS%thickness_diffuse .or. CS%interface_filter) .and. &
1466 .not.CS%thickness_diffuse_first) then
1467
14680 if (CS%debug) call hchksum(h,"Pre-thickness_diffuse h", G%HI, haloshift=0, unscale=GV%H_to_MKS)
1469
14700 if (CS%thickness_diffuse) then
1471 !$omp target update from(h, CS%uhtr, CS%vhtr)
14720 call cpu_clock_begin(id_clock_thick_diff)
1473
14740 if (CS%VarMix%use_variable_mixing) &
14750 call calc_slope_functions(h, CS%tv, dt, G, GV, US, CS%VarMix, OBC=CS%OBC)
1476
1477 call thickness_diffuse(h, CS%uhtr, CS%vhtr, CS%tv, dt, G, GV, US, &
14780 CS%MEKE, CS%VarMix, CS%CDp, CS%thickness_diffuse_CSp, CS%stoch_CS)
1479
14800 call cpu_clock_end(id_clock_thick_diff)
14810 call pass_var(h, G%Domain, clock=id_clock_pass, halo=CS%dyn_h_stencil)
14820 if (CS%debug) call hchksum(h,"Post-thickness_diffuse h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
1483 !$omp target update to(h, CS%uhtr, CS%vhtr)
14840 if (showCallTree) call callTree_waypoint("finished thickness_diffuse (step_MOM)")
1485 endif
1486
14870 if (CS%interface_filter) then
1488 !$omp target update from(h, CS%uhtr, CS%vhtr)
14890 if (allocated(CS%tv%SpV_avg)) call pass_var(CS%tv%SpV_avg, G%Domain, clock=id_clock_pass)
14900 CS%tv%valid_SpV_halo = min(G%Domain%nihalo, G%Domain%njhalo)
14910 call cpu_clock_begin(id_clock_int_filter)
14920 if (CS%interface_filter_dt_bug) then
1493 call interface_filter(h, CS%uhtr, CS%vhtr, CS%tv, dt_tr_adv, G, GV, US, &
14940 CS%CDp, CS%interface_filter_CSp)
1495 else
1496 call interface_filter(h, CS%uhtr, CS%vhtr, CS%tv, dt, G, GV, US, &
14970 CS%CDp, CS%interface_filter_CSp)
1498 endif
14990 call cpu_clock_end(id_clock_int_filter)
15000 call pass_var(h, G%Domain, clock=id_clock_pass, halo=CS%dyn_h_stencil)
1501 !$omp target update to(h, CS%uhtr, CS%vhtr)
15020 if (showCallTree) call callTree_waypoint("finished interface_filter (step_MOM)")
1503 endif
1504 endif
1505
1506 ! apply the submesoscale mixed layer restratification parameterization
150724 if (CS%mixedlayer_restrat) then
1508 !$omp target update from(h, CS%uhtr, CS%vhtr)
150924 if (CS%debug) then
15100 call hchksum(h,"Pre-mixedlayer_restrat h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
1511 call uvchksum("Pre-mixedlayer_restrat uhtr", &
15120 CS%uhtr, CS%vhtr, G%HI, haloshift=0, unscale=GV%H_to_MKS*US%L_to_m**2)
1513 endif
151424 call cpu_clock_begin(id_clock_ml_restrat)
1515 call mixedlayer_restrat(h, CS%uhtr, CS%vhtr, CS%tv, forces, dt, CS%visc%MLD, CS%visc%h_ML, &
151624 CS%visc%sfc_buoy_flx, CS%VarMix, G, GV, US, CS%mixedlayer_restrat_CSp)
151724 call cpu_clock_end(id_clock_ml_restrat)
151824 call pass_var(h, G%Domain, clock=id_clock_pass, halo=CS%dyn_h_stencil)
1519 !$omp target update to(h, CS%uhtr, CS%vhtr)
152024 if (CS%debug) then
15210 call hchksum(h,"Post-mixedlayer_restrat h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
1522 call uvchksum("Post-mixedlayer_restrat [uv]htr", &
15230 CS%uhtr, CS%vhtr, G%HI, haloshift=0, unscale=GV%H_to_MKS*US%L_to_m**2)
1524 endif
1525 endif
1526
1527 ! Whenever thickness changes let the diag manager know, target grids
1528 ! for vertical remapping may need to be regenerated.
152924 call diag_update_remap_grids(CS%diag)
1530
153124 if (CS%useMEKE .and. CS%MEKE_in_dynamics) then
1532 !$omp target update from(u, v, h)
1533 !$omp target update from(CS%visc%bbl_thick_u, CS%visc%bbl_thick_v)
1534 !$omp target update from(CS%visc%kv_bbl_u, CS%visc%kv_bbl_v)
1535 call step_forward_MEKE(CS%MEKE, h, CS%VarMix%SN_u, CS%VarMix%SN_v, &
1536 CS%visc, dt, G, GV, US, CS%MEKE_CSp, CS%uhtr, CS%vhtr, &
153724 CS%u, CS%v, CS%tv, Time_local)
1538 !$omp target update to(u, v)
1539 endif
154024 call disable_averaging(CS%diag)
1541
1542 ! Advance the dynamics time by dt.
154324 CS%t_dyn_rel_adv = CS%t_dyn_rel_adv + dt
1544
154524 if (CS%use_particles .and. CS%do_dynamics .and. CS%use_uh_particles .and. &
1546 CS%uh_particles_bug) then
1547 !$omp target update to(h, CS%uhtr, CS%vhtr)
1548 ! Run particles using thickness-weighted velocity
1549 call particles_run(CS%particles, Time_local, CS%uhtr, CS%vhtr, CS%h, &
15500 CS%tv, CS%t_dyn_rel_adv, CS%use_uh_particles)
1551 endif
1552
155324 CS%n_dyn_steps_in_adv = CS%n_dyn_steps_in_adv + 1
155424 if (CS%alternate_first_direction) then
15550 call set_first_direction(G, MODULO(G%first_direction+1,2))
15560 CS%first_dir_restart = real(G%first_direction)
155724 elseif (CS%use_particles .and. CS%do_dynamics .and. (.not.CS%use_uh_particles)) then
15580 call particles_to_k_space(CS%particles, h)
1559 endif
156024 CS%t_dyn_rel_thermo = CS%t_dyn_rel_thermo + dt
156124 if (abs(CS%t_dyn_rel_thermo) < 1e-6*dt) CS%t_dyn_rel_thermo = 0.0
156224 CS%t_dyn_rel_diag = CS%t_dyn_rel_diag + dt
1563
156424 call cpu_clock_end(id_clock_dynamics)
1565
1566 ! Diagnostic finalization
1567
156824 call cpu_clock_begin(id_clock_other)
156924 call cpu_clock_begin(id_clock_diagnostics)
1570
157124 call enable_averages(dt, Time_local, CS%diag)
1572
1573 ! These diagnostics are available after every time dynamics step.
157424 if (IDs%id_u > 0) then
1575 !$omp target update from(u)
15760 call post_data(IDs%id_u, u, CS%diag)
1577 endif
157824 if (IDs%id_v > 0) then
1579 !$omp target update from(v)
15800 call post_data(IDs%id_v, v, CS%diag)
1581 endif
158224 if (IDs%id_h > 0) then
1583 !$omp target update from(h)
15840 call post_data(IDs%id_h, h, CS%diag)
1585 endif
1586
158724 if (CS%use_stochastic_EOS) call post_stoch_EOS_diags(CS%stoch_eos_CS, CS%tv, CS%diag)
1588
158924 call disable_averaging(CS%diag)
1590
159124 call cpu_clock_end(id_clock_diagnostics)
159224 call cpu_clock_end(id_clock_other)
159324end subroutine step_MOM_dynamics
1594
1595!> step_MOM_tracer_dyn does tracer advection and lateral diffusion, bringing the
1596!! tracers up to date with the changes in state due to the dynamics. Surface
1597!! sources and sinks and remapping are handled via step_MOM_thermo.
159812subroutine step_MOM_tracer_dyn(CS, G, GV, US, h, Time_local)
1599 type(MOM_control_struct), intent(inout) :: CS !< control structure
1600 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1601 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
1602 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1603 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1604 intent(in) :: h !< layer thicknesses after the transports [H ~> m or kg m-2]
1605 type(time_type), intent(in) :: Time_local !< The model time at the end
1606 !! of the time step.
1607 type(group_pass_type) :: pass_T_S
1608 integer :: halo_sz ! The size of a halo where data must be valid.
1609 logical :: x_first ! If true, advect tracers first in the x-direction, then y.
1610 logical :: showCallTree
1611 integer :: i, j, k
1612
161312 showCallTree = callTree_showQuery()
1614
161512 if (CS%debug) then
1616 !$omp target update from(h, CS%uhtr, CS%vhtr)
16170 call cpu_clock_begin(id_clock_other)
16180 call hchksum(h,"Pre-advection h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
1619 call uvchksum("Pre-advection uhtr", CS%uhtr, CS%vhtr, G%HI, &
16200 haloshift=0, unscale=GV%H_to_MKS*US%L_to_m**2)
16210 if (associated(CS%tv%T)) call hchksum(CS%tv%T, "Pre-advection T", G%HI, haloshift=1, unscale=US%C_to_degC)
16220 if (associated(CS%tv%S)) call hchksum(CS%tv%S, "Pre-advection S", G%HI, haloshift=1, unscale=US%S_to_ppt)
16230 if (associated(CS%tv%frazil)) call hchksum(CS%tv%frazil, "Pre-advection frazil", G%HI, haloshift=0, &
16240 unscale=US%Q_to_J_kg*US%RZ_to_kg_m2)
16250 if (associated(CS%tv%salt_deficit)) call hchksum(CS%tv%salt_deficit, &
16260 "Pre-advection salt deficit", G%HI, haloshift=0, unscale=US%S_to_ppt*US%RZ_to_kg_m2)
1627 ! call MOM_thermo_chksum("Pre-advection ", CS%tv, G, US)
16280 call cpu_clock_end(id_clock_other)
1629 endif
1630
163112 call cpu_clock_begin(id_clock_thermo) ; call cpu_clock_begin(id_clock_tracer)
163212 call enable_averages(CS%t_dyn_rel_adv, Time_local, CS%diag)
1633
163412 if (CS%use_particles .and. CS%use_uh_particles .and. (.not. CS%uh_particles_bug)) then
1635 !$omp target update from(CS%uhtr, CS%vhtr, CS%h)
1636 ! Run particles using thickness-weighted velocity
1637 call particles_run(CS%particles, Time_local, CS%uhtr, CS%vhtr, CS%h, &
16380 CS%tv, CS%t_dyn_rel_adv, CS%use_uh_particles)
1639 endif
1640
164112 if (CS%alternate_first_direction) then
1642 ! This calculation of the value of G%first_direction from the start of the accumulation of
1643 ! mass transports for use by the tracers is the equivalent to adding 2*n_dyn_steps before
1644 ! subtracting n_dyn_steps so that the mod will be taken of a non-negative number.
16450 x_first = (MODULO(G%first_direction+CS%n_dyn_steps_in_adv,2) == 0)
1646 else
164712 x_first = (MODULO(G%first_direction,2) == 0)
1648 endif
164912 if (CS%debug) call MOM_tracer_chksum("Pre-advect ", CS%tracer_Reg, G)
1650 call advect_tracer(h, CS%uhtr, CS%vhtr, CS%OBC, CS%t_dyn_rel_adv, G, GV, US, &
165112 CS%tracer_adv_CSp, CS%tracer_Reg, x_first_in=x_first)
165212 if (CS%debug) call MOM_tracer_chksum("Post-advect ", CS%tracer_Reg, G)
1653 call tracer_hordiff(h, CS%t_dyn_rel_adv, CS%MEKE, CS%VarMix, CS%visc, G, GV, US, &
165412 CS%tracer_diff_CSp, CS%tracer_Reg, CS%tv)
165512 if (CS%debug) call MOM_tracer_chksum("Post-diffuse ", CS%tracer_Reg, G)
165612 if (showCallTree) call callTree_waypoint("finished tracer advection/diffusion (step_MOM)")
165712 if (associated(CS%OBC)) then
1658 !$omp target update from(CS%uhtr, CS%vhtr)
16590 call pass_vector(CS%uhtr, CS%vhtr, G%Domain)
1660 call update_segment_tracer_reservoirs(G, GV, CS%uhtr, CS%vhtr, h, CS%OBC, &
16610 CS%tracer_Reg)
1662 !$omp target update to(CS%uhtr, CS%vhtr)
1663 endif
166412 call cpu_clock_end(id_clock_tracer) ; call cpu_clock_end(id_clock_thermo)
1665
166612 call cpu_clock_begin(id_clock_other) ; call cpu_clock_begin(id_clock_diagnostics)
1667 call post_transport_diagnostics(G, GV, US, CS%uhtr, CS%vhtr, h, CS%transport_IDs, &
166812 CS%diag_pre_dyn, CS%diag, CS%t_dyn_rel_adv, CS%tracer_reg)
1669 ! Rebuild the remap grids now that we've posted the fields which rely on thicknesses
1670 ! from before the dynamics calls
167112 call diag_update_remap_grids(CS%diag)
1672
167312 call disable_averaging(CS%diag)
167412 call cpu_clock_end(id_clock_diagnostics) ; call cpu_clock_end(id_clock_other)
1675
1676 ! Reset the accumulated transports to 0 and record that the dynamics
1677 ! and advective times now agree.
167812 call cpu_clock_begin(id_clock_thermo) ; call cpu_clock_begin(id_clock_tracer)
1679
16801560 do concurrent (k=1:GV%ke, j=G%jsd:G%jed, I=G%IsdB:G%IedB)
16818001624 CS%uhtr(I,j,k) = 0.
1682 enddo
16831548 do concurrent (k=1:GV%ke, J=G%JsdB:G%JedB, i=G%isd:G%ied)
16848056332 CS%vhtr(i,J,k) = 0.
1685 enddo
1686
168712 CS%n_dyn_steps_in_adv = 0
168812 CS%t_dyn_rel_adv = 0.0
168912 call cpu_clock_end(id_clock_tracer) ; call cpu_clock_end(id_clock_thermo)
1690
169112 if (CS%useMEKE .and. (.not. CS%MEKE_in_dynamics)) then
1692 !$omp target update from(CS%u, CS%v)
1693 !$omp target update from(CS%visc%bbl_thick_u, CS%visc%bbl_thick_v)
1694 !$omp target update from(CS%visc%kv_bbl_u, CS%visc%kv_bbl_v)
1695 call step_forward_MEKE(CS%MEKE, h, CS%VarMix%SN_u, CS%VarMix%SN_v, &
1696 CS%visc, CS%t_dyn_rel_adv, G, GV, US, CS%MEKE_CSp, CS%uhtr, CS%vhtr, &
16970 CS%u, CS%v, CS%tv, Time_local)
1698 !$omp target update to(CS%u, CS%v)
1699 endif
1700
170112 if (associated(CS%tv%T)) then
170212 call extract_diabatic_member(CS%diabatic_CSp, diabatic_halo=halo_sz)
1703 ! The bottom boundary layer calculation may need halo values of SpV_avg, including the corners.
170412 if (allocated(CS%tv%SpV_avg)) halo_sz = max(halo_sz, 1)
170512 if (halo_sz > 0) then
170612 call create_group_pass(pass_T_S, CS%tv%T, G%Domain, To_All, halo=halo_sz)
170712 call create_group_pass(pass_T_S, CS%tv%S, G%Domain, To_All, halo=halo_sz)
170812 call do_group_pass(pass_T_S, G%Domain, clock=id_clock_pass)
17090 elseif (CS%diabatic_first) then
1710 ! Temperature and salinity need halo updates because they will be used
1711 ! in the dynamics before they are changed again.
17120 call create_group_pass(pass_T_S, CS%tv%T, G%Domain, To_All+Omit_Corners, halo=1)
17130 call create_group_pass(pass_T_S, CS%tv%S, G%Domain, To_All+Omit_Corners, halo=1)
17140 call do_group_pass(pass_T_S, G%Domain, clock=id_clock_pass)
17150 halo_sz = 1
1716 endif
1717
1718 ! Update derived thermodynamic quantities.
171912 if (allocated(CS%tv%SpV_avg)) then
1720 !$omp target update from(h)
17210 call calc_derived_thermo(CS%tv, h, G, GV, US, halo=halo_sz, debug=CS%debug)
1722 endif
1723 endif
1724
172512 CS%preadv_h_stored = .false.
1726
172712end subroutine step_MOM_tracer_dyn
1728
1729!> MOM_step_thermo orchestrates the thermodynamic time stepping and vertical
1730!! remapping, via calls to diabatic (or adiabatic).
173112subroutine step_MOM_thermo(CS, G, GV, US, u, v, h, tv, fluxes, dtdia, &
1732 Time_end_thermo, update_BBL, Waves)
1733 type(MOM_control_struct), intent(inout) :: CS !< Master MOM control structure
1734 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1735 type(verticalGrid_type), intent(inout) :: GV !< ocean vertical grid structure
1736 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1737 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
1738 intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
1739 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
1740 intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
1741 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1742 intent(inout) :: h !< layer thickness [H ~> m or kg m-2]
1743 type(thermo_var_ptrs), intent(inout) :: tv !< A structure pointing to various thermodynamic variables
1744 type(forcing), intent(inout) :: fluxes !< pointers to forcing fields
1745 real, intent(in) :: dtdia !< The time interval over which to advance [T ~> s]
1746 type(time_type), intent(in) :: Time_end_thermo !< End of averaging interval for thermo diags
1747 logical, intent(in) :: update_BBL !< If true, calculate the bottom boundary layer properties.
1748 type(wave_parameters_CS), &
1749 optional, pointer :: Waves !< Container for wave related parameters
1750 !! the fields in Waves are intent in here.
1751
1752 logical :: debug_redundant ! If true, check redundant values on PE boundaries when debugging.
1753 logical :: showCallTree
1754 type(group_pass_type) :: pass_T_S
1755 integer :: dynamics_stencil ! The computational stencil for the calculations
1756 ! in the dynamic core.
1757 integer :: halo_sz ! The size of a halo where data must be valid.
1758
175912 showCallTree = callTree_showQuery()
17600 if (showCallTree) call callTree_enter("step_MOM_thermo(), MOM.F90")
176112 if (CS%debug) call query_debugging_checks(do_redundant=debug_redundant)
1762
176312 call enable_averages(dtdia, Time_end_thermo, CS%diag)
1764
176512 if (associated(CS%odaCS)) then
17660 if (CS%debug) then
17670 call MOM_thermo_chksum("Pre-oda ", tv, G, US, haloshift=0)
1768 endif
17690 call apply_oda_tracer_increments(dtdia, Time_end_thermo, G, GV, tv, h, CS%odaCS)
17700 if (CS%debug) then
17710 call MOM_thermo_chksum("Post-oda ", tv, G, US, haloshift=0)
1772 endif
1773 endif
1774
177512 if (associated(fluxes%p_surf) .or. associated(fluxes%p_surf_full)) then
177612 call extract_diabatic_member(CS%diabatic_CSp, diabatic_halo=halo_sz)
177712 if (halo_sz > 0) then
177812 if (associated(fluxes%p_surf_full)) &
1779 call pass_var(fluxes%p_surf_full, G%Domain, &
17800 clock=id_clock_pass, halo=halo_sz, complete=.not.associated(fluxes%p_surf))
178112 call pass_var(fluxes%p_surf, G%Domain, clock=id_clock_pass, halo=halo_sz, complete=.true.)
1782 endif
1783 endif
1784
178512 if (update_BBL) then
1786 ! Calculate the BBL properties and store them inside visc (u,h).
1787 ! This is here so that CS%visc is updated before diabatic() when
1788 ! DIABATIC_FIRST=True. Otherwise diabatic() is called after the dynamics
1789 ! and set_viscous_BBL is called as a part of the dynamic stepping.
17900 call cpu_clock_begin(id_clock_BBL_visc)
1791 !update porous barrier fractional cell metrics
17920 if (CS%use_porbar) then
1793 !$omp target update from(h)
17940 call porous_widths_interface(h, CS%tv, G, GV, US, CS%pbv, CS%por_bar_CS)
1795 call pass_vector(CS%pbv%por_layer_widthU, CS%pbv%por_layer_widthV, &
17960 G%Domain, direction=To_ALL+SCALAR_PAIR, clock=id_clock_pass, halo=CS%cont_stencil)
1797 !$omp target update to(CS%pbv%por_layer_widthU, CS%pbv%por_layer_widthV)
1798 !$omp target update to(CS%pbv%por_face_areaU, CS%pbv%por_face_areaV)
1799 endif
18000 call set_viscous_BBL(u, v, h, tv, CS%visc, G, GV, US, CS%set_visc_CSp, CS%pbv)
18010 call cpu_clock_end(id_clock_BBL_visc)
18020 if (showCallTree) call callTree_wayPoint("done with set_viscous_BBL (step_MOM_thermo)")
1803 endif
1804
180512 call cpu_clock_begin(id_clock_thermo)
180612 if (.not.CS%adiabatic) then
1807 !$omp target update from(CS%visc%Ray_u) if (allocated(CS%visc%Ray_u))
1808 !$omp target update from(CS%visc%Ray_v) if (allocated(CS%visc%Ray_v))
1809 !$omp target update from(CS%visc%bbl_thick_u) if (allocated(CS%visc%bbl_thick_u))
1810 !$omp target update from(CS%visc%bbl_thick_v) if (allocated(CS%visc%bbl_thick_v))
1811 !$omp target update from(CS%visc%Kv_bbl_u) if (allocated(CS%visc%Kv_bbl_u))
1812 !$omp target update from(CS%visc%Kv_bbl_v) if (allocated(CS%visc%Kv_bbl_v))
181312 if (CS%debug) then
18140 call uvchksum("Pre-diabatic [uv]", u, v, G%HI, haloshift=2, unscale=US%L_T_to_m_s)
18150 call hchksum(h,"Pre-diabatic h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
1816 call uvchksum("Pre-diabatic [uv]h", CS%uhtr, CS%vhtr, G%HI, &
18170 haloshift=0, unscale=GV%H_to_MKS*US%L_to_m**2)
1818 ! call MOM_state_chksum("Pre-diabatic ", u, v, h, CS%uhtr, CS%vhtr, G, GV, vel_scale=1.0)
18190 call MOM_thermo_chksum("Pre-diabatic ", tv, G, US, haloshift=0)
18200 if (debug_redundant) &
18210 call check_redundant("Pre-diabatic ", u, v, G, unscale=US%L_T_to_m_s)
18220 call MOM_forcing_chksum("Pre-diabatic", fluxes, G, US, haloshift=0)
1823 endif
1824
182512 call cpu_clock_begin(id_clock_diabatic)
1826
1827 !$omp target update from(u, v, h)
1828 call diabatic(u, v, h, tv, CS%Hml, fluxes, CS%visc, CS%ADp, CS%CDp, dtdia, &
182912 Time_end_thermo, G, GV, US, CS%diabatic_CSp, CS%stoch_CS, CS%OBC, Waves)
1830 !$omp target update to (u,v,h)
183112 fluxes%fluxes_used = .true.
1832
183312 if (CS%stoch_CS%do_skeb) then
18340 call apply_skeb(CS%G,CS%GV,CS%stoch_CS,CS%u,CS%v,CS%h,CS%tv,dtdia,Time_end_thermo)
1835 endif
1836
183712 if (showCallTree) call callTree_waypoint("finished diabatic (step_MOM_thermo)")
1838
183912 if (CS%debug) then
18400 call uvchksum("Post-diabatic u", u, v, G%HI, haloshift=2, unscale=US%L_T_to_m_s)
18410 call hchksum(h, "Post-diabatic h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
1842 call uvchksum("Post-diabatic [uv]h", CS%uhtr, CS%vhtr, G%HI, &
18430 haloshift=0, unscale=GV%H_to_MKS*US%L_to_m**2)
1844 ! call MOM_state_chksum("Post-diabatic ", u, v, &
1845 ! h, CS%uhtr, CS%vhtr, G, GV, haloshift=1)
18460 if (associated(tv%T)) call hchksum(tv%T, "Post-diabatic T", G%HI, haloshift=1, unscale=US%C_to_degC)
18470 if (associated(tv%S)) call hchksum(tv%S, "Post-diabatic S", G%HI, haloshift=1, unscale=US%S_to_ppt)
18480 if (associated(tv%frazil)) call hchksum(tv%frazil, "Post-diabatic frazil", G%HI, haloshift=0, &
18490 unscale=US%Q_to_J_kg*US%RZ_to_kg_m2)
18500 if (associated(tv%salt_deficit)) call hchksum(tv%salt_deficit, &
18510 "Post-diabatic salt deficit", G%HI, haloshift=0, unscale=US%RZ_to_kg_m2)
1852 ! call MOM_thermo_chksum("Post-diabatic ", tv, G, US)
18530 if (debug_redundant) &
18540 call check_redundant("Post-diabatic ", u, v, G, unscale=US%L_T_to_m_s)
1855 endif
185612 call disable_averaging(CS%diag)
1857
185812 call cpu_clock_end(id_clock_diabatic)
1859 else ! complement of "if (.not.CS%adiabatic)"
1860
18610 call cpu_clock_begin(id_clock_adiabatic)
18620 call adiabatic(h, tv, fluxes, dtdia, G, GV, US, CS%diabatic_CSp)
18630 fluxes%fluxes_used = .true.
18640 call cpu_clock_end(id_clock_adiabatic)
1865
18660 if (associated(tv%T)) then
18670 dynamics_stencil = min(3, G%Domain%nihalo, G%Domain%njhalo)
18680 call create_group_pass(pass_T_S, tv%T, G%Domain, To_All+Omit_Corners, halo=dynamics_stencil)
18690 call create_group_pass(pass_T_S, tv%S, G%Domain, To_All+Omit_Corners, halo=dynamics_stencil)
18700 call do_group_pass(pass_T_S, G%Domain, clock=id_clock_pass)
18710 if (CS%debug) then
18720 if (associated(tv%T)) call hchksum(tv%T, "Post-diabatic T", G%HI, haloshift=1, unscale=US%C_to_degC)
18730 if (associated(tv%S)) call hchksum(tv%S, "Post-diabatic S", G%HI, haloshift=1, unscale=US%S_to_ppt)
1874 endif
1875
1876 ! Update derived thermodynamic quantities.
18770 if (allocated(tv%SpV_avg)) then
18780 call calc_derived_thermo(tv, h, G, GV, US, halo=dynamics_stencil, debug=CS%debug)
1879 endif
1880 endif
1881
1882 endif ! endif for the block "if (.not.CS%adiabatic)"
188312 call cpu_clock_end(id_clock_thermo)
1884
188512 call disable_averaging(CS%diag)
1886
1887! This works in general:
1888! if (associated(tv%T)) &
1889! call totalTandS(G%HI, h, G%areaT, tv%T, tv%S, "End of step_MOM", US, GV%H_to_mks)
1890! This works only if there is no rescaling being used:
1891! if (associated(tv%T)) &
1892! call totalTandS(G%HI, h, G%areaT, tv%T, tv%S, "End of step_MOM")
1893
189412 if (showCallTree) call callTree_leave("step_MOM_thermo(), MOM.F90")
1895
189612end subroutine step_MOM_thermo
1897
1898!> ALE_regridding_and_remapping does regridding (the generation of a new grid) and remapping
1899!! (from the old grid to the new grid). This is done after the themrodynamic step.
190012subroutine ALE_regridding_and_remapping(CS, G, GV, US, u, v, h, tv, dtdia, Time_end_thermo)
1901 type(MOM_control_struct), intent(inout) :: CS !< Master MOM control structure
1902 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
1903 type(verticalGrid_type), intent(inout) :: GV !< ocean vertical grid structure
1904 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1905 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
1906 intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
1907 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
1908 intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
1909 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1910 intent(inout) :: h !< layer thickness [H ~> m or kg m-2]
1911 type(thermo_var_ptrs), intent(inout) :: tv !< A structure pointing to various thermodynamic variables
1912 real, intent(in) :: dtdia !< The time interval over which to advance [T ~> s]
1913 type(time_type), intent(in) :: Time_end_thermo !< End of averaging interval for thermo diags
1914
191524 real :: h_new(SZI_(G),SZJ_(G),SZK_(GV)) ! Layer thicknesses after regridding [H ~> m or kg m-2]
191624 real :: dzRegrid(SZI_(G),SZJ_(G),SZK_(GV)+1) ! The change in grid interface positions due to regridding,
1917 ! in the same units as thicknesses [H ~> m or kg m-2]
191824 real :: h_old_u(SZIB_(G),SZJ_(G),SZK_(GV)) ! Source grid thickness at zonal
1919 ! velocity points [H ~> m or kg m-2]
192024 real :: h_old_v(SZI_(G),SZJB_(G),SZK_(GV)) ! Source grid thickness at meridional
1921 ! velocity points [H ~> m or kg m-2]
192224 real :: h_new_u(SZIB_(G),SZJ_(G),SZK_(GV)) ! Destination grid thickness at zonal
1923 ! velocity points [H ~> m or kg m-2]
192424 real :: h_new_v(SZI_(G),SZJB_(G),SZK_(GV)) ! Destination grid thickness at meridional
1925 ! velocity points [H ~> m or kg m-2]
192624 logical :: PCM_cell(SZI_(G),SZJ_(G),SZK_(GV)) ! If true, PCM remapping should be used in a cell.
1927 logical :: use_ice_shelf ! Needed for selecting the right ALE interface.
1928 logical :: debug_redundant ! If true, check redundant values on PE boundaries when debugging.
1929 logical :: showCallTree
1930 type(group_pass_type) :: pass_T_S_h
1931 integer :: i, j, k, is, ie, js, je, nz
1932
193312 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
193412 use_ice_shelf = .false.
19350 if (associated(CS%frac_shelf_h)) use_ice_shelf = .true.
193612 showCallTree = callTree_showQuery()
193712 if (showCallTree) call callTree_enter("ALE_regridding_and_remapping(), MOM.F90")
193812 if (CS%debug) call query_debugging_checks(do_redundant=debug_redundant)
1939
194012 call cpu_clock_begin(id_clock_remap)
1941
1942 ! Regridding/remapping is done here, at end of thermodynamics time step
1943 ! (that may comprise several dynamical time steps)
1944 ! The routine 'ALE_regrid' can be found in 'MOM_ALE.F90'.
194512 call enable_averages(dtdia, Time_end_thermo, CS%diag)
1946
194712 call cpu_clock_begin(id_clock_pass)
194812 if (associated(tv%T)) &
194912 call create_group_pass(pass_T_S_h, tv%T, G%Domain, To_All+Omit_Corners, halo=1)
195012 if (associated(tv%S)) &
195112 call create_group_pass(pass_T_S_h, tv%S, G%Domain, To_All+Omit_Corners, halo=1)
195212 call create_group_pass(pass_T_S_h, h, G%Domain, To_All+Omit_Corners, halo=1)
195312 call do_group_pass(pass_T_S_h, G%Domain)
195412 call cpu_clock_end(id_clock_pass)
1955
195612 call preAle_tracer_diagnostics(CS%tracer_Reg, G, GV)
1957
195812 if (CS%use_particles) then
19590 call particles_to_z_space(CS%particles, h)
1960 endif
1961
196212 if (CS%debug) then
19630 call MOM_state_chksum("Pre-ALE ", u, v, h, CS%uh, CS%vh, G, GV, US, omit_corners=.true.)
19640 call hchksum(tv%T,"Pre-ALE T", G%HI, haloshift=1, omit_corners=.true., unscale=US%C_to_degC)
19650 call hchksum(tv%S,"Pre-ALE S", G%HI, haloshift=1, omit_corners=.true., unscale=US%S_to_ppt)
19660 if (debug_redundant) &
19670 call check_redundant("Pre-ALE ", u, v, G, unscale=US%L_T_to_m_s)
1968 endif
196912 call cpu_clock_begin(id_clock_ALE)
1970
197112 call pre_ALE_diagnostics(G, GV, US, h, u, v, tv, CS%ALE_CSp)
197212 call ALE_update_regrid_weights(dtdia, CS%ALE_CSp)
1973 ! Do any necessary adjustments ot the state prior to remapping.
197412 call pre_ALE_adjustments(G, GV, US, h, tv, CS%tracer_Reg, CS%ALE_CSp, u, v)
1975 ! Adjust the target grids for diagnostics, in case there have been thickness adjustments.
197612 call diag_update_remap_grids(CS%diag)
1977
197812 if (use_ice_shelf) then
19790 call ALE_regrid(G, GV, US, h, h_new, dzRegrid, tv, CS%ALE_CSp, CS%frac_shelf_h, PCM_cell)
1980 else
198112 call ALE_regrid(G, GV, US, h, h_new, dzRegrid, tv, CS%ALE_CSp, PCM_cell=PCM_cell)
1982 endif
1983
198412 if (showCallTree) call callTree_waypoint("new grid generated")
1985 ! Remap all variables from the old grid h onto the new grid h_new
198612 call ALE_remap_tracers(CS%ALE_CSp, G, GV, h, h_new, CS%tracer_Reg, showCallTree, dtdia, PCM_cell)
1987
1988 ! Determine the old and new grid thicknesses at velocity points.
198912 call ALE_remap_set_h_vel(CS%ALE_CSp, G, GV, h, h_old_u, h_old_v, CS%OBC, debug=showCallTree)
199012 if (CS%remap_uv_using_old_alg) then
19910 call ALE_remap_set_h_vel_via_dz(CS%ALE_CSp, G, GV, h_new, h_new_u, h_new_v, CS%OBC, h, dzRegrid, showCallTree)
1992 else
199312 call ALE_remap_set_h_vel(CS%ALE_CSp, G, GV, h_new, h_new_u, h_new_v, CS%OBC, debug=showCallTree)
1994 endif
1995
1996 ! Remap the velocity components.
1997 call ALE_remap_velocities(CS%ALE_CSp, G, GV, h_old_u, h_old_v, h_new_u, h_new_v, u, v, showCallTree, &
199812 dtdia, allow_preserve_variance=.true.)
1999
200012 if (allocated(tv%SpV_avg)) tv%valid_SpV_halo = -1 ! Record that SpV_avg is no longer valid.
2001
200212 if (CS%remap_aux_vars) then
20030 if (CS%split .and. CS%use_alt_split) then
2004 call remap_dyn_split_RK2b_aux_vars(G, GV, CS%dyn_split_RK2b_CSp, h_old_u, h_old_v, &
20050 h_new_u, h_new_v, CS%ALE_CSp)
20060 elseif (CS%split) then
20070 call remap_dyn_split_RK2_aux_vars(G, GV, CS%dyn_split_RK2_CSp, h_old_u, h_old_v, h_new_u, h_new_v, CS%ALE_CSp)
2008 endif
2009
20100 if (associated(CS%OBC)) then
20110 call pass_var(h, G%Domain, complete=.false.)
20120 call pass_var(h_new, G%Domain, complete=.true.)
20130 call remap_OBC_fields(G, GV, h, h_new, CS%OBC, PCM_cell=PCM_cell)
2014 endif
2015
20160 call remap_vertvisc_aux_vars(G, GV, CS%visc, h, h_new, CS%ALE_CSp, CS%OBC)
20170 if (associated(CS%visc%Kv_shear)) &
20180 call pass_var(CS%visc%Kv_shear, G%Domain, To_All+Omit_Corners, clock=id_clock_pass, halo=1)
2019 endif
2020
2021 ! Replace the old grid with new one. All remapping must be done by this point in the code.
2022 !$OMP parallel do default(shared)
20236864312 do k=1,nz ; do j=js-1,je+1 ; do i=is-1,ie+1
20246863400 h(i,j,k) = h_new(i,j,k)
2025 enddo ; enddo ; enddo
2026
202712 if (showCallTree) call callTree_waypoint("finished ALE_regrid (ALE_regridding_and_remapping)")
202812 call cpu_clock_end(id_clock_ALE)
2029
2030 ! Update derived thermodynamic quantities.
203112 if (allocated(CS%tv%SpV_avg)) then
20320 call calc_derived_thermo(CS%tv, CS%h, G, GV, US, halo=1, debug=CS%debug)
2033 endif
2034
2035 ! Whenever thickness changes let the diag manager know, target grids
2036 ! for vertical remapping may need to be regenerated. In non-Boussinesq mode,
2037 ! calc_derived_thermo needs to be called before diag_update_remap_grids.
2038 ! This needs to happen after the H update and before the next post_data.
203912 call diag_update_remap_grids(CS%diag)
2040
204112 call postALE_tracer_diagnostics(CS%tracer_Reg, G, GV, CS%diag, dtdia)
2042
204312 if (CS%debug .and. CS%use_ALE_algorithm) then
20440 call MOM_state_chksum("Post-ALE ", u, v, h, CS%uh, CS%vh, G, GV, US)
20450 call hchksum(tv%T, "Post-ALE T", G%HI, haloshift=1, unscale=US%C_to_degC)
20460 call hchksum(tv%S, "Post-ALE S", G%HI, haloshift=1, unscale=US%S_to_ppt)
20470 if (debug_redundant) &
20480 call check_redundant("Post-ALE ", u, v, G, unscale=US%L_T_to_m_s)
2049 endif
205012 if (CS%debug) then
20510 call uvchksum("Post-ALE, Post-diabatic u", u, v, G%HI, haloshift=2, unscale=US%L_T_to_m_s)
20520 call hchksum(h, "Post-ALE, Post-diabatic h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
2053 call uvchksum("Post-ALE, Post-diabatic [uv]h", CS%uhtr, CS%vhtr, G%HI, &
20540 haloshift=0, unscale=GV%H_to_MKS*US%L_to_m**2)
2055 ! call MOM_state_chksum("Post-diabatic ", u, v, &
2056 ! h, CS%uhtr, CS%vhtr, G, GV, haloshift=1)
20570 if (associated(tv%T)) call hchksum(tv%T, "Post-ALE, Post-diabatic T", G%HI, haloshift=1, unscale=US%C_to_degC)
20580 if (associated(tv%S)) call hchksum(tv%S, "Post-ALE, Post-diabatic S", G%HI, haloshift=1, unscale=US%S_to_ppt)
20590 if (associated(tv%frazil)) call hchksum(tv%frazil, "Post-ALE, Post-diabatic frazil", G%HI, haloshift=0, &
20600 unscale=US%Q_to_J_kg*US%RZ_to_kg_m2)
20610 if (associated(tv%salt_deficit)) call hchksum(tv%salt_deficit, &
20620 "Post-ALE, Post-diabatic salt deficit", G%HI, haloshift=0, unscale=US%RZ_to_kg_m2)
2063 ! call MOM_thermo_chksum("Post-diabatic ", tv, G, US)
20640 if (debug_redundant) &
20650 call check_redundant("Post-ALE, Post-diabatic ", u, v, G, unscale=US%L_T_to_m_s)
2066 endif
206712 call disable_averaging(CS%diag)
2068
206912 call cpu_clock_end(id_clock_remap)
2070
207112 if (showCallTree) call callTree_leave("ALE_regridding_and_remapping(), MOM.F90")
2072
207312end subroutine ALE_regridding_and_remapping
2074
2075!> post_diabatic_halo_updates does halo updates and calculates derived thermodynamic quantities
2076!! (e.g. specific volume). This must be done after the diabatic step regardless of is ALE
2077!! cooridinates are used or not.
207812subroutine post_diabatic_halo_updates(CS, G, GV, US, u, v, h, tv)
2079 type(MOM_control_struct), intent(inout) :: CS !< Master MOM control structure
2080 type(ocean_grid_type), intent(inout) :: G !< ocean grid structure
2081 type(verticalGrid_type), intent(inout) :: GV !< ocean vertical grid structure
2082 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
2083 real, dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
2084 intent(inout) :: u !< zonal velocity [L T-1 ~> m s-1]
2085 real, dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
2086 intent(inout) :: v !< meridional velocity [L T-1 ~> m s-1]
2087 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
2088 intent(inout) :: h !< layer thickness [H ~> m or kg m-2]
2089 type(thermo_var_ptrs), intent(inout) :: tv !< A structure pointing to various thermodynamic variables
2090
2091 logical :: debug_redundant ! If true, check redundant values on PE boundaries when debugging.
2092 logical :: showCallTree
2093 type(group_pass_type) :: pass_uv_T_S_h
2094 integer :: dynamics_stencil ! The computational stencil for the calculations
2095 ! in the dynamic core.
2096
209712 showCallTree = callTree_showQuery()
20980 if (showCallTree) call callTree_enter("post_diabatic_halo_updates, MOM.F90")
209912 if (CS%debug) call query_debugging_checks(do_redundant=debug_redundant)
2100
210112 if (CS%use_particles) then
21020 call particles_to_k_space(CS%particles, h)
2103 endif
2104
210512 dynamics_stencil = min(3, G%Domain%nihalo, G%Domain%njhalo)
210612 call create_group_pass(pass_uv_T_S_h, u, v, G%Domain, halo=dynamics_stencil)
210712 if (associated(tv%T)) &
210812 call create_group_pass(pass_uv_T_S_h, tv%T, G%Domain, halo=dynamics_stencil)
210912 if (associated(tv%S)) &
211012 call create_group_pass(pass_uv_T_S_h, tv%S, G%Domain, halo=dynamics_stencil)
211112 call create_group_pass(pass_uv_T_S_h, h, G%Domain, halo=dynamics_stencil)
211212 call do_group_pass(pass_uv_T_S_h, G%Domain, clock=id_clock_pass, omp_offload=.true.)
2113
211412 if (associated(tv%frazil) .and. (.not.tv%frazil_was_reset) .and. CS%vertex_shear) &
211512 call pass_var(tv%frazil, G%Domain, halo=1)
2116
2117 ! Update derived thermodynamic quantities.
211812 if (allocated(tv%SpV_avg)) then
21190 call calc_derived_thermo(tv, h, G, GV, US, halo=dynamics_stencil, debug=CS%debug)
2120 endif
212112 if (showCallTree) call callTree_leave("post_diabatic_halo_updates, MOM.F90")
212212end subroutine post_diabatic_halo_updates
2123
2124!> step_offline is the main driver for running tracers offline in MOM6. This has been primarily
2125!! developed with ALE configurations in mind. Some work has been done in isopycnal configuration, but
2126!! the work is very preliminary. Some more detail about this capability along with some of the subroutines
2127!! called here can be found in tracers/MOM_offline_control.F90
21280subroutine step_offline(forces, fluxes, sfc_state, Time_start, time_interval, CS)
2129 type(mech_forcing), intent(in) :: forces !< A structure with the driving mechanical forces
2130 type(forcing), intent(inout) :: fluxes !< pointers to forcing fields
2131 type(surface), intent(inout) :: sfc_state !< surface ocean state
2132 type(time_type), intent(in) :: Time_start !< starting time of a segment, as a time type
2133 real, intent(in) :: time_interval !< time interval [T ~> s]
2134 type(MOM_control_struct), intent(inout) :: CS !< control structure from initialize_MOM
2135
2136 ! Local pointers
2137 type(ocean_grid_type), pointer :: G => NULL() ! Pointer to a structure containing
2138 ! metrics and related information
2139 type(verticalGrid_type), pointer :: GV => NULL() ! Pointer to structure containing information
2140 ! about the vertical grid
2141 type(unit_scale_type), pointer :: US => NULL() ! Pointer to a structure containing
2142 ! various unit conversion factors
2143
2144 logical :: first_iter !< True if this is the first time step_offline has been called in a given interval
2145 logical :: last_iter !< True if this is the last time step_tracer is to be called in an offline interval
2146 logical :: do_vertical !< If enough time has elapsed, do the diabatic tracer sources/sinks
2147 logical :: adv_converged !< True if all the horizontal fluxes have been used
2148
21490 real, allocatable, dimension(:,:,:) :: h_new ! Layer thicknesses after regridding [H ~> m or kg m-2]
21500 real, allocatable, dimension(:,:,:) :: dzRegrid ! The change in grid interface positions due to regridding,
2151 ! in the same units as thicknesses [H ~> m or kg m-2]
2152 real :: dt_offline ! The offline timestep for advection [T ~> s]
2153 real :: dt_offline_vertical ! The offline timestep for vertical fluxes and remapping [T ~> s]
2154 logical :: skip_diffusion
2155
2156 type(time_type), pointer :: accumulated_time => NULL()
2157 type(time_type), pointer :: vertical_time => NULL()
2158 integer :: dynamics_stencil ! The computational stencil for the calculations
2159 ! in the dynamic core.
2160 integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz
2161
2162 ! 3D pointers
2163 real, dimension(:,:,:), pointer :: &
2164 uhtr => NULL(), & ! Accumulated zonal thickness fluxes to advect tracers [H L2 ~> m3 or kg]
2165 vhtr => NULL(), & ! Accumulated meridional thickness fluxes to advect tracers [H L2 ~> m3 or kg]
2166 eatr => NULL(), & ! Layer entrainment rates across the interface above [H ~> m or kg m-2]
2167 ebtr => NULL(), & ! Layer entrainment rates across the interface below [H ~> m or kg m-2]
2168 h_end => NULL() ! Layer thicknesses at the end of a step [H ~> m or kg m-2]
2169
2170 type(time_type) :: Time_end ! End time of a segment, as a time type
2171
2172 ! Grid-related pointer assignments
21730 G => CS%G ; GV => CS%GV ; US => CS%US
2174
21750 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
21760 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
2177
21780 call cpu_clock_begin(id_clock_offline_tracer)
2179 call extract_offline_main(CS%offline_CSp, uhtr, vhtr, eatr, ebtr, h_end, accumulated_time, &
21800 vertical_time, dt_offline, dt_offline_vertical, skip_diffusion)
21810 Time_end = increment_date(Time_start, seconds=floor(US%T_to_s*time_interval+0.001))
2182
21830 call enable_averages(time_interval, Time_end, CS%diag)
2184
2185 ! Check to see if this is the first iteration of the offline interval
21860 first_iter = (accumulated_time == real_to_time(0.0))
2187
2188 ! Check to see if vertical tracer functions should be done
21890 do_vertical = (first_iter .or. (accumulated_time >= vertical_time))
21900 if (do_vertical) vertical_time = accumulated_time + real_to_time(dt_offline_vertical, unscale=US%T_to_s)
2191
2192 ! Increment the amount of time elapsed since last read and check if it's time to roll around
21930 accumulated_time = accumulated_time + real_to_time(time_interval, unscale=US%T_to_s)
2194
21950 last_iter = (accumulated_time >= real_to_time(dt_offline, unscale=US%T_to_s))
2196
21970 if (CS%use_ALE_algorithm) then
2198 ! If this is the first iteration in the offline timestep, then we need to read in fields and
2199 ! perform the main advection.
22000 if (first_iter) then
22010 call MOM_mesg("Reading in new offline fields")
2202 ! Read in new transport and other fields
2203 ! call update_transport_from_files(G, GV, CS%offline_CSp, h_end, eatr, ebtr, uhtr, vhtr, &
2204 ! CS%tv%T, CS%tv%S, fluxes, CS%use_ALE_algorithm)
2205 ! call update_transport_from_arrays(CS%offline_CSp)
22060 call update_offline_fields(CS%offline_CSp, G, GV, US, CS%h, fluxes, CS%use_ALE_algorithm)
2207
2208 ! Apply any fluxes into the ocean
22090 call offline_fw_fluxes_into_ocean(G, GV, CS%offline_CSp, fluxes, CS%h)
2210
22110 if (.not.CS%diabatic_first) then
2212 call offline_advection_ale(fluxes, Time_start, time_interval, G, GV, US, CS%offline_CSp, &
22130 id_clock_ALE, CS%h, uhtr, vhtr, converged=adv_converged)
2214
2215 ! Redistribute any remaining transport
22160 call offline_redistribute_residual(CS%offline_CSp, G, GV, US, CS%h, uhtr, vhtr, adv_converged)
2217
2218 ! Perform offline diffusion if requested
22190 if (.not. skip_diffusion) then
22200 if (CS%VarMix%use_variable_mixing) then
22210 call pass_var(CS%h, G%Domain)
22220 call calc_resoln_function(CS%h, CS%tv, G, GV, US, CS%VarMix, CS%MEKE, CS%OBC, dt_offline)
22230 call calc_depth_function(G, CS%VarMix)
22240 call calc_slope_functions(CS%h, CS%tv, dt_offline, G, GV, US, CS%VarMix, OBC=CS%OBC)
2225 endif
2226 call tracer_hordiff(CS%h, dt_offline, CS%MEKE, CS%VarMix, CS%visc, G, GV, US, &
22270 CS%tracer_diff_CSp, CS%tracer_Reg, CS%tv)
2228 endif
2229 endif
2230 endif
2231 ! The functions related to column physics of tracers is performed separately in ALE mode
22320 if (do_vertical) then
2233 call offline_diabatic_ale(fluxes, Time_start, Time_end, G, GV, US, CS%offline_CSp, &
22340 CS%h, CS%tv, eatr, ebtr)
2235 endif
2236
2237 ! Last thing that needs to be done is the final ALE remapping
22380 if (last_iter) then
22390 if (CS%diabatic_first) then
2240 call offline_advection_ale(fluxes, Time_start, time_interval, G, GV, US, CS%offline_CSp, &
22410 id_clock_ALE, CS%h, uhtr, vhtr, converged=adv_converged)
2242
2243 ! Redistribute any remaining transport and perform the remaining advection
22440 call offline_redistribute_residual(CS%offline_CSp, G, GV, US, CS%h, uhtr, vhtr, adv_converged)
2245 ! Perform offline diffusion if requested
22460 if (.not. skip_diffusion) then
22470 if (CS%VarMix%use_variable_mixing) then
22480 call pass_var(CS%h, G%Domain)
22490 call calc_resoln_function(CS%h, CS%tv, G, GV, US, CS%VarMix, CS%MEKE, CS%OBC, dt_offline)
22500 call calc_depth_function(G, CS%VarMix)
22510 call calc_slope_functions(CS%h, CS%tv, dt_offline, G, GV, US, CS%VarMix, OBC=CS%OBC)
2252 endif
2253 call tracer_hordiff(CS%h, dt_offline, CS%MEKE, CS%VarMix, CS%visc, G, GV, US, &
22540 CS%tracer_diff_CSp, CS%tracer_Reg, CS%tv)
2255 endif
2256 endif
2257
22580 call MOM_mesg("Last iteration of offline interval")
2259
2260 ! Apply freshwater fluxes out of the ocean
22610 call offline_fw_fluxes_out_ocean(G, GV, CS%offline_CSp, fluxes, CS%h)
2262 ! These diagnostic can be used to identify which grid points did not converge within
2263 ! the specified number of advection sub iterations
22640 call post_offline_convergence_diags(G, GV, CS%offline_CSp, CS%h, h_end, uhtr, vhtr)
2265
2266 ! Call ALE one last time to make sure that tracers are remapped onto the layer thicknesses
2267 ! stored from the forward run
22680 call cpu_clock_begin(id_clock_ALE)
2269
2270 ! Do any necessary adjustments ot the state prior to remapping.
22710 call pre_ALE_adjustments(G, GV, US, h_end, CS%tv, CS%tracer_Reg, CS%ALE_CSp)
2272
22730 allocate(h_new(isd:ied, jsd:jed, nz), source=0.0)
22740 allocate(dzRegrid(isd:ied, jsd:jed, nz+1), source=0.0)
2275
2276 ! Generate the new grid based on the tracer grid at the end of the interval.
22770 call ALE_regrid(G, GV, US, h_end, h_new, dzRegrid, CS%tv, CS%ALE_CSp)
2278
2279 ! Remap the tracers from the previous tracer grid onto the new grid. The thicknesses that
2280 ! are used are intended to ensure that in the case where transports don't quite conserve,
2281 ! the offline layer thicknesses do not drift too far away from the online model.
22820 call ALE_remap_tracers(CS%ALE_CSp, G, GV, CS%h, h_new, CS%tracer_Reg, debug=CS%debug)
22830 if (allocated(CS%tv%SpV_avg)) CS%tv%valid_SpV_halo = -1 ! Record that SpV_avg is no longer valid.
2284
2285 ! Update the tracer grid.
22860 do k=1,nz ; do j=js-1,je+1 ; do i=is-1,ie+1
22870 CS%h(i,j,k) = h_new(i,j,k)
2288 enddo ; enddo ; enddo
2289
22900 deallocate(h_new, dzRegrid)
2291
22920 call cpu_clock_end(id_clock_ALE)
22930 call pass_var(CS%h, G%Domain)
2294 endif
2295 else ! NON-ALE MODE...NOT WELL TESTED
2296 call MOM_error(WARNING, &
22970 "Offline tracer mode in non-ALE configuration has not been thoroughly tested")
2298 ! Note that for the layer mode case, the calls to tracer sources and sinks is embedded in
2299 ! main_offline_advection_layer. Warning: this may not be appropriate for tracers that
2300 ! exchange with the atmosphere
23010 if (abs(time_interval - dt_offline) > 1.0e-6*US%s_to_T) then
2302 call MOM_error(FATAL, &
23030 "For offline tracer mode in a non-ALE configuration, dt_offline must equal time_interval")
2304 endif
23050 call update_offline_fields(CS%offline_CSp, G, GV, US, CS%h, fluxes, CS%use_ALE_algorithm)
2306 call offline_advection_layer(fluxes, Time_start, time_interval, G, GV, US, CS%offline_CSp, &
23070 CS%h, eatr, ebtr, uhtr, vhtr)
2308 ! Perform offline diffusion if requested
23090 if (.not. skip_diffusion) then
2310 call tracer_hordiff(h_end, dt_offline, CS%MEKE, CS%VarMix, CS%visc, G, GV, US, &
23110 CS%tracer_diff_CSp, CS%tracer_Reg, CS%tv)
2312 endif
2313
23140 CS%h = h_end
2315
23160 call pass_var(CS%tv%T, G%Domain)
23170 call pass_var(CS%tv%S, G%Domain)
23180 call pass_var(CS%h, G%Domain)
2319
2320 endif
2321
2322 call adjust_ssh_for_p_atm(CS%tv, G, GV, US, CS%ave_ssh_ibc, forces%p_surf_SSH, &
23230 CS%calc_rho_for_sea_lev)
23240 call extract_surface_state(CS, sfc_state)
2325
23260 call disable_averaging(CS%diag)
23270 call pass_var(CS%tv%T, G%Domain)
23280 call pass_var(CS%tv%S, G%Domain)
23290 call pass_var(CS%h, G%Domain)
2330
23310 fluxes%fluxes_used = .true.
2332
2333 ! Update derived thermodynamic quantities.
23340 if (allocated(CS%tv%SpV_avg)) then
23350 dynamics_stencil = min(3, G%Domain%nihalo, G%Domain%njhalo)
23360 call calc_derived_thermo(CS%tv, CS%h, G, GV, US, halo=dynamics_stencil)
2337 endif
2338
23390 if (last_iter) then
23400 accumulated_time = real_to_time(0.0)
2341 endif
2342
23430 call cpu_clock_end(id_clock_offline_tracer)
2344
23450end subroutine step_offline
2346
2347!> Initialize MOM, including memory allocation, setting up parameters and diagnostics,
2348!! initializing the ocean state variables, and initializing subsidiary modules
234911subroutine initialize_MOM(Time, Time_init, param_file, dirs, CS, &
2350 Time_in, offline_tracer_mode, input_restart_file, diag_ptr, &
2351 count_calls, tracer_flow_CSp, ice_shelf_CSp, waves_CSp, ensemble_num, &
2352 calve_ice_shelf_bergs)
2353 type(time_type), target, intent(inout) :: Time !< model time, set in this routine
2354 type(time_type), intent(in) :: Time_init !< The start time for the coupled model's calendar
2355 type(param_file_type), intent(out) :: param_file !< structure indicating parameter file to parse
2356 type(directories), intent(out) :: dirs !< structure with directory paths
2357 type(MOM_control_struct), intent(inout), target :: CS !< pointer set in this routine to MOM control structure
2358 type(time_type), optional, intent(in) :: Time_in !< time passed to MOM_initialize_state when
2359 !! model is not being started from a restart file
2360 logical, optional, intent(out) :: offline_tracer_mode !< True is returned if tracers are being run offline
2361 character(len=*),optional, intent(in) :: input_restart_file !< If present, name of restart file to read
2362 type(diag_ctrl), optional, pointer :: diag_ptr !< A pointer set in this routine to the diagnostic
2363 !! regulatory structure
2364 type(tracer_flow_control_CS), &
2365 optional, pointer :: tracer_flow_CSp !< A pointer set in this routine to
2366 !! the tracer flow control structure.
2367 logical, optional, intent(in) :: count_calls !< If true, nstep_tot counts the number of
2368 !! calls to step_MOM instead of the number of
2369 !! dynamics timesteps.
2370 type(ice_shelf_CS), optional, pointer :: ice_shelf_CSp !< A pointer to an ice shelf control structure
2371 type(Wave_parameters_CS), &
2372 optional, pointer :: Waves_CSp !< An optional pointer to a wave property CS
2373 integer, optional :: ensemble_num !< Ensemble index provided by the cap (instead of FMS
2374 !! ensemble manager)
2375 logical, optional :: calve_ice_shelf_bergs !< If true, will add point iceberg calving variables to the ice
2376 !! shelf restart
2377 ! local variables
2378 type(ocean_grid_type), pointer :: G => NULL() ! A pointer to the metric grid use for the run
2379 type(ocean_grid_type), pointer :: G_in => NULL() ! Pointer to the input grid
2380 type(hor_index_type), pointer :: HI => NULL() ! A hor_index_type for array extents
2381 type(hor_index_type), target :: HI_in ! HI on the input grid
2382 type(hor_index_type) :: HI_in_unmasked ! HI on the unmasked input grid
2383 type(verticalGrid_type), pointer :: GV => NULL()
2384 type(dyn_horgrid_type), pointer :: dG => NULL(), test_dG => NULL()
2385 type(dyn_horgrid_type), pointer :: dG_in => NULL()
2386 type(dyn_horgrid_type), pointer :: dG_unmasked_in => NULL()
2387 type(diag_ctrl), pointer :: diag => NULL()
2388 type(unit_scale_type), pointer :: US => NULL()
2389 type(MOM_restart_CS), pointer :: restart_CSp => NULL()
2390 character(len=4), parameter :: vers_num = 'v2.0'
2391 integer :: turns ! Number of grid quarter-turns
2392 logical :: point_calving
2393
2394 ! Initial state on the input index map
23951 real, allocatable :: u_in(:,:,:) ! Initial zonal velocities [L T-1 ~> m s-1]
23961 real, allocatable :: v_in(:,:,:) ! Initial meridional velocities [L T-1 ~> m s-1]
23971 real, allocatable :: h_in(:,:,:) ! Initial layer thicknesses [H ~> m or kg m-2]
23981 real, allocatable, target :: frac_shelf_in(:,:) ! Initial fraction of the total cell area occupied
2399 ! by an ice shelf [nondim]
24001 real, allocatable, target :: mass_shelf_in(:,:) ! Initial mass of ice shelf contained within a grid cell
2401 ! [R Z ~> kg m-2]
24021 real, allocatable, target :: T_in(:,:,:) ! Initial temperatures [C ~> degC]
24031 real, allocatable, target :: S_in(:,:,:) ! Initial salinities [S ~> ppt]
2404
2405 type(ocean_OBC_type), pointer :: OBC_in => NULL()
2406 type(sponge_CS), pointer :: sponge_in_CSp => NULL()
2407 type(ALE_sponge_CS), pointer :: ALE_sponge_in_CSp => NULL()
2408 type(oda_incupd_CS),pointer :: oda_incupd_in_CSp => NULL()
2409 ! This include declares and sets the variable "version".
2410# include "version_variable.h"
2411
2412 integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz
2413 integer :: IsdB, IedB, JsdB, JedB
2414 real :: dtbt ! If negative, this specifies the barotropic timestep as a fraction
2415 ! of the maximum stable value [nondim].
2416
24171 real, allocatable, dimension(:,:) :: eta ! free surface height or column mass [H ~> m or kg m-2]
24181 real, allocatable, dimension(:,:,:) :: h_new ! Layer thicknesses after regridding [H ~> m or kg m-2]
24191 real, allocatable, dimension(:,:,:) :: dzRegrid ! The change in grid interface positions due to regridding,
2420 ! in the same units as thicknesses [H ~> m or kg m-2]
24211 real, allocatable, dimension(:,:,:) :: h_old_u ! Source grid thickness at zonal velocity points [H ~> m or kg m-2]
24221 real, allocatable, dimension(:,:,:) :: h_old_v ! Source grid thickness at meridional velocity
2423 ! points [H ~> m or kg m-2]
24241 real, allocatable, dimension(:,:,:) :: h_new_u ! Destination grid thickness at zonal
2425 ! velocity points [H ~> m or kg m-2]
24261 real, allocatable, dimension(:,:,:) :: h_new_v ! Destination grid thickness at meridional
2427 ! velocity points [H ~> m or kg m-2]
24281 logical, allocatable, dimension(:,:,:) :: PCM_cell ! If true, PCM remapping should be used in a cell.
2429 type(group_pass_type) :: tmp_pass_uv_T_S_h, pass_uv_T_S_h
2430
2431 real :: Hmix_z, Hmix_UV_z ! Temporary variables with averaging depths [Z ~> m]
2432 real :: HFrz_z ! Temporary variable with the melt potential depth [Z ~> m]
2433 real :: default_val ! The default value for DTBT_RESET_PERIOD [s]
2434 logical :: write_geom_files ! If true, write out the grid geometry files.
2435 logical :: new_sim ! If true, this has been determined to be a new simulation
2436 logical :: use_geothermal ! If true, apply geothermal heating.
2437 logical :: use_EOS ! If true, density calculated from T & S using an equation of state.
2438 logical :: symmetric ! If true, use symmetric memory allocation.
2439 logical :: save_IC ! If true, save the initial conditions.
2440 logical :: do_unit_tests ! If true, call unit tests.
2441 logical :: fpmix ! Needed to decide if BLD should be passed to RK2.
2442 logical :: test_grid_copy = .false.
2443
2444 logical :: bulkmixedlayer ! If true, a refined bulk mixed layer scheme is used
2445 ! with nkml sublayers and nkbl buffer layer.
2446 logical :: use_temperature ! If true, temperature and salinity used as state variables.
2447 logical :: use_p_surf_in_EOS ! If true, always include the surface pressure contributions
2448 ! in equation of state calculations.
2449 logical :: use_frazil ! If true, liquid seawater freezes if temp below freezing,
2450 ! with accumulated heat deficit returned to surface ocean.
2451 logical :: bound_salinity ! If true, salt is added to keep salinity above
2452 ! a minimum value, and the deficit is reported.
2453 integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags.
2454 logical :: use_conT_absS ! If true, the prognostics T & S are conservative temperature
2455 ! and absolute salinity. Care should be taken to convert them
2456 ! to potential temperature and practical salinity before
2457 ! exchanging them with the coupler and/or reporting T&S diagnostics.
2458 logical :: advect_TS ! If false, then no horizontal advection of temperature
2459 ! and salnity is performed
2460 logical :: use_ice_shelf ! Needed for ALE
2461 logical :: global_indexing ! If true use global horizontal index values instead
2462 ! of having the data domain on each processor start at 1.
2463 logical :: bathy_at_vel ! If true, also define bathymetric fields at the
2464 ! the velocity points.
2465 logical :: calc_dtbt ! Indicates whether the dynamically adjusted barotropic
2466 ! time step needs to be updated before it is used.
2467 logical :: debug_truncations ! If true, turn on diagnostics useful for debugging truncations.
2468 integer :: first_direction ! An integer that indicates which direction is to be
2469 ! updated first in directionally split parts of the
2470 ! calculation.
2471 logical :: enable_bugs ! If true, the defaults for certain recently added bug-fix flags are
2472 ! set to recreate the bugs so that the code can be moved forward
2473 ! without changing answers for existing configurations. When this is
2474 ! false, bugs are only used if they are actively selected.
2475 logical :: non_Bous ! If true, this run is fully non-Boussinesq
2476 logical :: Boussinesq ! If true, this run is fully Boussinesq
2477 logical :: semi_Boussinesq ! If true, this run is partially non-Boussinesq
2478 logical :: use_KPP ! If true, diabatic is using KPP vertical mixing
2479 logical :: MLE_use_PBL_MLD ! If true, use stored boundary layer depths for submesoscale restratification.
2480 logical :: OBC_reservoir_init_bug
2481 integer :: nkml, nkbl, verbosity, write_geom, number_of_OBC_segments
2482 integer :: dynamics_stencil ! The computational stencil for the calculations
2483 ! in the dynamic core.
2484 real :: salin_underflow ! A tiny value of salinity below which the it is set to 0 [S ~> ppt]
2485 real :: temp_underflow ! A tiny magnitude of temperatures below which they are set to 0 [C ~> degC]
2486 real :: conv2watt ! A conversion factor from temperature fluxes to heat
2487 ! fluxes [J m-2 H-1 C-1 ~> J m-3 degC-1 or J kg-1 degC-1]
2488 real :: conv2salt ! A conversion factor for salt fluxes [m H-1 ~> 1] or [kg m-2 H-1 ~> 1]
2489 character(len=48) :: S_flux_units
2490
249111 type(vardesc) :: vd_T, vd_S ! Structures describing temperature and salinity variables.
2492 type(time_type) :: Start_time
2493 type(ocean_internal_state) :: MOM_internal_state
2494 type(MOM_domain_type), pointer :: MOM_dom_unmasked => null() ! Unmasked MOM domain instance
2495 ! (To be used for writing out ocean geometry)
2496 character(len=240) :: geom_file ! Name of the ocean geometry file
2497
24981 CS%Time => Time
2499
25001 id_clock_ocean = cpu_clock_id('Ocean', grain=CLOCK_COMPONENT)
25011 id_clock_init = cpu_clock_id('Ocean Initialization', grain=CLOCK_SUBCOMPONENT)
25021 call cpu_clock_begin(id_clock_ocean) ; call cpu_clock_begin(id_clock_init)
2503
25041 Start_time = Time ; if (present(Time_in)) Start_time = Time_in
2505
2506 ! Read paths and filenames from namelist and store in "dirs".
2507 ! Also open the parsed input parameter file(s) and setup param_file.
25081 call get_MOM_input(param_file, dirs, default_input_filename=input_restart_file, ensemble_num=ensemble_num)
2509
25101 verbosity = 2 ; call read_param(param_file, "VERBOSITY", verbosity)
25111 call MOM_set_verbosity(verbosity)
25121 call callTree_enter("initialize_MOM(), MOM.F90")
2513
25141 call find_obsolete_params(param_file)
2515
2516 ! Determining the internal unit scaling factors for this run.
25171 call unit_scaling_init(param_file, CS%US)
25181 US => CS%US
2519 !$omp target enter data map(to: CS%US)
2520
2521 ! Read relevant parameters and write them to the model log.
25221 call log_version(param_file, "MOM", version, "", log_to_all=.true., layout=.true., debugging=.true.)
2523 call get_param(param_file, "MOM", "VERBOSITY", verbosity, &
2524 "Integer controlling level of messaging\n" // &
2525 "\t0 = Only FATAL messages\n" // &
2526 "\t2 = Only FATAL, WARNING, NOTE [default]\n" // &
25271 "\t9 = All)", default=2, debuggingParam=.true.)
2528 call get_param(param_file, "MOM", "DO_UNIT_TESTS", do_unit_tests, &
2529 "If True, exercises unit tests at model start up.", &
25301 default=.false., debuggingParam=.true.)
25311 if (do_unit_tests) then
25320 id_clock_unit_tests = cpu_clock_id('(Ocean unit tests)', grain=CLOCK_MODULE)
25330 call cpu_clock_begin(id_clock_unit_tests)
25340 call unit_tests(verbosity)
25350 call cpu_clock_end(id_clock_unit_tests)
2536 endif
2537
2538 call get_param(param_file, "MOM", "SPLIT", CS%split, &
25391 "Use the split time stepping if true.", default=.true.)
2540 call get_param(param_file, "MOM", "SPLIT_RK2B", CS%use_alt_split, &
2541 "If true, use a version of the split explicit time stepping scheme that "//&
2542 "exchanges velocities with step_MOM that have the average barotropic phase over "//&
2543 "a baroclinic timestep rather than the instantaneous barotropic phase.", &
25441 default=.false., do_not_log=.not.CS%split)
25451 if (CS%split) then
25461 CS%use_RK2 = .false.
2547 else
2548 call get_param(param_file, "MOM", "USE_RK2", CS%use_RK2, &
2549 "If true, use RK2 instead of RK3 in the unsplit time stepping.", &
25500 default=.false.)
2551 endif
2552
2553 ! FPMIX is needed to decide if boundary layer depth should be passed to RK2
2554 call get_param(param_file, '', "FPMIX", fpmix, &
2555 "If true, add non-local momentum flux increments and diffuse down the Eulerian gradient.", &
25561 default=.false., do_not_log=.true.)
2557
25581 if (fpmix .and. .not. CS%split) then
2559 call MOM_error(FATAL, "initialize_MOM: "//&
25600 "FPMIX=True only works when SPLIT=True.")
2561 endif
2562
2563 ! NOTE: tv is used, even if there is no thermodynamics
25641 allocate(CS%tv)
2565
2566 call get_param(param_file, "MOM", "BOUSSINESQ", Boussinesq, &
25671 "If true, make the Boussinesq approximation.", default=.true., do_not_log=.true.)
2568 call get_param(param_file, "MOM", "SEMI_BOUSSINESQ", semi_Boussinesq, &
2569 "If true, do non-Boussinesq pressure force calculations and use mass-based "//&
2570 "thicknesses, but use RHO_0 to convert layer thicknesses into certain "//&
2571 "height changes. This only applies if BOUSSINESQ is false.", &
25721 default=.true., do_not_log=.true.)
25731 non_Bous = .not.(Boussinesq .or. semi_Boussinesq)
2574 call get_param(param_file, "MOM", "CALC_RHO_FOR_SEA_LEVEL", CS%calc_rho_for_sea_lev, &
2575 "If true, the in-situ density is used to calculate the "//&
2576 "effective sea level that is returned to the coupler. If false, "//&
25771 "the Boussinesq parameter RHO_0 is used.", default=non_Bous)
2578 call get_param(param_file, "MOM", "ENABLE_THERMODYNAMICS", use_temperature, &
2579 "If true, Temperature and salinity are used as state "//&
25801 "variables.", default=.true.)
2581 call get_param(param_file, "MOM", "USE_EOS", use_EOS, &
2582 "If true, density is calculated from temperature and "//&
2583 "salinity with an equation of state. If USE_EOS is "//&
2584 "true, ENABLE_THERMODYNAMICS must be true as well.", &
25851 default=use_temperature)
2586 call get_param(param_file, "MOM", "DIABATIC_FIRST", CS%diabatic_first, &
2587 "If true, apply diabatic and thermodynamic processes, "//&
2588 "including buoyancy forcing and mass gain or loss, "//&
25891 "before stepping the dynamics forward.", default=.false.)
2590 call get_param(param_file, "MOM", "USE_CONTEMP_ABSSAL", use_conT_absS, &
2591 "If true, the prognostics T&S are the conservative temperature "//&
2592 "and absolute salinity. Care should be taken to convert them "//&
2593 "to potential temperature and practical salinity before "//&
2594 "exchanging them with the coupler and/or reporting T&S diagnostics.", &
25951 default=.false.)
25961 CS%tv%T_is_conT = use_conT_absS ; CS%tv%S_is_absS = use_conT_absS
2597 call get_param(param_file, "MOM", "ADIABATIC", CS%adiabatic, &
2598 "There are no diapycnal mass fluxes if ADIABATIC is true. "//&
2599 "This assumes that KD = 0.0 and that there is no buoyancy forcing, "//&
26001 "but makes the model faster by eliminating subroutine calls.", default=.false.)
2601 call get_param(param_file, "MOM", "DO_DYNAMICS", CS%do_dynamics, &
2602 "If False, skips the dynamics calls that update u & v, as well as "//&
2603 "the gravity wave adjustment to h. This may be a fragile feature, "//&
26041 "but can be useful during development", default=.true.)
2605 call get_param(param_file, "MOM", "ADVECT_TS", advect_TS, &
2606 "If True, advect temperature and salinity horizontally "//&
2607 "If False, T/S are registered for advection. "//&
2608 "This is intended only to be used in offline tracer mode "//&
2609 "and is by default false in that case.", &
26101 do_not_log=.true., default=.true.)
26111 if (present(offline_tracer_mode)) then ! Only read this parameter in enabled modes
2612 call get_param(param_file, "MOM", "OFFLINE_TRACER_MODE", CS%offline_tracer_mode, &
2613 "If true, barotropic and baroclinic dynamics, thermodynamics "//&
2614 "are all bypassed with all the fields necessary to integrate "//&
2615 "the tracer advection and diffusion equation are read in from "//&
2616 "files stored from a previous integration of the prognostic model. "//&
26171 "NOTE: This option only used in the ocean_solo_driver.", default=.false.)
26181 if (CS%offline_tracer_mode) then
2619 call get_param(param_file, "MOM", "ADVECT_TS", advect_TS, &
2620 "If True, advect temperature and salinity horizontally "//&
2621 "If False, T/S are registered for advection. "//&
2622 "This is intended only to be used in offline tracer mode, "//&
2623 "and is by default false in that case", &
26240 default=.false. )
2625 endif
2626 endif
2627 call get_param(param_file, "MOM", "USE_REGRIDDING", CS%use_ALE_algorithm, &
2628 "If True, use the ALE algorithm (regridding/remapping). "//&
26291 "If False, use the layered isopycnal algorithm.", default=.false. )
2630 call get_param(param_file, "MOM", "REMAP_UV_USING_OLD_ALG", CS%remap_uv_using_old_alg, &
2631 "If true, uses the old remapping-via-a-delta-z method for "//&
2632 "remapping u and v. If false, uses the new method that remaps "//&
2633 "between grids described by an old and new thickness.", &
26341 default=.false., do_not_log=.not.CS%use_ALE_algorithm)
2635 call get_param(param_file, "MOM", "REMAP_AUXILIARY_VARS", CS%remap_aux_vars, &
2636 "If true, apply ALE remapping to all of the auxiliary 3-dimensional "//&
2637 "variables that are needed to reproduce across restarts, similarly to "//&
2638 "what is already being done with the primary state variables. "//&
2639 "The default should be changed to true.", default=.false., &
26401 do_not_log=.not.CS%use_ALE_algorithm)
2641 call get_param(param_file, "MOM", "BULKMIXEDLAYER", bulkmixedlayer, &
2642 "If true, use a Kraus-Turner-like bulk mixed layer "//&
2643 "with transitional buffer layers. Layers 1 through "//&
2644 "NKML+NKBL have variable densities. There must be at "//&
2645 "least NKML+NKBL+1 layers if BULKMIXEDLAYER is true. "//&
2646 "BULKMIXEDLAYER can not be used with USE_REGRIDDING. "//&
2647 "The default is influenced by ENABLE_THERMODYNAMICS.", &
26481 default=use_temperature .and. .not.CS%use_ALE_algorithm)
2649 call get_param(param_file, "MOM", "USE_POROUS_BARRIER", CS%use_porbar, &
2650 "If true, use porous barrier to constrain the widths "//&
2651 "and face areas at the edges of the grid cells. ", &
26521 default=.false.)
2653 call get_param(param_file, "MOM", "BATHYMETRY_AT_VEL", bathy_at_vel, &
2654 "If true, there are separate values for the basin depths "//&
2655 "at velocity points. Otherwise the effects of topography "//&
2656 "are entirely determined from thickness points.", &
26571 default=.false.)
2658 call get_param(param_file, "MOM", "USE_WAVES", CS%UseWaves, default=.false., &
26591 do_not_log=.true.)
2660
2661 call get_param(param_file, "MOM", "DEBUG", CS%debug, &
2662 "If true, write out verbose debugging data.", &
26631 default=.false., debuggingParam=.true.)
2664 call get_param(param_file, "MOM", "DEBUG_TRUNCATIONS", debug_truncations, &
2665 "If true, calculate all diagnostics that are useful for "//&
26661 "debugging truncations.", default=.false., debuggingParam=.true.)
2667 call get_param(param_file, "MOM", "OBC_NUMBER_OF_SEGMENTS", number_of_OBC_segments, &
26681 default=0, do_not_log=.true.)
2669 call get_param(param_file, "MOM", "DEBUG_OBCS", CS%debug_OBCs, &
2670 "If true, write out verbose debugging data about OBCs.", &
26711 default=.false., debuggingParam=.true., do_not_log=(number_of_OBC_segments<=0))
2672 call get_param(param_file, "MOM", "ENABLE_BUGS_BY_DEFAULT", enable_bugs, &
2673 "If true, the defaults for certain recently added bug-fix flags are set to "//&
2674 "recreate the bugs so that the code can be moved forward without changing "//&
2675 "answers for existing configurations. The defaults for groups of bug-fix "//&
2676 "flags are periodically changed to correct the bugs, at which point this "//&
2677 "parameter will no longer be used to set their default. Setting this to false "//&
2678 "means that bugs are only used if they are actively selected, but it also "//&
2679 "means that answers may change when code is updated due to newly found bugs.", &
26801 default=.true.)
2681
2682 call get_param(param_file, "MOM", "DT", CS%dt, &
2683 "The (baroclinic) dynamics time step. The time-step that "//&
2684 "is actually used will be an integer fraction of the "//&
2685 "forcing time-step (DT_FORCING in ocean-only mode or the "//&
2686 "coupling timestep in coupled mode.)", units="s", scale=US%s_to_T, &
26871 fail_if_missing=.true.)
2688 call get_param(param_file, "MOM", "DT_THERM", CS%dt_therm, &
2689 "The thermodynamic time step. Ideally DT_THERM should be an "//&
2690 "integer multiple of DT and of DT_TRACER_ADVECT "//&
2691 "and less than the forcing or coupling time-step. However, if "//&
2692 "THERMO_SPANS_COUPLING is true, DT_THERM can be an integer multiple "//&
2693 "of the coupling timestep. By default DT_THERM is set to DT.", &
26941 units="s", scale=US%s_to_T, default=US%T_to_s*CS%dt)
2695 call get_param(param_file, "MOM", "THERMO_SPANS_COUPLING", CS%thermo_spans_coupling, &
2696 "If true, the MOM will take thermodynamic "//&
2697 "timesteps that can be longer than the coupling timestep. "//&
2698 "The actual thermodynamic timestep that is used in this "//&
2699 "case is the largest integer multiple of the coupling "//&
27001 "timestep that is less than or equal to DT_THERM.", default=.false.)
2701 call get_param(param_file, "MOM", "DT_TRACER_ADVECT", CS%dt_tr_adv, &
2702 "The tracer advection time step. Ideally DT_TRACER_ADVECT should be an "//&
2703 "integer multiple of DT, less than DT_THERM, and less than the forcing "//&
2704 "or coupling time-step. However, if TRADV_SPANS_COUPLING is true, "//&
2705 "DT_TRACER_ADVECT can be longer than the coupling timestep. By "//&
2706 "default DT_TRACER_ADVECT is set to DT_THERM.", &
27071 units="s", scale=US%s_to_T, default=US%T_to_s*CS%dt_therm)
2708 call get_param(param_file, "MOM", "TRADV_SPANS_COUPLING", CS%tradv_spans_coupling, &
2709 "If true, the MOM will take tracer advection "//&
2710 "timesteps that can be longer than the coupling timestep. "//&
2711 "The actual tracer advection timestep that is used in this "//&
2712 "case is the largest integer multiple of the coupling "//&
2713 "timestep that is less than or equal to DT_TRACER_ADVECT.", &
27141 default=CS%thermo_spans_coupling)
27151 if ( CS%diabatic_first .and. (CS%dt_tr_adv /= CS%dt_therm) ) then
27160 call MOM_error(FATAL,"MOM: If using DIABATIC_FIRST, DT_TRACER_ADVECT must equal DT_THERM.")
2717 endif
2718 call get_param(param_file, "MOM", "THICKNESSDIFFUSE", CS%thickness_diffuse, &
2719 "If true, isopycnal surfaces are diffused with a Laplacian "//&
27201 "coefficient of KHTH.", default=.false.)
2721 call get_param(param_file, "MOM", "APPLY_INTERFACE_FILTER", CS%interface_filter, &
2722 "If true, model interface heights are subjected to a grid-scale "//&
27231 "dependent spatial smoothing, often with biharmonic filter.", default=.false.)
2724 call get_param(param_file, "MOM", "THICKNESSDIFFUSE_FIRST", CS%thickness_diffuse_first, &
2725 "If true, do thickness diffusion or interface height smoothing before dynamics. "//&
2726 "This is only used if THICKNESSDIFFUSE or APPLY_INTERFACE_FILTER is true.", &
27271 default=.false., do_not_log=.not.(CS%thickness_diffuse.or.CS%interface_filter))
27281 CS%interface_filter_dt_bug = .false.
27291 if ((.not.CS%thickness_diffuse_first .and. CS%interface_filter) .or. &
2730 (CS%thickness_diffuse_first .and. (CS%thickness_diffuse .or. CS%interface_filter) &
2731 .and. (CS%dt_tr_adv /= CS%dt_therm))) then
2732 call get_param(param_file, "MOM", "INTERFACE_FILTER_DT_BUG", CS%interface_filter_dt_bug, &
2733 "If true, uses the wrong time interval in calls to interface_filter "//&
2734 "and thickness_diffuse. Has no effect when THICKNESSDIFFUSE_FIRST is "//&
2735 "true and DT_TRACER_ADVECT = DT_THERMO or when THICKNESSDIFFUSE_FIRST "//&
27360 "is false and APPLY_INTERFACE_FILTER is false. ", default=.false.)
2737 endif
2738
27391 if (bulkmixedlayer) then
27400 CS%Hmix = -1.0 ; CS%Hmix_UV = -1.0
2741 else
2742 call get_param(param_file, "MOM", "HMIX_SFC_PROP", Hmix_z, &
2743 "If BULKMIXEDLAYER is false, HMIX_SFC_PROP is the depth "//&
2744 "over which to average to find surface properties like "//&
2745 "SST and SSS or density (but not surface velocities).", &
27461 units="m", default=1.0, scale=US%m_to_Z)
2747 call get_param(param_file, "MOM", "HMIX_UV_SFC_PROP", Hmix_UV_z, &
2748 "If BULKMIXEDLAYER is false, HMIX_UV_SFC_PROP is the depth "//&
2749 "over which to average to find surface flow properties, "//&
2750 "SSU, SSV. A non-positive value indicates no averaging.", &
27511 units="m", default=0.0, scale=US%m_to_Z)
2752 endif
2753 call get_param(param_file, "MOM", "HFREEZE", HFrz_z, &
2754 "If HFREEZE > 0, melt potential will be computed. The actual depth "//&
2755 "over which melt potential is computed will be min(HFREEZE, OBLD), "//&
2756 "where OBLD is the boundary layer depth. If HFREEZE <= 0 (default), "//&
2757 "melt potential will not be computed.", &
27581 units="m", default=-1.0, scale=US%m_to_Z)
2759 call get_param(param_file, "MOM", "INTERPOLATE_P_SURF", CS%interp_p_surf, &
2760 "If true, linearly interpolate the surface pressure "//&
2761 "over the coupling time step, using the specified value "//&
27621 "at the end of the step.", default=.false.)
2763
27641 if (CS%split) then
27651 call get_param(param_file, "MOM", "DTBT", dtbt, units="s or nondim", default=-0.98)
27661 default_val = US%T_to_s*CS%dt_therm ; if (dtbt > 0.0) default_val = -1.0
27671 CS%dtbt_reset_period = -1.0
2768 call get_param(param_file, "MOM", "DTBT_RESET_PERIOD", CS%dtbt_reset_period, &
2769 "The period between recalculations of DTBT (if DTBT <= 0). "//&
2770 "If DTBT_RESET_PERIOD is negative, DTBT is set based "//&
2771 "only on information available at initialization. If 0, "//&
2772 "DTBT will be set every dynamics time step. The default "//&
2773 "is set by DT_THERM. This is only used if SPLIT is true.", &
27741 units="s", default=default_val, scale=US%s_to_T, do_not_read=(dtbt > 0.0))
2775 endif
2776
2777 call get_param(param_file, "MOM", "DT_OBC_SEG_UPDATE_OBGC", CS%dt_obc_seg_period, &
2778 "The time between OBC segment data updates for OBGC tracers. "//&
2779 "This must be an integer multiple of DT and DT_THERM. "//&
2780 "The default is set to DT.", &
27811 units="s", default=US%T_to_s*CS%dt, scale=US%s_to_T, do_not_log=.not.associated(OBC_in))
2782
2783 ! This is here in case these values are used inappropriately.
27841 use_frazil = .false. ; bound_salinity = .false. ; use_p_surf_in_EOS = .false.
27851 CS%tv%P_Ref = 2.0e7*US%Pa_to_RL2_T2
27861 if (use_temperature) then
2787 call get_param(param_file, "MOM", "FRAZIL", use_frazil, &
2788 "If true, water freezes if it gets too cold, and the "//&
2789 "accumulated heat deficit is returned in the "//&
2790 "surface state. FRAZIL is only used if "//&
27911 "ENABLE_THERMODYNAMICS is true.", default=.false.)
2792 call get_param(param_file, "MOM", "DO_GEOTHERMAL", use_geothermal, &
27931 "If true, apply geothermal heating.", default=.false.)
2794 call get_param(param_file, "MOM", "BOUND_SALINITY", bound_salinity, &
2795 "If true, limit salinity to being positive. (The sea-ice "//&
2796 "model may ask for more salt than is available and "//&
27971 "drive the salinity negative otherwise.)", default=.false.)
2798 call get_param(param_file, "MOM", "MIN_SALINITY", CS%tv%min_salinity, &
2799 "The minimum value of salinity when BOUND_SALINITY=True.", &
28001 units="PPT", default=0.0, scale=US%ppt_to_S, do_not_log=.not.bound_salinity)
2801 call get_param(param_file, "MOM", "SALINITY_UNDERFLOW", salin_underflow, &
2802 "A tiny value of salinity below which the it is set to 0. For reference, "//&
2803 "one molecule of salt per square meter of ocean is of order 1e-29 ppt.", &
28041 units="PPT", default=0.0, scale=US%ppt_to_S)
2805 call get_param(param_file, "MOM", "TEMPERATURE_UNDERFLOW", temp_underflow, &
2806 "A tiny magnitude of temperatures below which they are set to 0.", &
28071 units="degC", default=0.0, scale=US%degC_to_C)
2808 call get_param(param_file, "MOM", "C_P", CS%tv%C_p, &
2809 "The heat capacity of sea water, approximated as a constant. "//&
2810 "This is only used if ENABLE_THERMODYNAMICS is true. The default "//&
2811 "value is from the TEOS-10 definition of conservative temperature.", &
28121 units="J kg-1 K-1", default=3991.86795711963, scale=US%J_kg_to_Q*US%C_to_degC)
2813 call get_param(param_file, "MOM", "USE_PSURF_IN_EOS", use_p_surf_in_EOS, &
2814 "If true, always include the surface pressure contributions "//&
28151 "in equation of state calculations.", default=.true.)
2816 endif
28171 if (use_EOS) call get_param(param_file, "MOM", "P_REF", CS%tv%P_Ref, &
2818 "The pressure that is used for calculating the coordinate "//&
2819 "density. (1 Pa = 1e4 dbar, so 2e7 is commonly used.) "//&
2820 "This is only used if USE_EOS and ENABLE_THERMODYNAMICS are true.", &
28211 units="Pa", default=2.0e7, scale=US%Pa_to_RL2_T2)
2822
28231 if (bulkmixedlayer) then
2824 call get_param(param_file, "MOM", "NKML", nkml, &
2825 "The number of sublayers within the mixed layer if "//&
28260 "BULKMIXEDLAYER is true.", units="nondim", default=2)
2827 call get_param(param_file, "MOM", "NKBL", nkbl, &
2828 "The number of layers that are used as variable density buffer "//&
28290 "layers if BULKMIXEDLAYER is true.", units="nondim", default=2)
2830 endif
2831
2832 call get_param(param_file, "MOM", "GLOBAL_INDEXING", global_indexing, &
2833 "If true, use a global lateral indexing convention, so "//&
2834 "that corresponding points on different processors have "//&
2835 "the same index. This does not work with static memory.", &
28361 default=.false., layoutParam=.true.)
2837#ifdef STATIC_MEMORY_
2838 if (global_indexing) call MOM_error(FATAL, "initialize_MOM: "//&
2839 "GLOBAL_INDEXING can not be true with STATIC_MEMORY.")
2840#endif
2841 call get_param(param_file, "MOM", "FIRST_DIRECTION", first_direction, &
2842 "An integer that indicates which direction goes first "//&
2843 "in parts of the code that use directionally split "//&
2844 "updates, with even numbers (or 0) used for x- first "//&
28451 "and odd numbers used for y-first.", default=0)
2846 call get_param(param_file, "MOM", "ALTERNATE_FIRST_DIRECTION", CS%alternate_first_direction, &
2847 "If true, after every dynamic timestep alternate whether the x- or y- "//&
2848 "direction updates occur first in directionally split parts of the calculation. "//&
2849 "If this is true, FIRST_DIRECTION applies at the start of a new run or if "//&
28501 "the next first direction can not be found in the restart file.", default=.false.)
2851 call get_param(param_file, "MOM", "CHECK_BAD_SURFACE_VALS", CS%check_bad_sfc_vals, &
2852 "If true, check the surface state for ridiculous values.", &
28531 default=.false.)
28541 if (CS%check_bad_sfc_vals) then
2855 call get_param(param_file, "MOM", "BAD_VAL_SSH_MAX", CS%bad_val_ssh_max, &
2856 "The value of SSH above which a bad value message is "//&
2857 "triggered, if CHECK_BAD_SURFACE_VALS is true.", &
28580 units="m", default=20.0, scale=US%m_to_Z)
2859 call get_param(param_file, "MOM", "BAD_VAL_SSS_MAX", CS%bad_val_sss_max, &
2860 "The value of SSS above which a bad value message is "//&
2861 "triggered, if CHECK_BAD_SURFACE_VALS is true.", &
28620 units="PPT", default=45.0, scale=US%ppt_to_S)
2863 call get_param(param_file, "MOM", "BAD_VAL_SST_MAX", CS%bad_val_sst_max, &
2864 "The value of SST above which a bad value message is "//&
2865 "triggered, if CHECK_BAD_SURFACE_VALS is true.", &
28660 units="deg C", default=45.0, scale=US%degC_to_C)
2867 call get_param(param_file, "MOM", "BAD_VAL_SST_MIN", CS%bad_val_sst_min, &
2868 "The value of SST below which a bad value message is "//&
2869 "triggered, if CHECK_BAD_SURFACE_VALS is true.", &
28700 units="deg C", default=-2.1, scale=US%degC_to_C)
2871 call get_param(param_file, "MOM", "BAD_VAL_COLUMN_THICKNESS", CS%bad_val_col_thick, &
2872 "The value of column thickness below which a bad value message is "//&
2873 "triggered, if CHECK_BAD_SURFACE_VALS is true.", &
28740 units="m", default=0.0, scale=US%m_to_Z)
2875 endif
2876 call get_param(param_file, "MOM", "DEFAULT_ANSWER_DATE", default_answer_date, &
2877 "This sets the default value for the various _ANSWER_DATE parameters.", &
28781 default=99991231)
2879 call get_param(param_file, "MOM", "SURFACE_ANSWER_DATE", CS%answer_date, &
2880 "The vintage of the expressions for the surface properties. Values below "//&
2881 "20190101 recover the answers from the end of 2018, while higher values "//&
2882 "use updated and more robust forms of the same expressions.", &
28831 default=default_answer_date, do_not_log=non_Bous)
28841 if (non_Bous) CS%answer_date = 99991231
2885
2886 call get_param(param_file, "MOM", "SAVE_INITIAL_CONDS", save_IC, &
2887 "If true, write the initial conditions to a file given "//&
28881 "by IC_OUTPUT_FILE.", default=.false.)
2889 call get_param(param_file, "MOM", "IC_OUTPUT_FILE", CS%IC_file, &
2890 "The file into which to write the initial conditions.", &
28911 default="MOM_IC")
2892 call get_param(param_file, "MOM", "WRITE_GEOM", write_geom, &
2893 "If =0, never write the geometry and vertical grid files. "//&
2894 "If =1, write the geometry and vertical grid files only for "//&
2895 "a new simulation. If =2, always write the geometry and "//&
28961 "vertical grid files. Other values are invalid.", default=1)
28971 if (write_geom<0 .or. write_geom>2) call MOM_error(FATAL,"MOM: "//&
28980 "WRITE_GEOM must be equal to 0, 1 or 2.")
2899 call get_param(param_file, "MOM", "GEOM_FILE", geom_file, &
2900 "The file into which to write the ocean geometry.", &
29011 default="ocean_geometry")
2902 call get_param(param_file, "MOM", "USE_DBCLIENT", CS%use_dbclient, &
2903 "If true, initialize a client to a remote database that can "//&
2904 "be used for online analysis and machine-learning inference.",&
29051 default=.false.)
2906
2907 ! Check for inconsistent parameter settings.
29081 if (CS%use_ALE_algorithm .and. bulkmixedlayer) call MOM_error(FATAL, &
29090 "MOM: BULKMIXEDLAYER can not currently be used with the ALE algorithm.")
29101 if (CS%use_ALE_algorithm .and. .not.use_temperature) call MOM_error(FATAL, &
29110 "MOM: At this time, USE_EOS should be True when using the ALE algorithm.")
29121 if (CS%adiabatic .and. use_temperature) call MOM_error(WARNING, &
29130 "MOM: ADIABATIC and ENABLE_THERMODYNAMICS both defined is usually unwise.")
29141 if (use_EOS .and. .not.use_temperature) call MOM_error(FATAL, &
29150 "MOM: ENABLE_THERMODYNAMICS must be defined to use USE_EOS.")
29161 if (CS%adiabatic .and. bulkmixedlayer) call MOM_error(FATAL, &
29170 "MOM: ADIABATIC and BULKMIXEDLAYER can not both be defined.")
29181 if (bulkmixedlayer .and. .not.use_EOS) call MOM_error(FATAL, &
2919 "initialize_MOM: A bulk mixed layer can only be used with T & S as "//&
29200 "state variables. Add USE_EOS = True to MOM_input.")
2921
29221 use_ice_shelf = .false.
29231 if (present(ice_shelf_CSp)) then
2924 call get_param(param_file, "MOM", "ICE_SHELF", use_ice_shelf, &
29251 "If true, enables the ice shelf model.", default=.false.)
2926 endif
2927
2928 call get_param(param_file, "MOM", "USE_PARTICLES", CS%use_particles, &
29291 "If true, use the particles package.", default=.false.)
2930 call get_param(param_file, "MOM", "USE_UH_PARTICLES", CS%use_uh_particles, &
2931 "If true, use the uh velocity in the particles package.", &
29321 default=.false., do_not_log=.not.CS%use_particles)
2933 call get_param(param_file, "MOM", "UH_PARTICLES_BUG", CS%uh_particles_bug, &
2934 "If true, use a bug in which the particles are advected inconsistently"//&
2935 "with the dynamics timestep instead of the tracer timestep.", &
29361 default=enable_bugs, do_not_log=.not.CS%use_uh_particles)
29371 CS%ensemble_ocean=.false.
2938 call get_param(param_file, "MOM", "ENSEMBLE_OCEAN", CS%ensemble_ocean, &
2939 "If False, The model is being run in serial mode as a single realization. "//&
2940 "If True, The current model realization is part of a larger ensemble "//&
2941 "and at the end of step MOM, we will perform a gather of the ensemble "//&
29421 "members for statistical evaluation and/or data assimilation.", default=.false.)
2943
29441 call callTree_waypoint("MOM parameters read (initialize_MOM)")
2945
2946 call get_param(param_file, "MOM", "HOMOGENIZE_FORCINGS", CS%homogenize_forcings, &
29471 "If True, homogenize the forces and fluxes.", default=.false.)
2948 call get_param(param_file, "MOM", "UPDATE_USTAR",CS%update_ustar, &
2949 "If True, update ustar from homogenized tau when using the "//&
2950 "HOMOGENIZE_FORCINGS option. Note that this will not work "//&
2951 "with a non-zero gustiness factor.", default=.false., &
29521 do_not_log=.not.CS%homogenize_forcings)
2953
2954 ! Grid rotation test
2955 call get_param(param_file, "MOM", "ROTATE_INDEX", CS%rotate_index, &
2956 "Enable rotation of the horizontal indices.", default=.false., &
29571 debuggingParam=.true.)
29581 if (CS%rotate_index) then
2959 ! TODO: Index rotation currently only works when index rotation does not
2960 ! change the MPI rank of each domain. Resolving this will require a
2961 ! modification to FMS PE assignment.
2962 ! For now, we only permit single-core runs.
2963
29640 if (num_PEs() /= 1) &
29650 call MOM_error(FATAL, "Index rotation is only supported on one PE.")
2966
2967 ! Alternate_first_direction is not permitted with index rotation.
2968 ! This feature can be added later in the future if needed.
29690 if (CS%alternate_first_direction) &
29700 call MOM_error(FATAL, "Alternating_first_direction is not compatible with index rotation.")
2971
2972 call get_param(param_file, "MOM", "INDEX_TURNS", turns, &
2973 "Number of counterclockwise quarter-turn index rotations.", &
29740 default=1, debuggingParam=.true.)
2975 else
29761 turns = 0
2977 endif
2978
2979 ! Set up the model domain and grids.
2980#ifdef SYMMETRIC_MEMORY_
29811 symmetric = .true.
2982#else
2983 symmetric = .false.
2984#endif
29851 allocate(CS%G_in)
29861 G_in => CS%G_in
2987#ifdef STATIC_MEMORY_
2988 call MOM_domains_init(G_in%domain, param_file, symmetric=symmetric, &
2989 static_memory=.true., NIHALO=NIHALO_, NJHALO=NJHALO_, &
2990 NIGLOBAL=NIGLOBAL_, NJGLOBAL=NJGLOBAL_, NIPROC=NIPROC_, &
2991 NJPROC=NJPROC_, US=US, MOM_dom_unmasked=MOM_dom_unmasked)
2992#else
2993 call MOM_domains_init(G_in%domain, param_file, symmetric=symmetric, &
29941 domain_name="MOM_in", US=US, MOM_dom_unmasked=MOM_dom_unmasked)
2995#endif
2996
2997 ! Copy input grid (G_in) domain to active grid G
2998 ! Swap axes for quarter and 3-quarter turns
29991 if (CS%rotate_index) then
30000 allocate(CS%G)
30010 call clone_MOM_domain(G_in%Domain, CS%G%Domain, turns=turns, domain_name="MOM_rot")
3002 else
30031 CS%G => G_in
3004 endif
3005
3006 ! TODO: It is unlikely that test_grid_copy and rotate_index would work at the
3007 ! same time. It may be possible to enable both but for now we prevent it.
30081 if (test_grid_copy .and. CS%rotate_index) &
30090 call MOM_error(FATAL, "Grid cannot be copied during index rotation.")
3010
30111 if (test_grid_copy) then ; allocate(G)
30121 else ; G => CS%G ; endif
3013
30141 call callTree_waypoint("domains initialized (initialize_MOM)")
3015
30161 call MOM_debugging_init(param_file)
30171 call diag_mediator_infrastructure_init()
30181 call MOM_io_init(param_file)
3019
3020 ! Create HI and dG on the input index map.
3021 call hor_index_init(G_in%Domain, HI_in, param_file, &
30221 local_indexing=.not.global_indexing)
30231 call create_dyn_horgrid(dG_in, HI_in, bathymetry_at_vel=bathy_at_vel)
30241 call clone_MOM_domain(G_in%Domain, dG_in%Domain)
3025 ! Also allocate the input ocean_grid_type type at this point based on the same information.
30261 call MOM_grid_init(G_in, param_file, US, HI_in, bathymetry_at_vel=bathy_at_vel)
3027
3028 ! Allocate initialize time-invariant MOM variables.
30291 call MOM_initialize_fixed(dG_in, US, OBC_in, param_file)
3030
3031 ! Copy the grid metrics and bathymetry to the ocean_grid_type
30321 call copy_dyngrid_to_MOM_grid(dG_in, G_in, US)
3033
3034 !$omp target enter data map(to: CS%G_in)
3035 !$omp target enter data map(to: G%dxT, G%dxCu, G%dxCv, G%dxBu)
3036 !$omp target enter data map(to: G%dyT, G%dyCu, G%dyCv, G%dyBu)
3037 !$omp target enter data map(to: G%dx_Cv, G%dy_Cu)
3038 !$omp target enter data map(to: G%IdxT, G%IdxCu, G%IdxCv, G%IdxBu)
3039 !$omp target enter data map(to: G%IdyT, G%IdyCu, G%IdyCv, G%IdyBu)
3040 !$omp target enter data map(to: G%mask2dBu, G%mask2dT)
3041 !$omp target enter data map(to: G%areaT, G%areaCu, G%areaCv)
3042 !$omp target enter data map(to: G%IareaT, G%IareaCu, G%IareaCv, G%IareaBu)
3043 !$omp target enter data map(to: G%bathyT)
3044 !$omp target enter data map(to: G%CoriolisBu, G%Coriolis2Bu)
3045 !$omp target enter data map(to: G%mask2dCu, G%mask2dCv)
3046 !$omp target enter data map(to: G%OBCmaskCu, G%OBCmaskCv)
3047 !$omp target enter data map(to: G%IdxCu_OBCmask, G%IdyCv_OBCmask)
3048 ! NOTE: This may be time dependent
3049 !$omp target enter data map(to: G%meanSL)
3050
30511 call callTree_waypoint("returned from MOM_initialize_fixed() (initialize_MOM)")
3052
30531 call verticalGridInit( param_file, CS%GV, US )
30541 GV => CS%GV
3055
3056 ! This does not work. GV%RLay changes sometime later.
3057 !!!$omp target enter data map(to: GV, GV%Rlay, GV%g_prime)
3058
3059 ! Now that the vertical grid has been initialized, rescale parameters that depend on factors
3060 ! that are set with the vertical grid to their desired units. This added rescaling step would
3061 ! be unnecessary if the vertical grid were initialized earlier in this routine.
30621 if (.not.bulkmixedlayer) then
30631 CS%Hmix = (US%Z_to_m * GV%m_to_H) * Hmix_z
30641 CS%Hmix_UV = (US%Z_to_m * GV%m_to_H) * Hmix_UV_z
3065 endif
30661 CS%HFrz = (US%Z_to_m * GV%m_to_H) * HFrz_z
3067
3068 ! Shift from using the temporary dynamic grid type to using the final (potentially static)
3069 ! and properly rotated ocean-specific grid type and horizontal index type.
30701 if (CS%rotate_index) then
30710 allocate(HI)
30720 call rotate_hor_index(HI_in, turns, HI)
3073 ! NOTE: If indices are rotated, then G and G_in must both be initialized separately, and
3074 ! the dynamic grid must be created to handle the grid rotation. G%domain has already been
3075 ! initialized above.
30760 call MOM_grid_init(G, param_file, US, HI, bathymetry_at_vel=bathy_at_vel)
30770 call create_dyn_horgrid(dG, HI, bathymetry_at_vel=bathy_at_vel)
30780 call clone_MOM_domain(G%Domain, dG%Domain)
30790 call rotate_dyn_horgrid(dG_in, dG, US, turns)
30800 call copy_dyngrid_to_MOM_grid(dG, G, US)
3081
30820 if (associated(OBC_in)) then
30830 allocate(CS%OBC)
30840 call rotate_OBC_config(OBC_in, dG_in, CS%OBC, dG, turns)
3085 endif
3086
30870 call destroy_dyn_horgrid(dG)
3088 else
3089 ! If not rotated, then G_in and G are the same grid.
30901 HI => HI_in
30911 G => G_in
30921 CS%OBC => OBC_in
3093 endif
3094 ! dG_in is retained for now so that it can be used with write_ocean_geometry_file() below.
3095
30961 if (is_root_PE()) call check_MOM6_scaling_factors(CS%GV, US)
3097
30981 call callTree_waypoint("grids initialized (initialize_MOM)")
3099
31001 call MOM_timing_init(CS)
3101
31021 call tracer_registry_init(param_file, CS%tracer_Reg)
3103
3104 !$omp target update to(CS)
3105
3106 ! Allocate and initialize space for the primary time-varying MOM variables.
31071 is = HI%isc ; ie = HI%iec ; js = HI%jsc ; je = HI%jec ; nz = GV%ke
31081 isd = HI%isd ; ied = HI%ied ; jsd = HI%jsd ; jed = HI%jed
31091 IsdB = HI%IsdB ; IedB = HI%IedB ; JsdB = HI%JsdB ; JedB = HI%JedB
3110663076 ALLOC_(CS%u(IsdB:IedB,jsd:jed,nz)) ; CS%u(:,:,:) = 0.0
3111667651 ALLOC_(CS%v(isd:ied,JsdB:JedB,nz)) ; CS%v(:,:,:) = 0.0
3112657976 ALLOC_(CS%h(isd:ied,jsd:jed,nz)) ; CS%h(:,:,:) = GV%Angstrom_H
3113663076 ALLOC_(CS%uh(IsdB:IedB,jsd:jed,nz)) ; CS%uh(:,:,:) = 0.0
3114667651 ALLOC_(CS%vh(isd:ied,JsdB:JedB,nz)) ; CS%vh(:,:,:) = 0.0
3115 !$omp target enter data map(to: CS%u, CS%v, CS%h, CS%uh, CS%vh)
31161 if (use_temperature) then
3117657976 ALLOC_(CS%T(isd:ied,jsd:jed,nz)) ; CS%T(:,:,:) = 0.0
3118657976 ALLOC_(CS%S(isd:ied,jsd:jed,nz)) ; CS%S(:,:,:) = 0.0
31191 CS%tv%T => CS%T ; CS%tv%S => CS%S
31201 if (CS%tv%T_is_conT) then
3121 vd_T = var_desc(name="contemp", units="Celsius", longname="Conservative Temperature", &
3122 cmor_field_name="bigthetao", cmor_longname="Sea Water Conservative Temperature", &
31230 conversion=US%C_to_degC)
3124 else
3125 vd_T = var_desc(name="temp", units="degC", longname="Potential Temperature", &
3126 cmor_field_name="thetao", cmor_longname="Sea Water Potential Temperature", &
31276 conversion=US%C_to_degC)
3128 endif
31291 if (CS%tv%S_is_absS) then
3130 vd_S = var_desc(name="abssalt", units="g kg-1", longname="Absolute Salinity", &
3131 cmor_field_name="absso", cmor_longname="Sea Water Absolute Salinity", &
31320 conversion=US%S_to_ppt)
3133 else
3134 vd_S = var_desc(name="salt", units="psu", longname="Salinity", &
3135 cmor_field_name="so", cmor_longname="Sea Water Salinity", &
31366 conversion=US%S_to_ppt)
3137 endif
3138
31391 if (advect_TS) then
31401 S_flux_units = get_tr_flux_units(GV, "psu") ! Could change to "kg m-2 s-1"?
31411 conv2watt = GV%H_to_kg_m2 * US%Q_to_J_kg*CS%tv%C_p
31421 if (GV%Boussinesq) then
31431 conv2salt = US%S_to_ppt*GV%H_to_m ! Could change to US%S_to_ppt*GV%H_to_kg_m2 * 0.001?
3144 else
31450 conv2salt = US%S_to_ppt*GV%H_to_kg_m2
3146 endif
3147 call register_tracer(CS%tv%T, CS%tracer_Reg, param_file, HI, GV, &
3148 tr_desc=vd_T, registry_diags=.true., conc_scale=US%C_to_degC, &
3149 flux_nameroot='T', flux_units='W', flux_longname='Heat', &
3150 net_surfflux_name='KPP_QminusSW', NLT_budget_name='KPP_NLT_temp_budget', &
3151 net_surfflux_longname='Net temperature flux ignoring short-wave, as used by [CVMix] KPP', &
3152 flux_scale=conv2watt, convergence_units='W m-2', &
3153 convergence_scale=conv2watt, CMOR_tendprefix="opottemp", &
31541 diag_form=2, underflow_conc=temp_underflow, Tr_out=CS%tv%tr_T)
3155 call register_tracer(CS%tv%S, CS%tracer_Reg, param_file, HI, GV, &
3156 tr_desc=vd_S, registry_diags=.true., conc_scale=US%S_to_ppt, &
3157 flux_nameroot='S', flux_units=S_flux_units, flux_longname='Salt', &
3158 net_surfflux_name='KPP_netSalt', NLT_budget_name='KPP_NLT_saln_budget', &
3159 flux_scale=conv2salt, convergence_units='kg m-2 s-1', &
3160 convergence_scale=0.001*US%S_to_ppt*GV%H_to_kg_m2, CMOR_tendprefix="osalt", &
31611 diag_form=2, underflow_conc=salin_underflow, Tr_out=CS%tv%tr_S)
3162 endif
3163 endif
3164
31658773 if (use_p_surf_in_EOS) allocate(CS%tv%p_surf(isd:ied,jsd:jed), source=0.0)
31661 if (use_frazil) then
31678773 allocate(CS%tv%frazil(isd:ied,jsd:jed), source=0.0)
31681 CS%tv%frazil_was_reset = .true.
3169 endif
31701 if (bound_salinity) allocate(CS%tv%salt_deficit(isd:ied,jsd:jed), source=0.0)
3171
31728773 allocate(CS%Hml(isd:ied,jsd:jed), source=0.0)
3173
31741 if (bulkmixedlayer) then
31750 GV%nkml = nkml ; GV%nk_rho_varies = nkml + nkbl
3176 else
31771 GV%nkml = 0 ; GV%nk_rho_varies = 0
3178 endif
31791 if (CS%use_ALE_algorithm) then
31801 call get_param(param_file, "MOM", "NK_RHO_VARIES", GV%nk_rho_varies, default=0) ! Will default to nz later... -AJA
3181 endif
3182
3183663076 ALLOC_(CS%uhtr(IsdB:IedB,jsd:jed,nz)) ; CS%uhtr(:,:,:) = 0.0
3184667651 ALLOC_(CS%vhtr(isd:ied,JsdB:JedB,nz)) ; CS%vhtr(:,:,:) = 0.0
3185 !$omp target enter data map(to: CS%uhtr, CS%vhtr)
31861 CS%t_dyn_rel_adv = 0.0 ; CS%t_dyn_rel_thermo = 0.0 ; CS%t_dyn_rel_diag = 0.0
31871 CS%n_dyn_steps_in_adv = 0
3188
31891 allocate(CS%ADp)
3190 !$omp target enter data map(alloc: CS%ADp)
3191
31921 if (debug_truncations) then
31930 allocate(CS%u_prev(IsdB:IedB,jsd:jed,nz), source=0.0)
31940 allocate(CS%v_prev(isd:ied,JsdB:JedB,nz), source=0.0)
31950 MOM_internal_state%u_prev => CS%u_prev
31960 MOM_internal_state%v_prev => CS%v_prev
31970 call safe_alloc_ptr(CS%ADp%du_dt_visc,IsdB,IedB,jsd,jed,nz)
31980 call safe_alloc_ptr(CS%ADp%dv_dt_visc,isd,ied,JsdB,JedB,nz)
31990 if (.not.CS%adiabatic) then
32000 call safe_alloc_ptr(CS%ADp%du_dt_dia,IsdB,IedB,jsd,jed,nz)
32010 call safe_alloc_ptr(CS%ADp%dv_dt_dia,isd,ied,JsdB,JedB,nz)
3202 endif
3203 endif
3204
32051 MOM_internal_state%u => CS%u ; MOM_internal_state%v => CS%v
32061 MOM_internal_state%h => CS%h
32071 MOM_internal_state%uh => CS%uh ; MOM_internal_state%vh => CS%vh
32081 if (use_temperature) then
32091 MOM_internal_state%T => CS%T ; MOM_internal_state%S => CS%S
3210 endif
3211
32121 CS%CDp%uh => CS%uh ; CS%CDp%vh => CS%vh
3213
32141 if (CS%interp_p_surf) allocate(CS%p_surf_prev(isd:ied,jsd:jed), source=0.0)
3215
32168773 ALLOC_(CS%ssh_rint(isd:ied,jsd:jed)) ; CS%ssh_rint(:,:) = 0.0
3217 !$omp target enter data map(to: CS%ssh_rint)
32188773 ALLOC_(CS%ave_ssh_ibc(isd:ied,jsd:jed)) ; CS%ave_ssh_ibc(:,:) = 0.0
3219 !$omp target enter data map(to: CS%ave_ssh_ibc)
32208773 ALLOC_(CS%eta_av_bc(isd:ied,jsd:jed)) ; CS%eta_av_bc(:,:) = 0.0 ! -G%Z_ref
3221 !$omp target enter data map(to: CS%eta_av_bc)
32221 CS%time_in_cycle = 0.0 ; CS%time_in_thermo_cycle = 0.0
3223
3224 !allocate porous topography variables
3225663076 allocate(CS%pbv%por_face_areaU(IsdB:IedB,jsd:jed,nz), source=1.0)
3226667651 allocate(CS%pbv%por_face_areaV(isd:ied,JsdB:JedB,nz), source=1.0)
3227671917 allocate(CS%pbv%por_layer_widthU(IsdB:IedB,jsd:jed,nz+1), source=1.0)
3228676553 allocate(CS%pbv%por_layer_widthV(isd:ied,JsdB:JedB,nz+1), source=1.0)
3229 !$omp target enter data map(to: CS%pbv)
3230 !$omp target enter data map(to: CS%pbv%por_face_areaU, CS%pbv%por_face_areaV)
3231 !$omp target enter data map(to: CS%pbv%por_layer_widthU, CS%pbv%por_layer_widthV)
3232
3233 ! Use the Wright equation of state by default, unless otherwise specified
3234 ! Note: this line and the following block ought to be in a separate
3235 ! initialization routine for tv.
32361 if (use_EOS) then
32371 allocate(CS%tv%eqn_of_state)
32381 call EOS_init(param_file, CS%tv%eqn_of_state, US, use_conT_absS)
3239 endif
32401 if (use_temperature) then
32418773 allocate(CS%tv%TempxPmE(isd:ied,jsd:jed), source=0.0)
32421 if (use_geothermal) then
32438773 allocate(CS%tv%internal_heat(isd:ied,jsd:jed), source=0.0)
3244 endif
3245 endif
32461 call callTree_waypoint("state variables allocated (initialize_MOM)")
3247
3248 ! Set the fields that are needed for bitwise identical restarting
3249 ! the time stepping scheme.
32501 call restart_init(param_file, CS%restart_CS)
32511 restart_CSp => CS%restart_CS
3252
32531 call set_restart_fields(GV, US, param_file, CS, restart_CSp)
32541 if (CS%split .and. CS%use_alt_split) then
3255 call register_restarts_dyn_split_RK2b(HI, GV, US, param_file, &
32560 CS%dyn_split_RK2b_CSp, restart_CSp, CS%uh, CS%vh)
32571 elseif (CS%split) then
32581 allocate(CS%dyn_split_RK2_CSp)
3259 !$omp target enter data map(alloc: CS%dyn_split_RK2_CSp)
3260 call register_restarts_dyn_split_RK2(HI, GV, US, param_file, &
32611 CS%dyn_split_RK2_CSp, restart_CSp, CS%uh, CS%vh)
32620 elseif (CS%use_RK2) then
3263 call register_restarts_dyn_unsplit_RK2(HI, GV, param_file, &
32640 CS%dyn_unsplit_RK2_CSp)
3265 else
3266 call register_restarts_dyn_unsplit(HI, GV, param_file, &
32670 CS%dyn_unsplit_CSp)
3268 endif
3269
3270 ! This subroutine calls user-specified tracer registration routines.
3271 ! Additional calls can be added to MOM_tracer_flow_control.F90.
3272 call call_tracer_register(G, GV, US, param_file, CS%tracer_flow_CSp, &
32731 CS%tracer_Reg, restart_CSp)
3274
32751 call MEKE_alloc_register_restart(HI, US, param_file, CS%MEKE, restart_CSp)
3276
32771 allocate(CS%visc)
3278 !$omp target enter data map(alloc: CS%visc)
32791 call set_visc_register_restarts(HI, G, GV, US, param_file, CS%visc, restart_CSp, use_ice_shelf)
3280
3281 call mixedlayer_restrat_register_restarts(HI, GV, US, param_file, &
32821 CS%mixedlayer_restrat_CSp, restart_CSp)
3283
32841 if (associated(CS%OBC)) then
3285 ! This call initializes the relevant vertical remapping structures.
32860 call open_boundary_setup_vert(GV, US, CS%OBC)
3287
3288 ! Set up remaining information about open boundary conditions that is needed for OBCs.
3289 ! Package specific changes to OBCs occur here.
32900 call call_OBC_register(G, GV, US, param_file, CS%update_OBC_CSp, CS%OBC, CS%tracer_Reg)
3291
3292 ! This is the equivalent to 2 calls to register_segment_tracer (per segment), which
3293 ! could occur with the call to update_OBC_data or after the main initialization.
32940 if (use_temperature) &
32950 call register_temp_salt_segments(GV, US, CS%OBC, CS%tracer_Reg, param_file)
3296 ! This is the equivalent call to register_temp_salt_segments for external tracers with OBC
32970 call call_tracer_register_obc_segments(GV, param_file, CS%tracer_flow_CSp, CS%tracer_Reg, CS%OBC)
3298
3299 ! Set up the thickness reservoirs if using them.
33000 if (CS%OBC%use_h_res) &
33010 call segment_thickness_reservoir_init(GV, US, CS%OBC, param_file)
3302
3303 ! This needs the number of tracers and to have called any code that sets whether
3304 ! reservoirs are used.
3305 call open_boundary_register_restarts(HI, GV, US, CS%OBC, CS%tracer_Reg, &
33060 param_file, restart_CSp, use_temperature)
3307
3308 ! This call allocates the arrays on the segments for open boundary data, but it must occur
3309 ! after any calls to call_tracer_register_obc_segments.
33100 call initialize_segment_data(GV, US, CS%OBC, param_file, turns, use_temperature)
3311
33120 if (CS%debug_OBCs) call write_OBC_info(CS%OBC, G, GV, US)
3313 endif
3314
33151 if (present(waves_CSp)) then
33161 call waves_register_restarts(waves_CSp, HI, GV, US, param_file, restart_CSp)
3317 endif
3318
33191 if (use_temperature) then
33201 call stoch_EOS_register_restarts(HI, param_file, CS%stoch_eos_CS, restart_CSp)
3321 endif
3322
33231 if (.not. CS%adiabatic) then
33241 call register_diabatic_restarts(G, GV, US, param_file, CS%int_tide_CSp, restart_CSp, CS%diabatic_CSp)
3325 endif
3326
33271 call callTree_waypoint("restart registration complete (initialize_MOM)")
33281 call restart_registry_lock(restart_CSp)
3329
3330 ! Write out all of the grid data used by this run.
33311 new_sim = determine_is_new_run(dirs%input_filename, dirs%restart_input_dir, G_in, restart_CSp)
33321 write_geom_files = ((write_geom==2) .or. ((write_geom==1) .and. new_sim))
33331 if (write_geom_files) then
33340 if (associated(MOM_dom_unmasked)) then
3335 call hor_index_init(MOM_dom_unmasked, HI_in_unmasked, param_file, &
33360 local_indexing=.not.global_indexing)
33370 call create_dyn_horgrid(dG_unmasked_in, HI_in_unmasked, bathymetry_at_vel=bathy_at_vel)
33380 call clone_MOM_domain(MOM_dom_unmasked, dG_unmasked_in%Domain)
33390 call MOM_initialize_fixed(dG_unmasked_in, US, OBC_in, param_file)
33400 call write_ocean_geometry_file(dG_unmasked_in, param_file, dirs%output_directory, US=US, geom_file=geom_file)
33410 call deallocate_MOM_domain(MOM_dom_unmasked)
33420 call destroy_dyn_horgrid(dG_unmasked_in)
3343 else
33440 call write_ocean_geometry_file(dG_in, param_file, dirs%output_directory, US=US, geom_file=geom_file)
3345 endif
3346 endif
33471 call destroy_dyn_horgrid(dG_in)
3348
3349 ! Initialize dynamically evolving fields, perhaps from restart files.
33501 call cpu_clock_begin(id_clock_MOM_init)
33511 call MOM_initialize_coord(GV, US, param_file, CS%tv, G%max_depth)
33521 call callTree_waypoint("returned from MOM_initialize_coord() (initialize_MOM)")
3353
33541 if (CS%use_ALE_algorithm) then
33551 call ALE_init(param_file, G, GV, US, G%max_depth, CS%ALE_CSp)
33561 call callTree_waypoint("returned from ALE_init() (initialize_MOM)")
3357 endif
3358
3359 ! Set a few remaining fields that are specific to the ocean grid type.
33601 if (CS%rotate_index) then
33610 call set_first_direction(G, modulo(first_direction + turns, 2))
3362 else
33631 call set_first_direction(G, modulo(first_direction, 2))
3364 endif
3365 ! Allocate the auxiliary non-symmetric domain for debugging or I/O purposes.
33661 if (CS%debug .or. G%symmetric) then
33671 call clone_MOM_domain(G%Domain, G%Domain_aux, symmetric=.false.)
33680 else ; G%Domain_aux => G%Domain ; endif
3369 ! Copy common variables from the vertical grid to the horizontal grid.
3370 ! Consider removing this later?
33711 G%ke = GV%ke
3372
33731 if (use_ice_shelf) then
33740 point_calving = .false. ; if (present(calve_ice_shelf_bergs)) point_calving = calve_ice_shelf_bergs
3375 endif
3376
33771 if (CS%rotate_index) then
33780 G_in%ke = GV%ke
3379
3380 ! Allocate the auxiliary non-symmetric domain for debugging or I/O purposes.
33810 if (CS%debug .or. G_in%symmetric) then
33820 call clone_MOM_domain(G_in%Domain, G_in%Domain_aux, symmetric=.false.)
33830 else ; G_in%Domain_aux => G_in%Domain ; endif
3384
33850 allocate(u_in(G_in%IsdB:G_in%IedB, G_in%jsd:G_in%jed, nz), source=0.0)
33860 allocate(v_in(G_in%isd:G_in%ied, G_in%JsdB:G_in%JedB, nz), source=0.0)
33870 allocate(h_in(G_in%isd:G_in%ied, G_in%jsd:G_in%jed, nz), source=GV%Angstrom_H)
3388
33890 if (use_temperature) then
33900 allocate(T_in(G_in%isd:G_in%ied, G_in%jsd:G_in%jed, nz), source=0.0)
33910 allocate(S_in(G_in%isd:G_in%ied, G_in%jsd:G_in%jed, nz), source=0.0)
3392
33930 CS%tv%T => T_in
33940 CS%tv%S => S_in
3395
33960 if (associated(CS%OBC)) then
3397 ! Log this parameter in MOM_initialize_state
3398 call get_param(param_file, "MOM", "OBC_RESERVOIR_INIT_BUG", OBC_reservoir_init_bug, &
3399 "If true, set the OBC tracer reservoirs at the startup of a new run from the "//&
3400 "interior tracer concentrations regardless of properties that may be explicitly "//&
34010 "specified for the reservoir concentrations.", default=enable_bugs, do_not_log=.true.)
34020 if (OBC_reservoir_init_bug .and. (allocated(CS%OBC%tres_x) .or. allocated(CS%OBC%tres_y))) &
34030 call MOM_error(FATAL, "OBC_RESERVOIR_INIT_BUG can not be set to true with grid rotation.")
3404 endif
3405 endif
3406
34070 if (use_ice_shelf) then
3408 ! These arrays are not initialized in most solo cases, but are needed
3409 ! when using an ice shelf. Passing the ice shelf diagnostics CS from MOM
3410 ! for legacy reasons. The actual ice shelf diag CS is internal to the ice shelf
3411 call initialize_ice_shelf(param_file, G, Time, ice_shelf_CSp, diag_ptr, &
34120 Time_init, dirs%output_directory, calve_ice_shelf_bergs=point_calving)
34130 allocate(frac_shelf_in(G_in%isd:G_in%ied, G_in%jsd:G_in%jed), source=0.0)
34140 allocate(mass_shelf_in(G_in%isd:G_in%ied, G_in%jsd:G_in%jed), source=0.0)
34150 allocate(CS%frac_shelf_h(isd:ied, jsd:jed), source=0.0)
34160 allocate(CS%mass_shelf(isd:ied, jsd:jed), source=0.0)
34170 call ice_shelf_query(ice_shelf_CSp, G, CS%frac_shelf_h, CS%mass_shelf)
3418 ! MOM_initialize_state is using the unrotated metric
34190 call rotate_array(CS%frac_shelf_h, -turns, frac_shelf_in)
34200 call rotate_array(CS%mass_shelf, -turns, mass_shelf_in)
3421 call MOM_initialize_state(u_in, v_in, h_in, CS%tv, Time, G_in, GV, US, &
3422 param_file, dirs, restart_CSp, CS%ALE_CSp, CS%tracer_Reg, &
3423 sponge_in_CSp, ALE_sponge_in_CSp, oda_incupd_in_CSp, OBC_in, Time_in, &
34240 frac_shelf_h=frac_shelf_in, mass_shelf=mass_shelf_in)
3425 else
3426 call MOM_initialize_state(u_in, v_in, h_in, CS%tv, Time, G_in, GV, US, &
3427 param_file, dirs, restart_CSp, CS%ALE_CSp, CS%tracer_Reg, &
34280 sponge_in_CSp, ALE_sponge_in_CSp, oda_incupd_in_CSp, OBC_in, Time_in)
3429 endif
3430
34310 if (use_temperature) then
34320 CS%tv%T => CS%T
34330 CS%tv%S => CS%S
3434 endif
3435
3436 ! Reset the first direction if it was found in a restart file
34370 if (CS%first_dir_restart > -1.0) then
34380 call set_first_direction(G, modulo(NINT(CS%first_dir_restart) + turns, 2))
3439 else
34400 CS%first_dir_restart = real(modulo(first_direction, 2))
3441 endif
3442
3443 call rotate_initial_state(u_in, v_in, h_in, T_in, S_in, use_temperature, &
34440 turns, CS%u, CS%v, CS%h, CS%T, CS%S)
3445
34460 if (associated(sponge_in_CSp)) then
3447 ! TODO: Implementation and testing of non-ALE sponge rotation
34480 call MOM_error(FATAL, "Index rotation of non-ALE sponge is not yet implemented.")
3449 endif
3450
34510 if (associated(ALE_sponge_in_CSp)) then
34520 call rotate_ALE_sponge(ALE_sponge_in_CSp, G_in, CS%ALE_sponge_CSp, G, GV, US, turns, param_file)
34530 call update_ALE_sponge_field(CS%ALE_sponge_CSp, T_in, G, GV, CS%T)
34540 call update_ALE_sponge_field(CS%ALE_sponge_CSp, S_in, G, GV, CS%S)
3455 endif
3456
3457 ! Deallocate the unrotated arrays and types that are no longer needed.
34580 deallocate(u_in)
34590 deallocate(v_in)
34600 deallocate(h_in)
34610 if (use_temperature) then
34620 deallocate(T_in)
34630 deallocate(S_in)
3464 endif
34650 if (use_ice_shelf) deallocate(frac_shelf_in, mass_shelf_in)
34660 if (associated(OBC_in)) call open_boundary_end(OBC_in)
3467
3468 else ! The model is being run without grid rotation. This is true of all production runs.
34691 if (use_ice_shelf) then
3470 call initialize_ice_shelf(param_file, G, Time, ice_shelf_CSp, diag_ptr, Time_init, &
34710 dirs%output_directory, calve_ice_shelf_bergs=point_calving)
34720 allocate(CS%frac_shelf_h(isd:ied, jsd:jed), source=0.0)
34730 allocate(CS%mass_shelf(isd:ied, jsd:jed), source=0.0)
34740 call ice_shelf_query(ice_shelf_CSp,G,CS%frac_shelf_h, CS%mass_shelf)
3475 call MOM_initialize_state(CS%u, CS%v, CS%h, CS%tv, Time, G, GV, US, &
3476 param_file, dirs, restart_CSp, CS%ALE_CSp, CS%tracer_Reg, &
3477 CS%sponge_CSp, CS%ALE_sponge_CSp, CS%oda_incupd_CSp, CS%OBC, Time_in, &
34780 frac_shelf_h=CS%frac_shelf_h, mass_shelf=CS%mass_shelf, OBC_for_bug=CS%OBC)
3479 else
3480 call MOM_initialize_state(CS%u, CS%v, CS%h, CS%tv, Time, G, GV, US, &
3481 param_file, dirs, restart_CSp, CS%ALE_CSp, CS%tracer_Reg, &
34821 CS%sponge_CSp, CS%ALE_sponge_CSp, CS%oda_incupd_CSp, CS%OBC, Time_in, OBC_for_bug=CS%OBC)
3483 endif
3484
3485 ! Reset the first direction if it was found in a restart file.
34861 if (CS%first_dir_restart > -1.0) then
34870 call set_first_direction(G, NINT(CS%first_dir_restart))
3488 else
34891 CS%first_dir_restart = real(modulo(first_direction, 2))
3490 endif
3491 endif
3492
3493 ! Allocate any derived densities or other equation of state derived fields.
34941 if (.not.(GV%Boussinesq .or. GV%semi_Boussinesq)) then
34950 allocate(CS%tv%SpV_avg(isd:ied,jsd:jed,nz), source=0.0)
34960 CS%tv%valid_SpV_halo = -1 ! This array does not yet have any valid data.
3497 endif
3498
34991 if (associated(CS%OBC)) then
35000 call MOM_initialize_OBCs(CS%h, CS%tv, CS%OBC, Time, G, GV, US, param_file, restart_CSp, CS%tracer_Reg)
3501
35020 if (use_temperature) then
35030 call pass_var(CS%tv%T, G%Domain, complete=.false.)
35040 call pass_var(CS%tv%S, G%Domain, complete=.true.)
3505 endif
35060 call calc_derived_thermo(CS%tv, CS%h, G, GV, US)
3507
3508 ! Call this during initialization to fill boundary arrays from fixed values
35090 call read_OBC_segment_data(G, GV, US, CS%OBC, CS%tv, CS%h, Time)
35100 call update_OBC_segment_data(G, GV, US, CS%OBC, CS%h, Time)
35110 call initialize_OBC_segment_reservoirs(GV, CS%OBC)
3512 endif
3513
35141 if (use_ice_shelf .and. CS%debug) then
35150 call hchksum(CS%frac_shelf_h, "MOM:frac_shelf_h", G%HI, haloshift=0)
35160 call hchksum(CS%mass_shelf, "MOM:mass_shelf", G%HI, haloshift=0, unscale=US%RZ_to_kg_m2)
3517 endif
3518
35191 call cpu_clock_end(id_clock_MOM_init)
35201 call callTree_waypoint("returned from MOM_initialize_state() (initialize_MOM)")
3521
3522 ! From this point, there may be pointers being set, so the final grid type
3523 ! that will persist throughout the run has to be used.
3524
35251 if (test_grid_copy) then
3526 ! Copy the data from the temporary grid to the dyn_hor_grid to CS%G.
35270 call create_dyn_horgrid(test_dG, G%HI)
35280 call clone_MOM_domain(G%Domain, test_dG%Domain)
3529
35300 call clone_MOM_domain(G%Domain, CS%G%Domain)
35310 call MOM_grid_init(CS%G, param_file, US)
3532
35330 call copy_MOM_grid_to_dyngrid(G, test_dG, US)
35340 call copy_dyngrid_to_MOM_grid(test_dG, CS%G, US)
3535
35360 call destroy_dyn_horgrid(test_dG)
35370 call MOM_grid_end(G) ; deallocate(G)
3538
35390 G => CS%G
35400 if (CS%debug .or. CS%G%symmetric) then
35410 call clone_MOM_domain(CS%G%Domain, CS%G%Domain_aux, symmetric=.false.)
35420 else ; CS%G%Domain_aux => CS%G%Domain ; endif
35430 G%ke = GV%ke
3544 endif
3545
3546 ! At this point, all user-modified initialization code has been called. The
3547 ! remainder of this subroutine is controlled by the parameters that have
3548 ! have already been set.
3549
35501 if (ALE_remap_init_conds(CS%ALE_CSp) .and. .not. query_initialized(CS%h,"h",restart_CSp)) then
3551 ! This block is controlled by the ALE parameter REMAP_AFTER_INITIALIZATION.
3552 ! \todo This block exists for legacy reasons and we should phase it out of all examples. !###
35531 if (CS%debug) then
35540 call uvchksum("Pre ALE adjust init cond [uv]", CS%u, CS%v, G%HI, haloshift=1, unscale=US%L_T_to_m_s)
35550 call hchksum(CS%h,"Pre ALE adjust init cond h", G%HI, haloshift=1, unscale=GV%H_to_MKS)
3556 endif
35571 call callTree_waypoint("Calling adjustGridForIntegrity() to remap initial conditions (initialize_MOM)")
35581 call adjustGridForIntegrity(CS%ALE_CSp, G, GV, CS%h )
35591 if (allocated(CS%tv%SpV_avg)) call calc_derived_thermo(CS%tv, CS%h, G, GV, US, halo=1)
35601 call pre_ALE_adjustments(G, GV, US, CS%h, CS%tv, CS%tracer_Reg, CS%ALE_CSp, CS%u, CS%v)
3561
35621 call callTree_waypoint("Calling ALE_regrid() to remap initial conditions (initialize_MOM)")
3563657976 allocate(h_new(isd:ied, jsd:jed, nz), source=0.0)
3564666749 allocate(dzRegrid(isd:ied, jsd:jed, nz+1), source=0.0)
3565657976 allocate(PCM_cell(isd:ied, jsd:jed, nz), source=.false.)
3566663076 allocate(h_old_u(IsdB:IedB, jsd:jed, nz), source=0.0)
3567663076 allocate(h_new_u(IsdB:IedB, jsd:jed, nz), source=0.0)
3568667651 allocate(h_old_v(isd:ied, JsdB:JedB, nz), source=0.0)
3569667651 allocate(h_new_v(isd:ied, JsdB:JedB, nz), source=0.0)
35701 if (use_ice_shelf) then
35710 call ALE_regrid(G, GV, US, CS%h, h_new, dzRegrid, CS%tv, CS%ALE_CSp, CS%frac_shelf_h, PCM_cell)
3572 else
35731 call ALE_regrid(G, GV, US, CS%h, h_new, dzRegrid, CS%tv, CS%ALE_CSp, PCM_cell=PCM_cell)
3574 endif
3575
35761 if (callTree_showQuery()) call callTree_waypoint("new grid generated")
3577 ! Remap all variables from the old grid h onto the new grid h_new
35781 call ALE_remap_tracers(CS%ALE_CSp, G, GV, CS%h, h_new, CS%tracer_Reg, CS%debug, PCM_cell=PCM_cell)
3579
3580 ! Determine the old and new grid thicknesses at velocity points.
35811 call ALE_remap_set_h_vel(CS%ALE_CSp, G, GV, CS%h, h_old_u, h_old_v, CS%OBC, debug=CS%debug)
35821 if (CS%remap_uv_using_old_alg) then
35830 call ALE_remap_set_h_vel_via_dz(CS%ALE_CSp, G, GV, h_new, h_new_u, h_new_v, CS%OBC, CS%h, dzRegrid, CS%debug)
3584 else
35851 call ALE_remap_set_h_vel(CS%ALE_CSp, G, GV, h_new, h_new_u, h_new_v, CS%OBC, debug=CS%debug)
3586 endif
3587
3588 ! Remap the velocity components.
35891 call ALE_remap_velocities(CS%ALE_CSp, G, GV, h_old_u, h_old_v, h_new_u, h_new_v, CS%u, CS%v, CS%debug)
3590
35911 if (allocated(CS%tv%SpV_avg)) CS%tv%valid_SpV_halo = -1 ! Record that SpV_avg is no longer valid.
3592
3593 ! Replace the old grid with new one. All remapping must be done at this point.
3594 !$OMP parallel do default(shared)
3595572026 do k=1,nz ; do j=js-1,je+1 ; do i=is-1,ie+1
3596571950 CS%h(i,j,k) = h_new(i,j,k)
3597 enddo ; enddo ; enddo
3598
35991 deallocate(h_new, dzRegrid, PCM_cell, h_old_u, h_new_u, h_old_v, h_new_v)
3600
36011 call cpu_clock_begin(id_clock_pass_init)
36021 call create_group_pass(tmp_pass_uv_T_S_h, CS%u, CS%v, G%Domain)
36031 if (use_temperature) then
36041 call create_group_pass(tmp_pass_uv_T_S_h, CS%tv%T, G%Domain)
36051 call create_group_pass(tmp_pass_uv_T_S_h, CS%tv%S, G%Domain)
3606 endif
36071 call create_group_pass(tmp_pass_uv_T_S_h, CS%h, G%Domain)
36081 call do_group_pass(tmp_pass_uv_T_S_h, G%Domain)
36091 call cpu_clock_end(id_clock_pass_init)
3610
36111 if (CS%debug) then
36120 call uvchksum("Post ALE adjust init cond [uv]", CS%u, CS%v, G%HI, haloshift=1, unscale=US%L_T_to_m_s)
36130 call hchksum(CS%h, "Post ALE adjust init cond h", G%HI, haloshift=2, unscale=GV%H_to_MKS)
36140 if (use_temperature) then
36150 call hchksum(CS%tv%T, "Post ALE adjust init cond T", G%HI, haloshift=2, unscale=US%C_to_degC)
36160 call hchksum(CS%tv%S, "Post ALE adjust init cond S", G%HI, haloshift=2, unscale=US%S_to_ppt)
3617 endif
3618 endif
3619 endif
36201 if ( CS%use_ALE_algorithm ) then
36211 call ALE_set_extrap_boundaries (param_file, CS%ALE_CSp)
36221 call callTree_waypoint("returned from ALE_init() (initialize_MOM)")
36231 call ALE_updateVerticalGridType( CS%ALE_CSp, GV )
3624 endif
3625 ! The basic state variables have now been fully initialized, so update their halos and
3626 ! calculate any derived thermodynmics quantities.
3627
3628 !--- set up group pass for u,v,T,S and h. pass_uv_T_S_h also is used in step_MOM
36291 call cpu_clock_begin(id_clock_pass_init)
36301 dynamics_stencil = min(3, G%Domain%nihalo, G%Domain%njhalo)
36311 call create_group_pass(pass_uv_T_S_h, CS%u, CS%v, G%Domain, halo=dynamics_stencil)
36321 if (use_temperature) then
36331 call create_group_pass(pass_uv_T_S_h, CS%tv%T, G%Domain, halo=dynamics_stencil)
36341 call create_group_pass(pass_uv_T_S_h, CS%tv%S, G%Domain, halo=dynamics_stencil)
3635 endif
36361 call create_group_pass(pass_uv_T_S_h, CS%h, G%Domain, halo=dynamics_stencil)
3637
36381 call do_group_pass(pass_uv_T_S_h, G%Domain)
36391 if (associated(CS%tv%p_surf)) call pass_var(CS%tv%p_surf, G%Domain, halo=dynamics_stencil)
36401 call cpu_clock_end(id_clock_pass_init)
3641
3642 ! Update derived thermodynamic quantities.
36431 if (allocated(CS%tv%SpV_avg)) then
36440 call calc_derived_thermo(CS%tv, CS%h, G, GV, US, halo=dynamics_stencil, debug=CS%debug)
3645 endif
3646
3647 ! XXX: Where to put this??
3648 ! XXX: G transfer should possibly also be here.
3649
3650 !$omp target enter data map(to: GV, GV%Rlay, GV%g_prime)
3651
36521 diag => CS%diag
3653 ! Initialize the diag mediator.
36541 call diag_mediator_init(G, GV, US, GV%ke, param_file, diag, doc_file_dir=dirs%output_directory)
36551 if (present(diag_ptr)) diag_ptr => CS%diag
3656
3657 ! Initialize the diagnostics masks for native arrays.
3658 ! This step has to be done after call to MOM_initialize_state
3659 ! and before MOM_diagnostics_init
36601 call diag_masks_set(G, GV%ke, diag)
3661
3662 ! Set up pointers within diag mediator control structure,
3663 ! this needs to occur _after_ CS%h etc. have been allocated.
36641 call diag_set_state_ptrs(CS%h, CS%tv, diag)
3665
3666 ! This call sets up the diagnostic axes. These are needed,
3667 ! e.g. to generate the target grids below.
36681 call set_axes_info(G, GV, US, param_file, diag)
3669
3670 ! Whenever thickness/T/S changes let the diag manager know, target grids
3671 ! for vertical remapping may need to be regenerated. In non-Boussinesq mode,
3672 ! calc_derived_thermo needs to be called before diag_update_remap_grids.
36731 call diag_update_remap_grids(diag)
3674
3675 ! Setup the diagnostic grid storage types
36761 call diag_grid_storage_init(CS%diag_pre_sync, G, GV, diag)
36771 call diag_grid_storage_init(CS%diag_pre_dyn, G, GV, diag)
3678
3679 ! Calculate masks for diagnostics arrays in non-native coordinates
3680 ! This step has to be done after set_axes_info() because the axes needed
3681 ! to be configured, and after diag_update_remap_grids() because the grids
3682 ! must be defined.
36831 call set_masks_for_axes(G, diag)
3684
3685 ! Register the volume cell measure (must be one of first diagnostics)
36861 call register_cell_measure(G, CS%diag, Time)
3687
36881 call cpu_clock_begin(id_clock_MOM_init)
3689 ! Diagnose static fields AND associate areas/volumes with axes
36901 call write_static_fields(G, GV, US, CS%tv, CS%diag)
36911 call callTree_waypoint("static fields written (initialize_MOM)")
3692
36931 if (CS%use_ALE_algorithm) then
36941 call ALE_writeCoordinateFile( CS%ALE_CSp, GV, dirs%output_directory )
36951 call callTree_waypoint("ALE initialized (initialize_MOM)")
36960 elseif (write_geom_files) then
36970 call write_vertgrid_file(GV, US, param_file, dirs%output_directory)
3698 endif
36991 call cpu_clock_end(id_clock_MOM_init)
3700
37011 if (CS%use_dbclient) call database_comms_init(param_file, CS%dbcomms_CS)
3702 CS%useMEKE = MEKE_init(Time, G, GV, US, param_file, diag, CS%dbcomms_CS, CS%MEKE_CSp, CS%MEKE, &
37031 restart_CSp, CS%MEKE_in_dynamics)
3704
37051 allocate(CS%VarMix)
3706 !$omp target enter data map(alloc: CS%VarMix)
37071 call VarMix_init(Time, G, GV, US, param_file, diag, CS%VarMix)
3708
37091 allocate(CS%set_visc_CSp)
3710 !$omp target enter data map(alloc: CS%set_visc_CSp)
37111 call set_visc_init(Time, G, GV, US, param_file, diag, CS%visc, CS%set_visc_CSp, restart_CSp, CS%OBC)
3712
37131 call thickness_diffuse_init(Time, G, GV, US, param_file, diag, CS%CDp, CS%thickness_diffuse_CSp)
37141 if (CS%interface_filter) &
37150 call interface_filter_init(Time, G, GV, US, param_file, diag, CS%CDp, CS%interface_filter_CSp)
3716
37171 new_sim = is_new_run(restart_CSp)
37181 if (use_temperature) then
37191 CS%use_stochastic_EOS = MOM_stoch_eos_init(Time, G, GV, US, param_file, diag, CS%stoch_eos_CS, restart_CSp)
3720 else
37210 CS%use_stochastic_EOS = .false.
3722 endif
3723
37241 if (CS%use_porbar) &
37250 call porous_barriers_init(Time, GV, US, param_file, diag, CS%por_bar_CS)
3726
37271 if (CS%split) then
37288773 allocate(eta(SZI_(G),SZJ_(G)), source=0.0)
37291 if (CS%use_alt_split) then
3730 call initialize_dyn_split_RK2b(CS%u, CS%v, CS%h, CS%tv, CS%uh, CS%vh, eta, Time, &
3731 G, GV, US, param_file, diag, CS%dyn_split_RK2b_CSp, CS%HA_CSp, restart_CSp, &
3732 CS%dt, CS%ADp, CS%CDp, MOM_internal_state, CS%VarMix, CS%MEKE, &
3733 CS%thickness_diffuse_CSp, CS%OBC, CS%update_OBC_CSp, CS%ALE_CSp, CS%set_visc_CSp, &
3734 CS%visc, dirs, CS%ntrunc, CS%pbv, calc_dtbt=calc_dtbt, &
37350 cont_stencil=CS%cont_stencil, dyn_h_stencil=CS%dyn_h_stencil)
3736 else
3737 call initialize_dyn_split_RK2(CS%u, CS%v, CS%h, CS%tv, CS%uh, CS%vh, eta, Time, &
3738 G, GV, US, param_file, diag, CS%dyn_split_RK2_CSp, CS%HA_CSp, restart_CSp, &
3739 CS%dt, CS%ADp, CS%CDp, MOM_internal_state, CS%VarMix, CS%MEKE, &
3740 CS%thickness_diffuse_CSp, CS%OBC, CS%update_OBC_CSp, CS%ALE_CSp, CS%set_visc_CSp, &
3741 CS%visc, dirs, CS%ntrunc, CS%pbv, calc_dtbt=calc_dtbt, &
37421 cont_stencil=CS%cont_stencil, dyn_h_stencil=CS%dyn_h_stencil)
3743 endif
37441 if (CS%dtbt_reset_period > 0.0) then
37451 CS%dtbt_reset_interval = real_to_time(CS%dtbt_reset_period, unscale=US%T_to_s)
3746 ! Set dtbt_reset_time to be the next even multiple of dtbt_reset_interval.
3747 CS%dtbt_reset_time = Time_init + CS%dtbt_reset_interval * &
37481 ((Time - Time_init) / CS%dtbt_reset_interval)
37491 if ((CS%dtbt_reset_time > Time) .and. calc_dtbt) then
3750 ! Back up dtbt_reset_time one interval to force dtbt to be calculated,
3751 ! because the restart was not aligned with the interval to recalculate
3752 ! dtbt, and dtbt was not read from a restart file.
37530 CS%dtbt_reset_time = CS%dtbt_reset_time - CS%dtbt_reset_interval
3754 endif
3755 endif
37560 elseif (CS%use_RK2) then
3757 call initialize_dyn_unsplit_RK2(CS%u, CS%v, CS%h, CS%tv, Time, G, GV, &
3758 US, param_file, diag, CS%dyn_unsplit_RK2_CSp, &
3759 CS%ADp, CS%CDp, MOM_internal_state, CS%OBC, &
3760 CS%update_OBC_CSp, CS%ALE_CSp, CS%set_visc_CSp, CS%visc, dirs, &
37610 CS%ntrunc, cont_stencil=CS%cont_stencil, dyn_h_stencil=CS%dyn_h_stencil)
3762 else
3763 call initialize_dyn_unsplit(CS%u, CS%v, CS%h, CS%tv, Time, G, GV, &
3764 US, param_file, diag, CS%dyn_unsplit_CSp, &
3765 CS%ADp, CS%CDp, MOM_internal_state, CS%OBC, &
3766 CS%update_OBC_CSp, CS%ALE_CSp, CS%set_visc_CSp, CS%visc, dirs, &
37670 CS%ntrunc, cont_stencil=CS%cont_stencil, dyn_h_stencil=CS%dyn_h_stencil)
3768 endif
37691 CS%dyn_h_stencil = max(2, CS%dyn_h_stencil)
3770
3771 !Set OBC segment data update period
37721 if (associated(CS%OBC) .and. CS%dt_obc_seg_period > 0.0) then
37730 CS%dt_obc_seg_interval = real_to_time(CS%dt_obc_seg_period, unscale=US%T_to_s)
37740 CS%dt_obc_seg_time = Time + CS%dt_obc_seg_interval
3775 endif
3776
37771 call callTree_waypoint("dynamics initialized (initialize_MOM)")
3778
3779 CS%mixedlayer_restrat = mixedlayer_restrat_init(Time, G, GV, US, param_file, diag, &
37801 CS%mixedlayer_restrat_CSp, restart_CSp)
3781
37821 if (GV%Boussinesq .and. associated(CS%visc%h_ML)) then
3783 ! This is here to allow for a transition of restart files between model versions.
3784 call get_param(param_file, "MOM", "MLE_USE_PBL_MLD", MLE_use_PBL_MLD, &
37851 default=.false., do_not_log=.true.)
37861 if (MLE_use_PBL_MLD .and. .not.query_initialized(CS%visc%h_ML, "h_ML", restart_CSp) .and. &
3787 associated(CS%visc%MLD)) then
37887261 do j=js,je ; do i=is,ie ; CS%visc%h_ML(i,j) = GV%Z_to_H * CS%visc%MLD(i,j) ; enddo ; enddo
3789 endif
3790 endif
3791
37921 if (CS%mixedlayer_restrat) then
37931 if (.not.(bulkmixedlayer .or. CS%use_ALE_algorithm)) &
37940 call MOM_error(FATAL, "MOM: MIXEDLAYER_RESTRAT true requires a boundary layer scheme.")
3795 ! When DIABATIC_FIRST=False and using CS%visc%ML in mixedlayer_restrat we need to update after a restart
37961 if (.not. CS%diabatic_first .and. associated(CS%visc%MLD)) &
37971 call pass_var(CS%visc%MLD, G%domain, halo=1)
37981 if (.not. CS%diabatic_first .and. associated(CS%visc%h_ML)) &
37991 call pass_var(CS%visc%h_ML, G%domain, halo=1)
3800 endif
3801
3802 call MOM_diagnostics_init(MOM_internal_state, CS%ADp, CS%CDp, Time, G, GV, US, &
38031 param_file, diag, CS%diagnostics_CSp, CS%tv)
38041 call diag_copy_diag_to_storage(CS%diag_pre_sync, CS%h, CS%diag)
3805
3806
38071 if (CS%adiabatic) then
3808 call adiabatic_driver_init(Time, G, param_file, diag, CS%diabatic_CSp, &
38090 CS%tracer_flow_CSp)
3810 else
3811 call diabatic_driver_init(Time, G, GV, US, param_file, CS%use_ALE_algorithm, diag, &
3812 CS%ADp, CS%CDp, CS%diabatic_CSp, CS%tracer_flow_CSp, &
38131 CS%sponge_CSp, CS%ALE_sponge_CSp, CS%oda_incupd_CSp, CS%int_tide_CSp)
3814 endif
3815
38161 CS%vertex_shear = kappa_shear_at_vertex(param_file)
3817
3818 ! GMM, the following is needed to get BLDs into the dynamics module
38191 if (CS%split .and. fpmix) then
38200 call init_dyn_split_RK2_diabatic(CS%diabatic_CSp, CS%dyn_split_RK2_CSp)
3821 endif
3822
38231 if (associated(CS%sponge_CSp)) &
38240 call init_sponge_diags(Time, G, GV, US, diag, CS%sponge_CSp)
3825
38261 if (associated(CS%oda_incupd_CSp)) &
38270 call init_oda_incupd_diags(Time, G, GV, diag, CS%oda_incupd_CSp, US)
3828
38291 call tracer_advect_init(Time, G, US, param_file, diag, CS%tracer_adv_CSp)
3830 call tracer_hor_diff_init(Time, G, GV, US, param_file, diag, CS%tv%eqn_of_state, CS%diabatic_CSp, &
38311 CS%tracer_diff_CSp)
3832
38331 call lock_tracer_registry(CS%tracer_Reg)
38341 call callTree_waypoint("tracer registry now locked (initialize_MOM)")
3835
3836 ! now register some diagnostics since the tracer registry is now locked
38371 call register_surface_diags(Time, G, US, CS%sfc_IDs, CS%diag, CS%tv)
38381 call register_diags(Time, G, GV, US, CS%IDs, CS%diag)
38391 call register_transport_diags(Time, G, GV, US, CS%transport_IDs, CS%diag)
38401 call extract_diabatic_member(CS%diabatic_CSp, use_KPP=use_KPP)
3841 call register_tracer_diagnostics(CS%tracer_Reg, CS%h, Time, diag, G, GV, US, &
38421 CS%use_ALE_algorithm, use_KPP)
38431 if (CS%use_ALE_algorithm) then
38441 call ALE_register_diags(Time, G, GV, US, diag, CS%ALE_CSp)
3845 endif
3846
3847 ! Do any necessary halo updates on any auxiliary variables that have been initialized.
38481 call cpu_clock_begin(id_clock_pass_init)
38491 if (associated(CS%visc%Kv_shear)) &
38501 call pass_var(CS%visc%Kv_shear, G%Domain, To_All+Omit_Corners, halo=1)
3851
38521 if (associated(CS%visc%Kv_slow)) &
38530 call pass_var(CS%visc%Kv_slow, G%Domain, To_All+Omit_Corners, halo=1)
38541 call cpu_clock_end(id_clock_pass_init)
3855
3856 ! This subroutine initializes any tracer packages.
3857 call tracer_flow_control_init(.not.new_sim, Time, G, GV, US, CS%h, param_file, &
3858 CS%diag, CS%OBC, CS%tracer_flow_CSp, CS%sponge_CSp, &
38591 CS%ALE_sponge_CSp, CS%tv)
38601 if (present(tracer_flow_CSp)) tracer_flow_CSp => CS%tracer_flow_CSp
3861
38621 if (associated(CS%ALE_sponge_CSp)) &
38630 call init_ALE_sponge_diags(Time, G, diag, CS%ALE_sponge_CSp, US)
3864
3865 ! If running in offline tracer mode, initialize the necessary control structure and
3866 ! parameters
38671 if (present(offline_tracer_mode)) offline_tracer_mode=CS%offline_tracer_mode
3868
38691 if (CS%offline_tracer_mode) then
3870 ! Setup some initial parameterizations and also assign some of the subtypes
38710 call offline_transport_init(param_file, CS%offline_CSp, CS%diabatic_CSp, G, GV, US)
3872 call insert_offline_main( CS=CS%offline_CSp, ALE_CSp=CS%ALE_CSp, diabatic_CSp=CS%diabatic_CSp, &
3873 diag=CS%diag, OBC=CS%OBC, tracer_adv_CSp=CS%tracer_adv_CSp, &
3874 tracer_flow_CSp=CS%tracer_flow_CSp, tracer_Reg=CS%tracer_Reg, &
38750 tv=CS%tv, x_before_y=(MODULO(first_direction,2)==0), debug=CS%debug )
38760 call register_diags_offline_transport(Time, CS%diag, CS%offline_CSp, GV, US)
3877 endif
3878
38791 if (associated(CS%OBC)) then
3880 ! At this point any information related to the tracer reservoirs has either been read from
3881 ! the restart file or has been specified in the segments. Initialize the tracer reservoir
3882 ! values from the segments if they have not been set via the restart file.
38830 call setup_OBC_tracer_reservoirs(G, GV, CS%OBC, restart_CSp)
38840 call setup_OBC_thickness_reservoirs(G, GV, CS%OBC, restart_CSp)
38850 call open_boundary_halo_update(G, CS%OBC)
3886 endif
3887
38881 call register_obsolete_diagnostics(param_file, CS%diag)
3889
38901 if (use_frazil) then
38911 if (.not.query_initialized(CS%tv%frazil, "frazil", restart_CSp)) then
38928773 CS%tv%frazil(:,:) = 0.0
38931 call set_initialized(CS%tv%frazil, "frazil", restart_CSp)
3894 endif
3895 endif
3896
38971 if (CS%interp_p_surf) then
38980 CS%p_surf_prev_set = query_initialized(CS%p_surf_prev, "p_surf_prev", restart_CSp)
3899
39000 if (CS%p_surf_prev_set) then
39010 call pass_var(CS%p_surf_prev, G%domain)
3902 endif
3903 endif
3904
39051 if (.not.query_initialized(CS%ave_ssh_ibc, "ave_ssh", restart_CSp)) then
3906 !$omp target update to(CS%h)
39071 if (CS%split) then
3908 !$omp target enter data map(to: eta)
39091 call find_eta(CS%h, CS%tv, G, GV, US, CS%ave_ssh_ibc, eta_bt=eta, dZref=G%Z_ref)
3910 !$omp target exit data map(release: eta)
3911 else
39120 call find_eta(CS%h, CS%tv, G, GV, US, CS%ave_ssh_ibc, dZref=G%Z_ref)
3913 endif
3914 !$omp target update from(CS%ave_ssh_ibc)
39151 call set_initialized(CS%ave_ssh_ibc, "ave_ssh", restart_CSp)
3916 endif
39171 if (CS%split) deallocate(eta)
3918
39191 CS%nstep_tot = 0
39201 if (present(count_calls)) CS%count_calls = count_calls
3921 call MOM_sum_output_init(G_in, GV, US, param_file, dirs%output_directory, &
39221 CS%ntrunc, Time_init, CS%sum_output_CSp)
3923
3924 ! Flag whether to save initial conditions in finish_MOM_initialization() or not.
3925 CS%write_IC = save_IC .and. &
3926 .not.((dirs%input_filename(1:1) == 'r') .and. &
39271 (LEN_TRIM(dirs%input_filename) == 1))
3928
39291 if (CS%ensemble_ocean) then
39300 call init_oda(Time, G, GV, US, CS%diag, CS%odaCS)
3931 endif
3932
3933 ! initialize stochastic physics
39341 call stochastics_init(CS%dt_therm, CS%G, CS%GV, CS%stoch_CS, param_file, diag, Time)
3935
39361 call callTree_leave("initialize_MOM()")
39371 call cpu_clock_end(id_clock_init) ; call cpu_clock_end(id_clock_ocean)
3938
393913end subroutine initialize_MOM
3940
3941!> Finishes initializing MOM and writes out the initial conditions.
39421subroutine finish_MOM_initialization(Time, dirs, CS)
3943 type(time_type), intent(in) :: Time !< model time, used in this routine
3944 type(directories), intent(in) :: dirs !< structure with directory paths
3945 type(MOM_control_struct), intent(inout) :: CS !< MOM control structure
3946
3947 type(ocean_grid_type), pointer :: G => NULL() ! pointer to a structure containing
3948 ! metrics and related information
3949 type(verticalGrid_type), pointer :: GV => NULL() ! Pointer to the vertical grid structure
3950 type(unit_scale_type), pointer :: US => NULL() ! Pointer to a structure containing
3951 ! various unit conversion factors
3952 type(MOM_restart_CS), pointer :: restart_CSp_tmp => NULL()
39531 real, allocatable :: z_interface(:,:,:) ! Interface heights [Z ~> m]
3954
39551 call cpu_clock_begin(id_clock_init)
39561 call callTree_enter("finish_MOM_initialization()")
3957
3958 ! Pointers for convenience
39591 G => CS%G ; GV => CS%GV ; US => CS%US
3960
39611 if (CS%use_particles) then
39620 call particles_init(CS%particles, G, CS%Time, CS%dt_therm, CS%u, CS%v, CS%h)
3963 endif
3964
3965 ! Write initial conditions
39661 if (CS%write_IC) then
39671 allocate(restart_CSp_tmp)
39681 restart_CSp_tmp = CS%restart_CS
39691 call restart_registry_lock(restart_CSp_tmp, unlocked=.true.)
39701 allocate(z_interface(SZI_(G),SZJ_(G),SZK_(GV)+1))
3971 !$omp target update to(CS%h)
3972 !$omp target enter data map(alloc: z_interface)
39731 call find_eta(CS%h, CS%tv, G, GV, US, z_interface, dZref=G%Z_ref)
3974 !$omp target exit data map(from: z_interface)
3975 call register_restart_field(z_interface, "eta", .true., restart_CSp_tmp, &
39761 "Interface heights", "meter", z_grid='i', conversion=US%Z_to_m)
3977 ! NOTE: write_ic=.true. routes routine to fms2 IO write_initial_conditions interface
3978 call save_restart(dirs%output_directory, Time, CS%G_in, &
39791 restart_CSp_tmp, filename=CS%IC_file, GV=GV, write_ic=.true.)
39801 deallocate(z_interface)
39811 deallocate(restart_CSp_tmp)
3982 endif
3983
3984 !$omp target update to(CS%u, CS%v, CS%h)
3985 call write_energy(CS%u, CS%v, CS%h, CS%tv, Time, 0, G, GV, US, &
39861 CS%sum_output_CSp, CS%tracer_flow_CSp)
3987
39881 call callTree_leave("finish_MOM_initialization()")
39891 call cpu_clock_end(id_clock_init)
3990
39911end subroutine finish_MOM_initialization
3992
3993!> Register certain diagnostics
39941subroutine register_diags(Time, G, GV, US, IDs, diag)
3995 type(time_type), intent(in) :: Time !< current model time
3996 type(ocean_grid_type), intent(in) :: G !< ocean grid structure
3997 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
3998 type(unit_scale_type), intent(inout) :: US !< A dimensional unit scaling type
3999 type(MOM_diag_IDs), intent(inout) :: IDs !< A structure with the diagnostic IDs.
4000 type(diag_ctrl), intent(inout) :: diag !< regulates diagnostic output
4001
4002 character(len=48) :: thickness_units
4003
40041 thickness_units = get_thickness_units(GV)
4005
4006 ! Diagnostics of the rapidly varying dynamic state
4007 IDs%id_u = register_diag_field('ocean_model', 'u_dyn', diag%axesCuL, Time, &
40081 'Zonal velocity after the dynamics update', 'm s-1', conversion=US%L_T_to_m_s)
4009 IDs%id_v = register_diag_field('ocean_model', 'v_dyn', diag%axesCvL, Time, &
40101 'Meridional velocity after the dynamics update', 'm s-1', conversion=US%L_T_to_m_s)
4011 IDs%id_h = register_diag_field('ocean_model', 'h_dyn', diag%axesTL, Time, &
4012 'Layer Thickness after the dynamics update', thickness_units, conversion=GV%H_to_MKS, &
40131 v_extensive=.true.)
4014 IDs%id_ssh_inst = register_diag_field('ocean_model', 'SSH_inst', diag%axesT1, &
40151 Time, 'Instantaneous Sea Surface Height', 'm', conversion=US%Z_to_m)
4016
40171end subroutine register_diags
4018
4019!> Set up CPU clock IDs for timing various subroutines.
40201subroutine MOM_timing_init(CS)
4021 type(MOM_control_struct), intent(in) :: CS !< control structure set up by initialize_MOM.
4022
40231 id_clock_dynamics = cpu_clock_id('Ocean dynamics', grain=CLOCK_SUBCOMPONENT)
40241 id_clock_thermo = cpu_clock_id('Ocean thermodynamics and tracers', grain=CLOCK_SUBCOMPONENT)
40251 id_clock_remap = cpu_clock_id('Ocean grid generation and remapping', grain=CLOCK_SUBCOMPONENT)
40261 id_clock_other = cpu_clock_id('Ocean Other', grain=CLOCK_SUBCOMPONENT)
40271 id_clock_MOM_end = cpu_clock_id('Ocean MOM_end', grain=CLOCK_SUBCOMPONENT)
40281 id_clock_tracer = cpu_clock_id('(Ocean tracer advection)', grain=CLOCK_MODULE_DRIVER)
40291 if (.not.CS%adiabatic) then
40301 id_clock_diabatic = cpu_clock_id('(Ocean diabatic driver)', grain=CLOCK_MODULE_DRIVER)
4031 else
40320 id_clock_adiabatic = cpu_clock_id('(Ocean adiabatic driver)', grain=CLOCK_MODULE_DRIVER)
4033 endif
4034
40351 id_clock_continuity = cpu_clock_id('(Ocean continuity equation *)', grain=CLOCK_MODULE)
40361 id_clock_BBL_visc = cpu_clock_id('(Ocean set BBL viscosity)', grain=CLOCK_MODULE)
40371 id_clock_pass = cpu_clock_id('(Ocean message passing *)', grain=CLOCK_MODULE)
40381 id_clock_MOM_init = cpu_clock_id('(Ocean MOM_initialize_state)', grain=CLOCK_MODULE)
40391 id_clock_pass_init = cpu_clock_id('(Ocean init message passing *)', grain=CLOCK_ROUTINE)
40401 if (CS%thickness_diffuse) &
40411 id_clock_thick_diff = cpu_clock_id('(Ocean thickness diffusion *)', grain=CLOCK_MODULE)
40421 if (CS%interface_filter) &
40430 id_clock_int_filter = cpu_clock_id('(Ocean interface height filter *)', grain=CLOCK_MODULE)
4044 !if (CS%mixedlayer_restrat) &
40451 id_clock_ml_restrat = cpu_clock_id('(Ocean mixed layer restrat)', grain=CLOCK_MODULE)
40461 id_clock_diagnostics = cpu_clock_id('(Ocean collective diagnostics)', grain=CLOCK_MODULE)
40471 id_clock_Z_diag = cpu_clock_id('(Ocean Z-space diagnostics)', grain=CLOCK_MODULE)
40481 id_clock_ALE = cpu_clock_id('(Ocean ALE)', grain=CLOCK_MODULE)
40491 if (CS%offline_tracer_mode) then
40500 id_clock_offline_tracer = cpu_clock_id('Ocean offline tracers', grain=CLOCK_SUBCOMPONENT)
4051 endif
40521 id_clock_stoch = cpu_clock_id('(Stochastic EOS)', grain=CLOCK_MODULE)
40531 id_clock_varT = cpu_clock_id('(SGS Temperature Variance)', grain=CLOCK_MODULE)
4054
40551 id_clock_save_restart = cpu_clock_id('(Ocean MOM save_restart)', grain=CLOCK_MODULE)
4056
40571end subroutine MOM_timing_init
4058
4059!> Set the fields that are needed for bitwise identical restarting
4060!! the time stepping scheme. In addition to those specified here
4061!! directly, there may be fields related to the forcing or to the
4062!! barotropic solver that are needed; these are specified in sub-
4063!! routines that are called from this one.
4064!!
4065!! This routine should be altered if there are any changes to the
4066!! time stepping scheme. The CHECK_RESTART facility may be used to
4067!! confirm that all needed restart fields have been included.
40681subroutine set_restart_fields(GV, US, param_file, CS, restart_CSp)
4069 type(verticalGrid_type), intent(inout) :: GV !< ocean vertical grid structure
4070 type(unit_scale_type), intent(inout) :: US !< A dimensional unit scaling type
4071 type(param_file_type), intent(in) :: param_file !< opened file for parsing to get parameters
4072 type(MOM_control_struct), intent(in) :: CS !< control structure set up by initialize_MOM
4073 type(MOM_restart_CS), pointer :: restart_CSp !< pointer to the restart control
4074 !! structure that will be used for MOM.
4075 ! Local variables
4076 logical :: use_ice_shelf ! Needed to determine whether to add CS%Hml to restarts
4077 character(len=48) :: thickness_units, flux_units
407811 type(vardesc) :: u_desc, v_desc
4079
40801 thickness_units = get_thickness_units(GV)
40811 flux_units = get_flux_units(GV)
4082
40831 if (associated(CS%tv%T)) &
4084 call register_restart_field(CS%tv%T, "Temp", .true., restart_CSp, &
40851 "Potential Temperature", "degC", conversion=US%C_to_degC)
40861 if (associated(CS%tv%S)) &
4087 call register_restart_field(CS%tv%S, "Salt", .true., restart_CSp, &
40881 "Salinity", "PPT", conversion=US%S_to_ppt)
4089
4090 call register_restart_field(CS%h, "h", .true., restart_CSp, &
40911 "Layer Thickness", thickness_units, conversion=GV%H_to_MKS)
4092
40936 u_desc = var_desc("u", "m s-1", "Zonal velocity", hor_grid='Cu')
40946 v_desc = var_desc("v", "m s-1", "Meridional velocity", hor_grid='Cv')
40951 call register_restart_pair(CS%u, CS%v, u_desc, v_desc, .true., restart_CSp, conversion=US%L_T_to_m_s)
4096
40971 if (associated(CS%tv%frazil)) &
4098 call register_restart_field(CS%tv%frazil, "frazil", .false., restart_CSp, &
4099 "Frazil heat flux into ocean", &
41001 "J m-2", conversion=US%Q_to_J_kg*US%RZ_to_kg_m2)
4101
41021 if (CS%interp_p_surf) then
4103 call register_restart_field(CS%p_surf_prev, "p_surf_prev", .false., restart_CSp, &
41040 "Previous ocean surface pressure", "Pa", conversion=US%RL2_T2_to_Pa)
4105 endif
4106
41071 if (associated(CS%tv%p_surf)) &
4108 call register_restart_field(CS%tv%p_surf, "p_surf_EOS", .false., restart_CSp, &
41091 "Ocean surface pressure used in EoS", "Pa", conversion=US%RL2_T2_to_Pa)
4110
4111 call register_restart_field(CS%ave_ssh_ibc, "ave_ssh", .false., restart_CSp, &
41121 "Time average sea surface height", "meter", conversion=US%Z_to_m)
4113
4114 ! hML is needed when using the ice shelf module
4115 call get_param(param_file, '', "ICE_SHELF", use_ice_shelf, default=.false., &
41161 do_not_log=.true.)
41171 if (use_ice_shelf .and. associated(CS%Hml)) then
4118 call register_restart_field(CS%Hml, "hML", .false., restart_CSp, &
41190 "Mixed layer thickness", "m", conversion=US%Z_to_m)
4120 endif
4121
4122 ! Register scalar unit conversion factors.
4123 call register_restart_field(CS%first_dir_restart, "First_direction", .false., restart_CSp, &
41241 "Indicator of the first direction in split calculations.", "nondim")
4125
412611end subroutine set_restart_fields
4127
4128!> Apply a correction to the sea surface height to compensate
4129!! for the atmospheric pressure (the inverse barometer).
413012subroutine adjust_ssh_for_p_atm(tv, G, GV, US, ssh, p_atm, use_EOS)
4131 type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various thermodynamic variables
4132 type(ocean_grid_type), intent(in) :: G !< ocean grid structure
4133 type(verticalGrid_type), intent(in) :: GV !< ocean vertical grid structure
4134 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
4135 real, dimension(SZI_(G),SZJ_(G)), intent(inout) :: ssh !< time mean surface height [Z ~> m]
4136 real, dimension(:,:), pointer :: p_atm !< Ocean surface pressure [R L2 T-2 ~> Pa]
4137 logical, intent(in) :: use_EOS !< If true, calculate the density for
4138 !! the SSH correction using the equation of state.
4139
414024 real :: Rho_conv(SZI_(G)) ! The density used to convert surface pressure to
4141 ! a corrected effective SSH [R ~> kg m-3].
4142 real :: IgR0 ! The SSH conversion factor from R L2 T-2 to Z [Z T2 R-1 L-2 ~> m Pa-1].
4143 logical :: calc_rho
4144 integer, dimension(2) :: EOSdom ! The i-computational domain for the equation of state
4145 integer :: i, j, is, ie, js, je
4146
414712 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
414812 EOSdom(:) = EOS_domain(G%HI)
414912 if (associated(p_atm)) then
4150 !$omp target update from(ssh)
41510 calc_rho = use_EOS .and. associated(tv%eqn_of_state)
4152 ! Correct the output sea surface height for the contribution from the ice pressure.
41530 do j=js,je
41540 if (calc_rho) then
4155 call calculate_density(tv%T(:,j,1), tv%S(:,j,1), 0.5*p_atm(:,j), Rho_conv, &
41560 tv%eqn_of_state, EOSdom)
41570 do i=is,ie
41580 IgR0 = 1.0 / (Rho_conv(i) * GV%g_Earth)
41590 ssh(i,j) = ssh(i,j) + p_atm(i,j) * IgR0
4160 enddo
4161 else
41620 IgR0 = 1.0 / (GV%Rho0 * GV%g_Earth)
41630 do i=is,ie
41640 ssh(i,j) = ssh(i,j) + p_atm(i,j) * IgR0
4165 enddo
4166 endif
4167 enddo
4168 !$omp target update to(ssh)
4169 endif
417012end subroutine adjust_ssh_for_p_atm
4171
4172!> Set the surface (return) properties of the ocean model by
4173!! setting the appropriate fields in sfc_state. Unused fields
4174!! are set to NULL or are unallocated.
417513subroutine extract_surface_state(CS, sfc_state_in)
4176 type(MOM_control_struct), intent(inout), target :: CS !< Master MOM control structure
4177 type(surface), target, intent(inout) :: sfc_state_in !< transparent ocean surface state
4178 !! structure shared with the calling routine
4179 !! data in this structure is intent out.
4180
4181 ! Local variables
4182 real :: hu, hv ! Thicknesses interpolated to velocity points [H ~> m or kg m-2]
4183 type(ocean_grid_type), pointer :: G => NULL() !< pointer to a structure containing
4184 !! metrics and related information
4185 type(ocean_grid_type), pointer :: G_in => NULL() !< Input grid metric
4186 type(verticalGrid_type), pointer :: GV => NULL() !< structure containing vertical grid info
4187 type(unit_scale_type), pointer :: US => NULL() !< structure containing various unit conversion factors
4188 type(surface), pointer :: sfc_state => NULL() ! surface state on the model grid
4189 real, dimension(:,:,:), pointer :: h => NULL() !< h : layer thickness [H ~> m or kg m-2]
419026 real :: depth(SZI_(CS%G)) !< Distance from the surface in depth units [Z ~> m] or [H ~> m or kg m-2]
4191 real :: depth_ml !< Depth over which to average to determine mixed
4192 !! layer properties [Z ~> m] or [H ~> m or kg m-2]
4193 real :: dh !< Thickness of a layer within the mixed layer [Z ~> m] or [H ~> m or kg m-2]
4194 real :: mass !< Mass per unit area of a layer [R Z ~> kg m-2]
4195 real :: I_depth !< The inverse of depth [Z-1 ~> m-1] or [H-1 ~> m-1 or m2 kg-1]
4196 real :: missing_depth !< The portion of depth_ml that can not be found in a column [H ~> m or kg m-2]
4197 real :: H_rescale !< A conversion factor from thickness units to the units used in the
4198 !! calculation of properties of the uppermost ocean [nondim] or [Z H-1 ~> 1 or m3 kg-1]
4199 ! After the ANSWERS_2018 flag has been obsoleted, H_rescale will be 1.
420026 real :: T_freeze(SZI_(CS%G)) !< freezing temperature [C ~> degC]
420126 real :: pres(SZI_(CS%G)) !< Pressure to use for the freezing temperature calculation [R L2 T-2 ~> Pa]
420226 real :: delT(SZI_(CS%G)) !< Depth integral of T-T_freeze [H C ~> m degC or degC kg m-2]
4203 logical :: use_temperature !< If true, temperature and salinity are used as state variables.
4204 integer :: i, j, k, is, ie, js, je, nz, numberOfErrors, ig, jg
4205 integer :: isd, ied, jsd, jed
4206 integer :: iscB, iecB, jscB, jecB, isdB, iedB, jsdB, jedB
4207 logical :: localError
4208 logical :: use_iceshelves
4209 character(240) :: msg
4210 integer :: turns ! Number of quarter turns
4211
421213 call callTree_enter("extract_surface_state(), MOM.F90")
421313 G => CS%G ; G_in => CS%G_in ; GV => CS%GV ; US => CS%US
421413 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec ; nz = GV%ke
421513 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
421613 iscB = G%iscB ; iecB = G%iecB ; jscB = G%jscB ; jecB = G%jecB
421713 isdB = G%isdB ; iedB = G%iedB ; jsdB = G%jsdB ; jedB = G%jedB
421813 h => CS%h
4219
422013 use_temperature = associated(CS%tv%T)
4221
422213 use_iceshelves=.false.
422313 if (associated(CS%frac_shelf_h)) use_iceshelves = .true.
4224
422513 turns = 0
422613 if (CS%rotate_index) &
42270 turns = G%HI%turns
4228
422913 if (.not.sfc_state_in%arrays_allocated) then
4230 ! Consider using a run-time flag to determine whether to do the vertical
4231 ! integrals, since the 3-d sums are not negligible in cost.
4232 call allocate_surface_state(sfc_state_in, G_in, use_temperature, &
4233 do_integrals=.true., omit_frazil=.not.associated(CS%tv%frazil),&
42341 use_iceshelves=use_iceshelves)
4235 endif
4236
423713 if (CS%rotate_index) then
42380 allocate(sfc_state)
4239 call allocate_surface_state(sfc_state, G, use_temperature, &
4240 do_integrals=.true., omit_frazil=.not.associated(CS%tv%frazil),&
42410 use_iceshelves=use_iceshelves, sfc_state_in=sfc_state_in, turns=turns)
4242 else
424313 sfc_state => sfc_state_in
4244 endif
4245
424613 sfc_state%T_is_conT = CS%tv%T_is_conT
424713 sfc_state%S_is_absS = CS%tv%S_is_absS
4248
424994393 do j=js,je ; do i=is,ie
425094380 sfc_state%sea_lev(i,j) = CS%ave_ssh_ibc(i,j)
4251 enddo ; enddo
4252
425394393 if (allocated(sfc_state%frazil) .and. associated(CS%tv%frazil)) then ; do j=js,je ; do i=is,ie
425494380 sfc_state%frazil(i,j) = CS%tv%frazil(i,j)
4255 enddo ; enddo ; endif
4256
4257 ! copy Hml into sfc_state, so that caps can access it
425894393 do j=js,je ; do i=is,ie
425994380 sfc_state%Hml(i,j) = CS%Hml(i,j)
4260 enddo ; enddo
4261
426213 if (CS%Hmix < 0.0) then ! A bulk mixed layer is in use, so layer 1 has the properties
42630 if (use_temperature) then ; do j=js,je ; do i=is,ie
42640 sfc_state%SST(i,j) = CS%tv%T(i,j,1)
42650 sfc_state%SSS(i,j) = CS%tv%S(i,j,1)
4266 enddo ; enddo ; endif
42670 do j=js,je ; do I=is-1,ie
42680 sfc_state%u(I,j) = CS%u(I,j,1)
4269 enddo ; enddo
42700 do J=js-1,je ; do i=is,ie
42710 sfc_state%v(i,J) = CS%v(i,J,1)
4272 enddo ; enddo
4273
4274 else ! (CS%Hmix >= 0.0)
427513 H_rescale = 1.0
427613 depth_ml = CS%Hmix
427713 if (CS%answer_date < 20190101) then
42780 H_rescale = GV%H_to_Z
42790 depth_ml = GV%H_to_Z*CS%Hmix
4280 endif
4281 ! Determine the mean tracer properties of the uppermost depth_ml fluid.
4282
4283 !$OMP parallel do default(shared) private(depth,dh)
4284793 do j=js,je
428594380 do i=is,ie
428693600 depth(i) = 0.0
428794380 if (use_temperature) then
428893600 sfc_state%SST(i,j) = 0.0 ; sfc_state%SSS(i,j) = 0.0
4289 else
42900 sfc_state%sfc_density(i,j) = 0.0
4291 endif
4292 enddo
4293
42947079280 do k=1,nz ; do i=is,ie
42957020000 if (depth(i) + h(i,j,k)*H_rescale < depth_ml) then
42962131350 dh = h(i,j,k)*H_rescale
42974888650 elseif (depth(i) < depth_ml) then
429865182 dh = depth_ml - depth(i)
4299 else
43004823468 dh = 0.0
4301 endif
43027020000 if (use_temperature) then
43037020000 sfc_state%SST(i,j) = sfc_state%SST(i,j) + dh * CS%tv%T(i,j,k)
43047020000 sfc_state%SSS(i,j) = sfc_state%SSS(i,j) + dh * CS%tv%S(i,j,k)
4305 else
43060 sfc_state%sfc_density(i,j) = sfc_state%sfc_density(i,j) + dh * GV%Rlay(k)
4307 endif
43087078500 depth(i) = depth(i) + dh
4309 enddo ; enddo
4310 ! Calculate the average properties of the mixed layer depth.
431194393 do i=is,ie
431294380 if (CS%answer_date < 20190101) then
43130 if (depth(i) < GV%H_subroundoff*H_rescale) &
43140 depth(i) = GV%H_subroundoff*H_rescale
43150 if (use_temperature) then
43160 sfc_state%SST(i,j) = sfc_state%SST(i,j) / depth(i)
43170 sfc_state%SSS(i,j) = sfc_state%SSS(i,j) / depth(i)
4318 else
43190 sfc_state%sfc_density(i,j) = sfc_state%sfc_density(i,j) / depth(i)
4320 endif
4321 else
432293600 if (depth(i) < GV%H_subroundoff*H_rescale) then
43230 I_depth = 1.0 / (GV%H_subroundoff*H_rescale)
43240 missing_depth = GV%H_subroundoff*H_rescale - depth(i)
43250 if (use_temperature) then
43260 sfc_state%SST(i,j) = (sfc_state%SST(i,j) + missing_depth*CS%tv%T(i,j,1)) * I_depth
43270 sfc_state%SSS(i,j) = (sfc_state%SSS(i,j) + missing_depth*CS%tv%S(i,j,1)) * I_depth
4328 else
4329 sfc_state%sfc_density(i,j) = (sfc_state%sfc_density(i,j) + &
43300 missing_depth*GV%Rlay(1)) * I_depth
4331 endif
4332 else
433393600 I_depth = 1.0 / depth(i)
433493600 if (use_temperature) then
433593600 sfc_state%SST(i,j) = sfc_state%SST(i,j) * I_depth
433693600 sfc_state%SSS(i,j) = sfc_state%SSS(i,j) * I_depth
4337 else
43380 sfc_state%sfc_density(i,j) = sfc_state%sfc_density(i,j) * I_depth
4339 endif
4340 endif
4341 endif
4342 enddo
4343 enddo ! end of j loop
4344
4345! Determine the mean velocities in the uppermost depth_ml fluid.
4346 ! NOTE: Velocity loops start on `[ij]s-1` in order to update halo values
4347 ! required by the speed diagnostic on the non-symmetric grid.
4348 ! This assumes that u and v halos have already been updated.
434913 if (CS%Hmix_UV>0.) then
43500 depth_ml = CS%Hmix_UV
43510 if (CS%answer_date < 20190101) depth_ml = GV%H_to_Z*CS%Hmix_UV
4352 !$OMP parallel do default(shared) private(depth,dh,hv)
43530 do J=js-1,je
43540 do i=is,ie
43550 depth(i) = 0.0
43560 sfc_state%v(i,J) = 0.0
4357 enddo
43580 do k=1,nz ; do i=is,ie
43590 hv = 0.5 * (h(i,j,k) + h(i,j+1,k)) * H_rescale
43600 if (depth(i) + hv < depth_ml) then
43610 dh = hv
43620 elseif (depth(i) < depth_ml) then
43630 dh = depth_ml - depth(i)
4364 else
43650 dh = 0.0
4366 endif
43670 sfc_state%v(i,J) = sfc_state%v(i,J) + dh * CS%v(i,J,k)
43680 depth(i) = depth(i) + dh
4369 enddo ; enddo
4370 ! Calculate the average properties of the mixed layer depth.
43710 do i=is,ie
43720 sfc_state%v(i,J) = sfc_state%v(i,J) / max(depth(i), GV%H_subroundoff*H_rescale)
4373 enddo
4374 enddo ! end of j loop
4375
4376 !$OMP parallel do default(shared) private(depth,dh,hu)
43770 do j=js,je
43780 do I=is-1,ie
43790 depth(I) = 0.0
43800 sfc_state%u(I,j) = 0.0
4381 enddo
43820 do k=1,nz ; do I=is-1,ie
43830 hu = 0.5 * (h(i,j,k) + h(i+1,j,k)) * H_rescale
43840 if (depth(i) + hu < depth_ml) then
43850 dh = hu
43860 elseif (depth(I) < depth_ml) then
43870 dh = depth_ml - depth(I)
4388 else
43890 dh = 0.0
4390 endif
43910 sfc_state%u(I,j) = sfc_state%u(I,j) + dh * CS%u(I,j,k)
43920 depth(I) = depth(I) + dh
4393 enddo ; enddo
4394 ! Calculate the average properties of the mixed layer depth.
43950 do I=is-1,ie
43960 sfc_state%u(I,j) = sfc_state%u(I,j) / max(depth(I), GV%H_subroundoff*H_rescale)
4397 enddo
4398 enddo ! end of j loop
4399 else ! Hmix_UV<=0.
440095173 do j=js,je ; do I=is-1,ie
440195160 sfc_state%u(I,j) = CS%u(I,j,1)
4402 enddo ; enddo
440395966 do J=js-1,je ; do i=is,ie
440495953 sfc_state%v(i,J) = CS%v(i,J,1)
4405 enddo ; enddo
4406 endif
4407 endif ! (CS%Hmix >= 0.0)
4408
4409
441013 if (allocated(sfc_state%melt_potential)) then
4411 !$OMP parallel do default(shared) private(depth_ml, dh, T_freeze, depth, pres, delT)
44120 do j=js,je
44130 do i=is,ie
44140 depth(i) = 0.0
44150 delT(i) = 0.0
44160 pres(i) = 0.0
4417 ! Here it is assumed that p=0 is OK, since HFrz ~ 10 to 20m, but under ice-shelves this
4418 ! can be a very bad assumption. ###To fix this, uncomment the following...
4419 ! pres(i) = p_surface(i) + 0.5*(GV%g_Earth*GV%H_to_RZ)*h(i,j,1)
4420 enddo
4421
44220 do k=1,nz
44230 call calculate_TFreeze(CS%tv%S(is:ie,j,k), pres(is:ie), T_freeze(is:ie), CS%tv%eqn_of_state)
44240 do i=is,ie
44250 depth_ml = min(CS%HFrz, CS%visc%h_ML(i,j))
44260 if (depth(i) + h(i,j,k) < depth_ml) then
44270 dh = h(i,j,k)
44280 elseif (depth(i) < depth_ml) then
44290 dh = depth_ml - depth(i)
4430 else
44310 dh = 0.0
4432 endif
4433
44340 depth(i) = depth(i) + dh
44350 delT(i) = delT(i) + dh * (CS%tv%T(i,j,k) - T_freeze(i))
4436 enddo
4437 ! If there is a pressure-dependent freezing point calculation uncomment the following.
4438 ! if (k<nz) then ; do i=is,ie
4439 ! pres(i) = pres(i) + 0.5*(GV%g_Earth*GV%H_to_RZ) * (h(i,j,k) + h(i,j,k+1))
4440 ! enddo ; endif
4441 enddo
4442
44430 do i=is,ie
4444 ! set melt_potential to zero to avoid passing previous values
44450 sfc_state%melt_potential(i,j) = 0.0
4446
44470 if (G%mask2dT(i,j)>0.) then
4448 ! instantaneous melt_potential [Q R Z ~> J m-2]
44490 sfc_state%melt_potential(i,j) = CS%tv%C_p * GV%H_to_RZ * delT(i)
4450 endif
4451 enddo
4452 enddo ! end of j loop
4453 endif ! melt_potential
4454
445513 if (allocated(sfc_state%taux_shelf) .and. allocated(CS%visc%taux_shelf)) then
4456 !$OMP parallel do default(shared)
44570 do j=js,je ; do I=is-1,ie
44580 sfc_state%taux_shelf(I,j) = CS%visc%taux_shelf(I,j)
4459 enddo ; enddo
4460 endif
446113 if (allocated(sfc_state%tauy_shelf) .and. allocated(CS%visc%tauy_shelf)) then
4462 !$OMP parallel do default(shared)
44630 do J=js-1,je ; do i=is,ie
44640 sfc_state%tauy_shelf(i,J) = CS%visc%tauy_shelf(i,J)
4465 enddo ; enddo
4466 endif
4467
446813 if (allocated(sfc_state%ocean_mass) .and. allocated(sfc_state%ocean_heat) .and. &
4469 allocated(sfc_state%ocean_salt)) then
4470 !$OMP parallel do default(shared)
447194393 do j=js,je ; do i=is,ie
447293600 sfc_state%ocean_mass(i,j) = 0.0
447394380 sfc_state%ocean_heat(i,j) = 0.0 ; sfc_state%ocean_salt(i,j) = 0.0
4474 enddo ; enddo
4475 !$OMP parallel do default(shared) private(mass)
44767079293 do j=js,je ; do k=1,nz ; do i=is,ie
44777020000 mass = GV%H_to_RZ*h(i,j,k)
44787020000 sfc_state%ocean_mass(i,j) = sfc_state%ocean_mass(i,j) + mass
44797020000 sfc_state%ocean_heat(i,j) = sfc_state%ocean_heat(i,j) + mass * CS%tv%T(i,j,k)
44807078500 sfc_state%ocean_salt(i,j) = sfc_state%ocean_salt(i,j) + mass * (1.0e-3*CS%tv%S(i,j,k))
4481 enddo ; enddo ; enddo
4482 else
44830 if (allocated(sfc_state%ocean_mass)) then
4484 !$OMP parallel do default(shared)
44850 do j=js,je ; do i=is,ie ; sfc_state%ocean_mass(i,j) = 0.0 ; enddo ; enddo
4486 !$OMP parallel do default(shared)
44870 do j=js,je ; do k=1,nz ; do i=is,ie
44880 sfc_state%ocean_mass(i,j) = sfc_state%ocean_mass(i,j) + GV%H_to_RZ*h(i,j,k)
4489 enddo ; enddo ; enddo
4490 endif
44910 if (allocated(sfc_state%ocean_heat)) then
4492 !$OMP parallel do default(shared)
44930 do j=js,je ; do i=is,ie ; sfc_state%ocean_heat(i,j) = 0.0 ; enddo ; enddo
4494 !$OMP parallel do default(shared) private(mass)
44950 do j=js,je ; do k=1,nz ; do i=is,ie
44960 mass = GV%H_to_RZ*h(i,j,k)
44970 sfc_state%ocean_heat(i,j) = sfc_state%ocean_heat(i,j) + mass * CS%tv%T(i,j,k)
4498 enddo ; enddo ; enddo
4499 endif
45000 if (allocated(sfc_state%ocean_salt)) then
4501 !$OMP parallel do default(shared)
45020 do j=js,je ; do i=is,ie ; sfc_state%ocean_salt(i,j) = 0.0 ; enddo ; enddo
4503 !$OMP parallel do default(shared) private(mass)
45040 do j=js,je ; do k=1,nz ; do i=is,ie
45050 mass = GV%H_to_RZ*h(i,j,k)
45060 sfc_state%ocean_salt(i,j) = sfc_state%ocean_salt(i,j) + mass * (1.0e-3*CS%tv%S(i,j,k))
4507 enddo ; enddo ; enddo
4508 endif
4509 endif
4510
451113 if (associated(CS%tracer_flow_CSp)) then
451213 call call_tracer_surface_state(sfc_state, h, G, GV, US, CS%tracer_flow_CSp)
4513 endif
4514
451513 if (CS%check_bad_sfc_vals) then
45160 numberOfErrors=0 ! count number of errors
45170 do j=js,je ; do i=is,ie
45180 if (G%mask2dT(i,j)>0.) then
4519 localError = sfc_state%sea_lev(i,j) < -G%bathyT(i,j) - G%Z_ref &
4520 .or. sfc_state%sea_lev(i,j) >= CS%bad_val_ssh_max + (G%meanSL(i,j) - G%Z_ref) &
4521 .or. sfc_state%sea_lev(i,j) <= -CS%bad_val_ssh_max + (G%meanSL(i,j) - G%Z_ref) &
45220 .or. sfc_state%sea_lev(i,j) + G%bathyT(i,j) + G%Z_ref < CS%bad_val_col_thick
45230 if (use_temperature) localError = localError &
4524 .or. sfc_state%SSS(i,j)<0. &
4525 .or. sfc_state%SSS(i,j)>=CS%bad_val_sss_max &
4526 .or. sfc_state%SST(i,j)< CS%bad_val_sst_min &
45270 .or. sfc_state%SST(i,j)>=CS%bad_val_sst_max
45280 if (localError) then
45290 numberOfErrors=numberOfErrors+1
45300 if (numberOfErrors<9) then ! Only report details for the first few errors
45310 ig = i + G%HI%idg_offset ! Global i-index
45320 jg = j + G%HI%jdg_offset ! Global j-index
45330 if (use_temperature) then
4534 write(msg(1:240),'(2(a,I0,1x),4(a,f8.3,1x),8(a,es11.4,1x))') &
45350 'Extreme surface sfc_state detected: i=',ig,'j=',jg, &
45360 'lon=',G%geoLonT(i,j), 'lat=',G%geoLatT(i,j), &
45370 'x=',G%gridLonT(ig), 'y=',G%gridLatT(jg), &
45380 'D=',US%Z_to_m*(G%bathyT(i,j)+G%Z_ref), 'SSH=',US%Z_to_m*sfc_state%sea_lev(i,j), &
45390 'SST=',US%C_to_degC*sfc_state%SST(i,j), 'SSS=',US%S_to_ppt*sfc_state%SSS(i,j), &
45400 'U-=',US%L_T_to_m_s*sfc_state%u(I-1,j), 'U+=',US%L_T_to_m_s*sfc_state%u(I,j), &
45410 'V-=',US%L_T_to_m_s*sfc_state%v(i,J-1), 'V+=',US%L_T_to_m_s*sfc_state%v(i,J)
4542 else
4543 write(msg(1:240),'(2(a,I0,1x),4(a,f8.3,1x),6(a,es11.4))') &
45440 'Extreme surface sfc_state detected: i=',ig,'j=',jg, &
45450 'lon=',G%geoLonT(i,j), 'lat=',G%geoLatT(i,j), &
45460 'x=',G%gridLonT(ig), 'y=',G%gridLatT(jg), &
45470 'D=',US%Z_to_m*(G%bathyT(i,j)+G%Z_ref), 'SSH=',US%Z_to_m*sfc_state%sea_lev(i,j), &
45480 'U-=',US%L_T_to_m_s*sfc_state%u(I-1,j), 'U+=',US%L_T_to_m_s*sfc_state%u(I,j), &
45490 'V-=',US%L_T_to_m_s*sfc_state%v(i,J-1), 'V+=',US%L_T_to_m_s*sfc_state%v(i,J)
4550 endif
45510 call MOM_error(WARNING, trim(msg), all_print=.true.)
45520 elseif (numberOfErrors==9) then ! Indicate once that there are more errors
45530 call MOM_error(WARNING, 'There were more unreported extreme events!', all_print=.true.)
4554 endif ! numberOfErrors
4555 endif ! localError
4556 endif ! mask2dT
4557 enddo ; enddo
45580 call sum_across_PEs(numberOfErrors)
45590 if (numberOfErrors>0) then
45600 write(msg(1:240),'(a,i0,a)') 'There were a total of ',numberOfErrors, &
45610 ' locations detected with extreme surface values!'
45620 call MOM_error(FATAL, trim(msg))
4563 endif
4564 endif
4565
456613 if (CS%debug) call MOM_surface_chksum("Post extract_sfc", sfc_state, G, US, haloshift=0, symmetric=.true.)
4567
4568 ! Rotate sfc_state back onto the input grid, sfc_state_in
456913 if (CS%rotate_index) then
45700 call rotate_surface_state(sfc_state, sfc_state_in, G_in, -turns)
45710 call deallocate_surface_state(sfc_state)
4572 endif
4573
457413 call callTree_leave("extract_surface_sfc_state()")
457513end subroutine extract_surface_state
4576
4577!> Rotate initialization fields from input to rotated arrays.
45780subroutine rotate_initial_state(u_in, v_in, h_in, T_in, S_in, &
45790 use_temperature, turns, u, v, h, T, S)
4580 real, dimension(:,:,:), intent(in) :: u_in !< Zonal velocity on the initial grid [L T-1 ~> m s-1]
4581 real, dimension(:,:,:), intent(in) :: v_in !< Meridional velocity on the initial grid [L T-1 ~> m s-1]
4582 real, dimension(:,:,:), intent(in) :: h_in !< Layer thickness on the initial grid [H ~> m or kg m-2]
4583 real, dimension(:,:,:), intent(in) :: T_in !< Temperature on the initial grid [C ~> degC]
4584 real, dimension(:,:,:), intent(in) :: S_in !< Salinity on the initial grid [S ~> ppt]
4585 logical, intent(in) :: use_temperature !< If true, temperature and salinity are active
4586 integer, intent(in) :: turns !< The number quarter-turns to apply
4587 real, dimension(:,:,:), intent(out) :: u !< Zonal velocity on the rotated grid [L T-1 ~> m s-1]
4588 real, dimension(:,:,:), intent(out) :: v !< Meridional velocity on the rotated grid [L T-1 ~> m s-1]
4589 real, dimension(:,:,:), intent(out) :: h !< Layer thickness on the rotated grid [H ~> m or kg m-2]
4590 real, dimension(:,:,:), intent(out) :: T !< Temperature on the rotated grid [C ~> degC]
4591 real, dimension(:,:,:), intent(out) :: S !< Salinity on the rotated grid [S ~> ppt]
4592
45930 call rotate_vector(u_in, v_in, turns, u, v)
45940 call rotate_array(h_in, turns, h)
45950 if (use_temperature) then
45960 call rotate_array(T_in, turns, T)
45970 call rotate_array(S_in, turns, S)
4598 endif
45990end subroutine rotate_initial_state
4600
4601!> Return true if all phases of step_MOM are at the same point in time.
460237function MOM_state_is_synchronized(CS, adv_dyn) result(in_synch)
4603 type(MOM_control_struct), intent(inout) :: CS !< MOM control structure
4604 logical, optional, intent(in) :: adv_dyn !< If present and true, only check
4605 !! whether the advection is up-to-date with
4606 !! the dynamics.
4607 logical :: in_synch !< True if all phases of the update are synchronized.
4608
4609 logical :: adv_only
4610
461137 adv_only = .false. ; if (present(adv_dyn)) adv_only = adv_dyn
4612
461337 if (adv_only) then
46140 in_synch = (CS%t_dyn_rel_adv == 0.0)
4615 else
461637 in_synch = ((CS%t_dyn_rel_adv == 0.0) .and. (CS%t_dyn_rel_thermo == 0.0))
4617 endif
4618
461937end function MOM_state_is_synchronized
4620
4621!> This subroutine offers access to values or pointers to other types from within
4622!! the MOM_control_struct, allowing the MOM_control_struct to be opaque.
46231subroutine get_MOM_state_elements(CS, G, GV, US, C_p, C_p_scaled, use_temp)
4624 type(MOM_control_struct), intent(inout), target :: CS !< MOM control structure
4625 type(ocean_grid_type), optional, pointer :: G !< structure containing metrics and grid info
4626 type(verticalGrid_type), optional, pointer :: GV !< structure containing vertical grid info
4627 type(unit_scale_type), optional, pointer :: US !< A dimensional unit scaling type
4628 real, optional, intent(out) :: C_p !< The heat capacity [J kg degC-1]
4629 real, optional, intent(out) :: C_p_scaled !< The heat capacity in scaled
4630 !! units [Q C-1 ~> J kg-1 degC-1]
4631 logical, optional, intent(out) :: use_temp !< True if temperature is a state variable
4632
46331 if (present(G)) G => CS%G_in
46341 if (present(GV)) GV => CS%GV
46351 if (present(US)) US => CS%US
46361 if (present(C_p)) C_p = CS%US%Q_to_J_kg*US%degC_to_C * CS%tv%C_p
46371 if (present(C_p_scaled)) C_p_scaled = CS%tv%C_p
46381 if (present(use_temp)) use_temp = associated(CS%tv%T)
46391end subroutine get_MOM_state_elements
4640
4641!> Find the global integrals of various quantities.
46420subroutine get_ocean_stocks(CS, mass, heat, salt, on_PE_only)
4643 type(MOM_control_struct), intent(inout) :: CS !< MOM control structure
4644 real, optional, intent(out) :: heat !< The globally integrated integrated ocean heat [J].
4645 real, optional, intent(out) :: salt !< The globally integrated integrated ocean salt [kg].
4646 real, optional, intent(out) :: mass !< The globally integrated integrated ocean mass [kg].
4647 logical, optional, intent(in) :: on_PE_only !< If present and true, only sum on the local PE.
4648
46490 if (present(mass)) &
46500 mass = global_mass_integral(CS%h, CS%G, CS%GV, on_PE_only=on_PE_only)
46510 if (present(heat)) &
4652 heat = CS%US%Q_to_J_kg*CS%US%RZL2_to_kg * CS%tv%C_p * &
46530 global_mass_integral(CS%h, CS%G, CS%GV, CS%tv%T, on_PE_only=on_PE_only, tmp_scale=CS%US%C_to_degC)
46540 if (present(salt)) &
46550 salt = 1.0e-3 * global_mass_integral(CS%h, CS%G, CS%GV, CS%tv%S, on_PE_only=on_PE_only, unscale=CS%US%S_to_ppt)
4656
46570end subroutine get_ocean_stocks
4658
4659
4660!> Save restart/pickup files required to initialize the MOM6 internal state.
46611subroutine save_MOM_restart(CS, directory, time, G, time_stamped, filename, &
4662 GV, num_rest_files, write_IC)
4663 type(MOM_control_struct), intent(inout) :: CS
4664 !< MOM control structure
4665 character(len=*), intent(in) :: directory
4666 !< The directory where the restart files are to be written
4667 type(time_type), intent(in) :: time
4668 !< The current model time
4669 type(ocean_grid_type), intent(inout) :: G
4670 !< The ocean's grid structure
4671 logical, optional, intent(in) :: time_stamped
4672 !< If present and true, add time-stamp to the restart file names
4673 character(len=*), optional, intent(in) :: filename
4674 !< A filename that overrides the name in CS%restartfile
4675 type(verticalGrid_type), optional, intent(in) :: GV
4676 !< The ocean's vertical grid structure
4677 integer, optional, intent(out) :: num_rest_files
4678 !< number of restart files written
4679 logical, optional, intent(in) :: write_IC
4680 !< If present and true, initial conditions are being written
4681
4682 logical :: showCallTree
46831 showCallTree = callTree_showQuery()
4684
46851 call cpu_clock_begin(id_clock_ocean) ; call cpu_clock_begin(id_clock_save_restart)
46861 if (showCallTree) call callTree_waypoint("About to call save_restart (step_MOM)")
4687 call save_restart(directory, time, G, CS%restart_CS, &
4688 time_stamped=time_stamped, filename=filename, GV=GV, &
46891 num_rest_files=num_rest_files, write_IC=write_IC)
46901 if (showCallTree) call callTree_waypoint("Done with call to save_restart (step_MOM)")
4691
46921 if (CS%use_particles) call particles_save_restart(CS%particles, CS%h, directory, time, time_stamped)
46931 call cpu_clock_end(id_clock_save_restart) ; call cpu_clock_end(id_clock_ocean)
46941end subroutine save_MOM_restart
4695
4696
4697!> End of ocean model, including memory deallocation
46981subroutine MOM_end(CS)
4699 type(MOM_control_struct), intent(inout) :: CS !< MOM control structure
4700
47011 call cpu_clock_begin(id_clock_ocean) ; call cpu_clock_begin(id_clock_MOM_end)
4702
47031 call MOM_sum_output_end(CS%sum_output_CSp)
4704
47051 if (CS%use_ALE_algorithm) call ALE_end(CS%ALE_CSp)
4706
4707 !deallocate porous topography variables
4708 !$omp target exit data map(delete: CS%pbv%por_face_areaU, CS%pbv%por_face_areaV)
47091 deallocate(CS%pbv%por_face_areaU) ; deallocate(CS%pbv%por_face_areaV)
4710 !$omp target exit data map(delete: CS%pbv%por_layer_widthU, CS%pbv%por_layer_widthV)
47111 deallocate(CS%pbv%por_layer_widthU) ; deallocate(CS%pbv%por_layer_widthV)
4712
4713 ! NOTE: Allocated in PressureForce_FV_Bouss
47141 if (associated(CS%tv%varT)) deallocate(CS%tv%varT)
4715
47161 call tracer_advect_end(CS%tracer_adv_CSp)
47171 call tracer_hor_diff_end(CS%tracer_diff_CSp)
47181 call tracer_registry_end(CS%tracer_Reg)
47191 call tracer_flow_control_end(CS%tracer_flow_CSp)
4720
47211 if (.not. CS%adiabatic) then
47221 call diabatic_driver_end(CS%diabatic_CSp)
47233 deallocate(CS%diabatic_CSp)
4724 endif
4725
47261 call MOM_diagnostics_end(CS%diagnostics_CSp, CS%ADp, CS%CDp)
4727
47281 if (CS%offline_tracer_mode) call offline_transport_end(CS%offline_CSp)
4729
47301 if (CS%split .and. CS%use_alt_split) then
47310 call end_dyn_split_RK2b(CS%dyn_split_RK2b_CSp)
47321 elseif (CS%split) then
47331 call end_dyn_split_RK2(CS%dyn_split_RK2_CSp)
47340 elseif (CS%use_RK2) then
47350 call end_dyn_unsplit_RK2(CS%dyn_unsplit_RK2_CSp)
4736 else
47370 call end_dyn_unsplit(CS%dyn_unsplit_CSp)
4738 endif
4739
47401 if (CS%use_particles) then
47410 call particles_end(CS%particles, CS%h)
47420 deallocate(CS%particles)
4743 endif
4744
47451 call thickness_diffuse_end(CS%thickness_diffuse_CSp, CS%CDp)
47461 if (CS%interface_filter) call interface_filter_end(CS%interface_filter_CSp, CS%CDp)
47471 call VarMix_end(CS%VarMix)
4748
47491 call set_visc_end(CS%visc, CS%set_visc_CSp)
4750 !$omp target exit data map(delete: CS%visc, CS%set_visc_CSp)
47511 deallocate(CS%set_visc_CSp)
47521 deallocate(CS%visc)
4753
47541 call MEKE_end(CS%MEKE)
4755
47561 if (associated(CS%tv%internal_heat)) deallocate(CS%tv%internal_heat)
47571 if (associated(CS%tv%TempxPmE)) deallocate(CS%tv%TempxPmE)
4758
47591 DEALLOC_(CS%ave_ssh_ibc) ; DEALLOC_(CS%ssh_rint) ; DEALLOC_(CS%eta_av_bc)
4760 !$omp target exit data map(delete: CS%ave_ssh_ibc)
4761 !$omp target exit data map(delete: CS%ssh_rint)
4762 !$omp target exit data map(delete: CS%eta_av_bc)
4763
4764 ! TODO: debug_truncations deallocation
4765
47661 DEALLOC_(CS%uhtr) ; DEALLOC_(CS%vhtr)
4767 !$omp target exit data map(delete: CS%uhtr, CS%vhtr)
4768
47691 if (associated(CS%Hml)) deallocate(CS%Hml)
47701 if (associated(CS%tv%salt_deficit)) deallocate(CS%tv%salt_deficit)
47711 if (associated(CS%tv%frazil)) deallocate(CS%tv%frazil)
47721 if (allocated(CS%tv%SpV_avg)) deallocate(CS%tv%SpV_avg)
4773
47741 if (associated(CS%tv%T)) then
47751 DEALLOC_(CS%T) ; CS%tv%T => NULL() ; DEALLOC_(CS%S) ; CS%tv%S => NULL()
4776 endif
4777
47781 DEALLOC_(CS%u) ; DEALLOC_(CS%v) ; DEALLOC_(CS%h)
47791 DEALLOC_(CS%uh) ; DEALLOC_(CS%vh)
4780 !$omp target exit data map(delete: CS%u, CS%v, CS%h, CS%uh, CS%vh)
4781
47821 if (associated(CS%update_OBC_CSp)) call OBC_register_end(CS%update_OBC_CSp)
47831 if (associated(CS%OBC)) call open_boundary_end(CS%OBC)
4784
47851 call verticalGridEnd(CS%GV)
47861 call MOM_grid_end(CS%G)
4787
47881 if (CS%debug .or. CS%G%symmetric) &
47891 call deallocate_MOM_domain(CS%G%Domain_aux)
4790
47911 if (CS%rotate_index) &
47920 call deallocate_MOM_domain(CS%G%Domain)
4793
4794 ! The MPP domains may be needed by an external coupler, so use `cursory`.
4795 ! TODO: This may create a domain memory leak, and needs investigation.
47961 call deallocate_MOM_domain(CS%G_in%domain, cursory=.true.)
4797
47981 call unit_scaling_end(CS%US)
4799
48001 call cpu_clock_end(id_clock_MOM_end) ; call cpu_clock_end(id_clock_ocean)
4801
48021end subroutine MOM_end
4803
4804!> \namespace mom
4805!!
4806!! Modular Ocean Model (MOM) Version 6.0 (MOM6)
4807!!
4808!! \authors Alistair Adcroft, Robert Hallberg, and Stephen Griffies
4809!!
4810!! Additional contributions from:
4811!! * Whit Anderson
4812!! * Brian Arbic
4813!! * Will Cooke
4814!! * Anand Gnanadesikan
4815!! * Matthew Harrison
4816!! * Mehmet Ilicak
4817!! * Laura Jackson
4818!! * Jasmine John
4819!! * John Krasting
4820!! * Zhi Liang
4821!! * Bonnie Samuels
4822!! * Harper Simmons
4823!! * Laurent White
4824!! * Niki Zadeh
4825!!
4826!! MOM ice-shelf code was developed by
4827!! * Daniel Goldberg
4828!! * Robert Hallberg
4829!! * Chris Little
4830!! * Olga Sergienko
4831!!
4832!! \section section_overview Overview of MOM
4833!!
4834!! This program (MOM) simulates the ocean by numerically solving
4835!! the hydrostatic primitive equations in generalized Lagrangian
4836!! vertical coordinates, typically tracking stretched pressure (p*)
4837!! surfaces or following isopycnals in the ocean's interior, and
4838!! general orthogonal horizontal coordinates. Unlike earlier versions
4839!! of MOM, in MOM6 these equations are horizontally discretized on an
4840!! Arakawa C-grid. (It remains to be seen whether a B-grid dynamic
4841!! core will be revived in MOM6 at a later date; for now applications
4842!! requiring a B-grid discretization should use MOM5.1.) MOM6 offers
4843!! a range of options for the physical parameterizations, from those
4844!! most appropriate to highly idealized models for geophysical fluid
4845!! dynamics studies to a rich suite of processes appropriate for
4846!! realistic ocean simulations. The thermodynamic options typically
4847!! use conservative temperature and preformed salinity as conservative
4848!! state variables and a full nonlinear equation of state, but there
4849!! are also idealized adiabatic configurations of the model that use
4850!! fixed density layers. Version 6.0 of MOM continues in the long
4851!! tradition of a commitment to climate-quality ocean simulations
4852!! embodied in previous versions of MOM, even as it draws extensively
4853!! on the lessons learned in the development of the Generalized Ocean
4854!! Layered Dynamics (GOLD) ocean model, which was also primarily
4855!! developed at NOAA/GFDL. MOM has also benefited tremendously from
4856!! the FMS infrastructure, which it utilizes and shares with other
4857!! component models developed at NOAA/GFDL.
4858!!
4859!! When run is isopycnal-coordinate mode, the uppermost few layers
4860!! are often used to describe a bulk mixed layer, including the
4861!! effects of penetrating shortwave radiation. Either a split-
4862!! explicit time stepping scheme or a non-split scheme may be used
4863!! for the dynamics, while the time stepping may be split (and use
4864!! different numbers of steps to cover the same interval) for the
4865!! forcing, the thermodynamics, and for the dynamics. Most of the
4866!! numerics are second order accurate in space. MOM can run with an
4867!! absurdly thin minimum layer thickness. A variety of non-isopycnal
4868!! vertical coordinate options are under development, but all exploit
4869!! the advantages of a Lagrangian vertical coordinate, as discussed
4870!! in detail by Adcroft and Hallberg (Ocean Modelling, 2006).
4871!!
4872!! Details of the numerics and physical parameterizations are
4873!! provided in the appropriate source files. All of the available
4874!! options are selected at run-time by parsing the input files,
4875!! usually MOM_input and MOM_override, and the options choices are
4876!! then documented for each run in MOM_param_docs.
4877!!
4878!! MOM6 integrates the equations forward in time in three distinct
4879!! phases. In one phase, the dynamic equations for the velocities
4880!! and layer thicknesses are advanced, capturing the propagation of
4881!! external and internal inertia-gravity waves, Rossby waves, and
4882!! other strictly adiabatic processes, including lateral stresses,
4883!! vertical viscosity and momentum forcing, and interface height
4884!! diffusion (commonly called Gent-McWilliams diffusion in depth-
4885!! coordinate models). In the second phase, all tracers are advected
4886!! and diffused along the layers. The third phase applies diabatic
4887!! processes, vertical mixing of water properties, and perhaps
4888!! vertical remapping to cause the layers to track the desired
4889!! vertical coordinate.
4890!!
4891!! The present file (MOM.F90) orchestrates the main time stepping
4892!! loops. One time integration option for the dynamics uses a split
4893!! explicit time stepping scheme to rapidly step the barotropic
4894!! pressure and velocity fields. The barotropic velocities are
4895!! averaged over the baroclinic time step before they are used to
4896!! advect thickness and determine the baroclinic accelerations. As
4897!! described in Hallberg and Adcroft (2009), a barotropic correction
4898!! is applied to the time-mean layer velocities to ensure that the
4899!! sum of the layer transports agrees with the time-mean barotropic
4900!! transport, thereby ensuring that the estimates of the free surface
4901!! from the sum of the layer thicknesses agrees with the final free
4902!! surface height as calculated by the barotropic solver. The
4903!! barotropic and baroclinic velocities are kept consistent by
4904!! recalculating the barotropic velocities from the baroclinic
4905!! transports each time step. This scheme is described in Hallberg,
4906!! 1997, J. Comp. Phys. 135, 54-65 and in Hallberg and Adcroft, 2009,
4907!! Ocean Modelling, 29, 15-26.
4908!!
4909!! The other time integration options use non-split time stepping
4910!! schemes based on the 3-step third order Runge-Kutta scheme
4911!! described in Matsuno, 1966, J. Met. Soc. Japan, 44, 85-88, or on
4912!! a two-step quasi-2nd order Runge-Kutta scheme. These are much
4913!! slower than the split time-stepping scheme, but they are useful
4914!! for providing a more robust solution for debugging cases where the
4915!! more complicated split time-stepping scheme may be giving suspect
4916!! solutions.
4917!!
4918!! There are a range of closure options available. Horizontal
4919!! velocities are subject to a combination of horizontal biharmonic
4920!! and Laplacian friction (based on a stress tensor formalism) and a
4921!! vertical Fickian viscosity (perhaps using the kinematic viscosity
4922!! of water). The horizontal viscosities may be constant, spatially
4923!! varying or may be dynamically calculated using Smagorinsky's
4924!! approach. A diapycnal diffusion of density and thermodynamic
4925!! quantities is also allowed, but not required, as is horizontal
4926!! diffusion of interface heights (akin to the Gent-McWilliams
4927!! closure of geopotential coordinate models). The diapycnal mixing
4928!! may use a fixed diffusivity or it may use the shear Richardson
4929!! number dependent closure, like that described in Jackson et al.
4930!! (JPO, 2008). When there is diapycnal diffusion, it applies to
4931!! momentum as well. As this is in addition to the vertical viscosity,
4932!! the vertical Prandtl always exceeds 1. A refined bulk-mixed layer
4933!! is often used to describe the planetary boundary layer in realistic
4934!! ocean simulations.
4935!!
4936!! MOM has a number of noteworthy debugging capabilities.
4937!! Excessively large velocities are truncated and MOM will stop
4938!! itself after a number of such instances to keep the model from
4939!! crashing altogether. This is useful in diagnosing failures,
4940!! or (by accepting some truncations) it may be useful for getting
4941!! the model past the adjustment from an ill-balanced initial
4942!! condition. In addition, all of the accelerations in the columns
4943!! with excessively large velocities may be directed to a text file.
4944!! Parallelization errors may be diagnosed using the DEBUG option,
4945!! which causes extensive checksums to be written out along with
4946!! comments indicating where in the algorithm the sums originate and
4947!! what variable is being summed. The point where these checksums
4948!! differ between runs is usually a good indication of where in the
4949!! code the problem lies. All of the test cases provided with MOM
4950!! are routinely tested to ensure that they give bitwise identical
4951!! results regardless of the domain decomposition, or whether they
4952!! use static or dynamic memory allocation.
4953!!
4954!! \section section_structure Structure of MOM
4955!!
4956!! About 115 other files of source code and 4 header files comprise
4957!! the MOM code, although there are several hundred more files that
4958!! make up the FMS infrastructure upon which MOM is built. Each of
4959!! the MOM files contains comments documenting what it does, and
4960!! most of the file names are fairly self-evident. In addition, all
4961!! subroutines and data types are referenced via a module use, only
4962!! statement, and the module names are consistent with the file names,
4963!! so it is not too hard to find the source file for a subroutine.
4964!!
4965!! The typical MOM directory tree is as follows:
4966!!
4967!! \verbatim
4968!! ../MOM
4969!! |-- ac
4970!! |-- config_src
4971!! | |-- drivers
4972!! | ! |-- FMS_cap
4973!! | ! |-- ice_solo_driver
4974!! | ! |-- mct_cap
4975!! | ! |-- nuopc_cap
4976!! | ! |-- solo_driver
4977!! | ! `-- unit_drivers
4978!! | |-- external
4979!! | ! |-- drifters
4980!! | ! |-- GFDL_ocean_BGC
4981!! | ! `-- ODA_hooks
4982!! | |-- infra
4983!! | ! |-- FMS1
4984!! | ! `-- FMS2
4985!! | `-- memory
4986!! | ! |-- dynamic_nonsymmetric
4987!! | ! `-- dynamic_symmetric
4988!! |-- docs
4989!! |-- pkg
4990!! | |-- CVMix-src
4991!! | |-- ...
4992!! | `-- MOM6_DA_hooks
4993!! `-- src
4994!! |-- ALE
4995!! |-- core
4996!! |-- diagnostics
4997!! |-- equation_of_state
4998!! |-- framework
4999!! |-- ice_shelf
5000!! |-- initialization
5001!! |-- ocean_data_assim
5002!! |-- parameterizations
5003!! | |-- CVMix
5004!! | |-- lateral
5005!! | `-- vertical
5006!! |-- tracer
5007!! `-- user
5008!! \endverbatim
5009!!
5010!! Rather than describing each file here, selected directory contents
5011!! will be described to give a broad overview of the MOM code
5012!! structure.
5013!!
5014!! The directories under config_src contain files that are used for
5015!! configuring the code, for instance for coupled or ocean-only runs.
5016!! Only one or two of these directories are used in compiling any,
5017!! particular run.
5018!!
5019!! * config_src/drivers/FMS-cap:
5020!! The files here are used to couple MOM as a component in a larger
5021!! run driven by the FMS coupler. This includes code that converts
5022!! various forcing fields into the code structures and flux and unit
5023!! conventions used by MOM, and converts the MOM surface fields
5024!! back to the forms used by other FMS components.
5025!!
5026!! * config_src/drivers/nuopc-cap:
5027!! The files here are used to couple MOM as a component in a larger
5028!! run driven by the NUOPC coupler. This includes code that converts
5029!! various forcing fields into the code structures and flux and unit
5030!! conventions used by MOM, and converts the MOM surface fields
5031!! back to the forms used by other NUOPC components.
5032!!
5033!! * config_src/drivers/solo_driver:
5034!! The files here are include the _main driver that is used when
5035!! MOM is configured as an ocean-only model, as well as the files
5036!! that specify the surface forcing in this configuration.
5037!!
5038!! * config_src/external:
5039!! The files here are mostly just stubs, so that MOM6 can compile
5040!! with calls to the public interfaces external packages, but
5041!! without actually requiring those packages themselves. In more
5042!! elaborate configurations, would be linked to the actual code for
5043!! those external packages rather than these simple stubs.
5044!!
5045!! * config_src/memory/dynamic-symmetric:
5046!! The only file here is the version of MOM_memory.h that is used
5047!! for dynamic memory configurations of MOM.
5048!!
5049!! The directories under src contain most of the MOM files. These
5050!! files are used in every configuration using MOM.
5051!!
5052!! * src/core:
5053!! The files here constitute the MOM dynamic core. This directory
5054!! also includes files with the types that describe the model's
5055!! lateral grid and have defined types that are shared across
5056!! various MOM modules to allow for more succinct and flexible
5057!! subroutine argument lists.
5058!!
5059!! * src/diagnostics:
5060!! The files here calculate various diagnostics that are ancilliary
5061!! to the model itself. While most of these diagnostics do not
5062!! directly affect the model's solution, there are some, like the
5063!! calculation of the deformation radius, that are used in some
5064!! of the process parameterizations.
5065!!
5066!! * src/equation_of_state:
5067!! These files describe the physical properties of sea-water,
5068!! including both the equation of state and when it freezes.
5069!!
5070!! * src/framework:
5071!! These files provide infrastructure utilities for MOM. Many are
5072!! simply wrappers for capabilities provided by FMS, although others
5073!! provide capabilities (like the file_parser) that are unique to
5074!! MOM. When MOM is adapted to use a modeling infrastructure
5075!! distinct from FMS, most of the required changes are in this
5076!! directory.
5077!!
5078!! * src/initialization:
5079!! These are the files that are used to initialize the MOM grid
5080!! or provide the initial physical state for MOM. These files are
5081!! not intended to be modified, but provide a means for calling
5082!! user-specific initialization code like the examples in src/user.
5083!!
5084!! * src/parameterizations/lateral:
5085!! These files implement a number of quasi-lateral (along-layer)
5086!! process parameterizations, including lateral viscosities,
5087!! parameterizations of eddy effects, and the calculation of tidal
5088!! forcing.
5089!!
5090!! * src/parameterizations/vertical:
5091!! These files implement a number of vertical mixing or diabatic
5092!! processes, including the effects of vertical viscosity and
5093!! code to parameterize the planetary boundary layer. There is a
5094!! separate driver that orchestrates this portion of the algorithm,
5095!! and there is a diversity of parameterizations to be found here.
5096!!
5097!! * src/tracer:
5098!! These files handle the lateral transport and diffusion of
5099!! tracers, or are the code to implement various passive tracer
5100!! packages. Additional tracer packages are readily accommodated.
5101!!
5102!! * src/user:
5103!! These are either stub routines that a user could use to change
5104!! the model's initial conditions or forcing, or are examples that
5105!! implement specific test cases. These files can easily be hand
5106!! edited to create new analytically specified configurations.
5107!!
5108!!
5109!! Most simulations can be set up by modifying only the files
5110!! MOM_input, and possibly one or two of the files in src/user.
5111!! In addition, the diag_table (MOM_diag_table) will commonly be
5112!! modified to tailor the output to the needs of the question at
5113!! hand. The FMS utility mkmf works with a file called path_names
5114!! to build an appropriate makefile, and path_names should be edited
5115!! to reflect the actual location of the desired source code.
5116!!
5117!! The separate MOM-examples git repository provides a large number
5118!! of working configurations of MOM, along with reference solutions for several
5119!! different compilers on GFDL's latest large computer. The versions
5120!! of MOM_memory.h in these directories need not be used if dynamic
5121!! memory allocation is desired, and the answers should be unchanged.
5122!!
5123!!
5124!! There are 3 publicly visible subroutines in this file (MOM.F90).
5125!! * step_MOM steps MOM over a specified interval of time.
5126!! * MOM_initialize calls initialize and does other initialization
5127!! that does not warrant user modification.
5128!! * extract_surface_state determines the surface (bulk mixed layer
5129!! if traditional isopycnal vertical coordinate) properties of the
5130!! current model state and packages pointers to these fields into an
5131!! exported structure.
5132!!
5133!! The remaining subroutines in this file (src/core/MOM.F90) are:
5134!! * find_total_transport determines the barotropic mass transport.
5135!! * register_diags registers many diagnostic fields for the dynamic
5136!! solver, or of the main model variables.
5137!! * MOM_timing_init initializes various CPU time clocks.
5138!! * write_static_fields writes out various time-invariant fields.
5139!! * set_restart_fields is used to specify those fields that are
5140!! written to and read from the restart file.
5141!!
5142!! \section section_heat_budget Diagnosing MOM heat budget
5143!!
5144!! Here are some example heat budgets for the ALE version of MOM6.
5145!!
5146!! \subsection subsection_2d_heat_budget Depth integrated heat budget
5147!!
5148!! Depth integrated heat budget diagnostic for MOM.
5149!!
5150!! * OPOTTEMPTEND_2d = T_ADVECTION_XY_2d + OPOTTEMPPMDIFF_2d + HFDS + HFGEOU
5151!!
5152!! * T_ADVECTION_XY_2d = horizontal advection
5153!! * OPOTTEMPPMDIFF_2d = neutral diffusion
5154!! * HFDS = net surface boundary heat flux
5155!! * HFGEOU = geothermal heat flux
5156!!
5157!! * HFDS = net surface boundary heat flux entering the ocean
5158!! = rsntds + rlntds + hfls + hfss + heat_pme + hfsifrazil
5159!!
5160!! * More heat flux cross-checks
5161!! * hfds = net_heat_coupler + hfsifrazil + heat_pme
5162!! * heat_pme = heat_content_surfwater
5163!! = heat_content_massin + heat_content_massout
5164!! = heat_content_fprec + heat_content_cond + heat_content_vprec
5165!! + hfrunoffds + hfevapds + hfrainds
5166!!
5167!! \subsection subsection_3d_heat_budget Depth integrated heat budget
5168!!
5169!! Here is an example 3d heat budget diagnostic for MOM.
5170!!
5171!! * OPOTTEMPTEND = T_ADVECTION_XY + TH_TENDENCY_VERT_REMAP + OPOTTEMPDIFF + OPOTTEMPPMDIFF
5172!! + BOUNDARY_FORCING_HEAT_TENDENCY + FRAZIL_HEAT_TENDENCY
5173!!
5174!! * OPOTTEMPTEND = net tendency of heat as diagnosed in MOM.F90
5175!! * T_ADVECTION_XY = heating of a cell from lateral advection
5176!! * TH_TENDENCY_VERT_REMAP = heating of a cell from vertical remapping
5177!! * OPOTTEMPDIFF = heating of a cell from diabatic diffusion
5178!! * OPOTTEMPPMDIFF = heating of a cell from neutral diffusion
5179!! * BOUNDARY_FORCING_HEAT_TENDENCY = heating of cell from boundary fluxes
5180!! * FRAZIL_HEAT_TENDENCY = heating of cell from frazil
5181!!
5182!! * TH_TENDENCY_VERT_REMAP has zero vertical sum, as it redistributes heat in vertical.
5183!!
5184!! * OPOTTEMPDIFF has zero vertical sum, as it redistributes heat in the vertical.
5185!!
5186!! * BOUNDARY_FORCING_HEAT_TENDENCY generally has 3d structure, with k > 1 contributions from
5187!! penetrative shortwave, and from other fluxes for the case when layers are tiny, in which
5188!! case MOM6 partitions tendencies into k > 1 layers.
5189!!
5190!! * FRAZIL_HEAT_TENDENCY generally has 3d structure, since MOM6 frazil calculation checks the
5191!! full ocean column.
5192!!
5193!! * FRAZIL_HEAT_TENDENCY[k=\@sum] = HFSIFRAZIL = column integrated frazil heating.
5194!!
5195!! * HFDS = FRAZIL_HEAT_TENDENCY[k=\@sum] + BOUNDARY_FORCING_HEAT_TENDENCY[k=\@sum]
5196!!
5197!! Here is an example 2d heat budget (depth summed) diagnostic for MOM.
5198!!
5199!! * OPOTTEMPTEND_2d = T_ADVECTION_XY_2d + OPOTTEMPPMDIFF_2d + HFDS
5200!!
5201!!
5202!! Here is an example 3d salt budget diagnostic for MOM.
5203!!
5204!! * OSALTTEND = S_ADVECTION_XY + SH_TENDENCY_VERT_REMAP + OSALTDIFF + OSALTPMDIFF
5205!! + BOUNDARY_FORCING_SALT_TENDENCY
5206!!
5207!! * OSALTTEND = net tendency of salt as diagnosed in MOM.F90
5208!! * S_ADVECTION_XY = salt convergence to cell from lateral advection
5209!! * SH_TENDENCY_VERT_REMAP = salt convergence to cell from vertical remapping
5210!! * OSALTDIFF = salt convergence to cell from diabatic diffusion
5211!! * OSALTPMDIFF = salt convergence to cell from neutral diffusion
5212!! * BOUNDARY_FORCING_SALT_TENDENCY = salt convergence to cell from boundary fluxes
5213!!
5214!! * SH_TENDENCY_VERT_REMAP has zero vertical sum, as it redistributes salt in vertical.
5215!!
5216!! * OSALTDIFF has zero vertical sum, as it redistributes salt in the vertical.
5217!!
5218!! * BOUNDARY_FORCING_SALT_TENDENCY generally has 3d structure, with k > 1 contributions from
5219!! the case when layers are tiny, in which case MOM6 partitions tendencies into k > 1 layers.
5220!!
5221!! * SFDSI = BOUNDARY_FORCING_SALT_TENDENCY[k=\@sum]
5222!!
5223!! Here is an example 2d salt budget (depth summed) diagnostic for MOM.
5224!!
5225!! * OSALTTEND_2d = S_ADVECTION_XY_2d + OSALTPMDIFF_2d + SFDSI (+ SALT_FLUX_RESTORE)
5226!!
5227!!
5228!!
52290end module MOM