MOM6
MOM_dynamics_unsplit.F90
1 !> Time steps the ocean dynamics with an unsplit quasi 3rd order scheme
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 !********+*********+*********+*********+*********+*********+*********+**
7 !* *
8 !* By Robert Hallberg, 1993-2012 *
9 !* *
10 !* This file contains code that does the time-stepping of the *
11 !* adiabatic dynamic core, in this case with an unsplit third-order *
12 !* Runge-Kutta time stepping scheme for the momentum and a forward- *
13 !* backward coupling between the momentum and continuity equations. *
14 !* This was the orignal unsplit time stepping scheme used in early *
15 !* versions of HIM and its precuror. While it is very simple and *
16 !* accurate, it is much less efficient that the split time stepping *
17 !* scheme for realistic oceanographic applications. It has been *
18 !* retained for all of these years primarily to verify that the split *
19 !* scheme is giving the right answers, and to debug the failings of *
20 !* the split scheme when it is not. The split time stepping scheme *
21 !* is now sufficiently robust that it should be first choice for *
22 !* almost any conceivable application, except perhaps from cases *
23 !* with just a few layers for which the exact timing of the high- *
24 !* frequency barotropic gravity waves is of paramount importance. *
25 !* This scheme is slightly more efficient than the other unsplit *
26 !* scheme that can be found in MOM_dynamics_unsplit_RK2.F90. *
27 !* *
28 !* The subroutine step_MOM_dyn_unsplit actually does the time *
29 !* stepping, while register_restarts_dyn_unsplit sets the fields *
30 !* that are found in a full restart file with this scheme, and *
31 !* initialize_dyn_unsplit initializes the cpu clocks that are * *
32 !* used in this module. For largely historical reasons, this module *
33 !* does not have its own control structure, but shares the same *
34 !* control structure with MOM.F90 and the other MOM_dynamics_... *
35 !* modules. *
36 !* *
37 !* Macros written all in capital letters are defined in MOM_memory.h. *
38 !* *
39 !* A small fragment of the grid is shown below: *
40 !* *
41 !* j+1 x ^ x ^ x At x: q, CoriolisBu *
42 !* j+1 > o > o > At ^: v, PFv, CAv, vh, diffv, tauy, vbt, vhtr *
43 !* j x ^ x ^ x At >: u, PFu, CAu, uh, diffu, taux, ubt, uhtr *
44 !* j > o > o > At o: h, bathyT, eta, T, S, tr *
45 !* j-1 x ^ x ^ x *
46 !* i-1 i i+1 *
47 !* i i+1 *
48 !* *
49 !* The boundaries always run through q grid points (x). *
50 !* *
51 !********+*********+*********+*********+*********+*********+*********+**
52 
56 use mom_checksum_packages, only : mom_thermo_chksum, mom_state_chksum, mom_accel_chksum
57 use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
58 use mom_cpu_clock, only : clock_component, clock_subcomponent
59 use mom_cpu_clock, only : clock_module_driver, clock_module, clock_routine
60 use mom_diag_mediator, only : diag_mediator_init, enable_averages
61 use mom_diag_mediator, only : disable_averaging, post_data, safe_alloc_ptr
62 use mom_diag_mediator, only : register_diag_field, register_static_field
63 use mom_diag_mediator, only : set_diag_mediator_grid, diag_ctrl, diag_update_remap_grids
64 use mom_domains, only : mom_domains_init, pass_var, pass_vector
67 use mom_domains, only : to_south, to_west, to_all, cgrid_ne, scalar_pair
68 use mom_error_handler, only : mom_error, mom_mesg, fatal, warning, is_root_pe
70 use mom_get_input, only : directories
71 use mom_io, only : mom_io_init
72 use mom_restart, only : register_restart_field, query_initialized, save_restart
73 use mom_restart, only : restart_init, mom_restart_cs
74 use mom_time_manager, only : time_type, real_to_time, operator(+)
75 use mom_time_manager, only : operator(-), operator(>), operator(*), operator(/)
76 
77 use mom_ale, only : ale_cs
78 use mom_barotropic, only : barotropic_cs
79 use mom_boundary_update, only : update_obc_data, update_obc_cs
80 use mom_continuity, only : continuity, continuity_init, continuity_cs, continuity_stencil
81 use mom_coriolisadv, only : coradcalc, coriolisadv_init, coriolisadv_cs
83 use mom_grid, only : ocean_grid_type
84 use mom_hor_index, only : hor_index_type
85 use mom_hor_visc, only : horizontal_viscosity, hor_visc_init, hor_visc_cs
88 use mom_meke_types, only : meke_type
90 use mom_open_boundary, only : radiation_open_bdry_conds
91 use mom_open_boundary, only : open_boundary_zero_normal_flow
92 use mom_pressureforce, only : pressureforce, pressureforce_init, pressureforce_cs
93 use mom_set_visc, only : set_viscous_ml, set_visc_cs
95 use mom_tidal_forcing, only : tidal_forcing_init, tidal_forcing_cs
97 use mom_vert_friction, only : vertvisc, vertvisc_coef, vertvisc_init, vertvisc_cs
98 use mom_verticalgrid, only : verticalgrid_type, get_thickness_units
99 use mom_verticalgrid, only : get_flux_units, get_tr_flux_units
101 
102 implicit none ; private
103 
104 #include <MOM_memory.h>
105 
106 !> MOM_dynamics_unsplit module control structure
107 type, public :: mom_dyn_unsplit_cs ; private
108  real allocable_, dimension(NIMEMB_PTR_,NJMEM_,NKMEM_) :: &
109  cau, & !< CAu = f*v - u.grad(u) [L T-2 ~> m s-2].
110  pfu, & !< PFu = -dM/dx [L T-2 ~> m s-2].
111  diffu !< Zonal acceleration due to convergence of the along-isopycnal stress tensor [L T-2 ~> m s-2].
112 
113  real allocable_, dimension(NIMEM_,NJMEMB_PTR_,NKMEM_) :: &
114  cav, & !< CAv = -f*u - u.grad(v) [L T-2 ~> m s-2].
115  pfv, & !< PFv = -dM/dy [L T-2 ~> m s-2].
116  diffv !< Meridional acceleration due to convergence of the along-isopycnal stress tensor [L T-2 ~> m s-2].
117 
118  real, pointer, dimension(:,:) :: taux_bot => null() !< frictional x-bottom stress from the ocean
119  !! to the seafloor [R L Z T-2 ~> Pa]
120  real, pointer, dimension(:,:) :: tauy_bot => null() !< frictional y-bottom stress from the ocean
121  !! to the seafloor [R L Z T-2 ~> Pa]
122 
123  logical :: use_correct_dt_visc !< If true, use the correct timestep in the viscous terms applied
124  !! in the first predictor step with the unsplit time stepping scheme,
125  !! and in the calculation of the turbulent mixed layer properties
126  !! for viscosity. The default should be true, but it is false.
127  logical :: debug !< If true, write verbose checksums for debugging purposes.
128 
129  logical :: module_is_initialized = .false. !< Record whether this mouled has been initialzed.
130 
131  !>@{ Diagnostic IDs
132  integer :: id_uh = -1, id_vh = -1
133  integer :: id_pfu = -1, id_pfv = -1, id_cau = -1, id_cav = -1
134  !>@}
135 
136  type(diag_ctrl), pointer :: diag => null() !< A structure that is used to
137  !! regulate the timing of diagnostic output.
138  type(accel_diag_ptrs), pointer :: adp => null() !< A structure pointing to the
139  !! accelerations in the momentum equations,
140  !! which can later be used to calculate
141  !! derived diagnostics like energy budgets.
142  type(cont_diag_ptrs), pointer :: cdp => null() !< A structure with pointers to
143  !! various terms in the continuity equations,
144  !! which can later be used to calculate
145  !! derived diagnostics like energy budgets.
146 
147  ! The remainder of the structure points to child subroutines' control structures.
148  !> A pointer to the horizontal viscosity control structure
149  type(hor_visc_cs), pointer :: hor_visc_csp => null()
150  !> A pointer to the continuity control structure
151  type(continuity_cs), pointer :: continuity_csp => null()
152  !> A pointer to the CoriolisAdv control structure
153  type(coriolisadv_cs), pointer :: coriolisadv_csp => null()
154  !> A pointer to the PressureForce control structure
155  type(pressureforce_cs), pointer :: pressureforce_csp => null()
156  !> A pointer to the vertvisc control structure
157  type(vertvisc_cs), pointer :: vertvisc_csp => null()
158  !> A pointer to the set_visc control structure
159  type(set_visc_cs), pointer :: set_visc_csp => null()
160  !> A pointer to the tidal forcing control structure
161  type(tidal_forcing_cs), pointer :: tides_csp => null()
162  !> A pointer to the ALE control structure.
163  type(ale_cs), pointer :: ale_csp => null()
164 
165  type(ocean_obc_type), pointer :: obc => null() !< A pointer to an open boundary
166  ! condition type that specifies whether, where, and what open boundary
167  ! conditions are used. If no open BCs are used, this pointer stays
168  ! nullified. Flather OBCs use open boundary_CS as well.
169  !> A pointer to the update_OBC control structure
170  type(update_obc_cs), pointer :: update_obc_csp => null()
171 
172 end type mom_dyn_unsplit_cs
173 
174 public step_mom_dyn_unsplit, register_restarts_dyn_unsplit
175 public initialize_dyn_unsplit, end_dyn_unsplit
176 
177 !>@{ CPU time clock IDs
178 integer :: id_clock_cor, id_clock_pres, id_clock_vertvisc
179 integer :: id_clock_continuity, id_clock_horvisc, id_clock_mom_update
180 integer :: id_clock_pass, id_clock_pass_init
181 !>@}
182 
183 contains
184 
185 ! =============================================================================
186 
187 !> Step the MOM6 dynamics using an unsplit mixed 2nd order (for continuity) and
188 !! 3rd order (for the inviscid momentum equations) order scheme
189 subroutine step_mom_dyn_unsplit(u, v, h, tv, visc, Time_local, dt, forces, &
190  p_surf_begin, p_surf_end, uh, vh, uhtr, vhtr, eta_av, G, GV, US, CS, &
191  VarMix, MEKE, Waves)
192  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
193  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
194  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
195  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: u !< The zonal velocity [L T-1 ~> m s-1].
196  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: v !< The meridional velocity [L T-1 ~> m s-1].
197  real, dimension(SZI_(G),SZJ_(G),SZK_(G)), intent(inout) :: h !< Layer thicknesses [H ~> m or kg m-2].
198  type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various
199  !! thermodynamic variables.
200  type(vertvisc_type), intent(inout) :: visc !< A structure containing vertical
201  !! viscosities, bottom drag viscosities, and related fields.
202  type(time_type), intent(in) :: Time_local !< The model time at the end
203  !! of the time step.
204  real, intent(in) :: dt !< The dynamics time step [T ~> s].
205  type(mech_forcing), intent(in) :: forces !< A structure with the driving mechanical forces
206  real, dimension(:,:), pointer :: p_surf_begin !< A pointer (perhaps NULL) to the surface
207  !! pressure at the start of this dynamic step [R L2 T-2 ~> Pa].
208  real, dimension(:,:), pointer :: p_surf_end !< A pointer (perhaps NULL) to the surface
209  !! pressure at the end of this dynamic step [R L2 T-2 ~> Pa].
210  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: uh !< The zonal volume or mass transport
211  !! [H L2 T-1 ~> m3 s-1 or kg s-1].
212  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: vh !< The meridional volume or mass
213  !! transport [H L2 T-1 ~> m3 s-1 or kg s-1].
214  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), intent(inout) :: uhtr !< The accumulated zonal volume or mass
215  !! transport since the last tracer advection [H L2 ~> m3 or kg].
216  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), intent(inout) :: vhtr !< The accumulated meridional volume or mass
217  !! transport since the last tracer advection [H L2 ~> m3 or kg].
218  real, dimension(SZI_(G),SZJ_(G)), intent(out) :: eta_av !< The time-mean free surface height or
219  !! column mass [H ~> m or kg m-2].
220  type(mom_dyn_unsplit_cs), pointer :: CS !< The control structure set up by
221  !! initialize_dyn_unsplit.
222  type(varmix_cs), pointer :: VarMix !< A pointer to a structure with fields
223  !! that specify the spatially variable viscosities.
224  type(meke_type), pointer :: MEKE !< A pointer to a structure containing
225  !! fields related to the Mesoscale Eddy Kinetic Energy.
226  type(wave_parameters_cs), optional, pointer :: Waves !< A pointer to a structure containing
227  !! fields related to the surface wave conditions
228 
229  ! Local variables
230  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_av, hp ! Prediced or averaged layer thicknesses [H ~> m or kg m-2]
231  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)) :: up, upp ! Predicted zonal velocities [L T-1 ~> m s-1]
232  real, dimension(SZI_(G),SZJB_(G),SZK_(G)) :: vp, vpp ! Predicted meridional velocities [L T-1 ~> m s-1]
233  real, dimension(:,:), pointer :: p_surf => null()
234  real :: dt_pred ! The time step for the predictor part of the baroclinic time stepping [T ~> s].
235  real :: dt_visc ! The time step for a part of the update due to viscosity [T ~> s].
236  logical :: dyn_p_surf
237  integer :: i, j, k, is, ie, js, je, Isq, Ieq, Jsq, Jeq, nz
238  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
239  isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
240  dt_pred = dt / 3.0
241 
242  h_av(:,:,:) = 0; hp(:,:,:) = 0
243  up(:,:,:) = 0; upp(:,:,:) = 0
244  vp(:,:,:) = 0; vpp(:,:,:) = 0
245 
246  dyn_p_surf = associated(p_surf_begin) .and. associated(p_surf_end)
247  if (dyn_p_surf) then
248  call safe_alloc_ptr(p_surf,g%isd,g%ied,g%jsd,g%jed) ; p_surf(:,:) = 0.0
249  else
250  p_surf => forces%p_surf
251  endif
252 
253 ! Matsuno's third order accurate three step scheme is used to step
254 ! all of the fields except h. h is stepped separately.
255 
256  if (cs%debug) then
257  call mom_state_chksum("Start First Predictor ", u, v, h, uh, vh, g, gv, us)
258  endif
259 
260 ! diffu = horizontal viscosity terms (u,h)
261  call enable_averages(dt, time_local, cs%diag)
262  call cpu_clock_begin(id_clock_horvisc)
263  call horizontal_viscosity(u, v, h, cs%diffu, cs%diffv, meke, varmix, g, gv, us, cs%hor_visc_CSp)
264  call cpu_clock_end(id_clock_horvisc)
265  call disable_averaging(cs%diag)
266 
267 ! uh = u*h
268 ! hp = h + dt/2 div . uh
269  call cpu_clock_begin(id_clock_continuity)
270  call continuity(u, v, h, hp, uh, vh, dt*0.5, g, gv, us, cs%continuity_CSp, obc=cs%OBC)
271  call cpu_clock_end(id_clock_continuity)
272  call pass_var(hp, g%Domain, clock=id_clock_pass)
273  call pass_vector(uh, vh, g%Domain, clock=id_clock_pass)
274 
275  call enable_averages(0.5*dt, time_local-real_to_time(0.5*us%T_to_s*dt), cs%diag)
276 ! Here the first half of the thickness fluxes are offered for averaging.
277  if (cs%id_uh > 0) call post_data(cs%id_uh, uh, cs%diag)
278  if (cs%id_vh > 0) call post_data(cs%id_vh, vh, cs%diag)
279  call disable_averaging(cs%diag)
280 
281 ! h_av = (h + hp)/2
282 ! u = u + dt diffu
283  call cpu_clock_begin(id_clock_mom_update)
284  do k=1,nz
285  do j=js-2,je+2 ; do i=is-2,ie+2
286  h_av(i,j,k) = (h(i,j,k) + hp(i,j,k)) * 0.5
287  enddo ; enddo
288  do j=js,je ; do i=isq,ieq
289  u(i,j,k) = u(i,j,k) + dt * cs%diffu(i,j,k) * g%mask2dCu(i,j)
290  enddo ; enddo
291  do j=jsq,jeq ; do i=is,ie
292  v(i,j,k) = v(i,j,k) + dt * cs%diffv(i,j,k) * g%mask2dCv(i,j)
293  enddo ; enddo
294  do j=js-2,je+2 ; do i=isq-2,ieq+2
295  uhtr(i,j,k) = uhtr(i,j,k) + 0.5*dt*uh(i,j,k)
296  enddo ; enddo
297  do j=jsq-2,jeq+2 ; do i=is-2,ie+2
298  vhtr(i,j,k) = vhtr(i,j,k) + 0.5*dt*vh(i,j,k)
299  enddo ; enddo
300  enddo
301  call cpu_clock_end(id_clock_mom_update)
302  call pass_vector(u, v, g%Domain, clock=id_clock_pass)
303 
304 ! CAu = -(f+zeta)/h_av vh + d/dx KE
305  call cpu_clock_begin(id_clock_cor)
306  call coradcalc(u, v, h_av, uh, vh, cs%CAu, cs%CAv, cs%OBC, cs%ADp, &
307  g, gv, us, cs%CoriolisAdv_CSp)
308  call cpu_clock_end(id_clock_cor)
309 
310 ! PFu = d/dx M(h_av,T,S)
311  call cpu_clock_begin(id_clock_pres)
312  if (dyn_p_surf) then ; do j=js-2,je+2 ; do i=is-2,ie+2
313  p_surf(i,j) = 0.75*p_surf_begin(i,j) + 0.25*p_surf_end(i,j)
314  enddo ; enddo ; endif
315  call pressureforce(h_av, tv, cs%PFu, cs%PFv, g, gv, us, &
316  cs%PressureForce_CSp, cs%ALE_CSp, p_surf)
317  call cpu_clock_end(id_clock_pres)
318 
319  if (associated(cs%OBC)) then; if (cs%OBC%update_OBC) then
320  call update_obc_data(cs%OBC, g, gv, us, tv, h, cs%update_OBC_CSp, time_local)
321  endif; endif
322  if (associated(cs%OBC)) then
323  call open_boundary_zero_normal_flow(cs%OBC, g, cs%PFu, cs%PFv)
324  call open_boundary_zero_normal_flow(cs%OBC, g, cs%CAu, cs%CAv)
325  endif
326 
327 ! up = u + dt_pred * (PFu + CAu)
328  call cpu_clock_begin(id_clock_mom_update)
329  do k=1,nz ; do j=js,je ; do i=isq,ieq
330  up(i,j,k) = g%mask2dCu(i,j) * (u(i,j,k) + dt_pred * (cs%PFu(i,j,k) + cs%CAu(i,j,k)))
331  enddo ; enddo ; enddo
332  do k=1,nz ; do j=jsq,jeq ; do i=is,ie
333  vp(i,j,k) = g%mask2dCv(i,j) * (v(i,j,k) + dt_pred * (cs%PFv(i,j,k) + cs%CAv(i,j,k)))
334  enddo ; enddo ; enddo
335  call cpu_clock_end(id_clock_mom_update)
336 
337  if (cs%debug) then
338  call mom_state_chksum("Predictor 1", up, vp, h_av, uh, vh, g, gv, us)
339  call mom_accel_chksum("Predictor 1 accel", cs%CAu, cs%CAv, cs%PFu, cs%PFv, &
340  cs%diffu, cs%diffv, g, gv, us)
341  endif
342 
343  ! up <- up + dt/2 d/dz visc d/dz up
344  call cpu_clock_begin(id_clock_vertvisc)
345  call enable_averages(dt, time_local, cs%diag)
346  dt_visc = 0.5*dt ; if (cs%use_correct_dt_visc) dt_visc = dt
347  call set_viscous_ml(u, v, h_av, tv, forces, visc, dt_visc, g, gv, us, cs%set_visc_CSp)
348  call disable_averaging(cs%diag)
349 
350  dt_visc = 0.5*dt ; if (cs%use_correct_dt_visc) dt_visc = dt_pred
351  call vertvisc_coef(up, vp, h_av, forces, visc, dt_visc, g, gv, us, cs%vertvisc_CSp, cs%OBC)
352  call vertvisc(up, vp, h_av, forces, visc, dt_visc, cs%OBC, cs%ADp, cs%CDp, &
353  g, gv, us, cs%vertvisc_CSp, waves=waves)
354  call cpu_clock_end(id_clock_vertvisc)
355  call pass_vector(up, vp, g%Domain, clock=id_clock_pass)
356 
357 ! uh = up * hp
358 ! h_av = hp + dt/2 div . uh
359  call cpu_clock_begin(id_clock_continuity)
360  call continuity(up, vp, hp, h_av, uh, vh, (0.5*dt), g, gv, us, cs%continuity_CSp, obc=cs%OBC)
361  call cpu_clock_end(id_clock_continuity)
362  call pass_var(h_av, g%Domain, clock=id_clock_pass)
363  call pass_vector(uh, vh, g%Domain, clock=id_clock_pass)
364 
365 ! h_av <- (hp + h_av)/2
366  do k=1,nz ; do j=js-2,je+2 ; do i=is-2,ie+2
367  h_av(i,j,k) = (hp(i,j,k) + h_av(i,j,k)) * 0.5
368  enddo ; enddo ; enddo
369 
370 ! CAu = -(f+zeta(up))/h_av vh + d/dx KE(up)
371  call cpu_clock_begin(id_clock_cor)
372  call coradcalc(up, vp, h_av, uh, vh, cs%CAu, cs%CAv, cs%OBC, cs%ADp, &
373  g, gv, us, cs%CoriolisAdv_CSp)
374  call cpu_clock_end(id_clock_cor)
375 
376 ! PFu = d/dx M(h_av,T,S)
377  call cpu_clock_begin(id_clock_pres)
378  if (dyn_p_surf) then ; do j=js-2,je+2 ; do i=is-2,ie+2
379  p_surf(i,j) = 0.25*p_surf_begin(i,j) + 0.75*p_surf_end(i,j)
380  enddo ; enddo ; endif
381  call pressureforce(h_av, tv, cs%PFu, cs%PFv, g, gv, us, &
382  cs%PressureForce_CSp, cs%ALE_CSp, p_surf)
383  call cpu_clock_end(id_clock_pres)
384 
385  if (associated(cs%OBC)) then; if (cs%OBC%update_OBC) then
386  call update_obc_data(cs%OBC, g, gv, us, tv, h, cs%update_OBC_CSp, time_local)
387  endif; endif
388  if (associated(cs%OBC)) then
389  call open_boundary_zero_normal_flow(cs%OBC, g, cs%PFu, cs%PFv)
390  call open_boundary_zero_normal_flow(cs%OBC, g, cs%CAu, cs%CAv)
391  endif
392 
393 ! upp = u + dt/2 * ( PFu + CAu )
394  call cpu_clock_begin(id_clock_mom_update)
395  do k=1,nz ; do j=js,je ; do i=isq,ieq
396  upp(i,j,k) = g%mask2dCu(i,j) * (u(i,j,k) + dt * 0.5 * (cs%PFu(i,j,k) + cs%CAu(i,j,k)))
397  enddo ; enddo ; enddo
398  do k=1,nz ; do j=jsq,jeq ; do i=is,ie
399  vpp(i,j,k) = g%mask2dCv(i,j) * (v(i,j,k) + dt * 0.5 * (cs%PFv(i,j,k) + cs%CAv(i,j,k)))
400  enddo ; enddo ; enddo
401  call cpu_clock_end(id_clock_mom_update)
402 
403  if (cs%debug) then
404  call mom_state_chksum("Predictor 2", upp, vpp, h_av, uh, vh, g, gv, us)
405  call mom_accel_chksum("Predictor 2 accel", cs%CAu, cs%CAv, cs%PFu, cs%PFv, &
406  cs%diffu, cs%diffv, g, gv, us)
407  endif
408 
409 ! upp <- upp + dt/2 d/dz visc d/dz upp
410  call cpu_clock_begin(id_clock_vertvisc)
411  call vertvisc_coef(upp, vpp, hp, forces, visc, dt*0.5, g, gv, us, cs%vertvisc_CSp, cs%OBC)
412  call vertvisc(upp, vpp, hp, forces, visc, dt*0.5, cs%OBC, cs%ADp, cs%CDp, &
413  g, gv, us, cs%vertvisc_CSp, waves=waves)
414  call cpu_clock_end(id_clock_vertvisc)
415  call pass_vector(upp, vpp, g%Domain, clock=id_clock_pass)
416 
417 ! uh = upp * hp
418 ! h = hp + dt/2 div . uh
419  call cpu_clock_begin(id_clock_continuity)
420  call continuity(upp, vpp, hp, h, uh, vh, (dt*0.5), g, gv, us, cs%continuity_CSp, obc=cs%OBC)
421  call cpu_clock_end(id_clock_continuity)
422  call pass_var(h, g%Domain, clock=id_clock_pass)
423  call pass_vector(uh, vh, g%Domain, clock=id_clock_pass)
424  ! Whenever thickness changes let the diag manager know, target grids
425  ! for vertical remapping may need to be regenerated.
426  call diag_update_remap_grids(cs%diag)
427 
428  call enable_averages(0.5*dt, time_local, cs%diag)
429 ! Here the second half of the thickness fluxes are offered for averaging.
430  if (cs%id_uh > 0) call post_data(cs%id_uh, uh, cs%diag)
431  if (cs%id_vh > 0) call post_data(cs%id_vh, vh, cs%diag)
432  call disable_averaging(cs%diag)
433  call enable_averages(dt, time_local, cs%diag)
434 
435 ! h_av = (h + hp)/2
436  do k=1,nz
437  do j=js-2,je+2 ; do i=is-2,ie+2
438  h_av(i,j,k) = 0.5*(h(i,j,k) + hp(i,j,k))
439  enddo ; enddo
440  do j=js-2,je+2 ; do i=isq-2,ieq+2
441  uhtr(i,j,k) = uhtr(i,j,k) + 0.5*dt*uh(i,j,k)
442  enddo ; enddo
443  do j=jsq-2,jeq+2 ; do i=is-2,ie+2
444  vhtr(i,j,k) = vhtr(i,j,k) + 0.5*dt*vh(i,j,k)
445  enddo ; enddo
446  enddo
447 
448 ! CAu = -(f+zeta(upp))/h_av vh + d/dx KE(upp)
449  call cpu_clock_begin(id_clock_cor)
450  call coradcalc(upp, vpp, h_av, uh, vh, cs%CAu, cs%CAv, cs%OBC, cs%ADp, &
451  g, gv, us, cs%CoriolisAdv_CSp)
452  call cpu_clock_end(id_clock_cor)
453 
454 ! PFu = d/dx M(h_av,T,S)
455  call cpu_clock_begin(id_clock_pres)
456  call pressureforce(h_av, tv, cs%PFu, cs%PFv, g, gv, us, &
457  cs%PressureForce_CSp, cs%ALE_CSp, p_surf)
458  call cpu_clock_end(id_clock_pres)
459 
460  if (associated(cs%OBC)) then; if (cs%OBC%update_OBC) then
461  call update_obc_data(cs%OBC, g, gv, us, tv, h, cs%update_OBC_CSp, time_local)
462  endif; endif
463 
464 ! u = u + dt * ( PFu + CAu )
465  if (associated(cs%OBC)) then
466  call open_boundary_zero_normal_flow(cs%OBC, g, cs%PFu, cs%PFv)
467  call open_boundary_zero_normal_flow(cs%OBC, g, cs%CAu, cs%CAv)
468  endif
469  do k=1,nz ; do j=js,je ; do i=isq,ieq
470  u(i,j,k) = g%mask2dCu(i,j) * (u(i,j,k) + dt * (cs%PFu(i,j,k) + cs%CAu(i,j,k)))
471  enddo ; enddo ; enddo
472  do k=1,nz ; do j=jsq,jeq ; do i=is,ie
473  v(i,j,k) = g%mask2dCv(i,j) * (v(i,j,k) + dt * (cs%PFv(i,j,k) + cs%CAv(i,j,k)))
474  enddo ; enddo ; enddo
475 
476 ! u <- u + dt d/dz visc d/dz u
477  call cpu_clock_begin(id_clock_vertvisc)
478  call vertvisc_coef(u, v, h_av, forces, visc, dt, g, gv, us, cs%vertvisc_CSp, cs%OBC)
479  call vertvisc(u, v, h_av, forces, visc, dt, cs%OBC, cs%ADp, cs%CDp, &
480  g, gv, us, cs%vertvisc_CSp, cs%taux_bot, cs%tauy_bot, waves=waves)
481  call cpu_clock_end(id_clock_vertvisc)
482  call pass_vector(u, v, g%Domain, clock=id_clock_pass)
483 
484  if (cs%debug) then
485  call mom_state_chksum("Corrector", u, v, h, uh, vh, g, gv, us)
486  call mom_accel_chksum("Corrector accel", cs%CAu, cs%CAv, cs%PFu, cs%PFv, &
487  cs%diffu, cs%diffv, g, gv, us)
488  endif
489 
490  if (gv%Boussinesq) then
491  do j=js,je ; do i=is,ie ; eta_av(i,j) = -gv%Z_to_H*g%bathyT(i,j) ; enddo ; enddo
492  else
493  do j=js,je ; do i=is,ie ; eta_av(i,j) = 0.0 ; enddo ; enddo
494  endif
495  do k=1,nz ; do j=js,je ; do i=is,ie
496  eta_av(i,j) = eta_av(i,j) + h_av(i,j,k)
497  enddo ; enddo ; enddo
498 
499  if (dyn_p_surf) deallocate(p_surf)
500 
501 ! Here various terms used in to update the momentum equations are
502 ! offered for averaging.
503  if (cs%id_PFu > 0) call post_data(cs%id_PFu, cs%PFu, cs%diag)
504  if (cs%id_PFv > 0) call post_data(cs%id_PFv, cs%PFv, cs%diag)
505  if (cs%id_CAu > 0) call post_data(cs%id_CAu, cs%CAu, cs%diag)
506  if (cs%id_CAv > 0) call post_data(cs%id_CAv, cs%CAv, cs%diag)
507 
508 end subroutine step_mom_dyn_unsplit
509 
510 ! =============================================================================
511 
512 !> Allocate the control structure for this module, allocates memory in it, and registers
513 !! any auxiliary restart variables that are specific to the unsplit time stepping scheme.
514 !!
515 !! All variables registered here should have the ability to be recreated if they are not present
516 !! in a restart file.
517 subroutine register_restarts_dyn_unsplit(HI, GV, param_file, CS, restart_CS)
518  type(hor_index_type), intent(in) :: HI !< A horizontal index type structure.
519  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
520  type(param_file_type), intent(in) :: param_file !< A structure to parse for
521  !! run-time parameters.
522  type(mom_dyn_unsplit_cs), pointer :: CS !< The control structure set up by
523  !! initialize_dyn_unsplit.
524  type(mom_restart_cs), pointer :: restart_CS !< A pointer to the restart control structure.
525 
526  ! Local arguments
527  character(len=40) :: mdl = "MOM_dynamics_unsplit" ! This module's name.
528  character(len=48) :: thickness_units, flux_units
529  integer :: isd, ied, jsd, jed, nz, IsdB, IedB, JsdB, JedB
530  isd = hi%isd ; ied = hi%ied ; jsd = hi%jsd ; jed = hi%jed ; nz = gv%ke
531  isdb = hi%IsdB ; iedb = hi%IedB ; jsdb = hi%JsdB ; jedb = hi%JedB
532 
533  ! This is where a control structure that is specific to this module is allocated.
534  if (associated(cs)) then
535  call mom_error(warning, "register_restarts_dyn_unsplit called with an associated "// &
536  "control structure.")
537  return
538  endif
539  allocate(cs)
540 
541  alloc_(cs%diffu(isdb:iedb,jsd:jed,nz)) ; cs%diffu(:,:,:) = 0.0
542  alloc_(cs%diffv(isd:ied,jsdb:jedb,nz)) ; cs%diffv(:,:,:) = 0.0
543  alloc_(cs%CAu(isdb:iedb,jsd:jed,nz)) ; cs%CAu(:,:,:) = 0.0
544  alloc_(cs%CAv(isd:ied,jsdb:jedb,nz)) ; cs%CAv(:,:,:) = 0.0
545  alloc_(cs%PFu(isdb:iedb,jsd:jed,nz)) ; cs%PFu(:,:,:) = 0.0
546  alloc_(cs%PFv(isd:ied,jsdb:jedb,nz)) ; cs%PFv(:,:,:) = 0.0
547 
548  thickness_units = get_thickness_units(gv)
549  flux_units = get_flux_units(gv)
550 
551 ! No extra restart fields are needed with this time stepping scheme.
552 
553 end subroutine register_restarts_dyn_unsplit
554 
555 !> Initialize parameters and allocate memory associated with the unsplit dynamics module.
556 subroutine initialize_dyn_unsplit(u, v, h, Time, G, GV, US, param_file, diag, CS, &
557  restart_CS, Accel_diag, Cont_diag, MIS, MEKE, &
558  OBC, update_OBC_CSp, ALE_CSp, setVisc_CSp, &
559  visc, dirs, ntrunc, cont_stencil)
560  type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure.
561  type(verticalgrid_type), intent(in) :: GV !< The ocean's vertical grid structure.
562  type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
563  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
564  intent(inout) :: u !< The zonal velocity [L T-1 ~> m s-1].
565  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
566  intent(inout) :: v !< The meridional velocity [L T-1 ~> m s-1].
567  real, dimension(SZI_(G),SZJ_(G),SZK_(G)) , &
568  intent(inout) :: h !< Layer thicknesses [H ~> m or kg m-2]
569  type(time_type), target, intent(in) :: Time !< The current model time.
570  type(param_file_type), intent(in) :: param_file !< A structure to parse
571  !! for run-time parameters.
572  type(diag_ctrl), target, intent(inout) :: diag !< A structure that is used to
573  !! regulate diagnostic output.
574  type(mom_dyn_unsplit_cs), pointer :: CS !< The control structure set up
575  !! by initialize_dyn_unsplit.
576  type(mom_restart_cs), pointer :: restart_CS !< A pointer to the restart control
577  !!structure.
578  type(accel_diag_ptrs), target, intent(inout) :: Accel_diag !< A set of pointers to the various
579  !! accelerations in the momentum equations, which can be used
580  !! for later derived diagnostics, like energy budgets.
581  type(cont_diag_ptrs), target, intent(inout) :: Cont_diag !< A structure with pointers to
582  !! various terms in the continuity
583  !! equations.
584  type(ocean_internal_state), intent(inout) :: MIS !< The "MOM6 Internal State"
585  !! structure, used to pass around pointers
586  !! to various arrays for diagnostic purposes.
587  type(meke_type), pointer :: MEKE !< MEKE data
588  type(ocean_obc_type), pointer :: OBC !< If open boundary conditions are
589  !! used, this points to the ocean_OBC_type
590  !! that was set up in MOM_initialization.
591  type(update_obc_cs), pointer :: update_OBC_CSp !< If open boundary condition
592  !! updates are used, this points to
593  !! the appropriate control structure.
594  type(ale_cs), pointer :: ALE_CSp !< This points to the ALE control
595  !! structure.
596  type(set_visc_cs), pointer :: setVisc_CSp !< This points to the set_visc
597  !! control structure.
598  type(vertvisc_type), intent(inout) :: visc !< A structure containing vertical
599  !! viscosities, bottom drag
600  !! viscosities, and related fields.
601  type(directories), intent(in) :: dirs !< A structure containing several
602  !! relevant directory paths.
603  integer, target, intent(inout) :: ntrunc !< A target for the variable that
604  !! records the number of times the velocity
605  !! is truncated (this should be 0).
606  integer, optional, intent(out) :: cont_stencil !< The stencil for thickness
607  !! from the continuity solver.
608 
609  ! This subroutine initializes all of the variables that are used by this
610  ! dynamic core, including diagnostics and the cpu clocks.
611 
612  ! Local variables
613  character(len=40) :: mdl = "MOM_dynamics_unsplit" ! This module's name.
614  character(len=48) :: thickness_units, flux_units
615  ! This include declares and sets the variable "version".
616 # include "version_variable.h"
617  real :: H_convert
618  logical :: use_tides
619  integer :: isd, ied, jsd, jed, nz, IsdB, IedB, JsdB, JedB
620  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
621  isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
622 
623  if (.not.associated(cs)) call mom_error(fatal, &
624  "initialize_dyn_unsplit called with an unassociated control structure.")
625  if (cs%module_is_initialized) then
626  call mom_error(warning, "initialize_dyn_unsplit called with a control "// &
627  "structure that has already been initialized.")
628  return
629  endif
630  cs%module_is_initialized = .true.
631 
632  cs%diag => diag
633 
634  call log_version(param_file, mdl, version, "")
635  call get_param(param_file, mdl, "FIX_UNSPLIT_DT_VISC_BUG", cs%use_correct_dt_visc, &
636  "If true, use the correct timestep in the viscous terms applied in the first "//&
637  "predictor step with the unsplit time stepping scheme, and in the calculation "//&
638  "of the turbulent mixed layer properties for viscosity with unsplit or "//&
639  "unsplit_RK2.", default=.true.)
640  call get_param(param_file, mdl, "DEBUG", cs%debug, &
641  "If true, write out verbose debugging data.", &
642  default=.false., debuggingparam=.true.)
643  call get_param(param_file, mdl, "TIDES", use_tides, &
644  "If true, apply tidal momentum forcing.", default=.false.)
645 
646  allocate(cs%taux_bot(isdb:iedb,jsd:jed)) ; cs%taux_bot(:,:) = 0.0
647  allocate(cs%tauy_bot(isd:ied,jsdb:jedb)) ; cs%tauy_bot(:,:) = 0.0
648 
649  mis%diffu => cs%diffu ; mis%diffv => cs%diffv
650  mis%PFu => cs%PFu ; mis%PFv => cs%PFv
651  mis%CAu => cs%CAu ; mis%CAv => cs%CAv
652 
653  cs%ADp => accel_diag ; cs%CDp => cont_diag
654  accel_diag%diffu => cs%diffu ; accel_diag%diffv => cs%diffv
655  accel_diag%PFu => cs%PFu ; accel_diag%PFv => cs%PFv
656  accel_diag%CAu => cs%CAu ; accel_diag%CAv => cs%CAv
657 
658  call continuity_init(time, g, gv, us, param_file, diag, cs%continuity_CSp)
659  if (present(cont_stencil)) cont_stencil = continuity_stencil(cs%continuity_CSp)
660  call coriolisadv_init(time, g, gv, us, param_file, diag, cs%ADp, cs%CoriolisAdv_CSp)
661  if (use_tides) call tidal_forcing_init(time, g, param_file, cs%tides_CSp)
662  call pressureforce_init(time, g, gv, us, param_file, diag, cs%PressureForce_CSp, &
663  cs%tides_CSp)
664  call hor_visc_init(time, g, us, param_file, diag, cs%hor_visc_CSp, meke)
665  call vertvisc_init(mis, time, g, gv, us, param_file, diag, cs%ADp, dirs, &
666  ntrunc, cs%vertvisc_CSp)
667  if (.not.associated(setvisc_csp)) call mom_error(fatal, &
668  "initialize_dyn_unsplit called with setVisc_CSp unassociated.")
669  cs%set_visc_CSp => setvisc_csp
670 
671  if (associated(ale_csp)) cs%ALE_CSp => ale_csp
672  if (associated(obc)) cs%OBC => obc
673  if (associated(update_obc_csp)) cs%update_OBC_CSp => update_obc_csp
674 
675  flux_units = get_flux_units(gv)
676  h_convert = gv%H_to_m ; if (.not.gv%Boussinesq) h_convert = gv%H_to_kg_m2
677  cs%id_uh = register_diag_field('ocean_model', 'uh', diag%axesCuL, time, &
678  'Zonal Thickness Flux', flux_units, y_cell_method='sum', v_extensive=.true., &
679  conversion=h_convert*us%L_to_m**2*us%s_to_T)
680  cs%id_vh = register_diag_field('ocean_model', 'vh', diag%axesCvL, time, &
681  'Meridional Thickness Flux', flux_units, x_cell_method='sum', v_extensive=.true., &
682  conversion=h_convert*us%L_to_m**2*us%s_to_T)
683  cs%id_CAu = register_diag_field('ocean_model', 'CAu', diag%axesCuL, time, &
684  'Zonal Coriolis and Advective Acceleration', 'm s-2', &
685  conversion=us%L_T2_to_m_s2)
686  cs%id_CAv = register_diag_field('ocean_model', 'CAv', diag%axesCvL, time, &
687  'Meridional Coriolis and Advective Acceleration', 'm s-2', &
688  conversion=us%L_T2_to_m_s2)
689  cs%id_PFu = register_diag_field('ocean_model', 'PFu', diag%axesCuL, time, &
690  'Zonal Pressure Force Acceleration', 'm s-2', &
691  conversion=us%L_T2_to_m_s2)
692  cs%id_PFv = register_diag_field('ocean_model', 'PFv', diag%axesCvL, time, &
693  'Meridional Pressure Force Acceleration', 'm s-2', &
694  conversion=us%L_T2_to_m_s2)
695 
696  id_clock_cor = cpu_clock_id('(Ocean Coriolis & mom advection)', grain=clock_module)
697  id_clock_continuity = cpu_clock_id('(Ocean continuity equation)', grain=clock_module)
698  id_clock_pres = cpu_clock_id('(Ocean pressure force)', grain=clock_module)
699  id_clock_vertvisc = cpu_clock_id('(Ocean vertical viscosity)', grain=clock_module)
700  id_clock_horvisc = cpu_clock_id('(Ocean horizontal viscosity)', grain=clock_module)
701  id_clock_mom_update = cpu_clock_id('(Ocean momentum increments)', grain=clock_module)
702  id_clock_pass = cpu_clock_id('(Ocean message passing)', grain=clock_module)
703  id_clock_pass_init = cpu_clock_id('(Ocean init message passing)', grain=clock_routine)
704 
705 end subroutine initialize_dyn_unsplit
706 
707 !> Clean up and deallocate memory associated with the unsplit dynamics module.
708 subroutine end_dyn_unsplit(CS)
709  type(mom_dyn_unsplit_cs), pointer :: CS !< unsplit dynamics control structure that
710  !! will be deallocated in this subroutine.
711 
712  dealloc_(cs%diffu) ; dealloc_(cs%diffv)
713  dealloc_(cs%CAu) ; dealloc_(cs%CAv)
714  dealloc_(cs%PFu) ; dealloc_(cs%PFv)
715 
716  deallocate(cs)
717 end subroutine end_dyn_unsplit
718 
719 end module mom_dynamics_unsplit
Calculates the heights of sruface or all interfaces from layer thicknesses.
Wraps the FMS time manager functions.
Time steps the ocean dynamics with an unsplit quasi 3rd order scheme.
This module contains the main regridding routines.
Definition: MOM_ALE.F90:9
The control structure for the MOM_boundary_update module.
This module implements boundary forcing for MOM6.
Complete a halo update on a pair of arrays representing the two components of a vector.
Definition: MOM_domains.F90:79
Control structure for horizontal viscosity.
Functions for calculating interface heights, including free surface height.
Calculates horizontal viscosity and viscous stresses.
Definition: MOM_hor_visc.F90:2
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Solve the layer continuity equation.
Controls where open boundary conditions are applied.
Reads the only Fortran name list needed to boot-strap the model.
A structure that can be parsed to read and document run-time parameters.
Implements vertical viscosity (vertvisc)
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Vertical viscosities, drag coefficients, and related fields.
Complete a non-blocking halo update on an array.
Definition: MOM_domains.F90:69
Wraps the MPP cpu clock functions.
Register fields for restarts.
Accelerations due to the Coriolis force and momentum advection.
Control structure for MOM_set_visc.
A thin wrapper for Boussinesq/non-Boussinesq forms of the pressure force calculation.
This type is used to exchange information related to the MEKE calculations.
This module contains I/O framework code.
Definition: MOM_io.F90:2
Calculates various values related to the bottom boundary layer, such as the viscosity and thickness o...
The MOM6 facility to parse input files for runtime parameters.
Defines the horizontal index type (hor_index_type) used for providing index ranges.
Initiate a non-blocking halo update on an array.
Definition: MOM_domains.F90:64
Pointers to arrays with accelerations, which can later be used for derived diagnostics, like energy balances.
Variable mixing coefficients.
Do a halo update on a pair of arrays representing the two components of a vector. ...
Definition: MOM_domains.F90:59
Container for horizontal index ranges for data, computational and global domains. ...
Control structure for mom_coriolisadv.
Structure that contains pointers to the mechanical forcing at the surface used to drive the liquid oc...
Baropotric solver.
Interface for surface waves.
Make a diagnostic available for averaging or output.
A restart registry and the control structure for restarts.
Definition: MOM_restart.F90:75
Describes various unit conversion factors.
Control structure for mom_continuity.
Initiate a halo update on a pair of arrays representing the two components of a vector.
Definition: MOM_domains.F90:74
Provides routines that do checksums of groups of MOM variables.
Tidal contributions to geopotential.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
Thickness diffusion (or Gent McWilliams)
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Pointers to arrays with transports, which can later be used for derived diagnostics, like energy balances.
Routines for error handling and I/O management.
The MOM6 facility for reading and writing restart files, and querying what has been read...
Definition: MOM_restart.F90:2
Pointers to all of the prognostic variables allocated in MOM_variables.F90 and MOM.F90.
Container for all surface wave related parameters.
The control structure with parameters and memory for the MOM_vert_friction module.
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
MOM_dynamics_unsplit module control structure.
Check for consistency between the duplicated points of a C-grid vector.
Container for paths and parameter file names.
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
The control structure for the MOM_tidal_forcing module.
Control structure for thickness diffusion.
Indicate whether a field has been read from a restart file.
The barotropic stepping control stucture.
Controls where open boundary conditions are applied.
Provides a transparent vertical ocean grid type and supporting routines.
ALE control structure.
Definition: MOM_ALE.F90:63
Provides transparent structures with groups of MOM6 variables and supporting routines.
Pressure force control structure.
Do a halo update on an array.
Definition: MOM_domains.F90:54
Write out checksums of the MOM6 state variables.
An overloaded interface to read and log the values of various types of parameters.
Provides checksumming functions for debugging.