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> 98 logical :: use_ice_shelf
101 logical :: use_waves = .false.
104 logical :: permit_incr_restart = .true.
112 integer :: nmax=2000000000
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
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
193 tracer_flow_csp => null()
199 restart_csp => null()
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)
Pointers to various fields which may be used describe the surface state of MOM, and which will be ret...
Wraps the FMS time manager functions.
This module implements boundary forcing for MOM6.
A control structure that regulates the writing of CPU time.
Ocean grid type. See mom_grid for details.
Structure containing pointers to the forcing fields that may be used to drive MOM. All fluxes are positive into the ocean.
The central module of the MOM6 ocean model.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
A module to monitor the overall CPU time used by MOM6 and project when to stop the model...
Wraps the MPP cpu clock functions.
Functions that calculate the surface wind stresses and fluxes of buoyancy or temperature/salinity and...
This module contains I/O framework code.
The MOM6 facility to parse input files for runtime parameters.
An overloaded interface to log the values of various types of parameters.
Orchestrates the registration and calling of tracer packages.
Structure that contains pointers to the mechanical forcing at the surface used to drive the liquid oc...
Interface for surface waves.
Implements the thermodynamic aspects of ocean / ice-shelf interactions, along with a crude placeholde...
A restart registry and the control structure for restarts.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Describes the decomposed MOM domain and has routines for communications across PEs.
Routines for error handling and I/O management.
Control structure for the MOM module, including the variables that describe the state of the ocean...
The MOM6 facility for reading and writing restart files, and querying what has been read...
The control structure for orchestrating the calling of tracer packages.
Container for all surface wave related parameters.
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
An overloaded interface to log version information about modules.
Describes the vertical ocean grid, including unit conversion factors.
Indicate whether a file exists, perhaps with domain decomposition.
Control structure that contains ice shelf parameters and diagnostics handles.
An overloaded interface to read various types of parameters.
Handy functions for manipulating strings.
Provides a transparent vertical ocean grid type and supporting routines.
Provides transparent structures with groups of MOM6 variables and supporting routines.
An overloaded interface to read and log the values of various types of parameters.