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