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
69 use fms_affinity_mod,
only : fms_affinity_init, fms_affinity_set,fms_affinity_get
72 use mom_ice_shelf,
only : shelf_calc_flux, add_shelf_forces, ice_shelf_save_restart
80 #include <MOM_memory.h>
83 type(mech_forcing) :: forces
86 type(forcing) :: fluxes
89 type(surface) :: sfc_state
92 type(ocean_grid_type),
pointer :: grid
93 type(verticalGrid_type),
pointer :: GV
95 type(unit_scale_type),
pointer :: US
98 logical :: use_ice_shelf
101 logical :: use_waves = .false.
104 logical :: permit_incr_restart = .true.
112 integer :: nmax=2000000000
115 type(directories) :: dirs
118 type(time_type),
target :: Time
121 type(time_type) :: Master_Time
123 type(time_type) :: Time1
125 type(time_type) :: Start_time
126 type(time_type) :: segment_start_time
127 type(time_type) :: Time_end
128 type(time_type) :: restart_time
129 type(time_type) :: Time_step_ocean
131 real :: elapsed_time = 0.0
132 logical :: elapsed_time_master
145 real :: t_elapsed_seg
146 integer :: n, n_max, nts, n_last_thermo
147 logical :: diabatic_first, single_step_call
148 type(time_type) :: Time2, time_chg
150 integer :: Restart_control
158 type(time_type) :: restint
159 type(time_type) :: daymax
162 integer :: date_init(6)=0
163 integer :: date(6)=-1
164 integer :: years=0, months=0, days=0
165 integer :: hours=0, minutes=0, seconds=0
166 integer :: yr, mon, day, hr, mins, sec
167 type(param_file_type) :: param_file
169 character(len=9) :: month
170 character(len=16) :: calendar =
'julian'
171 integer :: calendar_type=-1
173 integer :: unit, io_status, ierr
174 integer :: ensemble_size, nPEs_per, ensemble_info(6)
176 integer,
dimension(0) :: atm_PElist, land_PElist, ice_PElist
177 integer,
dimension(:),
allocatable :: ocean_PElist
178 logical :: unit_in_use
179 integer :: initClock, mainClock, termClock
182 logical :: offline_tracer_mode
190 type(MOM_control_struct),
pointer :: MOM_CSp => null()
192 type(tracer_flow_control_CS),
pointer :: &
193 tracer_flow_CSp => null()
194 type(surface_forcing_CS),
pointer :: surface_forcing_CSp => null()
195 type(write_cputime_CS),
pointer :: write_CPU_CSp => null()
196 type(ice_shelf_CS),
pointer :: ice_shelf_CSp => null()
197 type(wave_parameters_cs),
pointer :: waves_CSp => null()
198 type(MOM_restart_CS),
pointer :: &
199 restart_CSp => null()
201 type(diag_ctrl),
pointer :: &
205 character(len=4),
parameter :: vers_num =
'v2.0'
207 #include "version_variable.h"
208 character(len=40) :: mod_name =
"MOM_main (MOM_driver)"
210 integer :: ocean_nthreads = 1
211 logical :: use_hyper_thread = .false.
212 integer :: omp_get_num_threads,omp_get_thread_num
213 namelist /ocean_solo_nml/ date_init, calendar, months, days, hours, minutes, seconds,&
214 ocean_nthreads, use_hyper_thread
218 call write_cputime_start_clock(write_cpu_csp)
220 call mom_infra_init() ;
call io_infra_init()
225 call ensemble_manager_init() ; ensemble_info(:) = get_ensemble_size()
226 ensemble_size=ensemble_info(1) ; npes_per=ensemble_info(2)
227 if (ensemble_size > 1)
then
228 allocate(ocean_pelist(npes_per))
229 call ensemble_pelist_setup(.true., 0, npes_per, 0, 0, atm_pelist, ocean_pelist, &
230 land_pelist, ice_pelist)
231 call set_current_pelist(ocean_pelist)
232 deallocate(ocean_pelist)
236 initclock = cpu_clock_id(
'Initialization' )
237 mainclock = cpu_clock_id(
'Main loop' )
238 termclock = cpu_clock_id(
'Termination' )
239 call cpu_clock_begin(initclock)
241 call mom_mesg(
'======== Model being driven by MOM_driver ========', 2)
242 call calltree_waypoint(
"Program MOM_main, MOM_driver.F90")
246 call open_file(unit,
'input.nml', form=ascii_file, action=readonly_file)
247 read(unit, ocean_solo_nml, iostat=io_status)
248 call close_file(unit)
249 ierr = check_nml_error(io_status,
'ocean_solo_nml')
250 if (years+months+days+hours+minutes+seconds > 0)
then
251 if (is_root_pe())
write(*,ocean_solo_nml)
264 if (
file_exists(trim(dirs%restart_input_dir)//
'ocean_solo.res'))
then
265 call open_file(unit,trim(dirs%restart_input_dir)//
'ocean_solo.res', &
266 form=ascii_file,action=readonly_file)
267 read(unit,*) calendar_type
268 read(unit,*) date_init
270 call close_file(unit)
272 calendar = uppercase(calendar)
273 if (calendar(1:6) ==
'JULIAN')
then ; calendar_type = julian
274 elseif (calendar(1:9) ==
'GREGORIAN')
then ; calendar_type = gregorian
275 elseif (calendar(1:6) ==
'NOLEAP')
then ; calendar_type = noleap
276 elseif (calendar(1:10)==
'THIRTY_DAY')
then ; calendar_type = thirty_day_months
277 elseif (calendar(1:11)==
'NO_CALENDAR') then; calendar_type = no_calendar
278 elseif (calendar(1:1) /=
' ')
then
279 call mom_error(fatal,
'MOM_driver: Invalid namelist value '//trim(calendar)//
' for calendar')
281 call mom_error(fatal,
'MOM_driver: No namelist value for calendar')
284 call set_calendar_type(calendar_type)
287 if (sum(date_init) > 0)
then
288 start_time = set_date(date_init(1),date_init(2), date_init(3), &
289 date_init(4),date_init(5),date_init(6))
291 start_time = real_to_time(0.0)
294 call time_interp_external_init
296 if (sum(date) >= 0)
then
298 segment_start_time = set_date(date(1),date(2),date(3),date(4),date(5),date(6))
299 time = segment_start_time
300 call initialize_mom(time, start_time, param_file, dirs, mom_csp, restart_csp, &
301 segment_start_time, offline_tracer_mode=offline_tracer_mode, &
302 diag_ptr=diag, tracer_flow_csp=tracer_flow_csp)
307 call initialize_mom(time, start_time, param_file, dirs, mom_csp, restart_csp, &
308 offline_tracer_mode=offline_tracer_mode, diag_ptr=diag, &
309 tracer_flow_csp=tracer_flow_csp)
312 call get_mom_state_elements(mom_csp, g=grid, gv=gv, us=us, c_p_scaled=fluxes%C_p)
315 call calltree_waypoint(
"done initialize_MOM")
317 call extract_surface_state(mom_csp, sfc_state)
319 call surface_forcing_init(time, grid, us, param_file, diag, &
320 surface_forcing_csp, tracer_flow_csp)
321 call calltree_waypoint(
"done surface_forcing_init")
323 call get_param(param_file, mod_name,
"ICE_SHELF", use_ice_shelf, &
324 "If true, enables the ice shelf model.", default=.false.)
325 if (use_ice_shelf)
then
328 call initialize_ice_shelf(param_file, grid, time, ice_shelf_csp, &
329 diag, forces, fluxes)
332 call get_param(param_file,mod_name,
"USE_WAVES",use_waves,&
333 "If true, enables surface wave modules.",default=.false.)
335 call mom_wave_interface_init(time, grid, gv, us, param_file, waves_csp, diag)
337 call mom_wave_interface_init_lite(param_file)
340 segment_start_time = time
344 call log_version(param_file, mod_name, version,
"")
345 call get_param(param_file, mod_name,
"DT", dt, fail_if_missing=.true.)
346 call get_param(param_file, mod_name,
"DT_FORCING", dt_forcing, &
347 "The time step for changing forcing, coupling with other "//&
348 "components, or potentially writing certain diagnostics. "//&
349 "The default value is given by DT.", units=
"s", default=dt)
350 if (offline_tracer_mode)
then
351 call get_param(param_file, mod_name,
"DT_OFFLINE", dt_forcing, &
352 "Time step for the offline time step")
355 ntstep = max(1,ceiling(dt_forcing/dt - 0.001))
357 time_step_ocean = real_to_time(dt_forcing)
358 elapsed_time_master = (abs(dt_forcing - time_type_to_real(time_step_ocean)) > 1.0e-12*dt_forcing)
359 if (elapsed_time_master) &
360 call mom_mesg(
"Using real elapsed time for the master clock.", 2)
363 call get_param(param_file, mod_name,
"TIMEUNIT", time_unit, &
364 "The time unit for DAYMAX, ENERGYSAVEDAYS, and RESTINT.", &
365 units=
"s", default=86400.0)
366 if (years+months+days+hours+minutes+seconds > 0)
then
367 time_end = increment_date(time, years, months, days, hours, minutes, seconds)
368 call mom_mesg(
'Segment run length determined from ocean_solo_nml.', 2)
369 call get_param(param_file, mod_name,
"DAYMAX", daymax, timeunit=time_unit, &
370 default=time_end, do_not_log=.true.)
371 call log_param(param_file, mod_name,
"DAYMAX", daymax, &
372 "The final time of the whole simulation, in units of "//&
373 "TIMEUNIT seconds. This also sets the potential end "//&
374 "time of the present run segment if the end time is "//&
375 "not set via ocean_solo_nml in input.nml.", &
378 call get_param(param_file, mod_name,
"DAYMAX", daymax, &
379 "The final time of the whole simulation, in units of "//&
380 "TIMEUNIT seconds. This also sets the potential end "//&
381 "time of the present run segment if the end time is "//&
382 "not set via ocean_solo_nml in input.nml.", &
383 timeunit=time_unit, fail_if_missing=.true.)
387 call get_param(param_file, mod_name,
"SINGLE_STEPPING_CALL", single_step_call, &
388 "If true, advance the state of MOM with a single step "//&
389 "including both dynamics and thermodynamics. If false "//&
390 "the two phases are advanced with separate calls.", default=.true.)
391 call get_param(param_file, mod_name,
"DT_THERM", dt_therm, &
392 "The thermodynamic and tracer advection time step. "//&
393 "Ideally DT_THERM should be an integer multiple of DT "//&
394 "and less than the forcing or coupling time-step, unless "//&
395 "THERMO_SPANS_COUPLING is true, in which case DT_THERM "//&
396 "can be an integer multiple of the coupling timestep. By "//&
397 "default DT_THERM is set to DT.", units=
"s", default=dt)
398 call get_param(param_file, mod_name,
"DIABATIC_FIRST", diabatic_first, &
399 "If true, apply diabatic and thermodynamic processes, "//&
400 "including buoyancy forcing and mass gain or loss, "//&
401 "before stepping the dynamics forward.", default=.false.)
404 if (time >= time_end)
call mom_error(fatal, &
405 "MOM_driver: The run has been started at or after the end time of the run.")
407 call get_param(param_file, mod_name,
"RESTART_CONTROL", restart_control, &
408 "An integer whose bits encode which restart files are "//&
409 "written. Add 2 (bit 1) for a time-stamped file, and odd "//&
410 "(bit 0) for a non-time-stamped file. A non-time-stamped "//&
411 "restart file is saved at the end of the run segment "//&
412 "for any non-negative value.", default=1)
413 call get_param(param_file, mod_name,
"RESTINT", restint, &
414 "The interval between saves of the restart file in units "//&
415 "of TIMEUNIT. Use 0 (the default) to not save "//&
416 "incremental restart files at all.", default=real_to_time(0.0), &
418 call get_param(param_file, mod_name,
"WRITE_CPU_STEPS", cpu_steps, &
419 "The number of coupled timesteps between writing the cpu "//&
420 "time. If this is not positive, do not check cpu time, and "//&
421 "the segment run-length can not be set via an elapsed CPU time.", &
423 call get_param(param_file,
"MOM",
"DEBUG", debug, &
424 "If true, write out verbose debugging data.", &
425 default=.false., debuggingparam=.true.)
427 call log_param(param_file, mod_name,
"ELAPSED TIME AS MASTER", elapsed_time_master)
430 call mom_write_cputime_init(param_file, dirs%output_directory, start_time, &
434 call close_param_file(param_file)
435 call diag_mediator_close_registration(diag)
438 if (calendar_type /= no_calendar)
then
439 call open_file(unit,
'time_stamp.out', form=ascii_file, action=append_file, &
440 threading=single_file)
441 call get_date(time, date(1), date(2), date(3), date(4), date(5), date(6))
442 month = month_name(date(2))
443 if (is_root_pe())
write(unit,
'(6i4,2x,a3)') date, month(1:3)
444 call get_date(time_end, date(1), date(2), date(3), date(4), date(5), date(6))
445 month = month_name(date(2))
446 if (is_root_pe())
write(unit,
'(6i4,2x,a3)') date, month(1:3)
447 call close_file(unit)
450 if (cpu_steps > 0)
call write_cputime(time, 0, write_cpu_csp)
452 if (((.not.btest(restart_control,1)) .and. (.not.btest(restart_control,0))) &
453 .or. (restart_control < 0)) permit_incr_restart = .false.
455 if (restint > real_to_time(0.0))
then
457 restart_time = start_time + restint * &
458 (1 + ((time + time_step_ocean) - start_time) / restint)
461 restart_time = time_end + time_step_ocean
462 permit_incr_restart = .false.
465 call cpu_clock_end(initclock)
467 call cpu_clock_begin(mainclock)
470 do while ((ns < nmax) .and. (time < time_end))
471 call calltree_enter(
"Main loop, MOM_driver.F90",ns)
474 if (.not. offline_tracer_mode)
then
475 call set_forcing(sfc_state, forces, fluxes, time, time_step_ocean, grid, us, &
479 call mom_mech_forcing_chksum(
"After set forcing", forces, grid, us, haloshift=0)
480 call mom_forcing_chksum(
"After set forcing", fluxes, grid, us, haloshift=0)
483 if (use_ice_shelf)
then
484 call shelf_calc_flux(sfc_state, fluxes, time, dt_forcing, ice_shelf_csp)
485 call add_shelf_forces(grid, us, ice_shelf_csp, forces)
487 fluxes%fluxes_used = .false.
488 fluxes%dt_buoy_accum = us%s_to_T*dt_forcing
491 call update_surface_waves(grid, gv, us, time, time_step_ocean, waves_csp)
495 call finish_mom_initialization(time, dirs, mom_csp, restart_csp)
499 time1 = master_time ; time = master_time
500 if (offline_tracer_mode)
then
501 call step_offline(forces, fluxes, sfc_state, time1, dt_forcing, mom_csp)
502 elseif (single_step_call)
then
503 call step_mom(forces, fluxes, sfc_state, time1, dt_forcing, mom_csp, waves=waves_csp)
505 n_max = 1 ;
if (dt_forcing > dt) n_max = ceiling(dt_forcing/dt - 0.001)
506 dt_dyn = dt_forcing / real(n_max)
508 nts = max(1,min(n_max,floor(dt_therm/dt_dyn + 0.001)))
511 time2 = time1 ; t_elapsed_seg = 0.0
513 if (diabatic_first)
then
514 if (modulo(n-1,nts)==0)
then
515 dtdia = dt_dyn*min(ntstep,n_max-(n-1))
516 call step_mom(forces, fluxes, sfc_state, time2, dtdia, mom_csp, &
517 do_dynamics=.false., do_thermodynamics=.true., &
518 start_cycle=(n==1), end_cycle=.false., cycle_length=dt_forcing)
521 call step_mom(forces, fluxes, sfc_state, time2, dt_dyn, mom_csp, &
522 do_dynamics=.true., do_thermodynamics=.false., &
523 start_cycle=.false., end_cycle=(n==n_max), cycle_length=dt_forcing)
525 call step_mom(forces, fluxes, sfc_state, time2, dt_dyn, mom_csp, &
526 do_dynamics=.true., do_thermodynamics=.false., &
527 start_cycle=(n==1), end_cycle=.false., cycle_length=dt_forcing)
529 if ((modulo(n,nts)==0) .or. (n==n_max))
then
530 dtdia = dt_dyn*(n - n_last_thermo)
532 if (n > n_last_thermo+1) &
533 time2 = time2 - real_to_time(dtdia - dt_dyn)
534 call step_mom(forces, fluxes, sfc_state, time2, dtdia, mom_csp, &
535 do_dynamics=.false., do_thermodynamics=.true., &
536 start_cycle=.false., end_cycle=(n==n_max), cycle_length=dt_forcing)
541 t_elapsed_seg = t_elapsed_seg + dt_dyn
542 time2 = time1 + real_to_time(t_elapsed_seg)
548 elapsed_time = elapsed_time + dt_forcing
549 if (elapsed_time > 2e9)
then
555 time_chg = real_to_time(elapsed_time)
556 segment_start_time = segment_start_time + time_chg
557 elapsed_time = elapsed_time - time_type_to_real(time_chg)
559 if (elapsed_time_master)
then
560 master_time = segment_start_time + real_to_time(elapsed_time)
562 master_time = master_time + time_step_ocean
566 if (cpu_steps > 0)
then ;
if (mod(ns, cpu_steps) == 0)
then
567 call write_cputime(time, ns+ntstep-1, write_cpu_csp, nmax)
570 call mech_forcing_diags(forces, dt_forcing, grid, time, diag, surface_forcing_csp%handles)
572 if (.not. offline_tracer_mode)
then
573 if (fluxes%fluxes_used)
then
574 call forcing_diagnostics(fluxes, sfc_state, grid, us, time, &
575 diag, surface_forcing_csp%handles)
577 call mom_error(fatal,
"The solo MOM_driver is not yet set up to handle "//&
578 "thermodynamic time steps that are longer than the coupling timestep.")
583 if ((permit_incr_restart) .and. (fluxes%fluxes_used) .and. &
584 (time + (time_step_ocean/2) > restart_time))
then
585 if (btest(restart_control,1))
then
586 call save_restart(dirs%restart_output_dir, time, grid, &
587 restart_csp, .true., gv=gv)
588 call forcing_save_restart(surface_forcing_csp, grid, time, &
589 dirs%restart_output_dir, .true.)
590 if (use_ice_shelf)
call ice_shelf_save_restart(ice_shelf_csp, time, &
591 dirs%restart_output_dir, .true.)
593 if (btest(restart_control,0))
then
594 call save_restart(dirs%restart_output_dir, time, grid, &
596 call forcing_save_restart(surface_forcing_csp, grid, time, &
597 dirs%restart_output_dir)
598 if (use_ice_shelf)
call ice_shelf_save_restart(ice_shelf_csp, time, &
599 dirs%restart_output_dir)
601 restart_time = restart_time + restint
605 call calltree_leave(
"Main loop")
608 call cpu_clock_end(mainclock)
609 call cpu_clock_begin(termclock)
610 if (restart_control>=0)
then
611 if (.not.mom_state_is_synchronized(mom_csp)) &
612 call mom_error(warning,
"End of MOM_main reached with inconsistent "//&
613 "dynamics and advective times. Additional restart fields "//&
614 "that have not been coded yet would be required for reproducibility.")
615 if (.not.fluxes%fluxes_used .and. .not.offline_tracer_mode)
call mom_error(fatal, &
616 "End of MOM_main reached with unused buoyancy fluxes. "//&
617 "For conservation, the ocean restart files can only be "//&
618 "created after the buoyancy forcing is applied.")
620 call save_restart(dirs%restart_output_dir, time, grid, restart_csp, gv=gv)
621 if (use_ice_shelf)
call ice_shelf_save_restart(ice_shelf_csp, time, &
622 dirs%restart_output_dir)
624 call open_file(unit, trim(dirs%restart_output_dir)//
'ocean_solo.res', nohdrs=.true.)
625 if (is_root_pe())
then
626 write(unit,
'(i6,8x,a)') calendar_type, &
627 '(Calendar: no_calendar=0, thirty_day_months=1, julian=2, gregorian=3, noleap=4)'
629 call get_date(start_time, yr, mon, day, hr, mins, sec)
630 write(unit,
'(6i6,8x,a)') yr, mon, day, hr, mins, sec, &
631 'Model start time: year, month, day, hour, minute, second'
632 call get_date(time, yr, mon, day, hr, mins, sec)
633 write(unit,
'(6i6,8x,a)') yr, mon, day, hr, mins, sec, &
634 'Current model time: year, month, day, hour, minute, second'
636 call close_file(unit)
639 if (is_root_pe())
then
641 INQUIRE(unit,opened=unit_in_use)
642 if (.not.unit_in_use)
exit
644 open(unit,file=
"exitcode",form=
"FORMATTED",status=
"REPLACE",action=
"WRITE")
645 if (time < daymax)
then
653 call calltree_waypoint(
"End MOM_main")
654 call diag_mediator_end(time, diag, end_diag_manager=.true.)
655 if (cpu_steps > 0)
call write_cputime(time, ns-1, write_cpu_csp, call_end=.true.)
656 call cpu_clock_end(termclock)
658 call io_infra_end ;
call mom_infra_end
660 call mom_end(mom_csp)
661 if (use_ice_shelf)
call ice_shelf_end(ice_shelf_csp)