MOM6
MOM_restart.F90
1 !> The MOM6 facility for reading and writing restart files, and querying what has been read.
2 module mom_restart
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use mom_domains, only : pe_here, num_pes
7 use mom_error_handler, only : mom_error, fatal, warning, note, is_root_pe
9 use mom_string_functions, only : lowercase
10 use mom_grid, only : ocean_grid_type
11 use mom_io, only : create_file, fieldtype, file_exists, open_file, close_file
12 use mom_io, only : write_field, mom_read_data, read_data, get_filename_appendix
13 use mom_io, only : get_file_info, get_file_atts, get_file_fields, get_file_times
14 use mom_io, only : vardesc, var_desc, query_vardesc, modify_vardesc
15 use mom_io, only : multiple, netcdf_file, readonly_file, single_file
16 use mom_io, only : center, corner, north_face, east_face
17 use mom_time_manager, only : time_type, time_type_to_real, real_to_time
18 use mom_time_manager, only : days_in_month, get_date, set_date
20 use mpp_mod, only: mpp_chksum,mpp_pe
21 use mpp_io_mod, only: mpp_attribute_exist, mpp_get_atts
22 
23 implicit none ; private
24 
25 public restart_init, restart_end, restore_state, register_restart_field
26 public save_restart, query_initialized, restart_init_end, vardesc
27 public restart_files_exist, determine_is_new_run, is_new_run
28 public register_restart_field_as_obsolete
29 
30 !> A type for making arrays of pointers to 4-d arrays
31 type p4d
32  real, dimension(:,:,:,:), pointer :: p => null() !< A pointer to a 4d array
33 end type p4d
34 
35 !> A type for making arrays of pointers to 3-d arrays
36 type p3d
37  real, dimension(:,:,:), pointer :: p => null() !< A pointer to a 3d array
38 end type p3d
39 
40 !> A type for making arrays of pointers to 2-d arrays
41 type p2d
42  real, dimension(:,:), pointer :: p => null() !< A pointer to a 2d array
43 end type p2d
44 
45 !> A type for making arrays of pointers to 1-d arrays
46 type p1d
47  real, dimension(:), pointer :: p => null() !< A pointer to a 1d array
48 end type p1d
49 
50 !> A type for making arrays of pointers to scalars
51 type p0d
52  real, pointer :: p => null() !< A pointer to a scalar
53 end type p0d
54 
55 !> A structure with information about a single restart field
57  type(vardesc) :: vars !< Description of a field that is to be read from or written
58  !! to the restart file.
59  logical :: mand_var !< If .true. the run will abort if this field is not successfully
60  !! read from the restart file.
61  logical :: initialized !< .true. if this field has been read from the restart file.
62  character(len=32) :: var_name !< A name by which a variable may be queried.
63 end type field_restart
64 
65 !> A structure to store information about restart fields that are no longer used
67  character(len=32) :: field_name !< Name of restart field that is no longer in use
68  character(len=32) :: replacement_name !< Name of replacement restart field, if applicable
69 end type obsolete_restart
70 
71 !> A restart registry and the control structure for restarts
72 type, public :: mom_restart_cs ; private
73  logical :: restart !< restart is set to .true. if the run has been started from a full restart
74  !! file. Otherwise some fields must be initialized approximately.
75  integer :: novars = 0 !< The number of restart fields that have been registered.
76  integer :: num_obsolete_vars = 0 !< The number of obsolete restart fields that have been registered.
77  logical :: parallel_restartfiles !< If true, each PE writes its own restart file,
78  !! otherwise they are combined internally.
79  logical :: large_file_support !< If true, NetCDF 3.6 or later is being used
80  !! and large-file-support is enabled.
81  logical :: new_run !< If true, the input filenames and restart file existence will
82  !! result in a new run that is not initialized from restart files.
83  logical :: new_run_set = .false. !< If true, new_run has been determined for this restart_CS.
84  logical :: checksum_required !< If true, require the restart checksums to match and error out otherwise.
85  !! Users may want to avoid this comparison if for example the restarts are
86  !! made from a run with a different mask_table than the current run,
87  !! in which case the checksums will not match and cause crash.
88  character(len=240) :: restartfile !< The name or name root for MOM restart files.
89 
90  !> An array of descriptions of the registered fields
91  type(field_restart), pointer :: restart_field(:) => null()
92 
93  !> An array of obsolete restart fields
94  type(obsolete_restart), pointer :: restart_obsolete(:) => null()
95 
96  !>@{ Pointers to the fields that have been registered for restarts
97  type(p0d), pointer :: var_ptr0d(:) => null()
98  type(p1d), pointer :: var_ptr1d(:) => null()
99  type(p2d), pointer :: var_ptr2d(:) => null()
100  type(p3d), pointer :: var_ptr3d(:) => null()
101  type(p4d), pointer :: var_ptr4d(:) => null()
102  !!@}
103  integer :: max_fields !< The maximum number of restart fields
104 end type mom_restart_cs
105 
106 !> Register fields for restarts
108  module procedure register_restart_field_ptr4d, register_restart_field_4d
109  module procedure register_restart_field_ptr3d, register_restart_field_3d
110  module procedure register_restart_field_ptr2d, register_restart_field_2d
111  module procedure register_restart_field_ptr1d, register_restart_field_1d
112  module procedure register_restart_field_ptr0d, register_restart_field_0d
113 end interface
114 
115 !> Indicate whether a field has been read from a restart file
117  module procedure query_initialized_name
118  module procedure query_initialized_0d, query_initialized_0d_name
119  module procedure query_initialized_1d, query_initialized_1d_name
120  module procedure query_initialized_2d, query_initialized_2d_name
121  module procedure query_initialized_3d, query_initialized_3d_name
122  module procedure query_initialized_4d, query_initialized_4d_name
123 end interface
124 
125 contains
126 !!> Register a restart field as obsolete
127 subroutine register_restart_field_as_obsolete(field_name, replacement_name, CS)
128  character(*), intent(in) :: field_name !< Name of restart field that is no longer in use
129  character(*), intent(in) :: replacement_name !< Name of replacement restart field, if applicable
130  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in/out)
131 
132  cs%num_obsolete_vars = cs%num_obsolete_vars+1
133  cs%restart_obsolete(cs%num_obsolete_vars)%field_name = field_name
134  cs%restart_obsolete(cs%num_obsolete_vars)%replacement_name = replacement_name
135 end subroutine register_restart_field_as_obsolete
136 
137 !> Register a 3-d field for restarts, providing the metadata in a structure
138 subroutine register_restart_field_ptr3d(f_ptr, var_desc, mandatory, CS)
139  real, dimension(:,:,:), &
140  target, intent(in) :: f_ptr !< A pointer to the field to be read or written
141  type(vardesc), intent(in) :: var_desc !< A structure with metadata about this variable
142  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
143  !! successfully read from the restart file.
144  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
145 
146  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
147  "register_restart_field: Module must be initialized before it is used.")
148 
149  cs%novars = cs%novars+1
150  if (cs%novars > cs%max_fields) return ! This is an error that will be reported
151  ! once the total number of fields is known.
152 
153  cs%restart_field(cs%novars)%vars = var_desc
154  cs%restart_field(cs%novars)%mand_var = mandatory
155  cs%restart_field(cs%novars)%initialized = .false.
156  call query_vardesc(cs%restart_field(cs%novars)%vars, &
157  name=cs%restart_field(cs%novars)%var_name, &
158  caller="register_restart_field_ptr3d")
159 
160  cs%var_ptr3d(cs%novars)%p => f_ptr
161  cs%var_ptr4d(cs%novars)%p => null()
162  cs%var_ptr2d(cs%novars)%p => null()
163  cs%var_ptr1d(cs%novars)%p => null()
164  cs%var_ptr0d(cs%novars)%p => null()
165 
166 end subroutine register_restart_field_ptr3d
167 
168 !> Register a 4-d field for restarts, providing the metadata in a structure
169 subroutine register_restart_field_ptr4d(f_ptr, var_desc, mandatory, CS)
170  real, dimension(:,:,:,:), &
171  target, intent(in) :: f_ptr !< A pointer to the field to be read or written
172  type(vardesc), intent(in) :: var_desc !< A structure with metadata about this variable
173  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
174  !! successfully read from the restart file.
175  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
176 
177  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
178  "register_restart_field: Module must be initialized before it is used.")
179 
180  cs%novars = cs%novars+1
181  if (cs%novars > cs%max_fields) return ! This is an error that will be reported
182  ! once the total number of fields is known.
183 
184  cs%restart_field(cs%novars)%vars = var_desc
185  cs%restart_field(cs%novars)%mand_var = mandatory
186  cs%restart_field(cs%novars)%initialized = .false.
187  call query_vardesc(cs%restart_field(cs%novars)%vars, &
188  name=cs%restart_field(cs%novars)%var_name, &
189  caller="register_restart_field_ptr4d")
190 
191  cs%var_ptr4d(cs%novars)%p => f_ptr
192  cs%var_ptr3d(cs%novars)%p => null()
193  cs%var_ptr2d(cs%novars)%p => null()
194  cs%var_ptr1d(cs%novars)%p => null()
195  cs%var_ptr0d(cs%novars)%p => null()
196 
197 end subroutine register_restart_field_ptr4d
198 
199 !> Register a 2-d field for restarts, providing the metadata in a structure
200 subroutine register_restart_field_ptr2d(f_ptr, var_desc, mandatory, CS)
201  real, dimension(:,:), &
202  target, intent(in) :: f_ptr !< A pointer to the field to be read or written
203  type(vardesc), intent(in) :: var_desc !< A structure with metadata about this variable
204  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
205  !! successfully read from the restart file.
206  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
207 
208  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
209  "register_restart_field: Module must be initialized before it is used.")
210 
211  cs%novars = cs%novars+1
212  if (cs%novars > cs%max_fields) return ! This is an error that will be reported
213  ! once the total number of fields is known.
214 
215  cs%restart_field(cs%novars)%vars = var_desc
216  cs%restart_field(cs%novars)%mand_var = mandatory
217  cs%restart_field(cs%novars)%initialized = .false.
218  call query_vardesc(cs%restart_field(cs%novars)%vars, &
219  name=cs%restart_field(cs%novars)%var_name, &
220  caller="register_restart_field_ptr2d")
221 
222  cs%var_ptr2d(cs%novars)%p => f_ptr
223  cs%var_ptr4d(cs%novars)%p => null()
224  cs%var_ptr3d(cs%novars)%p => null()
225  cs%var_ptr1d(cs%novars)%p => null()
226  cs%var_ptr0d(cs%novars)%p => null()
227 
228 end subroutine register_restart_field_ptr2d
229 
230 !> Register a 1-d field for restarts, providing the metadata in a structure
231 subroutine register_restart_field_ptr1d(f_ptr, var_desc, mandatory, CS)
232  real, dimension(:), target, intent(in) :: f_ptr !< A pointer to the field to be read or written
233  type(vardesc), intent(in) :: var_desc !< A structure with metadata about this variable
234  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
235  !! successfully read from the restart file.
236  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
237 
238  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
239  "register_restart_field: Module must be initialized before it is used.")
240 
241  cs%novars = cs%novars+1
242  if (cs%novars > cs%max_fields) return ! This is an error that will be reported
243  ! once the total number of fields is known.
244 
245  cs%restart_field(cs%novars)%vars = var_desc
246  cs%restart_field(cs%novars)%mand_var = mandatory
247  cs%restart_field(cs%novars)%initialized = .false.
248  call query_vardesc(cs%restart_field(cs%novars)%vars, &
249  name=cs%restart_field(cs%novars)%var_name, &
250  caller="register_restart_field_ptr1d")
251 
252  cs%var_ptr1d(cs%novars)%p => f_ptr
253  cs%var_ptr4d(cs%novars)%p => null()
254  cs%var_ptr3d(cs%novars)%p => null()
255  cs%var_ptr2d(cs%novars)%p => null()
256  cs%var_ptr0d(cs%novars)%p => null()
257 
258 end subroutine register_restart_field_ptr1d
259 
260 !> Register a 0-d field for restarts, providing the metadata in a structure
261 subroutine register_restart_field_ptr0d(f_ptr, var_desc, mandatory, CS)
262  real, target, intent(in) :: f_ptr !< A pointer to the field to be read or written
263  type(vardesc), intent(in) :: var_desc !< A structure with metadata about this variable
264  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
265  !! successfully read from the restart file.
266  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
267 
268  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
269  "register_restart_field: Module must be initialized before it is used.")
270 
271  cs%novars = cs%novars+1
272  if (cs%novars > cs%max_fields) return ! This is an error that will be reported
273  ! once the total number of fields is known.
274 
275  cs%restart_field(cs%novars)%vars = var_desc
276  cs%restart_field(cs%novars)%mand_var = mandatory
277  cs%restart_field(cs%novars)%initialized = .false.
278  call query_vardesc(cs%restart_field(cs%novars)%vars, &
279  name=cs%restart_field(cs%novars)%var_name, &
280  caller="register_restart_field_ptr0d")
281 
282  cs%var_ptr0d(cs%novars)%p => f_ptr
283  cs%var_ptr4d(cs%novars)%p => null()
284  cs%var_ptr3d(cs%novars)%p => null()
285  cs%var_ptr2d(cs%novars)%p => null()
286  cs%var_ptr1d(cs%novars)%p => null()
287 
288 end subroutine register_restart_field_ptr0d
289 
290 ! The following provide alternate interfaces to register restarts.
291 
292 !> Register a 4-d field for restarts, providing the metadata as individual arguments
293 subroutine register_restart_field_4d(f_ptr, name, mandatory, CS, longname, units, &
294  hor_grid, z_grid, t_grid)
295  real, dimension(:,:,:,:), &
296  target, intent(in) :: f_ptr !< A pointer to the field to be read or written
297  character(len=*), intent(in) :: name !< variable name to be used in the restart file
298  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
299  !! successfully read from the restart file.
300  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
301  character(len=*), optional, intent(in) :: longname !< variable long name
302  character(len=*), optional, intent(in) :: units !< variable units
303  character(len=*), optional, intent(in) :: hor_grid !< variable horizonal staggering, 'h' if absent
304  character(len=*), optional, intent(in) :: z_grid !< variable vertical staggering, 'L' if absent
305  character(len=*), optional, intent(in) :: t_grid !< time description: s, p, or 1, 's' if absent
306 
307  type(vardesc) :: vd
308 
309  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart: " // &
310  "register_restart_field_4d: Module must be initialized before "//&
311  "it is used to register "//trim(name))
312  vd = var_desc(name, units=units, longname=longname, hor_grid=hor_grid, &
313  z_grid=z_grid, t_grid=t_grid)
314 
315  call register_restart_field_ptr4d(f_ptr, vd, mandatory, cs)
316 
317 end subroutine register_restart_field_4d
318 
319 !> Register a 3-d field for restarts, providing the metadata as individual arguments
320 subroutine register_restart_field_3d(f_ptr, name, mandatory, CS, longname, units, &
321  hor_grid, z_grid, t_grid)
322  real, dimension(:,:,:), &
323  target, intent(in) :: f_ptr !< A pointer to the field to be read or written
324  character(len=*), intent(in) :: name !< variable name to be used in the restart file
325  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
326  !! successfully read from the restart file.
327  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
328  character(len=*), optional, intent(in) :: longname !< variable long name
329  character(len=*), optional, intent(in) :: units !< variable units
330  character(len=*), optional, intent(in) :: hor_grid !< variable horizonal staggering, 'h' if absent
331  character(len=*), optional, intent(in) :: z_grid !< variable vertical staggering, 'L' if absent
332  character(len=*), optional, intent(in) :: t_grid !< time description: s, p, or 1, 's' if absent
333 
334  type(vardesc) :: vd
335 
336  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart: " // &
337  "register_restart_field_3d: Module must be initialized before "//&
338  "it is used to register "//trim(name))
339  vd = var_desc(name, units=units, longname=longname, hor_grid=hor_grid, &
340  z_grid=z_grid, t_grid=t_grid)
341 
342  call register_restart_field_ptr3d(f_ptr, vd, mandatory, cs)
343 
344 end subroutine register_restart_field_3d
345 
346 !> Register a 2-d field for restarts, providing the metadata as individual arguments
347 subroutine register_restart_field_2d(f_ptr, name, mandatory, CS, longname, units, &
348  hor_grid, z_grid, t_grid)
349  real, dimension(:,:), &
350  target, intent(in) :: f_ptr !< A pointer to the field to be read or written
351  character(len=*), intent(in) :: name !< variable name to be used in the restart file
352  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
353  !! successfully read from the restart file.
354  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
355  character(len=*), optional, intent(in) :: longname !< variable long name
356  character(len=*), optional, intent(in) :: units !< variable units
357  character(len=*), optional, intent(in) :: hor_grid !< variable horizonal staggering, 'h' if absent
358  character(len=*), optional, intent(in) :: z_grid !< variable vertical staggering, '1' if absent
359  character(len=*), optional, intent(in) :: t_grid !< time description: s, p, or 1, 's' if absent
360 
361  type(vardesc) :: vd
362  character(len=8) :: Zgrid
363 
364  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart: " // &
365  "register_restart_field_2d: Module must be initialized before "//&
366  "it is used to register "//trim(name))
367  zgrid = '1' ; if (present(z_grid)) zgrid = z_grid
368  vd = var_desc(name, units=units, longname=longname, hor_grid=hor_grid, &
369  z_grid=zgrid, t_grid=t_grid)
370 
371  call register_restart_field_ptr2d(f_ptr, vd, mandatory, cs)
372 
373 end subroutine register_restart_field_2d
374 
375 !> Register a 1-d field for restarts, providing the metadata as individual arguments
376 subroutine register_restart_field_1d(f_ptr, name, mandatory, CS, longname, units, &
377  hor_grid, z_grid, t_grid)
378  real, dimension(:), target, intent(in) :: f_ptr !< A pointer to the field to be read or written
379  character(len=*), intent(in) :: name !< variable name to be used in the restart file
380  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
381  !! successfully read from the restart file.
382  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
383  character(len=*), optional, intent(in) :: longname !< variable long name
384  character(len=*), optional, intent(in) :: units !< variable units
385  character(len=*), optional, intent(in) :: hor_grid !< variable horizonal staggering, '1' if absent
386  character(len=*), optional, intent(in) :: z_grid !< variable vertical staggering, 'L' if absent
387  character(len=*), optional, intent(in) :: t_grid !< time description: s, p, or 1, 's' if absent
388 
389  type(vardesc) :: vd
390  character(len=8) :: hgrid
391 
392  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart: " // &
393  "register_restart_field_3d: Module must be initialized before "//&
394  "it is used to register "//trim(name))
395  hgrid = '1' ; if (present(hor_grid)) hgrid = hor_grid
396  vd = var_desc(name, units=units, longname=longname, hor_grid=hgrid, &
397  z_grid=z_grid, t_grid=t_grid)
398 
399  call register_restart_field_ptr1d(f_ptr, vd, mandatory, cs)
400 
401 end subroutine register_restart_field_1d
402 
403 !> Register a 0-d field for restarts, providing the metadata as individual arguments
404 subroutine register_restart_field_0d(f_ptr, name, mandatory, CS, longname, units, &
405  t_grid)
406  real, target, intent(in) :: f_ptr !< A pointer to the field to be read or written
407  character(len=*), intent(in) :: name !< variable name to be used in the restart file
408  logical, intent(in) :: mandatory !< If true, the run will abort if this field is not
409  !! successfully read from the restart file.
410  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object (intent in/out)
411  character(len=*), optional, intent(in) :: longname !< variable long name
412  character(len=*), optional, intent(in) :: units !< variable units
413  character(len=*), optional, intent(in) :: t_grid !< time description: s, p, or 1, 's' if absent
414 
415  type(vardesc) :: vd
416  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart: " // &
417  "register_restart_field_0d: Module must be initialized before "//&
418  "it is used to register "//trim(name))
419  vd = var_desc(name, units=units, longname=longname, hor_grid='1', &
420  z_grid='1', t_grid=t_grid)
421 
422  call register_restart_field_ptr0d(f_ptr, vd, mandatory, cs)
423 
424 end subroutine register_restart_field_0d
425 
426 
427 !> query_initialized_name determines whether a named field has been successfully
428 !! read from a restart file yet.
429 function query_initialized_name(name, CS) result(query_initialized)
430  character(len=*), intent(in) :: name !< The name of the field that is being queried
431  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
432  logical :: query_initialized
433 ! This subroutine returns .true. if the field referred to by name has
434 ! initialized from a restart file, and .false. otherwise.
435 
436  integer :: m,n
437  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
438  "query_initialized: Module must be initialized before it is used.")
439  if (cs%novars > cs%max_fields) call restart_error(cs)
440 
441  query_initialized = .false.
442  n = cs%novars+1
443  do m=1,cs%novars
444  if (trim(name) == cs%restart_field(m)%var_name) then
445  if (cs%restart_field(m)%initialized) query_initialized = .true.
446  n = m ; exit
447  endif
448  enddo
449 ! Assume that you are going to initialize it now, so set flag to initialized if
450 ! queried again.
451  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
452  if ((n==cs%novars+1) .and. (is_root_pe())) &
453  call mom_error(note,"MOM_restart: Unknown restart variable "//name// &
454  " queried for initialization.")
455 
456  if ((is_root_pe()) .and. query_initialized) &
457  call mom_error(note,"MOM_restart: "//name// &
458  " initialization confirmed by name.")
459 
460 end function query_initialized_name
461 
462 !> Indicate whether the field pointed to by f_ptr has been initialized from a restart file.
463 function query_initialized_0d(f_ptr, CS) result(query_initialized)
464  real, target, intent(in) :: f_ptr !< A pointer to the field that is being queried
465  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
466  logical :: query_initialized
467 ! This subroutine tests whether the field pointed to by f_ptr has
468 ! been initialized from a restart file.
469 
470  integer :: m,n
471  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
472  "query_initialized: Module must be initialized before it is used.")
473  if (cs%novars > cs%max_fields) call restart_error(cs)
474 
475  query_initialized = .false.
476  n = cs%novars+1
477  do m=1,cs%novars
478  if (associated(cs%var_ptr0d(m)%p,f_ptr)) then
479  if (cs%restart_field(m)%initialized) query_initialized = .true.
480  n = m ; exit
481  endif
482  enddo
483 ! Assume that you are going to initialize it now, so set flag to initialized if
484 ! queried again.
485  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
486 
487 end function query_initialized_0d
488 
489 !> Indicate whether the field pointed to by f_ptr has been initialized from a restart file.
490 function query_initialized_1d(f_ptr, CS) result(query_initialized)
491  real, dimension(:), target, intent(in) :: f_ptr !< A pointer to the field that is being queried
492  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
493  logical :: query_initialized
494 ! This subroutine tests whether the field pointed to by f_ptr has
495 ! been initialized from a restart file.
496 
497  integer :: m,n
498  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
499  "query_initialized: Module must be initialized before it is used.")
500  if (cs%novars > cs%max_fields) call restart_error(cs)
501 
502  query_initialized = .false.
503  n = cs%novars+1
504  do m=1,cs%novars
505  if (associated(cs%var_ptr1d(m)%p,f_ptr)) then
506  if (cs%restart_field(m)%initialized) query_initialized = .true.
507  n = m ; exit
508  endif
509  enddo
510 ! Assume that you are going to initialize it now, so set flag to initialized if
511 ! queried again.
512  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
513 
514 end function query_initialized_1d
515 
516 !> Indicate whether the field pointed to by f_ptr has been initialized from a restart file.
517 function query_initialized_2d(f_ptr, CS) result(query_initialized)
518  real, dimension(:,:), &
519  target, intent(in) :: f_ptr !< A pointer to the field that is being queried
520  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
521  logical :: query_initialized
522 ! This subroutine tests whether the field pointed to by f_ptr has
523 ! been initialized from a restart file.
524 
525  integer :: m,n
526  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
527  "query_initialized: Module must be initialized before it is used.")
528  if (cs%novars > cs%max_fields) call restart_error(cs)
529 
530  query_initialized = .false.
531  n = cs%novars+1
532  do m=1,cs%novars
533  if (associated(cs%var_ptr2d(m)%p,f_ptr)) then
534  if (cs%restart_field(m)%initialized) query_initialized = .true.
535  n = m ; exit
536  endif
537  enddo
538 ! Assume that you are going to initialize it now, so set flag to initialized if
539 ! queried again.
540  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
541 
542 end function query_initialized_2d
543 
544 !> Indicate whether the field pointed to by f_ptr has been initialized from a restart file.
545 function query_initialized_3d(f_ptr, CS) result(query_initialized)
546  real, dimension(:,:,:), &
547  target, intent(in) :: f_ptr !< A pointer to the field that is being queried
548  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
549  logical :: query_initialized
550 ! This subroutine tests whether the field pointed to by f_ptr has
551 ! been initialized from a restart file.
552 
553  integer :: m,n
554  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
555  "query_initialized: Module must be initialized before it is used.")
556  if (cs%novars > cs%max_fields) call restart_error(cs)
557 
558  query_initialized = .false.
559  n = cs%novars+1
560  do m=1,cs%novars
561  if (associated(cs%var_ptr3d(m)%p,f_ptr)) then
562  if (cs%restart_field(m)%initialized) query_initialized = .true.
563  n = m ; exit
564  endif
565  enddo
566 ! Assume that you are going to initialize it now, so set flag to initialized if
567 ! queried again.
568  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
569 
570 end function query_initialized_3d
571 
572 !> Indicate whether the field pointed to by f_ptr has been initialized from a restart file.
573 function query_initialized_4d(f_ptr, CS) result(query_initialized)
574  real, dimension(:,:,:,:), &
575  target, intent(in) :: f_ptr !< A pointer to the field that is being queried
576  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
577  logical :: query_initialized
578 ! This subroutine tests whether the field pointed to by f_ptr has
579 ! been initialized from a restart file.
580 
581  integer :: m,n
582  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
583  "query_initialized: Module must be initialized before it is used.")
584  if (cs%novars > cs%max_fields) call restart_error(cs)
585 
586  query_initialized = .false.
587  n = cs%novars+1
588  do m=1,cs%novars
589  if (associated(cs%var_ptr4d(m)%p,f_ptr)) then
590  if (cs%restart_field(m)%initialized) query_initialized = .true.
591  n = m ; exit
592  endif
593  enddo
594 ! Assume that you are going to initialize it now, so set flag to initialized if
595 ! queried again.
596  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
597 
598 end function query_initialized_4d
599 
600 !> Indicate whether the field pointed to by f_ptr or with the specified variable
601 !! name has been initialized from a restart file.
602 function query_initialized_0d_name(f_ptr, name, CS) result(query_initialized)
603  real, target, intent(in) :: f_ptr !< A pointer to the field that is being queried
604  character(len=*), intent(in) :: name !< The name of the field that is being queried
605  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
606  logical :: query_initialized
607 ! This subroutine tests whether the field pointed to by f_ptr or with the
608 ! specified variable name has been initialized from a restart file.
609 
610  integer :: m,n
611  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
612  "query_initialized: Module must be initialized before it is used.")
613  if (cs%novars > cs%max_fields) call restart_error(cs)
614 
615  query_initialized = .false.
616  n = cs%novars+1
617  do m=1,cs%novars
618  if (associated(cs%var_ptr0d(m)%p,f_ptr)) then
619  if (cs%restart_field(m)%initialized) query_initialized = .true.
620  n = m ; exit
621  endif
622  enddo
623 ! Assume that you are going to initialize it now, so set flag to initialized if
624 ! queried again.
625  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
626  if (n==cs%novars+1) then
627  if (is_root_pe()) &
628  call mom_error(note,"MOM_restart: Unable to find "//name//" queried by pointer, "//&
629  "probably because of the suspect comparison of pointers by ASSOCIATED.")
630  query_initialized = query_initialized_name(name, cs)
631  endif
632 
633 end function query_initialized_0d_name
634 
635 !> Indicate whether the field pointed to by f_ptr or with the specified variable
636 !! name has been initialized from a restart file.
637 function query_initialized_1d_name(f_ptr, name, CS) result(query_initialized)
638  real, dimension(:), &
639  target, intent(in) :: f_ptr !< A pointer to the field that is being queried
640  character(len=*), intent(in) :: name !< The name of the field that is being queried
641  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
642  logical :: query_initialized
643 ! This subroutine tests whether the field pointed to by f_ptr or with the
644 ! specified variable name has been initialized from a restart file.
645 
646  integer :: m,n
647  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
648  "query_initialized: Module must be initialized before it is used.")
649  if (cs%novars > cs%max_fields) call restart_error(cs)
650 
651  query_initialized = .false.
652  n = cs%novars+1
653  do m=1,cs%novars
654  if (associated(cs%var_ptr1d(m)%p,f_ptr)) then
655  if (cs%restart_field(m)%initialized) query_initialized = .true.
656  n = m ; exit
657  endif
658  enddo
659 ! Assume that you are going to initialize it now, so set flag to initialized if
660 ! queried again.
661  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
662  if (n==cs%novars+1) then
663  if (is_root_pe()) &
664  call mom_error(note,"MOM_restart: Unable to find "//name//" queried by pointer, "//&
665  "probably because of the suspect comparison of pointers by ASSOCIATED.")
666  query_initialized = query_initialized_name(name, cs)
667  endif
668 
669 end function query_initialized_1d_name
670 
671 !> Indicate whether the field pointed to by f_ptr or with the specified variable
672 !! name has been initialized from a restart file.
673 function query_initialized_2d_name(f_ptr, name, CS) result(query_initialized)
674  real, dimension(:,:), &
675  target, intent(in) :: f_ptr !< A pointer to the field that is being queried
676  character(len=*), intent(in) :: name !< The name of the field that is being queried
677  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
678  logical :: query_initialized
679 ! This subroutine tests whether the field pointed to by f_ptr or with the
680 ! specified variable name has been initialized from a restart file.
681 
682  integer :: m,n
683  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
684  "query_initialized: Module must be initialized before it is used.")
685  if (cs%novars > cs%max_fields) call restart_error(cs)
686 
687  query_initialized = .false.
688  n = cs%novars+1
689  do m=1,cs%novars
690  if (associated(cs%var_ptr2d(m)%p,f_ptr)) then
691  if (cs%restart_field(m)%initialized) query_initialized = .true.
692  n = m ; exit
693  endif
694  enddo
695 ! Assume that you are going to initialize it now, so set flag to initialized if
696 ! queried again.
697  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
698  if (n==cs%novars+1) then
699  if (is_root_pe()) &
700  call mom_error(note,"MOM_restart: Unable to find "//name//" queried by pointer, "//&
701  "probably because of the suspect comparison of pointers by ASSOCIATED.")
702  query_initialized = query_initialized_name(name, cs)
703  endif
704 
705 end function query_initialized_2d_name
706 
707 !> Indicate whether the field pointed to by f_ptr or with the specified variable
708 !! name has been initialized from a restart file.
709 function query_initialized_3d_name(f_ptr, name, CS) result(query_initialized)
710  real, dimension(:,:,:), &
711  target, intent(in) :: f_ptr !< A pointer to the field that is being queried
712  character(len=*), intent(in) :: name !< The name of the field that is being queried
713  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
714  logical :: query_initialized
715 ! This subroutine tests whether the field pointed to by f_ptr or with the
716 ! specified variable name has been initialized from a restart file.
717 
718  integer :: m, n
719  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
720  "query_initialized: Module must be initialized before it is used.")
721  if (cs%novars > cs%max_fields) call restart_error(cs)
722 
723  query_initialized = .false.
724  n = cs%novars+1
725  do m=1,cs%novars
726  if (associated(cs%var_ptr3d(m)%p,f_ptr)) then
727  if (cs%restart_field(m)%initialized) query_initialized = .true.
728  n = m ; exit
729  endif
730  enddo
731 ! Assume that you are going to initialize it now, so set flag to initialized if
732 ! queried again.
733  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
734  if (n==cs%novars+1) then
735  if (is_root_pe()) &
736  call mom_error(note, "MOM_restart: Unable to find "//name//" queried by pointer, "//&
737  "possibly because of the suspect comparison of pointers by ASSOCIATED.")
738  query_initialized = query_initialized_name(name, cs)
739  endif
740 
741 end function query_initialized_3d_name
742 
743 !> Indicate whether the field pointed to by f_ptr or with the specified variable
744 !! name has been initialized from a restart file.
745 function query_initialized_4d_name(f_ptr, name, CS) result(query_initialized)
746  real, dimension(:,:,:,:), &
747  target, intent(in) :: f_ptr !< A pointer to the field that is being queried
748  character(len=*), intent(in) :: name !< The name of the field that is being queried
749  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object (intent in)
750  logical :: query_initialized
751 ! This subroutine tests whether the field pointed to by f_ptr or with the
752 ! specified variable name has been initialized from a restart file.
753 
754  integer :: m, n
755  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
756  "query_initialized: Module must be initialized before it is used.")
757  if (cs%novars > cs%max_fields) call restart_error(cs)
758 
759  query_initialized = .false.
760  n = cs%novars+1
761  do m=1,cs%novars
762  if (associated(cs%var_ptr4d(m)%p,f_ptr)) then
763  if (cs%restart_field(m)%initialized) query_initialized = .true.
764  n = m ; exit
765  endif
766  enddo
767 ! Assume that you are going to initialize it now, so set flag to initialized if
768 ! queried again.
769  if (n<=cs%novars) cs%restart_field(n)%initialized = .true.
770  if (n==cs%novars+1) then
771  if (is_root_pe()) &
772  call mom_error(note, "MOM_restart: Unable to find "//name//" queried by pointer, "//&
773  "possibly because of the suspect comparison of pointers by ASSOCIATED.")
774  query_initialized = query_initialized_name(name, cs)
775  endif
776 
777 end function query_initialized_4d_name
778 
779 !> save_restart saves all registered variables to restart files.
780 subroutine save_restart(directory, time, G, CS, time_stamped, filename, GV)
781  character(len=*), intent(in) :: directory !< The directory where the restart files
782  !! are to be written
783  type(time_type), intent(in) :: time !< The current model time
784  type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure
785  type(mom_restart_cs), pointer :: cs !< The control structure returned by a previous
786  !! call to restart_init.
787  logical, optional, intent(in) :: time_stamped !< If present and true, add time-stamp
788  !! to the restart file names.
789  character(len=*), optional, intent(in) :: filename !< A filename that overrides the name in CS%restartfile.
790  type(verticalgrid_type), optional, intent(in) :: gv !< The ocean's vertical grid structure
791 
792  ! Local variables
793  type(vardesc) :: vars(cs%max_fields) ! Descriptions of the fields that
794  ! are to be read from the restart file.
795  type(fieldtype) :: fields(cs%max_fields) !
796  character(len=512) :: restartpath ! The restart file path (dir/file).
797  character(len=256) :: restartname ! The restart file name (no dir).
798  character(len=8) :: suffix ! A suffix (like _2) that is appended
799  ! to the name of files after the first.
800  integer(kind=8) :: var_sz, size_in_file ! The size in bytes of each variable
801  ! and the variables already in a file.
802  integer(kind=8) :: max_file_size = 2147483647_8 ! The maximum size in bytes
803  ! for any one file. With NetCDF3,
804  ! this should be 2 Gb or less.
805  integer :: start_var, next_var ! The starting variables of the
806  ! current and next files.
807  integer :: unit ! The mpp unit of the open file.
808  integer :: m, nz, num_files, var_periods
809  integer :: seconds, days, year, month, hour, minute
810  character(len=8) :: hor_grid, z_grid, t_grid ! Variable grid info.
811  character(len=8) :: t_grid_read
812  character(len=64) :: var_name ! A variable's name.
813  real :: restart_time
814  character(len=32) :: filename_appendix = '' !fms appendix to filename for ensemble runs
815  integer :: length
816  integer(kind=8) :: check_val(cs%max_fields,1)
817  integer :: isl, iel, jsl, jel, pos
818 
819  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
820  "save_restart: Module must be initialized before it is used.")
821  if (cs%novars > cs%max_fields) call restart_error(cs)
822 
823  ! With parallel read & write, it is possible to disable the following...
824 
825  ! The maximum file size is 4294967292, according to the NetCDF documentation.
826  if (cs%large_file_support) max_file_size = 4294967292_8
827 
828  num_files = 0
829  next_var = 0
830  nz = 1 ; if (present(gv)) nz = gv%ke
831 
832  restart_time = time_type_to_real(time) / 86400.0
833 
834  restartname = trim(cs%restartfile)
835  if (present(filename)) restartname = trim(filename)
836  if (PRESENT(time_stamped)) then ; if (time_stamped) then
837  call get_date(time,year,month,days,hour,minute,seconds)
838  ! Compute the year-day, because I don't like months. - RWH
839  do m=1,month-1
840  days = days + days_in_month(set_date(year,m,2,0,0,0))
841  enddo
842  seconds = seconds + 60*minute + 3600*hour
843  if (year <= 9999) then
844  write(restartname,'("_Y",I4.4,"_D",I3.3,"_S",I5.5)') year, days, seconds
845  elseif (year <= 99999) then
846  write(restartname,'("_Y",I5.5,"_D",I3.3,"_S",I5.5)') year, days, seconds
847  else
848  write(restartname,'("_Y",I10.10,"_D",I3.3,"_S",I5.5)') year, days, seconds
849  endif
850  restartname = trim(cs%restartfile)//trim(restartname)
851  endif ; endif
852 
853  next_var = 1
854  do while (next_var <= cs%novars )
855  start_var = next_var
856  size_in_file = 8*(2*g%Domain%niglobal+2*g%Domain%njglobal+2*nz+1000)
857 
858  do m=start_var,cs%novars
859  call query_vardesc(cs%restart_field(m)%vars, hor_grid=hor_grid, &
860  z_grid=z_grid, t_grid=t_grid, caller="save_restart")
861  if (hor_grid == '1') then
862  var_sz = 8
863  else
864  var_sz = 8*(g%Domain%niglobal+1)*(g%Domain%njglobal+1)
865  endif
866  select case (z_grid)
867  case ('L') ; var_sz = var_sz * nz
868  case ('i') ; var_sz = var_sz * (nz+1)
869  end select
870  t_grid = adjustl(t_grid)
871  if (t_grid(1:1) == 'p') then
872  if (len_trim(t_grid(2:8)) > 0) then
873  var_periods = -1
874  t_grid_read = adjustl(t_grid(2:8))
875  read(t_grid_read,*) var_periods
876  if (var_periods > 1) var_sz = var_sz * var_periods
877  endif
878  endif
879 
880  if ((m==start_var) .OR. (size_in_file < max_file_size-var_sz)) then
881  size_in_file = size_in_file + var_sz
882  else ; exit
883  endif
884 
885  enddo
886  next_var = m
887 
888  !query fms_io if there is a filename_appendix (for ensemble runs)
889  call get_filename_appendix(filename_appendix)
890  if (len_trim(filename_appendix) > 0) then
891  length = len_trim(restartname)
892  if (restartname(length-2:length) == '.nc') then
893  restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc'
894  else
895  restartname = restartname(1:length) //'.'//trim(filename_appendix)
896  endif
897  endif
898 
899  restartpath = trim(directory)// trim(restartname)
900 
901  if (num_files < 10) then
902  write(suffix,'("_",I1)') num_files
903  else
904  write(suffix,'("_",I2)') num_files
905  endif
906 
907  if (num_files > 0) restartpath = trim(restartpath) // trim(suffix)
908 
909  do m=start_var,next_var-1
910  vars(m-start_var+1) = cs%restart_field(m)%vars
911  enddo
912  call query_vardesc(vars(1), t_grid=t_grid, hor_grid=hor_grid, caller="save_restart")
913  t_grid = adjustl(t_grid)
914  if (t_grid(1:1) /= 'p') &
915  call modify_vardesc(vars(1), t_grid='s', caller="save_restart")
916  select case (hor_grid)
917  case ('q') ; pos = corner
918  case ('h') ; pos = center
919  case ('u') ; pos = east_face
920  case ('v') ; pos = north_face
921  case ('Bu') ; pos = corner
922  case ('T') ; pos = center
923  case ('Cu') ; pos = east_face
924  case ('Cv') ; pos = north_face
925  case ('1') ; pos = 0
926  case default ; pos = 0
927  end select
928 
929  !Prepare the checksum of the restart fields to be written to restart files
930  call get_checksum_loop_ranges(g, pos, isl, iel, jsl, jel)
931  do m=start_var,next_var-1
932  if (associated(cs%var_ptr3d(m)%p)) then
933  check_val(m-start_var+1,1) = mpp_chksum(cs%var_ptr3d(m)%p(isl:iel,jsl:jel,:))
934  elseif (associated(cs%var_ptr2d(m)%p)) then
935  check_val(m-start_var+1,1) = mpp_chksum(cs%var_ptr2d(m)%p(isl:iel,jsl:jel))
936  elseif (associated(cs%var_ptr4d(m)%p)) then
937  check_val(m-start_var+1,1) = mpp_chksum(cs%var_ptr4d(m)%p(isl:iel,jsl:jel,:,:))
938  elseif (associated(cs%var_ptr1d(m)%p)) then
939  check_val(m-start_var+1,1) = mpp_chksum(cs%var_ptr1d(m)%p)
940  elseif (associated(cs%var_ptr0d(m)%p)) then
941  check_val(m-start_var+1,1) = mpp_chksum(cs%var_ptr0d(m)%p,pelist=(/mpp_pe()/))
942  endif
943  enddo
944 
945  if (cs%parallel_restartfiles) then
946  call create_file(unit, trim(restartpath), vars, (next_var-start_var), &
947  fields, multiple, g=g, gv=gv, checksums=check_val)
948  else
949  call create_file(unit, trim(restartpath), vars, (next_var-start_var), &
950  fields, single_file, g=g, gv=gv, checksums=check_val)
951  endif
952 
953  do m=start_var,next_var-1
954 
955  if (associated(cs%var_ptr3d(m)%p)) then
956  call write_field(unit,fields(m-start_var+1), g%Domain%mpp_domain, &
957  cs%var_ptr3d(m)%p, restart_time)
958  elseif (associated(cs%var_ptr2d(m)%p)) then
959  call write_field(unit,fields(m-start_var+1), g%Domain%mpp_domain, &
960  cs%var_ptr2d(m)%p, restart_time)
961  elseif (associated(cs%var_ptr4d(m)%p)) then
962  call write_field(unit,fields(m-start_var+1), g%Domain%mpp_domain, &
963  cs%var_ptr4d(m)%p, restart_time)
964  elseif (associated(cs%var_ptr1d(m)%p)) then
965  call write_field(unit, fields(m-start_var+1), cs%var_ptr1d(m)%p, &
966  restart_time)
967  elseif (associated(cs%var_ptr0d(m)%p)) then
968  call write_field(unit, fields(m-start_var+1), cs%var_ptr0d(m)%p, &
969  restart_time)
970  endif
971  enddo
972 
973  call close_file(unit)
974 
975  num_files = num_files+1
976 
977  enddo
978 end subroutine save_restart
979 
980 !> restore_state reads the model state from previously generated files. All
981 !! restart variables are read from the first file in the input filename list
982 !! in which they are found.
983 subroutine restore_state(filename, directory, day, G, CS)
984  character(len=*), intent(in) :: filename !< The list of restart file names or a single
985  !! character 'r' to read automatically named files.
986  character(len=*), intent(in) :: directory !< The directory in which to find restart files
987  type(time_type), intent(out) :: day !< The time of the restarted run
988  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
989  type(mom_restart_cs), pointer :: cs !< The control structure returned by a previous
990  !! call to restart_init.
991 
992 ! This subroutine reads the model state from previously
993 ! generated files. All restart variables are read from the first
994 ! file in the input filename list in which they are found.
995 
996  ! Local variables
997  character(len=200) :: filepath ! The path (dir/file) to the file being opened.
998  character(len=80) :: fname ! The name of the current file.
999  character(len=8) :: suffix ! A suffix (like "_2") that is added to any
1000  ! additional restart files.
1001  character(len=512) :: mesg ! A message for warnings.
1002  character(len=80) :: varname ! A variable's name.
1003  integer :: num_file ! The number of files (restart files and others
1004  ! explicitly in filename) that are open.
1005  integer :: i, n, m, missing_fields
1006  integer :: isl, iel, jsl, jel, is0, js0
1007  integer :: sizes(7)
1008  integer :: ndim, nvar, natt, ntime, pos
1009 
1010  integer :: unit(cs%max_fields) ! The mpp unit of all open files.
1011  character(len=200) :: unit_path(cs%max_fields) ! The file names.
1012  logical :: unit_is_global(cs%max_fields) ! True if the file is global.
1013 
1014  character(len=8) :: hor_grid ! Variable grid info.
1015  real :: t1, t2 ! Two times.
1016  real, allocatable :: time_vals(:)
1017  type(fieldtype), allocatable :: fields(:)
1018  logical :: check_exist, is_there_a_checksum
1019  integer(kind=8),dimension(3) :: checksum_file
1020  integer(kind=8) :: checksum_data
1021 
1022  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
1023  "restore_state: Module must be initialized before it is used.")
1024  if (cs%novars > cs%max_fields) call restart_error(cs)
1025 
1026 ! Get NetCDF ids for all of the restart files.
1027  if ((len_trim(filename) == 1) .and. (filename(1:1) == 'F')) then
1028  num_file = open_restart_units('r', directory, g, cs, units=unit, &
1029  file_paths=unit_path, global_files=unit_is_global)
1030  else
1031  num_file = open_restart_units(filename, directory, g, cs, units=unit, &
1032  file_paths=unit_path, global_files=unit_is_global)
1033  endif
1034 
1035  if (num_file == 0) then
1036  write(mesg,'("Unable to find any restart files specified by ",A," in directory ",A,".")') &
1037  trim(filename), trim(directory)
1038  call mom_error(fatal,"MOM_restart: "//mesg)
1039  endif
1040 
1041 ! Get the time from the first file in the list that has one.
1042  do n=1,num_file
1043  call get_file_info(unit(n), ndim, nvar, natt, ntime)
1044  if (ntime < 1) cycle
1045 
1046  allocate(time_vals(ntime))
1047  call get_file_times(unit(n), time_vals)
1048  t1 = time_vals(1)
1049  deallocate(time_vals)
1050 
1051  day = real_to_time(t1*86400.0)
1052  exit
1053  enddo
1054 
1055  if (n>num_file) call mom_error(warning,"MOM_restart: " // &
1056  "No times found in restart files.")
1057 
1058 ! Check the remaining files for different times and issue a warning
1059 ! if they differ from the first time.
1060  if (is_root_pe()) then
1061  do m = n+1,num_file
1062  call get_file_info(unit(n), ndim, nvar, natt, ntime)
1063  if (ntime < 1) cycle
1064 
1065  allocate(time_vals(ntime))
1066  call get_file_times(unit(n), time_vals)
1067  t2 = time_vals(1)
1068  deallocate(time_vals)
1069 
1070  if (t1 /= t2) then
1071  write(mesg,'("WARNING: Restart file ",I2," has time ",F10.4,"whereas &
1072  &simulation is restarted at ",F10.4," (differing by ",F10.4,").")')&
1073  m,t1,t2,t1-t2
1074  call mom_error(warning, "MOM_restart: "//mesg)
1075  endif
1076  enddo
1077  endif
1078 
1079 ! Read each variable from the first file in which it is found.
1080  do n=1,num_file
1081  call get_file_info(unit(n), ndim, nvar, natt, ntime)
1082 
1083  allocate(fields(nvar))
1084  call get_file_fields(unit(n),fields(1:nvar))
1085 
1086  do m=1, nvar
1087  call get_file_atts(fields(m),name=varname)
1088  do i=1,cs%num_obsolete_vars
1089  if (adjustl(lowercase(trim(varname))) == adjustl(lowercase(trim(cs%restart_obsolete(i)%field_name)))) then
1090  call mom_error(fatal, "MOM_restart restore_state: Attempting to use obsolete restart field "//&
1091  trim(varname)//" - the new corresponding restart field is "//&
1092  trim(cs%restart_obsolete(i)%replacement_name))
1093  endif
1094  enddo
1095  enddo
1096 
1097  missing_fields = 0
1098 
1099  do m=1,cs%novars
1100  if (cs%restart_field(m)%initialized) cycle
1101  call query_vardesc(cs%restart_field(m)%vars, hor_grid=hor_grid, &
1102  caller="restore_state")
1103  select case (hor_grid)
1104  case ('q') ; pos = corner
1105  case ('h') ; pos = center
1106  case ('u') ; pos = east_face
1107  case ('v') ; pos = north_face
1108  case ('Bu') ; pos = corner
1109  case ('T') ; pos = center
1110  case ('Cu') ; pos = east_face
1111  case ('Cv') ; pos = north_face
1112  case ('1') ; pos = 0
1113  case default ; pos = 0
1114  end select
1115 
1116  call get_checksum_loop_ranges(g, pos, isl, iel, jsl, jel)
1117  do i=1, nvar
1118  call get_file_atts(fields(i),name=varname)
1119  if (lowercase(trim(varname)) == lowercase(trim(cs%restart_field(m)%var_name))) then
1120  check_exist = mpp_attribute_exist(fields(i),"checksum")
1121  checksum_file(:) = -1
1122  checksum_data = -1
1123  is_there_a_checksum = .false.
1124  if ( check_exist ) then
1125  call mpp_get_atts(fields(i),checksum=checksum_file)
1126  is_there_a_checksum = .true.
1127  endif
1128  if (.NOT. cs%checksum_required) is_there_a_checksum = .false. ! Do not need to do data checksumming.
1129 
1130  if (associated(cs%var_ptr1d(m)%p)) then
1131  ! Read a 1d array, which should be invariant to domain decomposition.
1132  call read_data(unit_path(n), varname, cs%var_ptr1d(m)%p, &
1133  g%Domain%mpp_domain, timelevel=1)
1134  if (is_there_a_checksum) checksum_data = mpp_chksum(cs%var_ptr1d(m)%p)
1135  elseif (associated(cs%var_ptr0d(m)%p)) then ! Read a scalar...
1136  call read_data(unit_path(n), varname, cs%var_ptr0d(m)%p, &
1137  g%Domain%mpp_domain, timelevel=1)
1138  if (is_there_a_checksum) checksum_data = mpp_chksum(cs%var_ptr0d(m)%p,pelist=(/mpp_pe()/))
1139  elseif (associated(cs%var_ptr2d(m)%p)) then ! Read a 2d array.
1140  if (pos /= 0) then
1141  call mom_read_data(unit_path(n), varname, cs%var_ptr2d(m)%p, &
1142  g%Domain, timelevel=1, position=pos)
1143  else ! This array is not domain-decomposed. This variant may be under-tested.
1144  call read_data(unit_path(n), varname, cs%var_ptr2d(m)%p, &
1145  no_domain=.true., timelevel=1)
1146  endif
1147  if (is_there_a_checksum) checksum_data = mpp_chksum(cs%var_ptr2d(m)%p(isl:iel,jsl:jel))
1148  elseif (associated(cs%var_ptr3d(m)%p)) then ! Read a 3d array.
1149  if (pos /= 0) then
1150  call mom_read_data(unit_path(n), varname, cs%var_ptr3d(m)%p, &
1151  g%Domain, timelevel=1, position=pos)
1152  else ! This array is not domain-decomposed. This variant may be under-tested.
1153  call read_data(unit_path(n), varname, cs%var_ptr3d(m)%p, &
1154  no_domain=.true., timelevel=1)
1155  endif
1156  if (is_there_a_checksum) checksum_data = mpp_chksum(cs%var_ptr3d(m)%p(isl:iel,jsl:jel,:))
1157  elseif (associated(cs%var_ptr4d(m)%p)) then ! Read a 4d array.
1158  if (pos /= 0) then
1159  call mom_read_data(unit_path(n), varname, cs%var_ptr4d(m)%p, &
1160  g%Domain, timelevel=1, position=pos)
1161  else ! This array is not domain-decomposed. This variant may be under-tested.
1162  call read_data(unit_path(n), varname, cs%var_ptr4d(m)%p, &
1163  no_domain=.true., timelevel=1)
1164  endif
1165  if (is_there_a_checksum) checksum_data = mpp_chksum(cs%var_ptr4d(m)%p(isl:iel,jsl:jel,:,:))
1166  else
1167  call mom_error(fatal, "MOM_restart restore_state: No pointers set for "//trim(varname))
1168  endif
1169 
1170  if (is_root_pe() .and. is_there_a_checksum .and. (checksum_file(1) /= checksum_data)) then
1171  write (mesg,'(a,Z16,a,Z16,a)') "Checksum of input field "// trim(varname)//" ",checksum_data,&
1172  " does not match value ", checksum_file(1), &
1173  " stored in "//trim(unit_path(n)//"." )
1174  call mom_error(fatal, "MOM_restart(restore_state): "//trim(mesg) )
1175  endif
1176 
1177  cs%restart_field(m)%initialized = .true.
1178  exit ! Start search for next restart variable.
1179  endif
1180  enddo
1181  if (i>nvar) missing_fields = missing_fields+1
1182  enddo
1183 
1184  deallocate(fields)
1185  if (missing_fields == 0) exit
1186  enddo
1187 
1188  do n=1,num_file
1189  call close_file(unit(n))
1190  enddo
1191 
1192 ! Check whether any mandatory fields have not been found.
1193  cs%restart = .true.
1194  do m=1,cs%novars
1195  if (.not.(cs%restart_field(m)%initialized)) then
1196  cs%restart = .false.
1197  if (cs%restart_field(m)%mand_var) then
1198  call mom_error(fatal,"MOM_restart: Unable to find mandatory variable " &
1199  //trim(cs%restart_field(m)%var_name)//" in restart files.")
1200  endif
1201  endif
1202  enddo
1203 
1204 end subroutine restore_state
1205 
1206 !> restart_files_exist determines whether any restart files exist.
1207 function restart_files_exist(filename, directory, G, CS)
1208  character(len=*), intent(in) :: filename !< The list of restart file names or a single
1209  !! character 'r' to read automatically named files.
1210  character(len=*), intent(in) :: directory !< The directory in which to find restart files
1211  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
1212  type(mom_restart_cs), pointer :: cs !< The control structure returned by a previous
1213  !! call to restart_init.
1214  logical :: restart_files_exist !< The function result, which indicates whether
1215  !! any of the explicitly or automatically named
1216  !! restart files exist in directory.
1217  integer :: num_files
1218 
1219  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
1220  "restart_files_exist: Module must be initialized before it is used.")
1221 
1222  if ((len_trim(filename) == 1) .and. (filename(1:1) == 'F')) then
1223  num_files = open_restart_units('r', directory, g, cs)
1224  else
1225  num_files = open_restart_units(filename, directory, g, cs)
1226  endif
1227  restart_files_exist = (num_files > 0)
1228 
1229 end function restart_files_exist
1230 
1231 !> determine_is_new_run determines from the value of filename and the existence
1232 !! automatically named restart files in directory whether this would be a new,
1233 !! and as a side effect stores this information in CS.
1234 function determine_is_new_run(filename, directory, G, CS) result(is_new_run)
1235  character(len=*), intent(in) :: filename !< The list of restart file names or a single
1236  !! character 'r' to read automatically named files.
1237  character(len=*), intent(in) :: directory !< The directory in which to find restart files
1238  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
1239  type(mom_restart_cs), pointer :: cs !< The control structure returned by a previous
1240  !! call to restart_init.
1241  logical :: is_new_run !< The function result, which indicates whether
1242  !! this is a new run, based on the value of
1243  !! filename and whether restart files exist.
1244 
1245  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
1246  "determine_is_new_run: Module must be initialized before it is used.")
1247  if (len_trim(filename) > 1) then
1248  cs%new_run = .false.
1249  elseif (len_trim(filename) == 0) then
1250  cs%new_run = .true.
1251  elseif (filename(1:1) == 'n') then
1252  cs%new_run = .true.
1253  elseif (filename(1:1) == 'F') then
1254  cs%new_run = (open_restart_units('r', directory, g, cs) == 0)
1255  else
1256  cs%new_run = .false.
1257  endif
1258 
1259  cs%new_run_set = .true.
1260  is_new_run = cs%new_run
1261 end function determine_is_new_run
1262 
1263 !> is_new_run returns whether this is going to be a new run based on the
1264 !! information stored in CS by a previous call to determine_is_new_run.
1265 function is_new_run(CS)
1266  type(mom_restart_cs), pointer :: cs !< The control structure returned by a previous
1267  !! call to restart_init.
1268  logical :: is_new_run !< The function result, which indicates whether
1269  !! this is a new run, based on the value of
1270  !! filename and whether restart files exist.
1271 
1272  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
1273  "is_new_run: Module must be initialized before it is used.")
1274  if (.not.cs%new_run_set) call mom_error(fatal, "MOM_restart " // &
1275  "determine_is_new_run must be called for a restart file before is_new_run.")
1276 
1277  is_new_run = cs%new_run
1278 end function is_new_run
1279 
1280 !> open_restart_units determines the number of existing restart files and optionally opens
1281 !! them and returns unit ids, paths and whether the files are global or spatially decomposed.
1282 function open_restart_units(filename, directory, G, CS, units, file_paths, &
1283  global_files) result(num_files)
1284  character(len=*), intent(in) :: filename !< The list of restart file names or a single
1285  !! character 'r' to read automatically named files.
1286  character(len=*), intent(in) :: directory !< The directory in which to find restart files
1287  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
1288  type(mom_restart_cs), pointer :: cs !< The control structure returned by a previous
1289  !! call to restart_init.
1290  integer, dimension(:), &
1291  optional, intent(out) :: units !< The mpp units of all opened files.
1292  character(len=*), dimension(:), &
1293  optional, intent(out) :: file_paths !< The full paths to open files.
1294  logical, dimension(:), &
1295  optional, intent(out) :: global_files !< True if a file is global.
1296 
1297  integer :: num_files !< The number of files (both automatically named restart
1298  !! files and others explicitly in filename) that have been opened.
1299 
1300 ! This subroutine reads the model state from previously
1301 ! generated files. All restart variables are read from the first
1302 ! file in the input filename list in which they are found.
1303 
1304  ! Local variables
1305  character(len=256) :: filepath ! The path (dir/file) to the file being opened.
1306  character(len=256) :: fname ! The name of the current file.
1307  character(len=8) :: suffix ! A suffix (like "_2") that is added to any
1308  ! additional restart files.
1309 ! character(len=256) :: mesg ! A message for warnings.
1310  integer :: num_restart ! The number of restart files that have already
1311  ! been opened.
1312  integer :: start_char ! The location of the starting character in the
1313  ! current file name.
1314  integer :: n, m, err, length
1315 
1316 
1317  logical :: fexists
1318  character(len=32) :: filename_appendix = '' !fms appendix to filename for ensemble runs
1319  character(len=80) :: restartname
1320 
1321  if (.not.associated(cs)) call mom_error(fatal, "MOM_restart " // &
1322  "open_restart_units: Module must be initialized before it is used.")
1323 
1324 ! Get NetCDF ids for all of the restart files.
1325  num_restart = 0 ; n = 1 ; start_char = 1
1326  do while (start_char <= len_trim(filename) )
1327  do m=start_char,len_trim(filename)
1328  if (filename(m:m) == ' ') exit
1329  enddo
1330  fname = filename(start_char:m-1)
1331  start_char = m
1332  do while (start_char <= len_trim(filename))
1333  if (filename(start_char:start_char) == ' ') then
1334  start_char = start_char + 1
1335  else
1336  exit
1337  endif
1338  enddo
1339 
1340  if ((fname(1:1)=='r') .and. ( len_trim(fname) == 1)) then
1341  err = 0
1342  if (num_restart > 0) err = 1 ! Avoid going through the file list twice.
1343  do while (err == 0)
1344  restartname = trim(cs%restartfile)
1345 
1346  !query fms_io if there is a filename_appendix (for ensemble runs)
1347  call get_filename_appendix(filename_appendix)
1348  if (len_trim(filename_appendix) > 0) then
1349  length = len_trim(restartname)
1350  if (restartname(length-2:length) == '.nc') then
1351  restartname = restartname(1:length-3)//'.'//trim(filename_appendix)//'.nc'
1352  else
1353  restartname = restartname(1:length) //'.'//trim(filename_appendix)
1354  endif
1355  endif
1356  filepath = trim(directory) // trim(restartname)
1357 
1358  if (num_restart < 10) then
1359  write(suffix,'("_",I1)') num_restart
1360  else
1361  write(suffix,'("_",I2)') num_restart
1362  endif
1363  if (num_restart > 0) filepath = trim(filepath) // suffix
1364 
1365  ! if (.not.file_exists(filepath)) &
1366  filepath = trim(filepath)//".nc"
1367 
1368  num_restart = num_restart + 1
1369  inquire(file=filepath, exist=fexists)
1370  if (fexists) then
1371  if (present(units)) &
1372  call open_file(units(n), trim(filepath), readonly_file, netcdf_file, &
1373  threading = multiple, fileset = single_file)
1374  if (present(global_files)) global_files(n) = .true.
1375  elseif (cs%parallel_restartfiles) then
1376  ! Look for decomposed files using the I/O Layout.
1377  fexists = file_exists(filepath, g%Domain)
1378  if (fexists .and. (present(units))) &
1379  call open_file(units(n), trim(filepath), readonly_file, netcdf_file, &
1380  domain=g%Domain%mpp_domain)
1381  if (fexists .and. present(global_files)) global_files(n) = .false.
1382  endif
1383 
1384  if (fexists) then
1385  if (present(file_paths)) file_paths(n) = filepath
1386  n = n + 1
1387  if (is_root_pe() .and. (present(units))) &
1388  call mom_error(note, "MOM_restart: MOM run restarted using : "//trim(filepath))
1389  else
1390  err = 1 ; exit
1391  endif
1392  enddo ! while (err == 0) loop
1393  else
1394  filepath = trim(directory)//trim(fname)
1395  inquire(file=filepath, exist=fexists)
1396  if (.not. fexists) filepath = trim(filepath)//".nc"
1397 
1398  inquire(file=filepath, exist=fexists)
1399  if (fexists) then
1400  if (present(units)) &
1401  call open_file(units(n), trim(filepath), readonly_file, netcdf_file, &
1402  threading = multiple, fileset = single_file)
1403  if (present(global_files)) global_files(n) = .true.
1404  if (present(file_paths)) file_paths(n) = filepath
1405  n = n + 1
1406  if (is_root_pe() .and. (present(units))) &
1407  call mom_error(note,"MOM_restart: MOM run restarted using : "//trim(filepath))
1408  else
1409  if (present(units)) &
1410  call mom_error(warning,"MOM_restart: Unable to find restart file : "//trim(filepath))
1411  endif
1412 
1413  endif
1414  enddo ! while (start_char < strlen(filename)) loop
1415  num_files = n-1
1416 
1417 end function open_restart_units
1418 
1419 !> Initialize this module and set up a restart control structure.
1420 subroutine restart_init(param_file, CS, restart_root)
1421  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
1422  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object that is allocated here
1423  character(len=*), optional, &
1424  intent(in) :: restart_root !< A filename root that overrides the value
1425  !! set by RESTARTFILE to enable the use of this module by
1426  !! other components than MOM.
1427 
1428 ! This include declares and sets the variable "version".
1429 #include "version_variable.h"
1430  character(len=40) :: mdl = "MOM_restart" ! This module's name.
1431 
1432  if (associated(cs)) then
1433  call mom_error(warning, "restart_init called with an associated control structure.")
1434  return
1435  endif
1436  allocate(cs)
1437 
1438  ! Read all relevant parameters and write them to the model log.
1439  call log_version(param_file, mdl, version, "")
1440  call get_param(param_file, mdl, "PARALLEL_RESTARTFILES", &
1441  cs%parallel_restartfiles, &
1442  "If true, each processor writes its own restart file, "//&
1443  "otherwise a single restart file is generated", &
1444  default=.false.)
1445 
1446  if (present(restart_root)) then
1447  cs%restartfile = restart_root
1448  call log_param(param_file, mdl, "RESTARTFILE from argument", cs%restartfile)
1449  else
1450  call get_param(param_file, mdl, "RESTARTFILE", cs%restartfile, &
1451  "The name-root of the restart file.", default="MOM.res")
1452  endif
1453  call get_param(param_file, mdl, "LARGE_FILE_SUPPORT", cs%large_file_support, &
1454  "If true, use the file-size limits with NetCDF large "//&
1455  "file support (4Gb), otherwise the limit is 2Gb.", &
1456  default=.true.)
1457  call get_param(param_file, mdl, "MAX_FIELDS", cs%max_fields, &
1458  "The maximum number of restart fields that can be used.", &
1459  default=100)
1460  call get_param(param_file, mdl, "RESTART_CHECKSUMS_REQUIRED", cs%checksum_required, &
1461  "If true, require the restart checksums to match and error out otherwise. "//&
1462  "Users may want to avoid this comparison if for example the restarts are "//&
1463  "made from a run with a different mask_table than the current run, "//&
1464  "in which case the checksums will not match and cause crash.",&
1465  default=.true.)
1466 
1467  allocate(cs%restart_field(cs%max_fields))
1468  allocate(cs%restart_obsolete(cs%max_fields))
1469  allocate(cs%var_ptr0d(cs%max_fields))
1470  allocate(cs%var_ptr1d(cs%max_fields))
1471  allocate(cs%var_ptr2d(cs%max_fields))
1472  allocate(cs%var_ptr3d(cs%max_fields))
1473  allocate(cs%var_ptr4d(cs%max_fields))
1474 
1475 end subroutine restart_init
1476 
1477 !> Indicate that all variables have now been registered.
1478 subroutine restart_init_end(CS)
1479  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object
1480 
1481  if (associated(cs)) then
1482  if (cs%novars == 0) call restart_end(cs)
1483  endif
1484 
1485 end subroutine restart_init_end
1486 
1487 !> Deallocate memory associated with a MOM_restart_CS variable.
1488 subroutine restart_end(CS)
1489  type(mom_restart_cs), pointer :: cs !< A pointer to a MOM_restart_CS object
1490 
1491  if (associated(cs%restart_field)) deallocate(cs%restart_field)
1492  if (associated(cs%restart_obsolete)) deallocate(cs%restart_obsolete)
1493  if (associated(cs%var_ptr0d)) deallocate(cs%var_ptr0d)
1494  if (associated(cs%var_ptr1d)) deallocate(cs%var_ptr1d)
1495  if (associated(cs%var_ptr2d)) deallocate(cs%var_ptr2d)
1496  if (associated(cs%var_ptr3d)) deallocate(cs%var_ptr3d)
1497  if (associated(cs%var_ptr4d)) deallocate(cs%var_ptr4d)
1498  deallocate(cs)
1499 
1500 end subroutine restart_end
1501 
1502 subroutine restart_error(CS)
1503  type(mom_restart_cs), pointer :: CS !< A pointer to a MOM_restart_CS object
1504 
1505  character(len=16) :: num ! String for error messages
1506 
1507  if (cs%novars > cs%max_fields) then
1508  write(num,'(I0)') cs%novars
1509  call mom_error(fatal,"MOM_restart: Too many fields registered for " // &
1510  "restart. Set MAX_FIELDS to be at least " // &
1511  trim(adjustl(num)) // " in the MOM input file.")
1512  else
1513  call mom_error(fatal,"MOM_restart: Unspecified fatal error.")
1514  endif
1515 end subroutine restart_error
1516 
1517 !> Return bounds for computing checksums to store in restart files
1518 subroutine get_checksum_loop_ranges(G, pos, isL, ieL, jsL, jeL)
1519  type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1520  integer, intent(in) :: pos !< An integer indicating staggering of variable
1521  integer, intent(out) :: isL !< i-start for checksum
1522  integer, intent(out) :: ieL !< i-end for checksum
1523  integer, intent(out) :: jsL !< j-start for checksum
1524  integer, intent(out) :: jeL !< j-end for checksum
1525 
1526  ! Regular non-symmetric compute domain
1527  isl = g%isc-g%isd+1
1528  iel = g%iec-g%isd+1
1529  jsl = g%jsc-g%jsd+1
1530  jel = g%jec-g%jsd+1
1531 
1532  ! Expand range east or south for symmetric arrays
1533  if (g%symmetric) then
1534  if ((pos == east_face) .or. (pos == corner)) then ! For u-, q-points only
1535  if (g%idg_offset == 0) isl = isl - 1 ! include western edge in checksums only for western PEs
1536  endif
1537  if ((pos == north_face) .or. (pos == corner)) then ! For v-, q-points only
1538  if (g%jdg_offset == 0) jsl = jsl - 1 ! include western edge in checksums only for southern PEs
1539  endif
1540  endif
1541 
1542 end subroutine get_checksum_loop_ranges
1543 
1544 end module mom_restart
mom_time_manager
Wraps the FMS time manager functions.
Definition: MOM_time_manager.F90:2
mom_restart::p1d
A type for making arrays of pointers to 1-d arrays.
Definition: MOM_restart.F90:46
mom_verticalgrid
Provides a transparent vertical ocean grid type and supporting routines.
Definition: MOM_verticalGrid.F90:2
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_string_functions
Handy functions for manipulating strings.
Definition: MOM_string_functions.F90:2
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_restart::obsolete_restart
A structure to store information about restart fields that are no longer used.
Definition: MOM_restart.F90:66
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
mom_io
This module contains I/O framework code.
Definition: MOM_io.F90:2
mom_restart::mom_restart_cs
A restart registry and the control structure for restarts.
Definition: MOM_restart.F90:72
mom_restart::p3d
A type for making arrays of pointers to 3-d arrays.
Definition: MOM_restart.F90:36
mom_verticalgrid::verticalgrid_type
Describes the vertical ocean grid, including unit conversion factors.
Definition: MOM_verticalGrid.F90:24
mom_restart
The MOM6 facility for reading and writing restart files, and querying what has been read.
Definition: MOM_restart.F90:2
mom_domains
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
mom_io::mom_read_data
Read a data field from a file.
Definition: MOM_io.F90:74
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_restart::p0d
A type for making arrays of pointers to scalars.
Definition: MOM_restart.F90:51
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_restart::register_restart_field
Register fields for restarts.
Definition: MOM_restart.F90:107
mom_restart::field_restart
A structure with information about a single restart field.
Definition: MOM_restart.F90:56
mom_io::vardesc
Type for describing a variable, typically a tracer.
Definition: MOM_io.F90:53
mom_io::file_exists
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
mom_restart::p4d
A type for making arrays of pointers to 4-d arrays.
Definition: MOM_restart.F90:31
mom_file_parser::log_param
An overloaded interface to log the values of various types of parameters.
Definition: MOM_file_parser.F90:96
mom_restart::query_initialized
Indicate whether a field has been read from a restart file.
Definition: MOM_restart.F90:116
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_restart::p2d
A type for making arrays of pointers to 2-d arrays.
Definition: MOM_restart.F90:41
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:25