27 use mom_cpu_clock,
only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
29 use mom_diag_mediator,
only : enable_averaging, disable_averaging, diag_mediator_end
32 use mom,
only : extract_surface_state, finish_mom_initialization
33 use mom,
only : get_mom_state_elements, mom_state_is_synchronized
34 use mom,
only : step_offline
35 use mom_domains,
only : mom_infra_init, mom_infra_end
41 use mom_forcing_type,
only : mech_forcing_diags, mom_forcing_chksum, mom_mech_forcing_chksum
45 use mom_io,
only : check_nml_error, io_infra_init, io_infra_end
46 use mom_io,
only : append_file, ascii_file, readonly_file, single_file
53 use mom_time_manager,
only :
operator(+),
operator(-),
operator(*),
operator(/)
65 use ensemble_manager_mod,
only : ensemble_manager_init, get_ensemble_size
66 use ensemble_manager_mod,
only : ensemble_pelist_setup
67 use mpp_mod,
only : set_current_pelist => mpp_set_current_pelist
68 use time_interp_external_mod,
only : time_interp_external_init
71 use mom_ice_shelf,
only : shelf_calc_flux, add_shelf_forces, ice_shelf_save_restart
79 #include <MOM_memory.h>
82 type(mech_forcing) :: forces
85 type(forcing) :: fluxes
88 type(surface) :: sfc_state
91 type(ocean_grid_type),
pointer :: grid
92 type(verticalGrid_type),
pointer :: GV
94 type(unit_scale_type),
pointer :: US
97 logical :: use_ice_shelf
100 logical :: use_waves = .false.
103 logical :: permit_incr_restart = .true.
111 integer :: nmax=2000000000
114 type(directories) :: dirs
117 type(time_type),
target :: Time
120 type(time_type) :: Master_Time
122 type(time_type) :: Time1
124 type(time_type) :: Start_time
125 type(time_type) :: segment_start_time
126 type(time_type) :: Time_end
127 type(time_type) :: restart_time
128 type(time_type) :: Time_step_ocean
130 real :: elapsed_time = 0.0
131 logical :: elapsed_time_master
141 real :: dt_dyn, dtdia, t_elapsed_seg
142 integer :: n, n_max, nts, n_last_thermo
143 logical :: diabatic_first, single_step_call
144 type(time_type) :: Time2, time_chg
146 integer :: Restart_control
154 type(time_type) :: restint
155 type(time_type) :: daymax
158 integer :: date_init(6)=0
159 integer :: date(6)=-1
160 integer :: years=0, months=0, days=0
161 integer :: hours=0, minutes=0, seconds=0
162 integer :: yr, mon, day, hr, mins, sec
163 type(param_file_type) :: param_file
165 character(len=9) :: month
166 character(len=16) :: calendar =
'julian'
167 integer :: calendar_type=-1
169 integer :: unit, io_status, ierr
170 integer :: ensemble_size, nPEs_per, ensemble_info(6)
172 integer,
dimension(0) :: atm_PElist, land_PElist, ice_PElist
173 integer,
dimension(:),
allocatable :: ocean_PElist
174 logical :: unit_in_use
175 integer :: initClock, mainClock, termClock
178 logical :: offline_tracer_mode
186 type(MOM_control_struct),
pointer :: MOM_CSp => null()
188 type(tracer_flow_control_CS),
pointer :: &
189 tracer_flow_CSp => null()
190 type(surface_forcing_CS),
pointer :: surface_forcing_CSp => null()
191 type(write_cputime_CS),
pointer :: write_CPU_CSp => null()
192 type(ice_shelf_CS),
pointer :: ice_shelf_CSp => null()
193 type(wave_parameters_cs),
pointer :: waves_CSp => null()
194 type(MOM_restart_CS),
pointer :: &
195 restart_CSp => null()
197 type(diag_ctrl),
pointer :: &
201 character(len=4),
parameter :: vers_num =
'v2.0'
203 #include "version_variable.h"
204 character(len=40) :: mod_name =
"MOM_main (MOM_driver)"
206 integer :: ocean_nthreads = 1
207 integer :: ncores_per_node = 36
208 logical :: use_hyper_thread = .false.
209 integer :: omp_get_num_threads,omp_get_thread_num,get_cpu_affinity,adder,base_cpu
210 namelist /ocean_solo_nml/ date_init, calendar, months, days, hours, minutes, seconds,&
211 ocean_nthreads, ncores_per_node, use_hyper_thread
215 call write_cputime_start_clock(write_cpu_csp)
217 call mom_infra_init() ;
call io_infra_init()
222 call ensemble_manager_init() ; ensemble_info(:) = get_ensemble_size()
223 ensemble_size=ensemble_info(1) ; npes_per=ensemble_info(2)
224 if (ensemble_size > 1)
then
225 allocate(ocean_pelist(npes_per))
226 call ensemble_pelist_setup(.true., 0, npes_per, 0, 0, atm_pelist, ocean_pelist, &
227 land_pelist, ice_pelist)
228 call set_current_pelist(ocean_pelist)
229 deallocate(ocean_pelist)
233 initclock = cpu_clock_id(
'Initialization' )
234 mainclock = cpu_clock_id(
'Main loop' )
235 termclock = cpu_clock_id(
'Termination' )
236 call cpu_clock_begin(initclock)
238 call mom_mesg(
'======== Model being driven by MOM_driver ========', 2)
239 call calltree_waypoint(
"Program MOM_main, MOM_driver.F90")
243 call open_file(unit,
'input.nml', form=ascii_file, action=readonly_file)
244 read(unit, ocean_solo_nml, iostat=io_status)
245 call close_file(unit)
246 ierr = check_nml_error(io_status,
'ocean_solo_nml')
247 if (years+months+days+hours+minutes+seconds > 0)
then
248 if (is_root_pe())
write(*,ocean_solo_nml)
270 if (
file_exists(trim(dirs%restart_input_dir)//
'ocean_solo.res'))
then
271 call open_file(unit,trim(dirs%restart_input_dir)//
'ocean_solo.res', &
272 form=ascii_file,action=readonly_file)
273 read(unit,*) calendar_type
274 read(unit,*) date_init
276 call close_file(unit)
278 calendar = uppercase(calendar)
279 if (calendar(1:6) ==
'JULIAN')
then ; calendar_type = julian
280 elseif (calendar(1:9) ==
'GREGORIAN')
then ; calendar_type = gregorian
281 elseif (calendar(1:6) ==
'NOLEAP')
then ; calendar_type = noleap
282 elseif (calendar(1:10)==
'THIRTY_DAY')
then ; calendar_type = thirty_day_months
283 elseif (calendar(1:11)==
'NO_CALENDAR') then; calendar_type = no_calendar
284 elseif (calendar(1:1) /=
' ')
then
285 call mom_error(fatal,
'MOM_driver: Invalid namelist value '//trim(calendar)//
' for calendar')
287 call mom_error(fatal,
'MOM_driver: No namelist value for calendar')
290 call set_calendar_type(calendar_type)
293 if (sum(date_init) > 0)
then
294 start_time = set_date(date_init(1),date_init(2), date_init(3), &
295 date_init(4),date_init(5),date_init(6))
297 start_time = real_to_time(0.0)
300 call time_interp_external_init
302 if (sum(date) >= 0)
then
304 segment_start_time = set_date(date(1),date(2),date(3),date(4),date(5),date(6))
305 time = segment_start_time
306 call initialize_mom(time, start_time, param_file, dirs, mom_csp, restart_csp, &
307 segment_start_time, offline_tracer_mode=offline_tracer_mode, &
308 diag_ptr=diag, tracer_flow_csp=tracer_flow_csp)
313 call initialize_mom(time, start_time, param_file, dirs, mom_csp, restart_csp, &
314 offline_tracer_mode=offline_tracer_mode, diag_ptr=diag, &
315 tracer_flow_csp=tracer_flow_csp)
318 call get_mom_state_elements(mom_csp, g=grid, gv=gv, us=us, c_p=fluxes%C_p)
321 call calltree_waypoint(
"done initialize_MOM")
323 call extract_surface_state(mom_csp, sfc_state)
325 call surface_forcing_init(time, grid, us, param_file, diag, &
326 surface_forcing_csp, tracer_flow_csp)
327 call calltree_waypoint(
"done surface_forcing_init")
329 call get_param(param_file, mod_name,
"ICE_SHELF", use_ice_shelf, &
330 "If true, enables the ice shelf model.", default=.false.)
331 if (use_ice_shelf)
then
334 call initialize_ice_shelf(param_file, grid, time, ice_shelf_csp, &
335 diag, forces, fluxes)
338 call get_param(param_file,mod_name,
"USE_WAVES",use_waves,&
339 "If true, enables surface wave modules.",default=.false.)
341 call mom_wave_interface_init(time, grid, gv, us, param_file, waves_csp, diag)
343 call mom_wave_interface_init_lite(param_file)
346 segment_start_time = time
350 call log_version(param_file, mod_name, version,
"")
351 call get_param(param_file, mod_name,
"DT", dt, fail_if_missing=.true.)
352 call get_param(param_file, mod_name,
"DT_FORCING", dt_forcing, &
353 "The time step for changing forcing, coupling with other "//&
354 "components, or potentially writing certain diagnostics. "//&
355 "The default value is given by DT.", units=
"s", default=dt)
356 if (offline_tracer_mode)
then
357 call get_param(param_file, mod_name,
"DT_OFFLINE", dt_forcing, &
358 "Time step for the offline time step")
361 ntstep = max(1,ceiling(dt_forcing/dt - 0.001))
363 time_step_ocean = real_to_time(dt_forcing)
364 elapsed_time_master = (abs(dt_forcing - time_type_to_real(time_step_ocean)) > 1.0e-12*dt_forcing)
365 if (elapsed_time_master) &
366 call mom_mesg(
"Using real elapsed time for the master clock.", 2)
369 call get_param(param_file, mod_name,
"TIMEUNIT", time_unit, &
370 "The time unit for DAYMAX, ENERGYSAVEDAYS, and RESTINT.", &
371 units=
"s", default=86400.0)
372 if (years+months+days+hours+minutes+seconds > 0)
then
373 time_end = increment_date(time, years, months, days, hours, minutes, seconds)
374 call mom_mesg(
'Segment run length determined from ocean_solo_nml.', 2)
375 call get_param(param_file, mod_name,
"DAYMAX", daymax, timeunit=time_unit, &
376 default=time_end, do_not_log=.true.)
377 call log_param(param_file, mod_name,
"DAYMAX", daymax, &
378 "The final time of the whole simulation, in units of "//&
379 "TIMEUNIT seconds. This also sets the potential end "//&
380 "time of the present run segment if the end time is "//&
381 "not set via ocean_solo_nml in input.nml.", &
384 call get_param(param_file, mod_name,
"DAYMAX", daymax, &
385 "The final time of the whole simulation, in units of "//&
386 "TIMEUNIT seconds. This also sets the potential end "//&
387 "time of the present run segment if the end time is "//&
388 "not set via ocean_solo_nml in input.nml.", &
389 timeunit=time_unit, fail_if_missing=.true.)
393 call get_param(param_file, mod_name,
"SINGLE_STEPPING_CALL", single_step_call, &
394 "If true, advance the state of MOM with a single step "//&
395 "including both dynamics and thermodynamics. If false "//&
396 "the two phases are advanced with separate calls.", default=.true.)
397 call get_param(param_file, mod_name,
"DT_THERM", dt_therm, &
398 "The thermodynamic and tracer advection time step. "//&
399 "Ideally DT_THERM should be an integer multiple of DT "//&
400 "and less than the forcing or coupling time-step, unless "//&
401 "THERMO_SPANS_COUPLING is true, in which case DT_THERM "//&
402 "can be an integer multiple of the coupling timestep. By "//&
403 "default DT_THERM is set to DT.", units=
"s", default=dt)
404 call get_param(param_file, mod_name,
"DIABATIC_FIRST", diabatic_first, &
405 "If true, apply diabatic and thermodynamic processes, "//&
406 "including buoyancy forcing and mass gain or loss, "//&
407 "before stepping the dynamics forward.", default=.false.)
410 if (time >= time_end)
call mom_error(fatal, &
411 "MOM_driver: The run has been started at or after the end time of the run.")
413 call get_param(param_file, mod_name,
"RESTART_CONTROL", restart_control, &
414 "An integer whose bits encode which restart files are "//&
415 "written. Add 2 (bit 1) for a time-stamped file, and odd "//&
416 "(bit 0) for a non-time-stamped file. A non-time-stamped "//&
417 "restart file is saved at the end of the run segment "//&
418 "for any non-negative value.", default=1)
419 call get_param(param_file, mod_name,
"RESTINT", restint, &
420 "The interval between saves of the restart file in units "//&
421 "of TIMEUNIT. Use 0 (the default) to not save "//&
422 "incremental restart files at all.", default=real_to_time(0.0), &
424 call get_param(param_file, mod_name,
"WRITE_CPU_STEPS", cpu_steps, &
425 "The number of coupled timesteps between writing the cpu "//&
426 "time. If this is not positive, do not check cpu time, and "//&
427 "the segment run-length can not be set via an elapsed CPU time.", &
429 call get_param(param_file,
"MOM",
"DEBUG", debug, &
430 "If true, write out verbose debugging data.", &
431 default=.false., debuggingparam=.true.)
433 call log_param(param_file, mod_name,
"ELAPSED TIME AS MASTER", elapsed_time_master)
436 call mom_write_cputime_init(param_file, dirs%output_directory, start_time, &
440 call close_param_file(param_file)
441 call diag_mediator_close_registration(diag)
444 if (calendar_type /= no_calendar)
then
445 call open_file(unit,
'time_stamp.out', form=ascii_file, action=append_file, &
446 threading=single_file)
447 call get_date(time, date(1), date(2), date(3), date(4), date(5), date(6))
448 month = month_name(date(2))
449 if (is_root_pe())
write(unit,
'(6i4,2x,a3)') date, month(1:3)
450 call get_date(time_end, date(1), date(2), date(3), date(4), date(5), date(6))
451 month = month_name(date(2))
452 if (is_root_pe())
write(unit,
'(6i4,2x,a3)') date, month(1:3)
453 call close_file(unit)
456 if (cpu_steps > 0)
call write_cputime(time, 0, nmax, write_cpu_csp)
458 if (((.not.btest(restart_control,1)) .and. (.not.btest(restart_control,0))) &
459 .or. (restart_control < 0)) permit_incr_restart = .false.
461 if (restint > real_to_time(0.0))
then
463 restart_time = start_time + restint * &
464 (1 + ((time + time_step_ocean) - start_time) / restint)
467 restart_time = time_end + time_step_ocean
468 permit_incr_restart = .false.
471 call cpu_clock_end(initclock)
473 call cpu_clock_begin(mainclock)
476 do while ((ns < nmax) .and. (time < time_end))
477 call calltree_enter(
"Main loop, MOM_driver.F90",ns)
480 if (.not. offline_tracer_mode)
then
481 call set_forcing(sfc_state, forces, fluxes, time, time_step_ocean, grid, us, &
485 call mom_mech_forcing_chksum(
"After set forcing", forces, grid, us, haloshift=0)
486 call mom_forcing_chksum(
"After set forcing", fluxes, grid, us, haloshift=0)
489 if (use_ice_shelf)
then
490 call shelf_calc_flux(sfc_state, fluxes, time, dt_forcing, ice_shelf_csp)
491 call add_shelf_forces(grid, ice_shelf_csp, forces)
493 fluxes%fluxes_used = .false.
494 fluxes%dt_buoy_accum = dt_forcing
497 call update_surface_waves(grid, gv, us, time, time_step_ocean, waves_csp)
501 call finish_mom_initialization(time, dirs, mom_csp, restart_csp)
505 time1 = master_time ; time = master_time
506 if (offline_tracer_mode)
then
507 call step_offline(forces, fluxes, sfc_state, time1, dt_forcing, mom_csp)
508 elseif (single_step_call)
then
509 call step_mom(forces, fluxes, sfc_state, time1, dt_forcing, mom_csp, waves=waves_csp)
511 n_max = 1 ;
if (dt_forcing > dt) n_max = ceiling(dt_forcing/dt - 0.001)
512 dt_dyn = dt_forcing / real(n_max)
514 nts = max(1,min(n_max,floor(dt_therm/dt_dyn + 0.001)))
517 time2 = time1 ; t_elapsed_seg = 0.0
519 if (diabatic_first)
then
520 if (modulo(n-1,nts)==0)
then
521 dtdia = dt_dyn*min(ntstep,n_max-(n-1))
522 call step_mom(forces, fluxes, sfc_state, time2, dtdia, mom_csp, &
523 do_dynamics=.false., do_thermodynamics=.true., &
524 start_cycle=(n==1), end_cycle=.false., cycle_length=dt_forcing)
527 call step_mom(forces, fluxes, sfc_state, time2, dt_dyn, mom_csp, &
528 do_dynamics=.true., do_thermodynamics=.false., &
529 start_cycle=.false., end_cycle=(n==n_max), cycle_length=dt_forcing)
531 call step_mom(forces, fluxes, sfc_state, time2, dt_dyn, mom_csp, &
532 do_dynamics=.true., do_thermodynamics=.false., &
533 start_cycle=(n==1), end_cycle=.false., cycle_length=dt_forcing)
535 if ((modulo(n,nts)==0) .or. (n==n_max))
then
536 dtdia = dt_dyn*(n - n_last_thermo)
538 if (n > n_last_thermo+1) &
539 time2 = time2 - real_to_time(dtdia - dt_dyn)
540 call step_mom(forces, fluxes, sfc_state, time2, dtdia, mom_csp, &
541 do_dynamics=.false., do_thermodynamics=.true., &
542 start_cycle=.false., end_cycle=(n==n_max), cycle_length=dt_forcing)
547 t_elapsed_seg = t_elapsed_seg + dt_dyn
548 time2 = time1 + real_to_time(t_elapsed_seg)
554 elapsed_time = elapsed_time + dt_forcing
555 if (elapsed_time > 2e9)
then
561 time_chg = real_to_time(elapsed_time)
562 segment_start_time = segment_start_time + time_chg
563 elapsed_time = elapsed_time - time_type_to_real(time_chg)
565 if (elapsed_time_master)
then
566 master_time = segment_start_time + real_to_time(elapsed_time)
568 master_time = master_time + time_step_ocean
572 if (cpu_steps > 0)
then ;
if (mod(ns, cpu_steps) == 0)
then
573 call write_cputime(time, ns+ntstep-1, nmax, write_cpu_csp)
576 call enable_averaging(dt_forcing, time, diag)
577 call mech_forcing_diags(forces, dt_forcing, grid, diag, surface_forcing_csp%handles)
578 call disable_averaging(diag)
580 if (.not. offline_tracer_mode)
then
581 if (fluxes%fluxes_used)
then
582 call enable_averaging(fluxes%dt_buoy_accum, time, diag)
583 call forcing_diagnostics(fluxes, sfc_state, fluxes%dt_buoy_accum, grid, &
584 diag, surface_forcing_csp%handles)
585 call disable_averaging(diag)
587 call mom_error(fatal,
"The solo MOM_driver is not yet set up to handle "//&
588 "thermodynamic time steps that are longer than the coupling timestep.")
593 if ((permit_incr_restart) .and. (fluxes%fluxes_used) .and. &
594 (time + (time_step_ocean/2) > restart_time))
then
595 if (btest(restart_control,1))
then
596 call save_restart(dirs%restart_output_dir, time, grid, &
597 restart_csp, .true., gv=gv)
598 call forcing_save_restart(surface_forcing_csp, grid, time, &
599 dirs%restart_output_dir, .true.)
600 if (use_ice_shelf)
call ice_shelf_save_restart(ice_shelf_csp, time, &
601 dirs%restart_output_dir, .true.)
603 if (btest(restart_control,0))
then
604 call save_restart(dirs%restart_output_dir, time, grid, &
606 call forcing_save_restart(surface_forcing_csp, grid, time, &
607 dirs%restart_output_dir)
608 if (use_ice_shelf)
call ice_shelf_save_restart(ice_shelf_csp, time, &
609 dirs%restart_output_dir)
611 restart_time = restart_time + restint
615 call calltree_leave(
"Main loop")
618 call cpu_clock_end(mainclock)
619 call cpu_clock_begin(termclock)
620 if (restart_control>=0)
then
621 if (.not.mom_state_is_synchronized(mom_csp)) &
622 call mom_error(warning,
"End of MOM_main reached with inconsistent "//&
623 "dynamics and advective times. Additional restart fields "//&
624 "that have not been coded yet would be required for reproducibility.")
625 if (.not.fluxes%fluxes_used .and. .not.offline_tracer_mode)
call mom_error(fatal, &
626 "End of MOM_main reached with unused buoyancy fluxes. "//&
627 "For conservation, the ocean restart files can only be "//&
628 "created after the buoyancy forcing is applied.")
630 call save_restart(dirs%restart_output_dir, time, grid, restart_csp, gv=gv)
631 if (use_ice_shelf)
call ice_shelf_save_restart(ice_shelf_csp, time, &
632 dirs%restart_output_dir)
634 call open_file(unit, trim(dirs%restart_output_dir)//
'ocean_solo.res', nohdrs=.true.)
635 if (is_root_pe())
then
636 write(unit,
'(i6,8x,a)') calendar_type, &
637 '(Calendar: no_calendar=0, thirty_day_months=1, julian=2, gregorian=3, noleap=4)'
639 call get_date(start_time, yr, mon, day, hr, mins, sec)
640 write(unit,
'(6i6,8x,a)') yr, mon, day, hr, mins, sec, &
641 'Model start time: year, month, day, hour, minute, second'
642 call get_date(time, yr, mon, day, hr, mins, sec)
643 write(unit,
'(6i6,8x,a)') yr, mon, day, hr, mins, sec, &
644 'Current model time: year, month, day, hour, minute, second'
646 call close_file(unit)
649 if (is_root_pe())
then
651 INQUIRE(unit,opened=unit_in_use)
652 if (.not.unit_in_use)
exit
654 open(unit,file=
"exitcode",form=
"FORMATTED",status=
"REPLACE",action=
"WRITE")
655 if (time < daymax)
then
663 call calltree_waypoint(
"End MOM_main")
664 call diag_mediator_end(time, diag, end_diag_manager=.true.)
665 call cpu_clock_end(termclock)
667 call io_infra_end ;
call mom_infra_end
669 call mom_end(mom_csp)
670 if (use_ice_shelf)
call ice_shelf_end(ice_shelf_csp)