← back to index

config_src/drivers/solo_driver/MOM_driver.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
52program MOM6
6
7!********+*********+*********+*********+*********+*********+*********+**
8!* *
9!* The Modular Ocean Model, version 6 *
10!* MOM6 *
11!* *
12!* By Alistair Adcroft, Stephen Griffies and Robert Hallberg *
13!* *
14!* This file is the ocean-only driver for Version 6 of the Modular *
15!* Ocean Model (MOM). A separate ocean interface for use with *
16!* coupled models is provided in ocean_model_MOM.F90. These two *
17!* drivers are kept in separate directories for convenience of code *
18!* selection during compiling. This file orchestrates the calls to *
19!* the MOM initialization routines, to the subroutine that steps *
20!* the model, and coordinates the output and saving restarts. A *
21!* description of all of the files that constitute MOM is found in *
22!* the comments at the beginning of MOM.F90. The arguments of each *
23!* subroutine are described where the subroutine is defined. *
24!* *
25!* Macros written all in capital letters are defined in MOM_memory.h. *
26!* *
27!********+*********+*********+*********+*********+*********+*********+**
28
291 use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
30 use MOM_cpu_clock, only : CLOCK_COMPONENT
31 use MOM_data_override, only : data_override_init
32 use MOM_diag_mediator, only : diag_mediator_end, diag_ctrl, diag_mediator_close_registration
33 use MOM_diag_manager_infra, only : diag_manager_set_time_end_infra
34 use MOM, only : initialize_MOM, step_MOM, MOM_control_struct, MOM_end
35 use MOM, only : extract_surface_state, finish_MOM_initialization
36 use MOM, only : get_MOM_state_elements, MOM_state_is_synchronized
37 use MOM, only : step_offline
38 use MOM, only : save_MOM_restart
39 use MOM_coms, only : Set_PElist
40 use MOM_domains, only : MOM_infra_init, MOM_infra_end, set_MOM_thread_affinity
41 use MOM_ensemble_manager, only : ensemble_manager_init, get_ensemble_size
42 use MOM_ensemble_manager, only : ensemble_pelist_setup
43 use MOM_error_handler, only : MOM_error, MOM_mesg, WARNING, FATAL, is_root_pe
44 use MOM_error_handler, only : callTree_enter, callTree_leave, callTree_waypoint
45 use MOM_file_parser, only : read_param, get_param, log_param, log_version, param_file_type
46 use MOM_file_parser, only : close_param_file
47 use MOM_forcing_type, only : forcing, mech_forcing, forcing_diagnostics
48 use MOM_forcing_type, only : mech_forcing_diags, MOM_forcing_chksum, MOM_mech_forcing_chksum
49 use MOM_get_input, only : get_MOM_input, directories
50 use MOM_grid, only : ocean_grid_type
51 use MOM_ice_shelf, only : initialize_ice_shelf, ice_shelf_end, ice_shelf_CS
52 use MOM_ice_shelf, only : shelf_calc_flux, add_shelf_forces, ice_shelf_save_restart
53 use MOM_ice_shelf, only : initialize_ice_shelf_fluxes, initialize_ice_shelf_forces
54 use MOM_ice_shelf, only : ice_shelf_query, adjust_ice_sheet_frazil
55 use MOM_ice_shelf_initialize, only : initialize_ice_SMB
56 use MOM_interpolate, only : time_interp_external_init
57 use MOM_io, only : file_exists, open_ASCII_file, close_file
58 use MOM_io, only : check_nml_error, io_infra_init, io_infra_end
59 use MOM_io, only : APPEND_FILE, READONLY_FILE
60 use MOM_string_functions,only : uppercase
61 use MOM_surface_forcing, only : set_forcing, forcing_save_restart
62 use MOM_surface_forcing, only : surface_forcing_init, surface_forcing_CS
63 use MOM_time_manager, only : time_type, set_date, get_date, real_to_time, time_to_real
64 use MOM_time_manager, only : operator(+), operator(-), operator(*), operator(/)
65 use MOM_time_manager, only : operator(>), operator(<), operator(>=)
66 use MOM_time_manager, only : increment_date, set_calendar_type, month_name
67 use MOM_time_manager, only : JULIAN, GREGORIAN, NOLEAP, THIRTY_DAY_MONTHS, NO_CALENDAR
68 use MOM_tracer_flow_control, only : tracer_flow_control_CS
69 use MOM_unit_scaling, only : unit_scale_type
70 use MOM_variables, only : surface
71 use MOM_verticalGrid, only : verticalGrid_type
72 use MOM_wave_interface, only : wave_parameters_CS, MOM_wave_interface_init
73 use MOM_wave_interface, only : Update_Surface_Waves
74 use MOM_write_cputime, only : write_cputime, MOM_write_cputime_init
75 use MOM_write_cputime, only : write_cputime_start_clock, write_cputime_CS
76
77 implicit none
78
79#include <MOM_memory.h>
80
81 ! A structure with the driving mechanical surface forces
82 type(mech_forcing) :: forces
83 ! A structure containing pointers to the thermodynamic forcing fields
84 ! at the ocean surface.
85 type(forcing) :: fluxes
86 ! A structure containing pointers to the ocean surface state fields.
871 type(surface) :: sfc_state
88
89 ! A pointer to a structure containing metrics and related information.
90 type(ocean_grid_type), pointer :: grid => NULL()
91 type(verticalGrid_type), pointer :: GV => NULL()
92 ! A pointer to a structure containing dimensional unit scaling factors.
93 type(unit_scale_type), pointer :: US => NULL()
94
95 ! If .true., use the ice shelf model for part of the domain.
96 logical :: use_ice_shelf = .false.
97
98 ! If .true., use surface wave coupling
99 logical :: use_waves = .false.
100
101 ! This is .true. if incremental restart files may be saved.
102 logical :: permit_incr_restart = .true.
103
104 ! nmax is the number of iterations after which to stop so that the
105 ! simulation does not exceed its CPU time limit. nmax is determined by
106 ! evaluating the CPU time used between successive calls to write_cputime.
107 ! Initially it is set to be very large.
108 integer :: nmax=2000000000
109
110 ! A structure containing several relevant directory paths.
111 type(directories) :: dirs
112
113 ! A suite of time types for use by MOM
114 type(time_type), target :: Time ! A copy of the ocean model's time.
115 ! Other modules can set pointers to this and
116 ! change it to manage diagnostics.
117 type(time_type) :: Master_Time ! The ocean model's master clock. No other
118 ! modules are ever given access to this.
119 type(time_type) :: Time1 ! The value of the ocean model's time at the
120 ! start of a call to step_MOM.
121 type(time_type) :: Start_time ! The start time of the simulation.
122 type(time_type) :: segment_start_time ! The start time of this run segment.
123 type(time_type) :: Time_end ! End time for the segment or experiment.
124 type(time_type) :: restart_time ! The next time to write restart files.
125 type(time_type) :: Time_step_ocean ! A time_type version of dt_forcing.
126 logical :: segment_start_time_set ! True if segment_start_time has been set to a valid value.
127
128 real :: elapsed_time = 0.0 ! Elapsed time in this run [T ~> s].
129 logical :: elapsed_time_master ! If true, elapsed time is used to set the model's master
130 ! clock (Time). This is needed if Time_step_ocean is not
131 ! an exact representation of dt_forcing.
132 real :: dt_forcing ! The coupling time step [T ~> s].
133 real :: dt ! The nominal baroclinic dynamics time step [T ~> s].
134 integer :: ntstep ! The number of baroclinic dynamics time steps within dt_forcing.
135 real :: dt_therm ! The thermodynamic timestep [T ~> s]
136 real :: dt_dyn ! The actual dynamic timestep used [T ~> s]. The value of dt_dyn
137 ! is chosen so that dt_forcing is an integer multiple of dt_dyn.
138 real :: dtdia ! The diabatic timestep [T ~> s]
139 real :: t_elapsed_seg ! The elapsed time in this run segment [T ~> s]
140 integer :: n, ns, n_max, nts, n_last_thermo
141 logical :: diabatic_first, single_step_call, initialize_smb
142 type(time_type) :: Time2, time_chg ! Temporary time variables
143
144 integer :: Restart_control ! An integer that is bit-tested to determine whether
145 ! incremental restart files are saved and whether they
146 ! have a time stamped name. +1 (bit 0) for generic
147 ! files and +2 (bit 1) for time-stamped files. A
148 ! restart file is saved at the end of a run segment
149 ! unless Restart_control is negative.
150
151 real :: Time_unit ! The time unit for the following input fields [s].
152 type(time_type) :: restint ! The time between saves of the restart file.
153 type(time_type) :: daymax ! The final day of the simulation.
154
155 integer :: CPU_steps ! The number of steps between writing CPU time.
156 integer :: date(6) ! Possibly the start date of this run segment.
1576 type(param_file_type) :: param_file ! The structure indicating the file(s)
158 ! containing all run-time parameters.
159
160 integer :: calendar_type=-1 ! A coded integer indicating the calendar type.
161
162 integer :: unit, io_status, ierr
163 integer :: initClock, mainClock, termClock
164
165 logical :: debug ! If true, write verbose checksums for debugging purposes.
166 logical :: offline_tracer_mode ! If false, use the model in prognostic mode where
167 ! the barotropic and baroclinic dynamics, thermodynamics,
168 ! etc. are stepped forward integrated in time.
169 ! If true, then all of the above are bypassed with all
170 ! fields necessary to integrate only the tracer advection
171 ! and diffusion equation are read in from files stored from
172 ! a previous integration of the prognostic model
173
174179 type(MOM_control_struct) :: MOM_CSp !< The control structure with all the MOM6 internal types,
175 !! parameters and variables
176 type(tracer_flow_control_CS), pointer :: &
177 tracer_flow_CSp => NULL() !< A pointer to the tracer flow control structure
178 type(surface_forcing_CS), pointer :: surface_forcing_CSp => NULL()
179 type(write_cputime_CS), pointer :: write_CPU_CSp => NULL()
180 type(ice_shelf_CS), pointer :: ice_shelf_CSp => NULL()
181 logical :: override_shelf_fluxes !< If true, and shelf dynamics are active,
182 !! the data_override feature is enabled (only for MOSAIC grid types)
183 type(wave_parameters_cs), pointer :: waves_CSp => NULL()
184 type(diag_ctrl), pointer :: &
185 diag => NULL() !< A pointer to the diagnostic regulatory structure
186 !-----------------------------------------------------------------------
187
188 character(len=4), parameter :: vers_num = 'v2.0'
189 ! This include declares and sets the variable "version".
190# include "version_variable.h"
191 character(len=40) :: mod_name = "MOM_main (MOM_driver)" ! This module's name.
192
193 ! These are the variables that might be read via the namelist capability.
194 integer :: date_init(6)=0 ! The start date of the whole simulation.
195 character(len=16) :: calendar = 'julian' ! The name of the calendar type.
196 integer :: years=0, months=0, days=0 ! These may determine the segment run
197 integer :: hours=0, minutes=0, seconds=0 ! length, if read from a namelist.
198 integer :: ocean_nthreads = 1
199 logical :: use_hyper_thread = .false.
200 namelist /ocean_solo_nml/ date_init, calendar, months, days, hours, minutes, seconds, &
201 ocean_nthreads, use_hyper_thread
202
203 !=====================================================================
204
2051 call write_cputime_start_clock(write_CPU_CSp)
206
2071 call MOM_infra_init() ; call io_infra_init()
208
209 !allocate(forces,fluxes,sfc_state)
210
211 ! Initialize the ensemble manager based on settings in input.nml(ensemble.nml).
2121 call initialize_ocean_only_ensembles()
213
214 ! These clocks are on the global pelist.
2151 initClock = cpu_clock_id( 'Initialization' )
2161 mainClock = cpu_clock_id( 'Main loop' )
2171 termClock = cpu_clock_id( 'Termination' )
2181 call cpu_clock_begin(initClock)
219
2201 call MOM_mesg('======== Model being driven by MOM_driver ========', 2)
2211 call callTree_waypoint("Program MOM_main, MOM_driver.F90")
222
2231 if (file_exists('input.nml')) then
224 ! Provide for namelist specification of the run length and calendar data.
2251 call open_ASCII_file(unit, 'input.nml', action=READONLY_FILE)
2261 read(unit, ocean_solo_nml, iostat=io_status)
2271 call close_file(unit)
2281 ierr = check_nml_error(io_status,'ocean_solo_nml')
2291 if (is_root_pe() .and. (years+months+days+hours+minutes+seconds > 0)) write(*,ocean_solo_nml)
230 endif
231
232 ! This call sets the number and affinity of threads with openMP.
233 !$ call set_MOM_thread_affinity(ocean_nthreads, use_hyper_thread)
234
235 ! This call is required to initiate dirs%restart_input_dir for ocean_solo.res
236 ! The contents of dirs will be reread in initialize_MOM.
2371 call get_MOM_input(dirs=dirs)
238
2391 segment_start_time_set = .false.
240 ! Read ocean_solo restart, which can override settings from the namelist.
2411 if (file_exists(trim(dirs%restart_input_dir)//'ocean_solo.res')) then
2420 date(:) = -1
2430 call open_ASCII_file(unit, trim(dirs%restart_input_dir)//'ocean_solo.res', action=READONLY_FILE)
2440 read(unit,*) calendar_type
2450 read(unit,*) date_init
2460 read(unit,*) date
2470 call close_file(unit)
248
2490 call set_calendar_type(calendar_type)
2500 if (sum(date) >= 0) then
251 ! In this case, the segment starts at a time fixed by ocean_solo.res
2520 segment_start_time = set_date(date(1), date(2), date(3), date(4), date(5), date(6))
2530 segment_start_time_set = .true.
254 endif
255 else
2561 calendar = uppercase(calendar)
2571 if (calendar(1:6) == 'JULIAN') then ; calendar_type = JULIAN
2580 elseif (calendar(1:9) == 'GREGORIAN') then ; calendar_type = GREGORIAN
2590 elseif (calendar(1:6) == 'NOLEAP') then ; calendar_type = NOLEAP
2600 elseif (calendar(1:10)=='THIRTY_DAY') then ; calendar_type = THIRTY_DAY_MONTHS
2610 elseif (calendar(1:11)=='NO_CALENDAR') then ; calendar_type = NO_CALENDAR
2620 elseif (calendar(1:1) /= ' ') then
2630 call MOM_error(FATAL,'MOM_driver: Invalid namelist value '//trim(calendar)//' for calendar')
264 else
2650 call MOM_error(FATAL,'MOM_driver: No namelist value for calendar')
266 endif
2671 call set_calendar_type(calendar_type)
268 endif
269
270
2717 if (sum(date_init) > 0) then
272 Start_time = set_date(date_init(1), date_init(2), date_init(3), &
2730 date_init(4), date_init(5), date_init(6))
274 else
2751 Start_time = real_to_time(0.0)
276 endif
277
2781 call time_interp_external_init()
279
280 ! Call initialize MOM with an optional Ice Shelf CS which, if present triggers
281 ! initialization of ice shelf parameters and arrays.
282 !$omp target enter data map(alloc: MOM_CSp)
2831 if (segment_start_time_set) then
284 ! In this case, the segment starts at a time fixed by ocean_solo.res
2850 Time = segment_start_time
286 call initialize_MOM(Time, Start_time, param_file, dirs, MOM_CSp, &
287 segment_start_time, offline_tracer_mode=offline_tracer_mode, &
288 diag_ptr=diag, tracer_flow_CSp=tracer_flow_CSp, ice_shelf_CSp=ice_shelf_CSp, &
2890 waves_CSp=Waves_CSp)
290 else
291 ! In this case, the segment starts at a time read from the MOM restart file
292 ! or is left at Start_time by MOM_initialize.
2931 Time = Start_time
294 call initialize_MOM(Time, Start_time, param_file, dirs, MOM_CSp, &
295 offline_tracer_mode=offline_tracer_mode, diag_ptr=diag, &
2961 tracer_flow_CSp=tracer_flow_CSp, ice_shelf_CSp=ice_shelf_CSp, waves_CSp=Waves_CSp)
297 endif
298
2991 call get_MOM_state_elements(MOM_CSp, G=grid, GV=GV, US=US, C_p_scaled=fluxes%C_p)
3001 Master_Time = Time
3011 use_ice_shelf = associated(ice_shelf_CSp)
302
3031 if (use_ice_shelf) then
304 ! These arrays are not initialized in most solo cases, but are needed
305 ! when using an ice shelf
3060 call initialize_ice_shelf_fluxes(ice_shelf_CSp, grid, US, fluxes)
3070 call initialize_ice_shelf_forces(ice_shelf_CSp, grid, US, forces)
3080 call ice_shelf_query(ice_shelf_CSp, grid, data_override_shelf_fluxes=override_shelf_fluxes)
3090 if (override_shelf_fluxes) call data_override_init(Ocean_Domain_in=grid%domain%mpp_domain)
310 call get_param(param_file, mod_name, "INITIALIZE_ICE_SHEET_SMB", &
3110 initialize_smb, "Read in a constant SMB for the ice sheet", default=.false.)
3120 if (initialize_smb) call initialize_ice_SMB(fluxes%shelf_sfc_mass_flux, grid, US, param_file)
313 endif
314
315
3161 call callTree_waypoint("done initialize_MOM")
317
3181 call extract_surface_state(MOM_CSp, sfc_state)
319
3201 if (use_ice_shelf .and. allocated(sfc_state%frazil)) &
3210 call adjust_ice_sheet_frazil(sfc_state, fluxes, Ice_shelf_CSp)
322
323 call surface_forcing_init(Time, grid, US, param_file, diag, &
3241 surface_forcing_CSp, tracer_flow_CSp)
3251 call callTree_waypoint("done surface_forcing_init")
326
327
328 call get_param(param_file, mod_name, "USE_WAVES", Use_Waves, &
3291 "If true, enables surface wave modules.",default=.false.)
330 ! MOM_wave_interface_init is called regardless of the value of USE_WAVES because
331 ! it also initializes statistical waves.
3321 call MOM_wave_interface_init(Time, grid, GV, US, param_file, Waves_CSp, diag)
333
3341 segment_start_time = Time
3351 elapsed_time = 0.0
336
337 ! Read all relevant parameters and write them to the model log.
3381 call log_version(param_file, mod_name, version, "")
339 call get_param(param_file, mod_name, "DT", dt, &
3401 units="s", scale=US%s_to_T, fail_if_missing=.true.)
341 call get_param(param_file, mod_name, "DT_FORCING", dt_forcing, &
342 "The time step for changing forcing, coupling with other "//&
343 "components, or potentially writing certain diagnostics. "//&
344 "The default value is given by DT.", &
3451 units="s", default=US%T_to_s*dt, scale=US%s_to_T)
3461 if (offline_tracer_mode) then
347 call get_param(param_file, mod_name, "DT_OFFLINE", dt_forcing, &
348 "Length of time between reading in of input fields", &
3490 units="s", scale=US%s_to_T, fail_if_missing=.true.)
3500 dt = dt_forcing
351 endif
3521 ntstep = MAX(1,ceiling(dt_forcing/dt - 0.001))
353
3541 Time_step_ocean = real_to_time(dt_forcing, unscale=US%T_to_s)
3551 elapsed_time_master = (abs(dt_forcing - time_to_real(Time_step_ocean, scale=US%s_to_T)) > 1.0e-12*dt_forcing)
3561 if (elapsed_time_master) &
3570 call MOM_mesg("Using real elapsed time for the master clock.", 2)
358
359 ! Determine the segment end time, either from the namelist file or parsed input file.
360 ! Note that Time_unit always is in [s].
361 call get_param(param_file, mod_name, "TIMEUNIT", Time_unit, &
362 "The time unit for DAYMAX, ENERGYSAVEDAYS, and RESTINT.", &
3631 units="s", default=86400.0)
3641 if (years+months+days+hours+minutes+seconds > 0) then
3650 Time_end = increment_date(Time, years, months, days, hours, minutes, seconds)
3660 call MOM_mesg('Segment run length determined from ocean_solo_nml.', 2)
367 call get_param(param_file, mod_name, "DAYMAX", daymax, timeunit=Time_unit, &
3680 default=Time_end, do_not_log=.true.)
369 call log_param(param_file, mod_name, "DAYMAX", daymax, &
370 "The final time of the whole simulation, in units of "//&
371 "TIMEUNIT seconds. This also sets the potential end "//&
372 "time of the present run segment if the end time is "//&
373 "not set via ocean_solo_nml in input.nml.", &
3740 timeunit=Time_unit)
375 else
376 call get_param(param_file, mod_name, "DAYMAX", daymax, &
377 "The final time of the whole simulation, in units of "//&
378 "TIMEUNIT seconds. This also sets the potential end "//&
379 "time of the present run segment if the end time is "//&
380 "not set via ocean_solo_nml in input.nml.", &
3811 timeunit=Time_unit, fail_if_missing=.true.)
3821 Time_end = daymax
383 endif
384
3851 call diag_manager_set_time_end_infra(Time_end)
386
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 "//&
3901 "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.", &
3981 units="s", default=US%T_to_s*dt, scale=US%s_to_T)
399 call get_param(param_file, mod_name, "DIABATIC_FIRST", diabatic_first, &
400 "If true, apply diabatic and thermodynamic processes, "//&
401 "including buoyancy forcing and mass gain or loss, "//&
4021 "before stepping the dynamics forward.", default=.false.)
403
404
4051 if (Time >= Time_end) call MOM_error(FATAL, &
4060 "MOM_driver: The run has been started at or after the end time of the run.")
407
408 call get_param(param_file, mod_name, "RESTART_CONTROL", Restart_control, &
409 "An integer whose bits encode which restart files are "//&
410 "written. Add 2 (bit 1) for a time-stamped file, and odd "//&
411 "(bit 0) for a non-time-stamped file. A non-time-stamped "//&
412 "restart file is saved at the end of the run segment "//&
4131 "for any non-negative value.", default=1)
414 call get_param(param_file, mod_name, "RESTINT", restint, &
415 "The interval between saves of the restart file in units "//&
416 "of TIMEUNIT. Use 0 (the default) to not save "//&
417 "incremental restart files at all.", default=real_to_time(0.0), &
4181 timeunit=Time_unit)
419 call get_param(param_file, mod_name, "WRITE_CPU_STEPS", cpu_steps, &
420 "The number of coupled timesteps between writing the cpu "//&
421 "time. If this is not positive, do not check cpu time, and "//&
422 "the segment run-length can not be set via an elapsed CPU time.", &
4231 default=1000)
424 call get_param(param_file, "MOM", "DEBUG", debug, &
425 "If true, write out verbose debugging data.", &
4261 default=.false., debuggingParam=.true.)
427
4281 call log_param(param_file, mod_name, "ELAPSED TIME AS MASTER", elapsed_time_master)
429
4301 if (cpu_steps > 0) &
431 call MOM_write_cputime_init(param_file, dirs%output_directory, Start_time, &
4321 write_CPU_CSp)
433
434 ! Close the param_file. No further parsing of input is possible after this.
4351 call close_param_file(param_file)
4361 call diag_mediator_close_registration(diag)
437
438 ! Write out a time stamp file.
4391 if (is_root_pe() .and. (calendar_type /= NO_CALENDAR)) call write_time_stamp_file(Time)
440
4411 if (cpu_steps > 0) call write_cputime(Time, 0, write_CPU_CSp)
442
443 if (((.not.BTEST(Restart_control,1)) .and. (.not.BTEST(Restart_control,0))) &
4441 .or. (Restart_control < 0)) permit_incr_restart = .false.
445
4461 if (restint > real_to_time(0.0)) then
447 ! restart_time is the next integral multiple of restint.
448 restart_time = Start_time + restint * &
4490 (1 + ((Time + Time_step_ocean) - Start_time) / restint)
450 else
451 ! Set the time so late that there is no intermediate restart.
4521 restart_time = Time_end + Time_step_ocean
4531 permit_incr_restart = .false.
454 endif
455
4561 call cpu_clock_end(initClock) !end initialization
457
4581 call cpu_clock_begin(mainClock) !begin main loop
459
4601 ns = 1
46113 do while ((ns < nmax) .and. (Time < Time_end))
46212 call callTree_enter("Main loop, MOM_driver.F90",ns)
463
464 ! Set the forcing for the next steps.
46512 if (.not. offline_tracer_mode) then
466 call set_forcing(sfc_state, forces, fluxes, Time, Time_step_ocean, grid, US, &
46712 surface_forcing_CSp)
468 endif
46912 if (debug) then
4700 call MOM_mech_forcing_chksum("After set forcing", forces, grid, US, haloshift=0)
4710 call MOM_forcing_chksum("After set forcing", fluxes, grid, US, haloshift=0)
472 endif
473
47412 if (use_ice_shelf) then
4750 call shelf_calc_flux(sfc_state, fluxes, Time, dt_forcing, ice_shelf_CSp)
4760 call add_shelf_forces(grid, US, Ice_shelf_CSp, forces, external_call=.true.)
477 endif
47812 fluxes%fluxes_used = .false.
47912 fluxes%dt_buoy_accum = dt_forcing
480
48112 if (use_waves) then
4820 call Update_Surface_Waves(grid, GV, US, time, time_step_ocean, waves_csp)
483 endif
484
48512 if (ns==1) then
4861 call finish_MOM_initialization(Time, dirs, MOM_CSp)
487 endif
488
489 ! This call steps the model over a time dt_forcing.
49012 Time1 = Master_Time ; Time = Master_Time
49112 if (offline_tracer_mode) then
4920 call step_offline(forces, fluxes, sfc_state, Time1, dt_forcing, MOM_CSp)
49312 elseif (single_step_call) then
49412 call step_MOM(forces, fluxes, sfc_state, Time1, dt_forcing, MOM_CSp, Waves=Waves_CSP)
495 else
4960 n_max = 1 ; if (dt_forcing > dt) n_max = ceiling(dt_forcing/dt - 0.001)
4970 dt_dyn = dt_forcing / real(n_max)
498
4990 nts = MAX(1,MIN(n_max,floor(dt_therm/dt_dyn + 0.001)))
5000 n_last_thermo = 0
501
5020 Time2 = Time1 ; t_elapsed_seg = 0.0
5030 do n=1,n_max
5040 if (diabatic_first) then
5050 if (modulo(n-1,nts)==0) then
5060 dtdia = dt_dyn*min(ntstep,n_max-(n-1))
507 call step_MOM(forces, fluxes, sfc_state, Time2, dtdia, MOM_CSp, &
508 do_dynamics=.false., do_thermodynamics=.true., &
5090 start_cycle=(n==1), end_cycle=.false., cycle_length=dt_forcing)
510 endif
511
512 call step_MOM(forces, fluxes, sfc_state, Time2, dt_dyn, MOM_CSp, &
513 do_dynamics=.true., do_thermodynamics=.false., &
5140 start_cycle=.false., end_cycle=(n==n_max), cycle_length=dt_forcing)
515 else
516 call step_MOM(forces, fluxes, sfc_state, Time2, dt_dyn, MOM_CSp, &
517 do_dynamics=.true., do_thermodynamics=.false., &
5180 start_cycle=(n==1), end_cycle=.false., cycle_length=dt_forcing)
519
5200 if ((modulo(n,nts)==0) .or. (n==n_max)) then
5210 dtdia = dt_dyn*(n - n_last_thermo)
522 ! Back up Time2 to the start of the thermodynamic segment.
5230 if (n > n_last_thermo+1) &
5240 Time2 = Time2 - real_to_time((dtdia - dt_dyn), unscale=US%T_to_s)
525 call step_MOM(forces, fluxes, sfc_state, Time2, dtdia, MOM_CSp, &
526 do_dynamics=.false., do_thermodynamics=.true., &
5270 start_cycle=.false., end_cycle=(n==n_max), cycle_length=dt_forcing)
5280 n_last_thermo = n
529 endif
530 endif
531
5320 t_elapsed_seg = t_elapsed_seg + dt_dyn
5330 Time2 = Time1 + real_to_time(t_elapsed_seg, unscale=US%T_to_s)
534 enddo
535 endif
536
537! Time = Time + Time_step_ocean
538! This is here to enable fractional-second time steps.
53912 elapsed_time = elapsed_time + dt_forcing
54012 if (elapsed_time > 2.0e9*US%s_to_T) then
541 ! This is here to ensure that the conversion from a real to an integer can be accurately
542 ! represented in long runs (longer than ~63 years). It will also ensure that elapsed time
543 ! does not lose resolution of order the timetype's resolution, provided that the timestep and
544 ! tick are larger than 10-5 seconds. If a clock with a finer resolution is used, a smaller
545 ! value would be required.
5460 time_chg = real_to_time(elapsed_time, unscale=US%T_to_s)
5470 segment_start_time = segment_start_time + time_chg
5480 elapsed_time = elapsed_time - time_to_real(time_chg, scale=US%s_to_T)
549 endif
55012 if (elapsed_time_master) then
5510 Master_Time = segment_start_time + real_to_time(elapsed_time, unscale=US%T_to_s)
552 else
55312 Master_Time = Master_Time + Time_step_ocean
554 endif
55512 Time = Master_Time
556
55712 if (cpu_steps > 0) then ; if (MOD(ns, cpu_steps) == 0) then
5580 call write_cputime(Time, ns+ntstep-1, write_CPU_CSp, nmax)
559 endif ; endif
560
56112 call mech_forcing_diags(forces, dt_forcing, grid, Time, diag, surface_forcing_CSp%handles)
562
56312 if (.not. offline_tracer_mode) then
56412 if (fluxes%fluxes_used) then
565 call forcing_diagnostics(fluxes, sfc_state, grid, US, Time, &
56612 diag, surface_forcing_CSp%handles)
567 else
568 call MOM_error(FATAL, "The solo MOM_driver is not yet set up to handle "//&
5690 "thermodynamic time steps that are longer than the coupling timestep.")
570 endif
571 endif
572
573! See if it is time to write out a restart file - timestamped or not.
57412 if ((permit_incr_restart) .and. (fluxes%fluxes_used) .and. &
575 (Time + (Time_step_ocean/2) > restart_time)) then
5760 if (BTEST(Restart_control,1)) then
577 call save_MOM_restart(MOM_CSp, dirs%restart_output_dir, Time, grid, &
5780 time_stamped=.true., GV=GV)
579 call forcing_save_restart(surface_forcing_CSp, grid, Time, &
5800 dirs%restart_output_dir, .true.)
5810 if (use_ice_shelf) call ice_shelf_save_restart(ice_shelf_CSp, Time, &
5820 dirs%restart_output_dir, .true.)
583 endif
5840 if (BTEST(Restart_control,0)) then
5850 call save_MOM_restart(MOM_CSp, dirs%restart_output_dir, Time, grid, GV=GV)
586 call forcing_save_restart(surface_forcing_CSp, grid, Time, &
5870 dirs%restart_output_dir)
5880 if (use_ice_shelf) call ice_shelf_save_restart(ice_shelf_CSp, Time, &
5890 dirs%restart_output_dir)
590 endif
5910 restart_time = restart_time + restint
592 endif
593
59412 ns = ns + ntstep
59512 call callTree_leave("Main loop")
596 enddo
597
5981 call cpu_clock_end(mainClock)
5991 call cpu_clock_begin(termClock)
6001 if (Restart_control>=0) then
6011 if (.not.MOM_state_is_synchronized(MOM_CSp)) &
602 call MOM_error(WARNING, "End of MOM_main reached with inconsistent "//&
603 "dynamics and advective times. Additional restart fields "//&
6040 "that have not been coded yet would be required for reproducibility.")
6051 if (.not.fluxes%fluxes_used .and. .not.offline_tracer_mode) call MOM_error(FATAL, &
606 "End of MOM_main reached with unused buoyancy fluxes. "//&
607 "For conservation, the ocean restart files can only be "//&
6080 "created after the buoyancy forcing is applied.")
609
6101 call save_MOM_restart(MOM_CSp, dirs%restart_output_dir, Time, grid, GV=GV)
6111 if (use_ice_shelf) call ice_shelf_save_restart(ice_shelf_CSp, Time, &
6120 dirs%restart_output_dir)
613
614 ! Write the ocean solo restart file.
615 call write_ocean_solo_res(Time, Start_time, calendar_type, &
6161 trim(dirs%restart_output_dir)//'ocean_solo.res')
617 endif
618
6191 if (is_root_pe()) then
6201 call open_ASCII_file(unit, "exitcode")
6211 if (Time < daymax) then
6220 write(unit,*) 9
623 else
6241 write(unit,*) 0
625 endif
6261 call close_file(unit)
627 endif
628
6291 call callTree_waypoint("End MOM_main")
6301 if (use_ice_shelf) call ice_shelf_end(ice_shelf_CSp)
6311 call diag_mediator_end(Time, diag, end_diag_manager=.true.)
6321 if (cpu_steps > 0) call write_cputime(Time, ns-1, write_CPU_CSp, call_end=.true.)
6331 call cpu_clock_end(termClock)
634
6351 call MOM_end(MOM_CSp)
636 !$omp target exit data map(delete: MOM_CSp)
637
638 ! This closes out the infrastructure, including clocks, I/O and message passing communicators.
6391 call io_infra_end() ; call MOM_infra_end()
640
641contains
642
643!> Write out the ocean solo restart file to the indicated path.
6443subroutine write_ocean_solo_res(Time, Start_time, calendar, file_path)
645 type(time_type), intent(in) :: Time !< The current model time.
646 type(time_type), intent(in) :: Start_Time !< The start time of the simulation.
647 integer, intent(in) :: calendar !< A coded integer indicating the calendar type.
648 character(len=*), intent(in) :: file_path !< The full path and name of the restart file
649
650 ! Local variables
651 integer :: unit
652 integer :: yr, mon, day, hr, mins, sec ! Temp variables for writing the date.
653
6541 if (.not.is_root_pe()) return
655
6561 call open_ASCII_file(unit, trim(file_path))
6571 write(unit, '(i6,8x,a)') calendar, &
6582 '(Calendar: no_calendar=0, thirty_day_months=1, julian=2, gregorian=3, noleap=4)'
659
6601 call get_date(Start_time, yr, mon, day, hr, mins, sec)
6611 write(unit, '(6i6,8x,a)') yr, mon, day, hr, mins, sec, &
6622 'Model start time: year, month, day, hour, minute, second'
6631 call get_date(Time, yr, mon, day, hr, mins, sec)
6641 write(unit, '(6i6,8x,a)') yr, mon, day, hr, mins, sec, &
6652 'Current model time: year, month, day, hour, minute, second'
6661 call close_file(unit)
6671end subroutine write_ocean_solo_res
668
669
670!> Write out an ascii time stamp file with the model time, following FMS conventions.
6713subroutine write_time_stamp_file(Time)
672 type(time_type), intent(in) :: Time !< The current model time.
673 ! Local variables
674 integer :: unit
675 integer :: yr, mon, day, hr, mins, sec ! Temp variables for writing the date.
676 character(len=9) :: month ! The name of the month
677
6781 if (.not.is_root_PE()) return
679
6801 call open_ASCII_file(unit, 'time_stamp.out', action=APPEND_FILE)
6811 call get_date(Time, yr, mon, day, hr, mins, sec)
6821 month = month_name(mon)
6831 write(unit,'(6i4,2x,a3)') yr, mon, day, hr, mins, sec, month(1:3)
6841 call get_date(Time_end, yr, mon, day, hr, mins, sec)
6851 month = month_name(mon)
6861 write(unit,'(6i4,2x,a3)') yr, mon, day, hr, mins, sec, month(1:3)
6871 call close_file(unit)
688end subroutine write_time_stamp_file
689
690!> Initialize the ensemble manager. If there are no settings for ensemble_size
691!! in input.nml(ensemble.nml), these should not do anything. In coupled
692!! configurations, this all occurs in the external driver.
6931subroutine initialize_ocean_only_ensembles()
6941 integer, dimension(:), allocatable :: ocean_PElist
695 integer, dimension(0) :: atm_PElist, land_PElist, ice_PElist
696 integer :: ensemble_size, nPEs_per, ensemble_info(6)
697
6981 call ensemble_manager_init() ; ensemble_info(:) = get_ensemble_size()
6991 ensemble_size = ensemble_info(1) ; nPEs_per = ensemble_info(2)
7001 if (ensemble_size > 1) then ! There are multiple ensemble members.
7010 allocate(ocean_pelist(nPEs_per))
702 call ensemble_pelist_setup(.true., 0, nPEs_per, 0, 0, atm_pelist, ocean_pelist, &
7030 land_pelist, ice_pelist)
7040 call Set_PElist(ocean_pelist)
7050 deallocate(ocean_pelist)
706 endif
7071end subroutine initialize_ocean_only_ensembles
708
709end program MOM6