FMS  2026.01.01-dev
Flexible Modeling System
fms_netcdf_domain_io.F90
1 !***********************************************************************
2 !* Apache License 2.0
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* Licensed under the Apache License, Version 2.0 (the "License");
7 !* you may not use this file except in compliance with the License.
8 !* You may obtain a copy of the License at
9 !*
10 !* http://www.apache.org/licenses/LICENSE-2.0
11 !*
12 !* FMS is distributed in the hope that it will be useful, but WITHOUT
13 !* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied;
14 !* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15 !* PARTICULAR PURPOSE. See the License for the specific language
16 !* governing permissions and limitations under the License.
17 !***********************************************************************
18 !> @defgroup fms_netcdf_domain_io_mod fms_netcdf_domain_io_mod
19 !> @ingroup fms2_io
20 !> @brief This module defines the derived type, FmsNetcdfDomainFile_t, and routines
21 !! to handle calls to the netcdf library for data on a domain decomposed standard rectangular grid.
22 !! See mpp_domains_mod for more information on domain decomposition.
23 !!
24 !! This module is not intended to be used externally. Please use the public interfaces in fms2_io_mod
25 !! for IO operations.
26 !!
27 !> @addtogroup fms_netcdf_domain_io_mod
28 !> @{
29 module fms_netcdf_domain_io_mod
30 use netcdf
31 use mpp_mod
32 use mpp_domains_mod
33 use fms_io_utils_mod
34 use netcdf_io_mod
35 use platform_mod
36 implicit none
37 private
38 
39 
40 !Module constants.
41 integer, parameter :: no_domain_decomposed_dimension = 0
42 integer, parameter, public :: max_num_domain_decomposed_dims = 10
43 integer, parameter :: variable_not_found = 0
44 integer, parameter :: default_domain_position = center
45 character(len=16), parameter :: domain_pos_att = "domain_position"
46 character(len=16), parameter :: domain_axis_att_name = "domain_axis"
47 character(len=16), parameter :: x = "x"
48 character(len=16), parameter :: y = "y"
49 
50 !> @}
51 
52 !> @brief Domain variable.
53 !> @ingroup fms_netcdf_domain_io_mod
54 type, private :: domaindimension_t
55  character(len=nf90_max_name) :: varname !< Variable name.
56  integer :: pos !< Domain position.
57 endtype domaindimension_t
58 
59 
60 !> @brief Type to represent a netCDF file when on a domain decomposed standard rectangular
61 !! grid. Used to do distributed I/O across ranks,
62 !! as determined by the io_layout. The io_layout is a 1D array (nx_pe,ny_pe) of size 2 set via mpp_set_io_domain
63 !! and determines how many PEs will be performing IO operations within a given
64 !! domain decompositon. The total number of writing PEs is nx_pe * ny_pe.
65 !!
66 !! For example, if domain's layout was (4,4) so 16 PEs total,
67 !! then a io_layout of (2,2) would have 4 PEs performing I/O operations.
68 !! When doing a read, each IO PE will receive a portion of data from 3 of the non-IO PEs and then write the aggregate.
69 !! When doing a write, each IO PE will read the data and then send a data portion to 3 of the non-IO PEs.
70 !!
71 !> @ingroup fms_netcdf_domain_io_mod
72 type, extends(fmsnetcdffile_t), public :: fmsnetcdfdomainfile_t
73  type(domain2d) :: domain !< Two-dimensional domain.
74  type(domaindimension_t), dimension(:), allocatable :: xdims !< Dimensions associated
75  !! with the "x" axis
76  !! of a 2d domain.
77  integer :: nx !< Number of "x" dimensions.
78  type(domaindimension_t), dimension(:), allocatable :: ydims !< Dimensions associated
79  !! with the "y" axis
80  !! of a 2d domain.
81  integer :: ny !< Number of "y" dimensions.
82  character(len=FMS_PATH_LEN) :: non_mangled_path !< Non-domain-mangled file path.
83  logical :: adjust_indices !< Flag telling if indices need to be adjusted
84  !! for domain-decomposed read.
86 
87 
88 public :: open_domain_file
89 public :: close_domain_file
98 public :: domain_read_0d
99 public :: domain_read_1d
100 public :: domain_read_2d
101 public :: domain_read_3d
102 public :: domain_read_4d
103 public :: domain_read_5d
104 public :: domain_write_0d
105 public :: domain_write_1d
106 public :: domain_write_2d
107 public :: domain_write_3d
108 public :: domain_write_4d
109 public :: domain_write_5d
110 public :: save_domain_restart
111 public :: restore_domain_state
114 public :: is_dimension_registered
115 public :: get_mosaic_tile_grid
116 
117 !> @ingroup fms_netcdf_domain_io_mod
119  module procedure compute_global_checksum_2d
120  module procedure compute_global_checksum_3d
121  module procedure compute_global_checksum_4d
122 end interface compute_global_checksum
123 
124 !> @addtogroup fms_netcdf_domain_io_mod
125 !> @{
126 
127 contains
128 
129 
130 !> @brief Get the index of a domain decomposed dimension.
131 !! @return Index of domain decomposed dimension.
132 function get_domain_decomposed_index(name_, array, size_) &
133  result(index_)
134 
135  character(len=*), intent(in) :: name_ !< Name.
136  type(domaindimension_t), dimension(:), intent(in) :: array !< Array to search through.
137  integer, intent(in) :: size_ !< Number of spots to look in.
138  integer :: index_
139 
140  integer :: i
141 
142  index_ = variable_not_found
143  do i = 1, size_
144  if (string_compare(array(i)%varname, name_)) then
145  index_ = i
146  return
147  endif
148  enddo
149 end function get_domain_decomposed_index
150 
151 
152 !> @brief Add a domain decomposed dimension to an array.
153 subroutine append_domain_decomposed_dimension(name_, position_, array, size_)
154 
155  character(len=*), intent(in) :: name_ !< Variable name.
156  integer, intent(in) :: position_ !< Domain position.
157  type(domaindimension_t), dimension(:), intent(inout) :: array !< Array to search through.
158  integer, intent(inout) :: size_ !< Number of spots to look in.
159 
160  integer :: i
161 
162  do i = 1, size_
163  if (string_compare(array(i)%varname, name_)) then
164  call error("variable "//trim(name_)//" already registered.")
165  endif
166  enddo
167  size_ = size_ + 1
168  if (size_ .gt. size(array)) then
169  call error("number of domain decomposed variables exceeds limit.")
170  endif
171  call string_copy(array(size_)%varname, name_)
172  array(size_)%pos = position_
174 
175 
176 !> @brief Given a domain decomposed dimension, get its domain position.
177 !! @return Position of the domain decomposed variable.
178 function get_domain_position(name_, array, size_) &
179  result(dpos)
180 
181  character(len=*), intent(in) :: name_ !< Variable name.
182  type(domaindimension_t), dimension(:), intent(in) :: array !< Array to search through.
183  integer, intent(in) :: size_
184  integer :: dpos
185 
186  dpos = get_domain_decomposed_index(name_, array, size_)
187  if (dpos .ne. variable_not_found) then
188  dpos = array(dpos)%pos
189  endif
190 end function get_domain_position
191 
192 
193 !> @brief Given a variable, get the index of the "x" or "y" domain decomposed
194 !! dimension.
195 !! @return Index of the domain decomposed dimension or else
196 !! no_domain_decomposed_dimension.
197 function get_domain_decomposed_dimension_index(fileobj, variable_name, &
198  xory, broadcast) &
199  result(index_)
200 
201  type(fmsnetcdfdomainfile_t), intent(in), target :: fileobj !< File object.
202  character(len=*), intent(in) :: variable_name !< Variable name.
203  character(len=*), intent(in) :: xory !< String telling which dimension to
204  !! look for. Valid values are "x"
205  !! or "y".
206  logical, intent(in), optional :: broadcast !< Flag controlling whether or
207  !! not the index will be
208  !! broadcast to non "I/O root"
209  !! ranks. The broadcast will
210  !! be done by default.
211  integer :: index_
212 
213  integer :: ndims
214  character(len=nf90_max_name), dimension(:), allocatable :: dim_names
215  type(domaindimension_t), dimension(:), pointer :: p
216  integer :: n
217  integer :: i
218 
219  index_ = no_domain_decomposed_dimension
220  if (fileobj%is_root) then
221  ndims = get_variable_num_dimensions(fileobj, variable_name, broadcast=.false.)
222  allocate(dim_names(ndims))
223  dim_names(:) = ""
224  call get_variable_dimension_names(fileobj, variable_name, dim_names, broadcast=.false.)
225  if (string_compare(xory, x, .true.)) then
226  p => fileobj%xdims
227  n = fileobj%nx
228  elseif (string_compare(xory, y, .true.)) then
229  p => fileobj%ydims
230  n = fileobj%ny
231  else
232  call error("unrecognized xory flag value.")
233  endif
234  do i = 1, size(dim_names)
235  if (get_domain_decomposed_index(dim_names(i), p, n) .ne. variable_not_found) then
236  index_ = i
237  exit
238  endif
239  enddo
240  deallocate(dim_names)
241  endif
242  if (present(broadcast)) then
243  if (.not. broadcast) then
244  return
245  endif
246  endif
247  call mpp_broadcast(index_, fileobj%io_root, pelist=fileobj%pelist)
249 
250 
251 !> @brief Determine if a variable is "domain decomposed."
252 !! @return Flag telling if the variable is "domain decomposed."
253 function is_variable_domain_decomposed(fileobj, variable_name, broadcast, &
254  xindex, yindex, xpos, ypos) &
255  result(is_decomposed)
256 
257  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
258  character(len=*), intent(in) :: variable_name !< Variable name.
259  logical, intent(in), optional :: broadcast !< Flag controlling whether or
260  !! not the index will be
261  !! broadcast to non "I/O root"
262  !! ranks. The broadcast will
263  !! be done by default.
264  integer, intent(out), optional :: xindex !< The index of the domain
265  !! x dimension.
266  integer, intent(out), optional :: yindex !< The index of the domain
267  !! y dimension.
268  integer, intent(out), optional :: xpos !< Domain position of the x dimension.
269  integer, intent(out), optional :: ypos !< Domain position of the y dimension.
270  logical :: is_decomposed
271 
272  integer, dimension(2) :: indices
273  integer :: ndims
274  character(len=nf90_max_name), dimension(:), allocatable :: dim_names
275 
276  indices(1) = get_domain_decomposed_dimension_index(fileobj, variable_name, x, broadcast)
277  if (present(xindex)) then
278  xindex = indices(1)
279  endif
280  indices(2) = get_domain_decomposed_dimension_index(fileobj, variable_name, y, broadcast)
281  if (present(yindex)) then
282  yindex = indices(2)
283  endif
284  is_decomposed = (indices(1) .ne. no_domain_decomposed_dimension) .and. &
285  (indices(2) .ne. no_domain_decomposed_dimension)
286  if (is_decomposed) then
287  if (.not. present(xpos) .and. .not. present(ypos)) then
288  return
289  endif
290  ndims = get_variable_num_dimensions(fileobj, variable_name, broadcast)
291  allocate(dim_names(ndims))
292  dim_names(:) = ""
293  call get_variable_dimension_names(fileobj, variable_name, dim_names, broadcast)
294  if (present(xpos)) then
295  xpos = get_domain_position(dim_names(indices(1)), fileobj%xdims, fileobj%nx)
296  endif
297  if (present(ypos)) then
298  ypos = get_domain_position(dim_names(indices(2)), fileobj%ydims, fileobj%ny)
299  endif
300  deallocate(dim_names)
301  else
302  if (present(xpos)) then
303  xpos = -1
304  endif
305  if (present(ypos)) then
306  ypos = -1
307  endif
308  endif
310 
311 
312 !> @brief Determine whether a domain-decomposed dimension has been registered to the file object
313 !! @return Flag telling if the dimension is registered to the file object
314 function is_dimension_registered(fileobj, dimension_name) &
315  result(is_registered)
316 
317  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
318  character(len=*), intent(in) :: dimension_name !< Dimension name.
319 
320  ! local
321  logical :: is_registered
322  integer :: dpos
323 
324  dpos = 0
325  is_registered = .false.
326  dpos = get_domain_decomposed_index(dimension_name, fileobj%xdims, fileobj%nx)
327  if (dpos .ne. variable_not_found) then
328  is_registered = .true.
329  else
330  dpos = get_domain_decomposed_index(dimension_name, fileobj%ydims, fileobj%ny)
331  if (dpos .ne. variable_not_found) is_registered = .true.
332  endif
333 
334 end function is_dimension_registered
335 
336 !> @brief Open a domain netcdf file.
337 !! @return Flag telling if the open completed successfully.
338 function open_domain_file(fileobj, path, mode, domain, nc_format, is_restart, dont_add_res_to_filename, &
339  use_netcdf_mpi, use_collective) result(success)
340 
341  type(fmsnetcdfdomainfile_t),intent(inout) :: fileobj !< File object.
342  character(len=*), intent(in) :: path !< File path.
343  character(len=*), intent(in) :: mode !< File mode. Allowed values
344  !! are "read", "append", "write", or
345  !! "overwrite".
346  type(domain2d), intent(in) :: domain !< Two-dimensional domain.
347  character(len=*), intent(in), optional :: nc_format !< Netcdf format that
348  !! new files are written
349  !! as. Allowed values
350  !! are: "64bit", "classic",
351  !! or "netcdf4". Defaults to
352  !! "64bit".
353  logical, intent(in), optional :: is_restart !< Flag telling if this file
354  !! is a restart file. Defaults
355  !! to false.
356  logical, intent(in), optional :: dont_add_res_to_filename !< Flag indicating not to add ".res" to the filename
357  logical, intent(in), optional :: use_netcdf_mpi !< Flag telling if this file should be using netcdf4 parallel
358  !! reads and writes. Defaults to false.
359  !! nc_format is automatically set to netcdf4
360  logical, intent(in), optional :: use_collective !< Flag indicating whether reads and writes should be performed
361  !! collectively rather than independently.
362  logical :: success
363 
364  integer, dimension(2) :: io_layout
365  integer, dimension(1) :: tile_id
366  character(len=FMS_PATH_LEN) :: combined_filepath
367  type(domain2d), pointer :: io_domain
368  character(len=FMS_PATH_LEN) :: distributed_filepath
369  integer :: pelist_size
370  integer, dimension(:), allocatable :: pelist
371  logical :: success2
372  type(fmsnetcdfdomainfile_t) :: fileobj2
373 
374  io_domain => mpp_get_io_domain(domain)
375 
376  if (present(use_netcdf_mpi)) then
377  if (use_netcdf_mpi) then
378  if (associated(io_domain)) then
379  call mpp_error(note, "NetCDF MPI is enabled: ignoring I/O domain. Only one output file will be produced.")
380  endif
381 
382  fileobj%domain = domain
383 
384  allocate(fileobj%xdims(max_num_domain_decomposed_dims))
385  fileobj%nx = 0
386  allocate(fileobj%ydims(max_num_domain_decomposed_dims))
387  fileobj%ny = 0
388 
389  call string_copy(fileobj%non_mangled_path, path)
390 
391  !! If the number of tiles is greater than 1 or if the current tile is greater
392  !than 1 add .tileX. to the filename
393  tile_id = mpp_get_tile_id(domain)
394  if (mpp_get_ntile_count(domain) .gt. 1 .or. tile_id(1) > 1) then
395  call domain_tile_filepath_mangle(combined_filepath, path, tile_id(1))
396  else
397  call string_copy(combined_filepath, path)
398  endif
399 
400  success = netcdf_file_open(fileobj, combined_filepath, mode, &
401  nc_format="netcdf4", &
402  is_restart=is_restart, &
403  dont_add_res_to_filename=dont_add_res_to_filename, &
404  tile_comm=mpp_get_domain_tile_commid(domain), &
405  use_collective=use_collective)
406  return
407  endif
408  endif
409 
410  !Get the path of a "combined" file.
411  io_layout = mpp_get_io_domain_layout(domain)
412  tile_id = mpp_get_tile_id(domain)
413 
414  !< If the number of tiles is greater than 1 or if the current tile is greater
415  !than 1 add .tileX. to the filename
416  if (mpp_get_ntile_count(domain) .gt. 1 .or. tile_id(1) > 1) then
417  call domain_tile_filepath_mangle(combined_filepath, path, tile_id(1))
418  else
419  call string_copy(combined_filepath, path)
420  endif
421 
422  !Get the path of a "distributed" file.
423  if (.not. associated(io_domain)) then
424  call error("The domain associated with the file:"//trim(path)//" does not have an io_domain.")
425  endif
426  if (io_layout(1)*io_layout(2) .gt. 1) then
427  tile_id = mpp_get_tile_id(io_domain)
428  call io_domain_tile_filepath_mangle(distributed_filepath, combined_filepath, tile_id(1))
429  else
430  call string_copy(distributed_filepath, combined_filepath)
431  endif
432 
433  !Make sure the input domain has an I/O domain and get its pelist.
434  pelist_size = mpp_get_domain_npes(io_domain)
435  allocate(pelist(pelist_size))
436  call mpp_get_pelist(io_domain, pelist)
437  fileobj%adjust_indices = .true. !Set the default to true
438 
439  !Open the distibuted files.
440  success = netcdf_file_open(fileobj, distributed_filepath, mode, nc_format, pelist, &
441  is_restart, dont_add_res_to_filename)
442  if (string_compare(mode, "read", .true.) .or. string_compare(mode, "append", .true.)) then
443  if (success) then
444  if (.not. string_compare(distributed_filepath, combined_filepath)) then
445  success2 = netcdf_file_open(fileobj2, combined_filepath, mode, nc_format, pelist, &
446  is_restart, dont_add_res_to_filename)
447  if (success2) then
448  call error("The domain decomposed file:"//trim(path)// &
449  & " contains both combined (*.nc) and distributed files (*.nc.XXXX).")
450  endif
451  endif
452  else
453  success = netcdf_file_open(fileobj, combined_filepath, mode, nc_format, pelist, &
454  is_restart, dont_add_res_to_filename)
455  !If the file is combined and the layout is not (1,1) set the adjust_indices flag to false
456  if (success .and. (io_layout(1)*io_layout(2) .gt. 1)) fileobj%adjust_indices = .false.
457  endif
458  endif
459  if (.not. success) then
460  deallocate(pelist)
461  return
462  endif
463 
464  !Store/initialize necessary properties.
465  call string_copy(fileobj%non_mangled_path, path)
466  fileobj%domain = domain
467  allocate(fileobj%xdims(max_num_domain_decomposed_dims))
468  fileobj%nx = 0
469  allocate(fileobj%ydims(max_num_domain_decomposed_dims))
470  fileobj%ny = 0
471  call string_copy(fileobj%non_mangled_path, path)
472 
473  if (string_compare(mode, "write", .true.) .or. string_compare(mode, "overwrite", .true.)) then
474  !Add global attribute needed by mppnccombine.
475  call register_global_attribute(fileobj, "NumFilesInSet", io_layout(1)*io_layout(2))
476  endif
477 end function open_domain_file
478 
479 
480 !> @brief Close a domain netcdf file.
481 subroutine close_domain_file(fileobj)
482 
483  type(fmsnetcdfdomainfile_t), intent(inout) :: fileobj !< File object.
484 
485  call netcdf_file_close(fileobj)
486  deallocate(fileobj%xdims)
487  fileobj%nx = 0
488  deallocate(fileobj%ydims)
489  fileobj%ny = 0
490 end subroutine close_domain_file
491 
492 
493 !> @brief Add a dimension to a file associated with a two-dimensional domain.
494 subroutine register_domain_decomposed_dimension(fileobj, dim_name, xory, domain_position)
495 
496  type(fmsnetcdfdomainfile_t), target, intent(inout) :: fileobj !< File object.
497  character(len=*), intent(in) :: dim_name !< Dimension name.
498  character(len=*), intent(in) :: xory !< Flag telling if the dimension
499  !! is associated with the "x" or "y"
500  !! axis of the 2d domain. Allowed
501  !! values are "x" or "y".
502  integer, intent(in), optional :: domain_position !< Domain position.
503 
504  integer :: dpos
505  type(domain2d), pointer :: io_domain
506  integer :: domain_size
507  integer :: dim_size
508 
509  dpos = default_domain_position
510  if (mpp_domain_is_symmetry(fileobj%domain) .and. present(domain_position)) then
511  dpos = domain_position
512  endif
513 
514  ! If using NetCDF MPI, the IO domain is ignored, so use the domain to determine the correct size of each
515  ! domain-decomposed dimension.
516  if (fileobj%use_netcdf_mpi) then
517  io_domain => fileobj%domain
518  else
519  io_domain => mpp_get_io_domain(fileobj%domain)
520  endif
521 
522  if (string_compare(xory, x, .true.)) then
523  if (dpos .ne. center .and. dpos .ne. east) then
524  call error("Only domain_position=center or domain_position=EAST is supported for x dimensions."// &
525  & " Fix your register_axis call for file:"&
526  &//trim(fileobj%path)//" and dimension:"//trim(dim_name))
527  endif
528  call mpp_get_global_domain(io_domain, xsize=domain_size, position=dpos)
529  call append_domain_decomposed_dimension(dim_name, dpos, fileobj%xdims, fileobj%nx)
530  elseif (string_compare(xory, y, .true.)) then
531  if (dpos .ne. center .and. dpos .ne. north) then
532  call error("Only domain_position=center or domain_position=NORTH is supported for y dimensions."// &
533  & " Fix your register_axis call for file:"&
534  &//trim(fileobj%path)//" and dimension:"//trim(dim_name))
535  endif
536  call mpp_get_global_domain(io_domain, ysize=domain_size, position=dpos)
537  call append_domain_decomposed_dimension(dim_name, dpos, fileobj%ydims, fileobj%ny)
538  else
539  call error("The register_axis call for file:"//trim(fileobj%path)//" and dimension:"//trim(dim_name)// &
540  & " has an unrecognized xory flag value:"&
541  &//trim(xory)//" only 'x' and 'y' are allowed.")
542  endif
543  if (fileobj%is_readonly .or. (fileobj%mode_is_append .and. dimension_exists(fileobj, dim_name))) then
544  call get_dimension_size(fileobj, dim_name, dim_size, broadcast=.true.)
545  if (dim_size .lt. domain_size) then
546  call error("dimension "//trim(dim_name)//" in the file "//trim(fileobj%path)//" is smaller than the size of" &
547  //" the associated domain "//trim(xory)//" axis.")
548  endif
549  else
550  call netcdf_add_dimension(fileobj, dim_name, domain_size, is_compressed=.false.)
551  endif
553 
554 
555 !> @brief Add a "domain_decomposed" attribute to the axis variables because it is
556 !! required by mppnccombine.
557 !! @internal
558 subroutine add_domain_attribute(fileobj, variable_name)
559 
560  type(fmsnetcdfdomainfile_t), intent(inout) :: fileobj !< File object.
561  character(len=*), intent(in) :: variable_name !< Variable name.
562 
563  type(domain2d), pointer :: io_domain
564  integer :: dpos
565  integer :: sg
566  integer :: eg
567  integer :: s
568  integer :: e
569  integer, dimension(2) :: io_layout !< Io_layout in the fileobj's domain
570 
571  !< Don't add the "domain_decomposition" variable attribute if the io_layout is
572  !! 1,1, or if using mpi netcdf for writes, to avoid frecheck "failures"
573  io_layout = mpp_get_io_domain_layout(fileobj%domain)
574  if (io_layout(1) .eq. 1 .and. io_layout(2) .eq. 1) return
575  if (fileobj%use_netcdf_mpi) return
576 
577  io_domain => mpp_get_io_domain(fileobj%domain)
578  dpos = get_domain_decomposed_index(variable_name, fileobj%xdims, fileobj%nx)
579  if (dpos .ne. variable_not_found) then
580  dpos = fileobj%xdims(dpos)%pos
581  call mpp_get_global_domain(fileobj%domain, xbegin=sg, xend=eg, position=dpos)
582  call mpp_get_global_domain(io_domain, xbegin=s, xend=e, position=dpos)
583  call register_variable_attribute(fileobj, variable_name, "domain_decomposition", &
584  (/sg, eg, s, e/))
585  else
586  dpos = get_domain_decomposed_index(variable_name, fileobj%ydims, fileobj%ny)
587  if (dpos .ne. variable_not_found) then
588  dpos = fileobj%ydims(dpos)%pos
589  call mpp_get_global_domain(fileobj%domain, ybegin=sg, yend=eg, position=dpos)
590  call mpp_get_global_domain(io_domain, ybegin=s, yend=e, position=dpos)
591  call register_variable_attribute(fileobj, variable_name, "domain_decomposition", &
592  (/sg, eg, s, e/))
593  endif
594  endif
595 end subroutine add_domain_attribute
596 
597 
598 !> @brief Add a domain decomposed variable.
599 subroutine register_domain_variable(fileobj, variable_name, variable_type, dimensions, chunksizes)
600 
601  type(fmsnetcdfdomainfile_t), intent(inout) :: fileobj !< File object.
602  character(len=*), intent(in) :: variable_name !< Variable name.
603  character(len=*), intent(in) :: variable_type !< Variable type. Allowed
604  !! values are: "int", "int64",
605  !! "float", or "double".
606  character(len=*), dimension(:), intent(in), optional :: dimensions !< Dimension names.
607  integer, intent(in), optional :: chunksizes(:) !< netcdf chunksize to use for this variable (netcdf4 only)
608 
609  if (.not. fileobj%is_readonly) then
610  call netcdf_add_variable(fileobj, variable_name, variable_type, dimensions, chunksizes)
611  if (present(dimensions)) then
612  if (size(dimensions) .eq. 1) then
613  call add_domain_attribute(fileobj, variable_name)
614  endif
615  endif
616  endif
617 end subroutine register_domain_variable
618 
619 
620 !> @brief Loop through registered restart variables and write them to
621 !! a netcdf file.
622 subroutine save_domain_restart(fileobj, unlim_dim_level)
623 
624  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
625  integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension level.
626 
627  integer :: i
628  character(len=32) :: chksum
629  logical :: is_decomposed
630 
631  if (.not. fileobj%is_restart) then
632  call error("file "//trim(fileobj%path)// &
633  & " is not a restart file. You must set is_restart=.true. in your open_file call.")
634  endif
635 
636 ! Calculate the variable's checksum and write it to the netcdf file
637  do i = 1, fileobj%num_restart_vars
638  if (associated(fileobj%restart_vars(i)%data2d)) then
639  chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
640  fileobj%restart_vars(i)%data2d, is_decomposed)
641  if (is_decomposed) then
642  call register_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
643  "checksum", chksum(1:len(chksum)), str_len=len(chksum))
644  endif
645  elseif (associated(fileobj%restart_vars(i)%data3d)) then
646  chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
647  fileobj%restart_vars(i)%data3d, is_decomposed)
648  if (is_decomposed) then
649  call register_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
650  "checksum", chksum(1:len(chksum)), str_len=len(chksum))
651  endif
652  elseif (associated(fileobj%restart_vars(i)%data4d)) then
653  chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
654  fileobj%restart_vars(i)%data4d, is_decomposed)
655  if (is_decomposed) then
656  call register_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
657  "checksum", chksum(1:len(chksum)), str_len=len(chksum))
658  endif
659  endif
660  enddo
661 
662 ! Write the variable's data to the netcdf file
663  do i = 1, fileobj%num_restart_vars
664  if (associated(fileobj%restart_vars(i)%data0d)) then
665  call domain_write_0d(fileobj, fileobj%restart_vars(i)%varname, &
666  fileobj%restart_vars(i)%data0d, unlim_dim_level=unlim_dim_level)
667  elseif (associated(fileobj%restart_vars(i)%data1d)) then
668  call domain_write_1d(fileobj, fileobj%restart_vars(i)%varname, &
669  fileobj%restart_vars(i)%data1d, unlim_dim_level=unlim_dim_level)
670  elseif (associated(fileobj%restart_vars(i)%data2d)) then
671  call domain_write_2d(fileobj, fileobj%restart_vars(i)%varname, &
672  fileobj%restart_vars(i)%data2d, unlim_dim_level=unlim_dim_level)
673  elseif (associated(fileobj%restart_vars(i)%data3d)) then
674  call domain_write_3d(fileobj, fileobj%restart_vars(i)%varname, &
675  fileobj%restart_vars(i)%data3d, unlim_dim_level=unlim_dim_level)
676  elseif (associated(fileobj%restart_vars(i)%data4d)) then
677  call domain_write_4d(fileobj, fileobj%restart_vars(i)%varname, &
678  fileobj%restart_vars(i)%data4d, unlim_dim_level=unlim_dim_level)
679  else
680  call error("This routine only accepts data that is scalar, 1d 2d 3d or 4d."//&
681  " The data sent in has an unsupported dimensionality")
682  endif
683  enddo
684 
685 end subroutine save_domain_restart
686 
687 
688 !> @brief Loop through registered restart variables and read them from
689 !! a netcdf file.
690 subroutine restore_domain_state(fileobj, unlim_dim_level, ignore_checksum)
691 
692  type(fmsnetcdfdomainfile_t), intent(inout) :: fileobj !< File object.
693  integer, intent(in), optional :: unlim_dim_level !< Unlimited dimension level.
694  logical, intent(in), optional :: ignore_checksum !< Checksum data integrity flag.
695 
696  integer :: i
697  character(len=32) :: chksum_in_file
698  character(len=32) :: chksum
699  logical :: chksum_ignore = .false. !< local variable for data integrity checks
700  !! default: .FALSE. - checks enabled
701  logical :: is_decomposed
702 
703  if (PRESENT(ignore_checksum)) chksum_ignore = ignore_checksum
704 
705  if (.not. fileobj%is_restart) then
706  call error("file "//trim(fileobj%path)// &
707  & " is not a restart file. You must set is_restart=.true. in your open_file call.")
708  endif
709  do i = 1, fileobj%num_restart_vars
710  if (associated(fileobj%restart_vars(i)%data0d)) then
711  call domain_read_0d(fileobj, fileobj%restart_vars(i)%varname, &
712  fileobj%restart_vars(i)%data0d, unlim_dim_level=unlim_dim_level)
713  elseif (associated(fileobj%restart_vars(i)%data1d)) then
714  call domain_read_1d(fileobj, fileobj%restart_vars(i)%varname, &
715  fileobj%restart_vars(i)%data1d, unlim_dim_level=unlim_dim_level)
716  elseif (associated(fileobj%restart_vars(i)%data2d)) then
717  call domain_read_2d(fileobj, fileobj%restart_vars(i)%varname, &
718  fileobj%restart_vars(i)%data2d, unlim_dim_level=unlim_dim_level)
719  if (.not.chksum_ignore) then
720  chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
721  fileobj%restart_vars(i)%data2d, is_decomposed)
722  if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
723  is_decomposed) then
724  call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
725  "checksum", chksum_in_file)
726  if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
727  call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"// &
728  & trim(fileobj%restart_vars(i)%varname)// &
729  &" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
730  &" from data:"//trim(adjustl(chksum)))
731  endif
732  endif
733  endif
734  elseif (associated(fileobj%restart_vars(i)%data3d)) then
735  call domain_read_3d(fileobj, fileobj%restart_vars(i)%varname, &
736  fileobj%restart_vars(i)%data3d, unlim_dim_level=unlim_dim_level)
737  if (.not.chksum_ignore) then
738  chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
739  fileobj%restart_vars(i)%data3d, is_decomposed)
740  if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
741  is_decomposed) then
742  call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
743  "checksum", chksum_in_file(1:len(chksum_in_file)))
744  if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
745  call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"// &
746  & trim(fileobj%restart_vars(i)%varname)//&
747  &" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
748  &" from data:"//trim(adjustl(chksum)))
749  endif
750  endif
751  endif
752  elseif (associated(fileobj%restart_vars(i)%data4d)) then
753  call domain_read_4d(fileobj, fileobj%restart_vars(i)%varname, &
754  fileobj%restart_vars(i)%data4d, unlim_dim_level=unlim_dim_level)
755  if (.not.chksum_ignore) then
756  chksum = compute_global_checksum(fileobj, fileobj%restart_vars(i)%varname, &
757  fileobj%restart_vars(i)%data4d, is_decomposed)
758  if (variable_att_exists(fileobj, fileobj%restart_vars(i)%varname, "checksum") .and. &
759  is_decomposed) then
760  call get_variable_attribute(fileobj, fileobj%restart_vars(i)%varname, &
761  "checksum", chksum_in_file)
762  if (.not. string_compare(trim(adjustl(chksum_in_file)), trim(adjustl(chksum)))) then
763  call error("The checksum in the file:"//trim(fileobj%path)//" and variable:"// &
764  & trim(fileobj%restart_vars(i)%varname)//&
765  &" does not match the checksum calculated from the data. file:"//trim(adjustl(chksum_in_file))//&
766  &" from data:"//trim(adjustl(chksum)))
767  endif
768  endif
769  endif
770  else
771  call error("There is no data associated with the variable: "//trim(fileobj%restart_vars(i)%varname)//&
772  &" and the file: "//trim(fileobj%path)//". Check your register_restart_variable call")
773  endif
774  enddo
775 end subroutine restore_domain_state
776 
777 
778 !> @brief Return an array of compute domain indices.
779 subroutine get_compute_domain_dimension_indices(fileobj, dimname, indices)
780 
781  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
782  character(len=*), intent(in) :: dimname !< Name of dimension variable.
783  integer, dimension(:), allocatable, intent(inout) :: indices !< Compute domain indices.
784 
785  type(domain2d), pointer :: io_domain
786  integer :: dpos
787  integer :: s
788  integer :: e
789  integer :: i
790 
791  io_domain => mpp_get_io_domain(fileobj%domain)
792  dpos = get_domain_decomposed_index(dimname, fileobj%xdims, fileobj%nx)
793  if (dpos .ne. variable_not_found) then
794  dpos = fileobj%xdims(dpos)%pos
795  call mpp_get_compute_domain(io_domain, xbegin=s, xend=e, position=dpos)
796  else
797  dpos = get_domain_decomposed_index(dimname, fileobj%ydims, fileobj%ny)
798  if (dpos .ne. variable_not_found) then
799  dpos = fileobj%ydims(dpos)%pos
800  call mpp_get_compute_domain(io_domain, ybegin=s, yend=e, position=dpos)
801  else
802  call error("get_compute_domain_dimension_indices: the input dimension:"//trim(dimname)// &
803  & " is not domain decomposed.")
804  endif
805  endif
806  if (allocated(indices)) then
807  deallocate(indices)
808  endif
809  allocate(indices(e-s+1))
810  do i = s, e
811  indices(i-s+1) = i
812  enddo
814 
815 
816 !> @brief Utility routine that retrieves domain indices.
817 !! @internal
818 subroutine domain_offsets(data_xsize, data_ysize, domain, xpos, ypos, &
819  isd, isc, xc_size, jsd, jsc, yc_size, &
820  buffer_includes_halos, extra_x_point, &
821  extra_y_point, msg)
822 
823  integer, intent(in) :: data_xsize !< Size of buffer's domain "x" dimension.
824  integer, intent(in) :: data_ysize !< Size of buffer's domain "y" dimension.
825  type(domain2d), intent(in) :: domain !< Parent domain.
826  integer, intent(in) :: xpos !< Variable's domain x dimension position.
827  integer, intent(in) :: ypos !< Variable's domain y dimension position.
828  integer, intent(out) :: isd !< Starting index for x dimension of data domain.
829  integer, intent(out) :: isc !< Starting index for x dimension of compute domain.
830  integer, intent(out) :: xc_size !< Size of x dimension of compute domain.
831  integer, intent(out) :: jsd !< Starting index for y dimension of data domain.
832  integer, intent(out) :: jsc !< Starting index for y dimension of compute domain.
833  integer, intent(out) :: yc_size !< Size of y dimension of compute domain.
834  logical, intent(out) :: buffer_includes_halos !< Flag telling if input buffer includes space for halos.
835  logical, intent(out), optional :: extra_x_point !< Flag indicating if data_array has an extra point in x
836  logical, intent(out), optional :: extra_y_point !< Flag indicating if data_array has an extra point in y
837  character(len=*), intent(in), optional :: msg !< Message appended to fatal error
838 
839  integer :: xd_size
840  integer :: yd_size
841  integer :: iec
842  integer :: xmax
843  integer :: jec
844  integer :: ymax
845  type(domain2d), pointer :: io_domain !< I/O domain variable is decomposed over.
846 
847  io_domain => mpp_get_io_domain(domain)
848 
849  call mpp_get_global_domain(domain, xend=xmax, position=xpos)
850  call mpp_get_global_domain(domain, yend=ymax, position=ypos)
851  call mpp_get_data_domain(io_domain, xbegin=isd, xsize=xd_size, position=xpos)
852  call mpp_get_data_domain(io_domain, ybegin=jsd, ysize=yd_size, position=ypos)
853 
854  call mpp_get_compute_domain(io_domain, xbegin=isc, xend=iec, xsize=xc_size, &
855  position=xpos)
856  ! If the xpos is east and the ending x index is NOT equal to max allowed, set extra_x_point to true
857  if (present(extra_x_point)) then
858  if ((xpos .eq. east) .and. (iec .ne. xmax)) then
859  extra_x_point = .true.
860  else
861  extra_x_point = .false.
862  endif
863  endif
864 
865  call mpp_get_compute_domain(io_domain, ybegin=jsc, yend=jec, ysize=yc_size, &
866  position=ypos)
867  ! If the ypost is north and the ending y index is NOT equal to max allowed, set extra_y_point to true
868  if (present(extra_y_point)) then
869  if ((ypos .eq. north) .and. (jec .ne. ymax)) then
870  extra_y_point = .true.
871  else
872  extra_y_point = .false.
873  endif
874  endif
875 
876  buffer_includes_halos = (data_xsize .eq. xd_size) .and. (data_ysize .eq. yd_size)
877  if (.not. buffer_includes_halos .and. data_xsize .ne. xc_size .and. data_ysize &
878  .ne. yc_size) then
879  print *, "buffer_includes_halos:", buffer_includes_halos, " data_xsize:", &
880  data_xsize, " xc_size:", xc_size, " data_ysize:", data_ysize, " yc_size:", &
881  yc_size
882  call error(trim(msg)//" The data is not on the compute domain or the data domain")
883  endif
884 end subroutine domain_offsets
885 
886 
887 !> @brief Get starting/ending global indices of the I/O domain for a domain decomposed
888 !! file.
889 subroutine get_global_io_domain_indices(fileobj, dimname, is, ie, indices)
890 
891  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
892  character(len=*), intent(in) :: dimname !< Name of dimension variable.
893  integer, intent(out) :: is !< Starting index of I/O global domain.
894  integer, intent(out) :: ie !< Ending index of I/O global domain.
895  integer, dimension(:), allocatable, intent(out), optional :: indices !< Global domain indices
896 
897  type(domain2d), pointer :: io_domain
898  integer :: dpos
899  integer :: i
900 
901  io_domain => mpp_get_io_domain(fileobj%domain)
902  dpos = get_domain_decomposed_index(dimname, fileobj%xdims, fileobj%nx)
903  if (dpos .ne. variable_not_found) then
904  dpos = fileobj%xdims(dpos)%pos
905  call mpp_get_global_domain(io_domain, xbegin=is, xend=ie, position=dpos)
906  else
907  dpos = get_domain_decomposed_index(dimname, fileobj%ydims, fileobj%ny)
908  if (dpos .ne. variable_not_found) then
909  dpos = fileobj%ydims(dpos)%pos
910  call mpp_get_global_domain(io_domain, ybegin=is, yend=ie, position=dpos)
911  else
912  call error("get_global_io_domain_indices: the dimension "//trim(dimname)//" in the file: "//trim(fileobj%path)//&
913  &" is not domain decomposed. Check your register_axis call")
914  endif
915  endif
916 
917 ! Allocate indices to the difference between the ending and starting indices and
918 ! fill indices with the data
919  if (present(indices)) then
920  if(allocated(indices)) then
921  call error("get_global_io_domain_indices: the variable indices should not be allocated.")
922  endif
923  allocate(indices(ie-is+1))
924  do i = is, ie
925  indices(i-is+1) = i
926  enddo
927  endif
928 
929 
930 end subroutine get_global_io_domain_indices
931 
932 !> @brief Read a mosaic_file and get the grid filename for the current tile or
933 !! for the tile specified
934 subroutine get_mosaic_tile_grid(grid_file,mosaic_file, domain, tile_count)
935  character(len=*), intent(out) :: grid_file !< Filename of the grid file for the
936  !! current domain tile or for tile
937  !! specified in tile_count
938  character(len=*), intent(in) :: mosaic_file !< Filename that will be read
939  type(domain2d), intent(in) :: domain !< Input domain
940  integer, intent(in), optional :: tile_count !< Optional argument indicating
941  !! the tile you want grid file name for
942  !! this is for when a pe is in more than
943  !! tile.
944  integer :: tile !< Current domian tile or tile_count
945  integer :: ntileme !< Total number of tiles in the domain
946  integer, dimension(:), allocatable :: tile_id !< List of tiles in the domain
947  type(fmsnetcdffile_t) :: fileobj !< Fms2io file object
948 
949  tile = 1
950  if(present(tile_count)) tile = tile_count
951  ntileme = mpp_get_current_ntile(domain)
952  allocate(tile_id(ntileme))
953  tile_id = mpp_get_tile_id(domain)
954 
955  if (netcdf_file_open(fileobj, mosaic_file, "read")) then
956  call netcdf_read_data(fileobj, "gridfiles", grid_file, corner=tile_id(tile))
957  grid_file = 'INPUT/'//trim(grid_file)
958  call netcdf_file_close(fileobj)
959  endif
960 
961 end subroutine get_mosaic_tile_grid
962 
963 include "register_domain_restart_variable.inc"
964 include "domain_read.inc"
965 include "domain_write.inc"
966 #include "compute_global_checksum.inc"
967 
968 
969 end module fms_netcdf_domain_io_mod
970 !> @}
971 ! close documentation grouping
subroutine domain_read_0d(fileobj, variable_name, vdata, unlim_dim_level, corner)
I/O domain root reads in a domain decomposed variable at a specific unlimited dimension level and sca...
Definition: domain_read.inc:30
subroutine domain_write_3d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
Gather "compute" domain data on the I/O root rank and then have the I/O root write out the data that ...
subroutine register_domain_restart_variable_3d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine domain_write_4d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
Gather "compute" domain data on the I/O root rank and then have the I/O root write out the data that ...
subroutine register_domain_restart_variable_1d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine domain_write_1d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
Gather "compute" domain data on the I/O root rank and then have the I/O root write out the data that ...
subroutine domain_write_5d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
Gather "compute" domain data on the I/O root rank and then have the I/O root write out the data that ...
subroutine register_domain_restart_variable_5d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine domain_write_0d(fileobj, variable_name, vdata, unlim_dim_level, corner)
Gather "compute" domain data on the I/O root rank and then have the I/O root write out the data that ...
subroutine domain_write_2d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
Gather "compute" domain data on the I/O root rank and then have the I/O root write out the data that ...
subroutine domain_read_3d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
I/O domain root reads in a domain decomposed variable at a specific unlimited dimension level and sca...
subroutine register_domain_restart_variable_4d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine domain_read_1d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
I/O domain root reads in a domain decomposed variable at a specific unlimited dimension level and sca...
Definition: domain_read.inc:57
subroutine domain_read_2d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
I/O domain root reads in a domain decomposed variable at a specific unlimited dimension level and sca...
Definition: domain_read.inc:88
subroutine domain_read_4d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
I/O domain root reads in a domain decomposed variable at a specific unlimited dimension level and sca...
subroutine domain_read_5d(fileobj, variable_name, vdata, unlim_dim_level, corner, edge_lengths)
I/O domain root reads in a domain decomposed variable at a specific unlimited dimension level and sca...
subroutine register_domain_restart_variable_0d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine register_domain_restart_variable_2d(fileobj, variable_name, vdata, dimensions, is_optional, chunksizes)
Add a domain decomposed variable.
subroutine, public io_domain_tile_filepath_mangle(dest, source, io_domain_tile_id)
Add the I/O domain tile id to an input filepath.
logical function, public string_compare(string1, string2, ignore_case)
Compare strings.
subroutine, public domain_tile_filepath_mangle(dest, source, domain_tile_id)
Add the domain tile id to an input filepath.
subroutine add_domain_attribute(fileobj, variable_name)
Add a "domain_decomposed" attribute to the axis variables because it is required by mppnccombine.
integer function get_domain_decomposed_dimension_index(fileobj, variable_name, xory, broadcast)
Given a variable, get the index of the "x" or "y" domain decomposed dimension.
integer function get_domain_decomposed_index(name_, array, size_)
Get the index of a domain decomposed dimension.
subroutine, public save_domain_restart(fileobj, unlim_dim_level)
Loop through registered restart variables and write them to a netcdf file.
logical function is_variable_domain_decomposed(fileobj, variable_name, broadcast, xindex, yindex, xpos, ypos)
Determine if a variable is "domain decomposed.".
logical function, public is_dimension_registered(fileobj, dimension_name)
Determine whether a domain-decomposed dimension has been registered to the file object.
subroutine domain_offsets(data_xsize, data_ysize, domain, xpos, ypos, isd, isc, xc_size, jsd, jsc, yc_size, buffer_includes_halos, extra_x_point, extra_y_point, msg)
Utility routine that retrieves domain indices.
subroutine, public get_global_io_domain_indices(fileobj, dimname, is, ie, indices)
Get starting/ending global indices of the I/O domain for a domain decomposed file.
subroutine, public register_domain_variable(fileobj, variable_name, variable_type, dimensions, chunksizes)
Add a domain decomposed variable.
subroutine, public get_mosaic_tile_grid(grid_file, mosaic_file, domain, tile_count)
Read a mosaic_file and get the grid filename for the current tile or for the tile specified.
subroutine, public register_domain_decomposed_dimension(fileobj, dim_name, xory, domain_position)
Add a dimension to a file associated with a two-dimensional domain.
logical function, public open_domain_file(fileobj, path, mode, domain, nc_format, is_restart, dont_add_res_to_filename, use_netcdf_mpi, use_collective)
Open a domain netcdf file.
subroutine, public close_domain_file(fileobj)
Close a domain netcdf file.
character(len=32) function compute_global_checksum_3d(fileobj, variable_name, variable_data, is_decomposed)
@briefs Calculates a variable's checksum across all ranks in the current pelist.
subroutine, public restore_domain_state(fileobj, unlim_dim_level, ignore_checksum)
Loop through registered restart variables and read them from a netcdf file.
character(len=32) function compute_global_checksum_4d(fileobj, variable_name, variable_data, is_decomposed)
@briefs Calculates a variable's checksum across all ranks in the current pelist.
subroutine append_domain_decomposed_dimension(name_, position_, array, size_)
Add a domain decomposed dimension to an array.
character(len=32) function compute_global_checksum_2d(fileobj, variable_name, variable_data, is_decomposed)
@briefs Calculates a variable's checksum across all ranks in the current pelist.
subroutine, public get_compute_domain_dimension_indices(fileobj, dimname, indices)
Return an array of compute domain indices.
integer function get_domain_position(name_, array, size_)
Given a domain decomposed dimension, get its domain position.
Type to represent a netCDF file when on a domain decomposed standard rectangular grid....
integer function mpp_get_domain_npes(domain)
Set user stack size.
integer function mpp_get_domain_tile_commid(domain)
Set user stack size.
integer function, dimension(size(domain%tile_id(:))) mpp_get_tile_id(domain)
Returns the tile_id on current pe.
logical function mpp_domain_is_symmetry(domain)
Set user stack size.
integer function mpp_get_current_ntile(domain)
Returns number of tile on current pe.
integer function mpp_get_ntile_count(domain)
Returns number of tiles in mosaic.
integer function, dimension(2) mpp_get_io_domain_layout(domain)
Set user stack size.
type(domain2d) function, pointer mpp_get_io_domain(domain)
Set user stack size.
These routines retrieve the axis specifications associated with the compute domains....
These routines retrieve the axis specifications associated with the data domains. The domain is a der...
These routines retrieve the axis specifications associated with the global domains....
Retrieve list of PEs associated with a domain decomposition. The 1D version of this call returns an a...
The domain2D type contains all the necessary information to define the global, compute and data domai...
Perform parallel broadcasts.
Definition: mpp.F90:1153
Error handler.
Definition: mpp.F90:385
subroutine, public netcdf_file_close(fileobj)
Close a netcdf file.
Definition: netcdf_io.F90:768
subroutine, public netcdf_add_dimension(fileobj, dimension_name, dimension_length, is_compressed)
Add a dimension to a file.
Definition: netcdf_io.F90:901
integer function, public get_variable_num_dimensions(fileobj, variable_name, broadcast)
Get the number of dimensions a variable depends on.
Definition: netcdf_io.F90:1624
subroutine, public get_dimension_size(fileobj, dimension_name, dim_size, broadcast)
Get the length of a dimension.
Definition: netcdf_io.F90:1474
logical function, public dimension_exists(fileobj, dimension_name, broadcast)
Determine if a dimension exists.
Definition: netcdf_io.F90:1368
logical function, public variable_att_exists(fileobj, variable_name, attribute_name, broadcast)
Determine if a variable's attribute exists.
Definition: netcdf_io.F90:1248
subroutine, public get_variable_dimension_names(fileobj, variable_name, dim_names, broadcast)
Get the name of a variable's dimensions.
Definition: netcdf_io.F90:1658
subroutine, public netcdf_add_variable(fileobj, variable_name, variable_type, dimensions, chunksizes)
Add a variable to a file.
Definition: netcdf_io.F90:982
logical function, public netcdf_file_open(fileobj, path, mode, nc_format, pelist, is_restart, dont_add_res_to_filename, tile_comm, use_collective)
Open a netcdf file.
Definition: netcdf_io.F90:565
Type to represent a netCDF file. Can be used with multiple cores but only the root pe will perform an...
Definition: netcdf_io.F90:147