55 use mom_cpu_clock,
only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
57 use mom_cpu_clock,
only : clock_module_driver, clock_module, clock_routine
65 use mom_domains,
only : to_south, to_west, to_all, cgrid_ne, scalar_pair
70 use mom_io,
only : mom_io_init
74 use mom_time_manager,
only :
operator(-),
operator(>),
operator(*),
operator(/)
99 implicit none ;
private
101 #include <MOM_memory.h>
105 real allocable_,
dimension(NIMEMB_PTR_,NJMEM_,NKMEM_) :: &
106 cau, & !< CAu = f*v - u.grad(u) [L T-2 ~> m s-2].
107 pfu, & !< PFu = -dM/dx [L T-2 ~> m s-2].
110 real allocable_,
dimension(NIMEM_,NJMEMB_PTR_,NKMEM_) :: &
111 cav, & !< CAv = -f*u - u.grad(v) [L T-2 ~> m s-2].
112 pfv, & !< PFv = -dM/dy [L T-2 ~> m s-2].
115 real,
pointer,
dimension(:,:) :: taux_bot => null()
117 real,
pointer,
dimension(:,:) :: tauy_bot => null()
126 logical :: use_correct_dt_visc
131 logical :: module_is_initialized = .false.
134 integer :: id_uh = -1, id_vh = -1
135 integer :: id_pfu = -1, id_pfv = -1, id_cau = -1, id_cav = -1
165 type(
ale_cs),
pointer :: ale_csp => null()
177 public step_mom_dyn_unsplit_rk2, register_restarts_dyn_unsplit_rk2
178 public initialize_dyn_unsplit_rk2, end_dyn_unsplit_rk2
181 integer :: id_clock_cor, id_clock_pres, id_clock_vertvisc
182 integer :: id_clock_horvisc, id_clock_continuity, id_clock_mom_update
183 integer :: id_clock_pass, id_clock_pass_init
191 subroutine step_mom_dyn_unsplit_rk2(u_in, v_in, h_in, tv, visc, Time_local, dt, forces, &
192 p_surf_begin, p_surf_end, uh, vh, uhtr, vhtr, eta_av, G, GV, US, CS, &
197 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: u_in
199 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: v_in
201 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)),
intent(inout) :: h_in
209 type(time_type),
intent(in) :: time_local
211 real,
intent(in) :: dt
213 real,
dimension(:,:),
pointer :: p_surf_begin
216 real,
dimension(:,:),
pointer :: p_surf_end
219 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: uh
221 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: vh
223 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: uhtr
226 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: vhtr
229 real,
dimension(SZI_(G),SZJ_(G)),
intent(out) :: eta_av
240 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) :: h_av, hp
241 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)) :: up
242 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)) :: vp
243 real,
dimension(:,:),
pointer :: p_surf => null()
246 logical :: dyn_p_surf
247 integer :: i, j, k, is, ie, js, je, isq, ieq, jsq, jeq, nz
248 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
249 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
252 h_av(:,:,:) = 0; hp(:,:,:) = 0
256 dyn_p_surf =
associated(p_surf_begin) .and.
associated(p_surf_end)
258 call safe_alloc_ptr(p_surf,g%isd,g%ied,g%jsd,g%jed) ; p_surf(:,:) = 0.0
260 p_surf => forces%p_surf
267 call mom_state_chksum(
"Start Predictor ", u_in, v_in, h_in, uh, vh, g, gv, us)
271 call enable_averages(dt,time_local, cs%diag)
272 call cpu_clock_begin(id_clock_horvisc)
273 call horizontal_viscosity(u_in, v_in, h_in, cs%diffu, cs%diffv, meke, varmix, &
274 g, gv, us, cs%hor_visc_CSp)
275 call cpu_clock_end(id_clock_horvisc)
276 call disable_averaging(cs%diag)
277 call pass_vector(cs%diffu, cs%diffv, g%Domain, clock=id_clock_pass)
283 call cpu_clock_begin(id_clock_continuity)
286 call continuity(u_in, v_in, h_in, hp, uh, vh, dt_pred, g, gv, us, cs%continuity_CSp, obc=cs%OBC)
287 call cpu_clock_end(id_clock_continuity)
288 call pass_var(hp, g%Domain, clock=id_clock_pass)
289 call pass_vector(uh, vh, g%Domain, clock=id_clock_pass)
292 call cpu_clock_begin(id_clock_mom_update)
293 do k=1,nz ;
do j=js-2,je+2 ;
do i=is-2,ie+2
294 h_av(i,j,k) = (h_in(i,j,k) + hp(i,j,k)) * 0.5
295 enddo ;
enddo ;
enddo
296 call cpu_clock_end(id_clock_mom_update)
299 call cpu_clock_begin(id_clock_cor)
300 call coradcalc(u_in, v_in, h_av, uh, vh, cs%CAu, cs%CAv, cs%OBC, cs%ADp, &
301 g, gv, us, cs%CoriolisAdv_CSp)
302 call cpu_clock_end(id_clock_cor)
305 call cpu_clock_begin(id_clock_pres)
306 if (dyn_p_surf)
then ;
do j=js-2,je+2 ;
do i=is-2,ie+2
307 p_surf(i,j) = 0.5*p_surf_begin(i,j) + 0.5*p_surf_end(i,j)
308 enddo ;
enddo ;
endif
309 call pressureforce(h_in, tv, cs%PFu, cs%PFv, g, gv, us, cs%PressureForce_CSp, cs%ALE_CSp, p_surf)
310 call cpu_clock_end(id_clock_pres)
311 call pass_vector(cs%PFu, cs%PFv, g%Domain, clock=id_clock_pass)
312 call pass_vector(cs%CAu, cs%CAv, g%Domain, clock=id_clock_pass)
314 if (
associated(cs%OBC)) then;
if (cs%OBC%update_OBC)
then
315 call update_obc_data(cs%OBC, g, gv, us, tv, h_in, cs%update_OBC_CSp, time_local)
317 if (
associated(cs%OBC))
then
318 call open_boundary_zero_normal_flow(cs%OBC, g, cs%PFu, cs%PFv)
319 call open_boundary_zero_normal_flow(cs%OBC, g, cs%CAu, cs%CAv)
320 call open_boundary_zero_normal_flow(cs%OBC, g, cs%diffu, cs%diffv)
324 call cpu_clock_begin(id_clock_mom_update)
325 do k=1,nz ;
do j=js,je ;
do i=isq,ieq
326 up(i,j,k) = g%mask2dCu(i,j) * (u_in(i,j,k) + dt_pred * &
327 ((cs%PFu(i,j,k) + cs%CAu(i,j,k)) + cs%diffu(i,j,k)))
328 enddo ;
enddo ;
enddo
329 do k=1,nz ;
do j=jsq,jeq ;
do i=is,ie
330 vp(i,j,k) = g%mask2dCv(i,j) * (v_in(i,j,k) + dt_pred * &
331 ((cs%PFv(i,j,k) + cs%CAv(i,j,k)) + cs%diffv(i,j,k)))
332 enddo ;
enddo ;
enddo
333 call cpu_clock_end(id_clock_mom_update)
336 call mom_accel_chksum(
"Predictor 1 accel", cs%CAu, cs%CAv, cs%PFu, cs%PFv,&
337 cs%diffu, cs%diffv, g, gv, us)
340 call cpu_clock_begin(id_clock_vertvisc)
341 call enable_averages(dt, time_local, cs%diag)
342 dt_visc = dt_pred ;
if (cs%use_correct_dt_visc) dt_visc = dt
343 call set_viscous_ml(u_in, v_in, h_av, tv, forces, visc, dt_visc, g, gv, us, cs%set_visc_CSp)
344 call disable_averaging(cs%diag)
346 call vertvisc_coef(up, vp, h_av, forces, visc, dt_pred, g, gv, us, cs%vertvisc_CSp, cs%OBC)
347 call vertvisc(up, vp, h_av, forces, visc, dt_pred, cs%OBC, cs%ADp, cs%CDp, &
348 g, gv, us, cs%vertvisc_CSp)
349 call cpu_clock_end(id_clock_vertvisc)
350 call pass_vector(up, vp, g%Domain, clock=id_clock_pass)
354 call cpu_clock_begin(id_clock_continuity)
355 call continuity(up, vp, h_in, hp, uh, vh, dt, g, gv, us, cs%continuity_CSp, obc=cs%OBC)
356 call cpu_clock_end(id_clock_continuity)
357 call pass_var(hp, g%Domain, clock=id_clock_pass)
358 call pass_vector(uh, vh, g%Domain, clock=id_clock_pass)
361 do k=1,nz ;
do j=js-2,je+2 ;
do i=is-2,ie+2
362 h_av(i,j,k) = (h_in(i,j,k) + hp(i,j,k)) * 0.5
363 enddo ;
enddo ;
enddo
369 call cpu_clock_begin(id_clock_cor)
370 call coradcalc(up, vp, h_av, uh, vh, cs%CAu, cs%CAv, cs%OBC, cs%ADp, &
371 g, gv, us, cs%CoriolisAdv_CSp)
372 call cpu_clock_end(id_clock_cor)
373 if (
associated(cs%OBC))
then
374 call open_boundary_zero_normal_flow(cs%OBC, g, cs%CAu, cs%CAv)
381 do k=1,nz ;
do j=js,je ;
do i=isq,ieq
382 up(i,j,k) = g%mask2dCu(i,j) * (u_in(i,j,k) + dt * (1.+cs%begw) * &
383 ((cs%PFu(i,j,k) + cs%CAu(i,j,k)) + cs%diffu(i,j,k)))
384 u_in(i,j,k) = g%mask2dCu(i,j) * (u_in(i,j,k) + dt * &
385 ((cs%PFu(i,j,k) + cs%CAu(i,j,k)) + cs%diffu(i,j,k)))
386 enddo ;
enddo ;
enddo
387 do k=1,nz ;
do j=jsq,jeq ;
do i=is,ie
388 vp(i,j,k) = g%mask2dCv(i,j) * (v_in(i,j,k) + dt * (1.+cs%begw) * &
389 ((cs%PFv(i,j,k) + cs%CAv(i,j,k)) + cs%diffv(i,j,k)))
390 v_in(i,j,k) = g%mask2dCv(i,j) * (v_in(i,j,k) + dt * &
391 ((cs%PFv(i,j,k) + cs%CAv(i,j,k)) + cs%diffv(i,j,k)))
392 enddo ;
enddo ;
enddo
396 call cpu_clock_begin(id_clock_vertvisc)
397 call vertvisc_coef(up, vp, h_av, forces, visc, dt, g, gv, us, cs%vertvisc_CSp, cs%OBC)
398 call vertvisc(up, vp, h_av, forces, visc, dt, cs%OBC, cs%ADp, cs%CDp, &
399 g, gv, us, cs%vertvisc_CSp, cs%taux_bot, cs%tauy_bot)
400 call vertvisc_coef(u_in, v_in, h_av, forces, visc, dt, g, gv, us, cs%vertvisc_CSp, cs%OBC)
401 call vertvisc(u_in, v_in, h_av, forces, visc, dt, cs%OBC, cs%ADp, cs%CDp,&
402 g, gv, us, cs%vertvisc_CSp, cs%taux_bot, cs%tauy_bot)
403 call cpu_clock_end(id_clock_vertvisc)
404 call pass_vector(up, vp, g%Domain, clock=id_clock_pass)
405 call pass_vector(u_in, v_in, g%Domain, clock=id_clock_pass)
409 call cpu_clock_begin(id_clock_continuity)
410 call continuity(up, vp, h_in, h_in, uh, vh, dt, g, gv, us, cs%continuity_CSp, obc=cs%OBC)
411 call cpu_clock_end(id_clock_continuity)
412 call pass_var(h_in, g%Domain, clock=id_clock_pass)
413 call pass_vector(uh, vh, g%Domain, clock=id_clock_pass)
417 do j=js-2,je+2 ;
do i=isq-2,ieq+2
418 uhtr(i,j,k) = uhtr(i,j,k) + dt*uh(i,j,k)
420 do j=jsq-2,jeq+2 ;
do i=is-2,ie+2
421 vhtr(i,j,k) = vhtr(i,j,k) + dt*vh(i,j,k)
427 call mom_accel_chksum(
"Corrector accel", cs%CAu, cs%CAv, cs%PFu, cs%PFv, &
428 cs%diffu, cs%diffv, g, gv, us)
431 if (gv%Boussinesq)
then
432 do j=js,je ;
do i=is,ie ; eta_av(i,j) = -gv%Z_to_H*g%bathyT(i,j) ;
enddo ;
enddo
434 do j=js,je ;
do i=is,ie ; eta_av(i,j) = 0.0 ;
enddo ;
enddo
436 do k=1,nz ;
do j=js,je ;
do i=is,ie
437 eta_av(i,j) = eta_av(i,j) + h_av(i,j,k)
438 enddo ;
enddo ;
enddo
440 if (dyn_p_surf)
deallocate(p_surf)
444 if (cs%id_PFu > 0)
call post_data(cs%id_PFu, cs%PFu, cs%diag)
445 if (cs%id_PFv > 0)
call post_data(cs%id_PFv, cs%PFv, cs%diag)
446 if (cs%id_CAu > 0)
call post_data(cs%id_CAu, cs%CAu, cs%diag)
447 if (cs%id_CAv > 0)
call post_data(cs%id_CAv, cs%CAv, cs%diag)
450 if (cs%id_uh > 0)
call post_data(cs%id_uh, uh, cs%diag)
451 if (cs%id_vh > 0)
call post_data(cs%id_vh, vh, cs%diag)
453 end subroutine step_mom_dyn_unsplit_rk2
462 subroutine register_restarts_dyn_unsplit_rk2(HI, GV, param_file, CS, restart_CS)
476 character(len=48) :: thickness_units, flux_units
477 integer :: isd, ied, jsd, jed, nz, isdb, iedb, jsdb, jedb
478 isd = hi%isd ; ied = hi%ied ; jsd = hi%jsd ; jed = hi%jed ; nz = gv%ke
479 isdb = hi%IsdB ; iedb = hi%IedB ; jsdb = hi%JsdB ; jedb = hi%JedB
482 if (
associated(cs))
then
483 call mom_error(warning,
"register_restarts_dyn_unsplit_RK2 called with an associated "// &
484 "control structure.")
489 alloc_(cs%diffu(isdb:iedb,jsd:jed,nz)) ; cs%diffu(:,:,:) = 0.0
490 alloc_(cs%diffv(isd:ied,jsdb:jedb,nz)) ; cs%diffv(:,:,:) = 0.0
491 alloc_(cs%CAu(isdb:iedb,jsd:jed,nz)) ; cs%CAu(:,:,:) = 0.0
492 alloc_(cs%CAv(isd:ied,jsdb:jedb,nz)) ; cs%CAv(:,:,:) = 0.0
493 alloc_(cs%PFu(isdb:iedb,jsd:jed,nz)) ; cs%PFu(:,:,:) = 0.0
494 alloc_(cs%PFv(isd:ied,jsdb:jedb,nz)) ; cs%PFv(:,:,:) = 0.0
496 thickness_units = get_thickness_units(gv)
497 flux_units = get_flux_units(gv)
501 end subroutine register_restarts_dyn_unsplit_rk2
504 subroutine initialize_dyn_unsplit_rk2(u, v, h, Time, G, GV, US, param_file, diag, CS, &
505 restart_CS, Accel_diag, Cont_diag, MIS, MEKE, &
506 OBC, update_OBC_CSp, ALE_CSp, setVisc_CSp, &
507 visc, dirs, ntrunc, cont_stencil)
511 real,
dimension(SZIB_(G),SZJ_(G),SZK_(G)),
intent(inout) :: u
512 real,
dimension(SZI_(G),SZJB_(G),SZK_(G)),
intent(inout) :: v
513 real,
dimension(SZI_(G),SZJ_(G),SZK_(G)) ,
intent(inout) :: h
514 type(time_type),
target,
intent(in) :: time
517 type(
diag_ctrl),
target,
intent(inout) :: diag
539 type(
ale_cs),
pointer :: ale_csp
549 integer,
target,
intent(inout) :: ntrunc
552 integer,
optional,
intent(out) :: cont_stencil
559 character(len=40) :: mdl =
"MOM_dynamics_unsplit_RK2"
560 character(len=48) :: thickness_units, flux_units
562 # include "version_variable.h"
565 integer :: isd, ied, jsd, jed, nz, isdb, iedb, jsdb, jedb
566 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed ; nz = g%ke
567 isdb = g%IsdB ; iedb = g%IedB ; jsdb = g%JsdB ; jedb = g%JedB
569 if (.not.
associated(cs))
call mom_error(fatal, &
570 "initialize_dyn_unsplit_RK2 called with an unassociated control structure.")
571 if (cs%module_is_initialized)
then
572 call mom_error(warning,
"initialize_dyn_unsplit_RK2 called with a control "// &
573 "structure that has already been initialized.")
576 cs%module_is_initialized = .true.
581 call get_param(param_file, mdl,
"BE", cs%be, &
582 "If SPLIT is true, BE determines the relative weighting "//&
583 "of a 2nd-order Runga-Kutta baroclinic time stepping "//&
584 "scheme (0.5) and a backward Euler scheme (1) that is "//&
585 "used for the Coriolis and inertial terms. BE may be "//&
586 "from 0.5 to 1, but instability may occur near 0.5. "//&
587 "BE is also applicable if SPLIT is false and USE_RK2 "//&
588 "is true.", units=
"nondim", default=0.6)
589 call get_param(param_file, mdl,
"BEGW", cs%begw, &
590 "If SPLIT is true, BEGW is a number from 0 to 1 that "//&
591 "controls the extent to which the treatment of gravity "//&
592 "waves is forward-backward (0) or simulated backward "//&
593 "Euler (1). 0 is almost always used. "//&
594 "If SPLIT is false and USE_RK2 is true, BEGW can be "//&
595 "between 0 and 0.5 to damp gravity waves.", &
596 units=
"nondim", default=0.0)
597 call get_param(param_file, mdl,
"FIX_UNSPLIT_DT_VISC_BUG", cs%use_correct_dt_visc, &
598 "If true, use the correct timestep in the viscous terms applied in the first "//&
599 "predictor step with the unsplit time stepping scheme, and in the calculation "//&
600 "of the turbulent mixed layer properties for viscosity with unsplit or "//&
601 "unsplit_RK2.", default=.true.)
602 call get_param(param_file, mdl,
"DEBUG", cs%debug, &
603 "If true, write out verbose debugging data.", &
604 default=.false., debuggingparam=.true.)
605 call get_param(param_file, mdl,
"TIDES", use_tides, &
606 "If true, apply tidal momentum forcing.", default=.false.)
608 allocate(cs%taux_bot(isdb:iedb,jsd:jed)) ; cs%taux_bot(:,:) = 0.0
609 allocate(cs%tauy_bot(isd:ied,jsdb:jedb)) ; cs%tauy_bot(:,:) = 0.0
611 mis%diffu => cs%diffu ; mis%diffv => cs%diffv
612 mis%PFu => cs%PFu ; mis%PFv => cs%PFv
613 mis%CAu => cs%CAu ; mis%CAv => cs%CAv
615 cs%ADp => accel_diag ; cs%CDp => cont_diag
616 accel_diag%diffu => cs%diffu ; accel_diag%diffv => cs%diffv
617 accel_diag%PFu => cs%PFu ; accel_diag%PFv => cs%PFv
618 accel_diag%CAu => cs%CAu ; accel_diag%CAv => cs%CAv
620 call continuity_init(time, g, gv, us, param_file, diag, cs%continuity_CSp)
621 if (
present(cont_stencil)) cont_stencil = continuity_stencil(cs%continuity_CSp)
622 call coriolisadv_init(time, g, gv, us, param_file, diag, cs%ADp, cs%CoriolisAdv_CSp)
623 if (use_tides)
call tidal_forcing_init(time, g, param_file, cs%tides_CSp)
624 call pressureforce_init(time, g, gv, us, param_file, diag, cs%PressureForce_CSp, &
626 call hor_visc_init(time, g, us, param_file, diag, cs%hor_visc_CSp, meke)
627 call vertvisc_init(mis, time, g, gv, us, param_file, diag, cs%ADp, dirs, &
628 ntrunc, cs%vertvisc_CSp)
629 if (.not.
associated(setvisc_csp))
call mom_error(fatal, &
630 "initialize_dyn_unsplit_RK2 called with setVisc_CSp unassociated.")
631 cs%set_visc_CSp => setvisc_csp
633 if (
associated(ale_csp)) cs%ALE_CSp => ale_csp
634 if (
associated(obc)) cs%OBC => obc
636 flux_units = get_flux_units(gv)
637 h_convert = gv%H_to_m ;
if (.not.gv%Boussinesq) h_convert = gv%H_to_kg_m2
638 cs%id_uh = register_diag_field(
'ocean_model',
'uh', diag%axesCuL, time, &
639 'Zonal Thickness Flux', flux_units, y_cell_method=
'sum', v_extensive=.true., &
640 conversion=h_convert*us%L_to_m**2*us%s_to_T)
641 cs%id_vh = register_diag_field(
'ocean_model',
'vh', diag%axesCvL, time, &
642 'Meridional Thickness Flux', flux_units, x_cell_method=
'sum', v_extensive=.true., &
643 conversion=h_convert*us%L_to_m**2*us%s_to_T)
644 cs%id_CAu = register_diag_field(
'ocean_model',
'CAu', diag%axesCuL, time, &
645 'Zonal Coriolis and Advective Acceleration',
'meter second-2', conversion=us%L_T2_to_m_s2)
646 cs%id_CAv = register_diag_field(
'ocean_model',
'CAv', diag%axesCvL, time, &
647 'Meridional Coriolis and Advective Acceleration',
'meter second-2', conversion=us%L_T2_to_m_s2)
648 cs%id_PFu = register_diag_field(
'ocean_model',
'PFu', diag%axesCuL, time, &
649 'Zonal Pressure Force Acceleration',
'meter second-2', conversion=us%L_T2_to_m_s2)
650 cs%id_PFv = register_diag_field(
'ocean_model',
'PFv', diag%axesCvL, time, &
651 'Meridional Pressure Force Acceleration',
'meter second-2', conversion=us%L_T2_to_m_s2)
653 id_clock_cor = cpu_clock_id(
'(Ocean Coriolis & mom advection)', grain=clock_module)
654 id_clock_continuity = cpu_clock_id(
'(Ocean continuity equation)', grain=clock_module)
655 id_clock_pres = cpu_clock_id(
'(Ocean pressure force)', grain=clock_module)
656 id_clock_vertvisc = cpu_clock_id(
'(Ocean vertical viscosity)', grain=clock_module)
657 id_clock_horvisc = cpu_clock_id(
'(Ocean horizontal viscosity)', grain=clock_module)
658 id_clock_mom_update = cpu_clock_id(
'(Ocean momentum increments)', grain=clock_module)
659 id_clock_pass = cpu_clock_id(
'(Ocean message passing)', grain=clock_module)
660 id_clock_pass_init = cpu_clock_id(
'(Ocean init message passing)', grain=clock_routine)
662 end subroutine initialize_dyn_unsplit_rk2
665 subroutine end_dyn_unsplit_rk2(CS)
669 dealloc_(cs%diffu) ; dealloc_(cs%diffv)
670 dealloc_(cs%CAu) ; dealloc_(cs%CAv)
671 dealloc_(cs%PFu) ; dealloc_(cs%PFv)
674 end subroutine end_dyn_unsplit_rk2