FMS  2026.01.01-dev
Flexible Modeling System
domain_read.inc
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 !> @file
19 !> @brief Reads domain decomposed variables and scatters data to pe's for the @ref read_data interface
20 
21 !> @addtogroup fms2_io_mod
22 !> @{
23 
24 !> @brief I/O domain root reads in a domain decomposed variable at a
25 !! specific unlimited dimension level and scatters the data to the
26 !! rest of the ranks using its I/O compute domain indices. This
27 !! routine may only be used with variables that are "domain
28 !! decomposed".
29 subroutine domain_read_0d(fileobj, variable_name, vdata, unlim_dim_level, corner)
30 
31  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
32  character(len=*), intent(in) :: variable_name !< Variable name.
33  class(*), intent(inout) :: vdata !< Data that will
34  !! be read out
35  !! to the netcdf file.
36  integer, intent(in), optional :: unlim_dim_level !< Level for the unlimited
37  !! dimension.
38  integer, intent(in), optional :: corner !< Array of starting
39  !! indices describing
40  !! where the data
41  !! will be read to.
42 
43  call netcdf_read_data(fileobj, variable_name, vdata, &
44  unlim_dim_level=unlim_dim_level, corner=corner, &
45  broadcast=.true.)
46 
47 end subroutine domain_read_0d
48 
49 
50 !> @brief I/O domain root reads in a domain decomposed variable at a
51 !! specific unlimited dimension level and scatters the data to the
52 !! rest of the ranks using its I/O compute domain indices. This
53 !! routine may only be used with variables that are "domain
54 !! decomposed".
55 subroutine domain_read_1d(fileobj, variable_name, vdata, unlim_dim_level, &
56  corner, edge_lengths)
57 
58  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
59  character(len=*), intent(in) :: variable_name !< Variable name.
60  class(*), dimension(:), intent(inout) :: vdata !< Data that will
61  !! be read out
62  !! to the netcdf file.
63  integer, intent(in), optional :: unlim_dim_level !< Level for the unlimited
64  !! dimension.
65  integer, dimension(1), intent(in), optional :: corner !< Array of starting
66  !! indices describing
67  !! where the data
68  !! will be read to.
69  integer, dimension(1), intent(in), optional :: edge_lengths !< The number of
70  !! elements that
71  !! will be read
72  !! in each dimension.
73 
74  call netcdf_read_data(fileobj, variable_name, vdata, &
75  unlim_dim_level=unlim_dim_level, corner=corner, &
76  edge_lengths=edge_lengths, broadcast=.true.)
77 
78 end subroutine domain_read_1d
79 
80 
81 !> @brief I/O domain root reads in a domain decomposed variable at a
82 !! specific unlimited dimension level and scatters the data to the
83 !! rest of the ranks using its I/O compute domain indices. This
84 !! routine may only be used with variables that are "domain
85 !! decomposed".
86 subroutine domain_read_2d(fileobj, variable_name, vdata, unlim_dim_level, &
87  corner, edge_lengths)
88  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
89  character(len=*), intent(in) :: variable_name !< Variable name.
90  class(*), contiguous, target, intent(inout) :: vdata(:,:) !< Data that will
91  !! be read out
92  !! to the netcdf file.
93  integer, intent(in), optional :: unlim_dim_level !< Level for the unlimited
94  !! dimension.
95  integer, dimension(2), intent(in), optional :: corner !< Array of starting
96  !! indices describing
97  !! where the data
98  !! will be read to.
99  integer, dimension(2), intent(in), optional :: edge_lengths !< The number of
100  !! elements that
101  !! will be read
102  !! in each dimension.
103 
104  integer :: xdim_index !< The index of the variable that is the x dimension
105  integer :: ydim_index !< The index of the variable that is the y dimension
106  integer :: xpos !< The position of the x axis
107  integer :: ypos !< The position of the y axis
108  integer :: i !< For do loops
109  integer :: isd !< The starting x position of the data io_domain
110  integer :: isc !< The starting x position of the compute io_domain
111  integer :: xc_size !< The size of the x compute io_domain
112  integer :: yc_size !< The size of the y compute io_domain
113  integer :: jsd !< The ending x position of the data io_domain
114  integer :: jsc !< The ending y position of the compute io_domain
115  integer :: c(2) !< The corners of the data
116  integer :: e(2) !< The number of points (edges)
117  logical :: buffer_includes_halos !< .True. if vdata includes halo points
118  integer :: xgbegin !< Starting x index of global io domain
119  integer :: xgsize !< Size of global x io domain
120  integer :: ygbegin !< Starting y index of global io domain
121  integer :: ygsize !< Size of global y io domain
122  integer :: dim_order(2) !< Order of the dimensions
123  type(domain2d), pointer :: io_domain !< pointer to the io_domain
124 
125  !< The global data is only allocated by the io root PEs
126  integer(kind=i4_kind), dimension(:,:), allocatable :: buf_i4_kind_pe !< PES section of the data
127  integer(kind=i8_kind), dimension(:,:), allocatable :: buf_i8_kind_pe !< PES section of the data
128  real(kind=r4_kind), dimension(:,:), allocatable :: buf_r4_kind_pe !< PES section of the data
129  real(kind=r8_kind), dimension(:,:), allocatable :: buf_r8_kind_pe !< PES section of the data
130  integer(kind=i4_kind), dimension(:,:), allocatable :: buf_i4_kind !< Global section of the data
131  integer(kind=i8_kind), dimension(:,:), allocatable :: buf_i8_kind !< Global section of the data
132  real(kind=r4_kind), dimension(:,:), allocatable :: buf_r4_kind !< Global section of the data
133  real(kind=r8_kind), dimension(:,:), allocatable :: buf_r8_kind !< Global section of the data
134  class(*), dimension(:,:,:,:), pointer :: vdata_dummy !< Vdata remapped as 4D
135 
136  if (.not. is_variable_domain_decomposed(fileobj, variable_name, .true., &
137  xdim_index, ydim_index, xpos, ypos)) then
138  call netcdf_read_data(fileobj, variable_name, vdata, &
139  unlim_dim_level=unlim_dim_level, corner=corner, &
140  edge_lengths=edge_lengths, broadcast=.true.)
141  return
142  endif
143 
144  call domain_offsets(size(vdata, xdim_index), size(vdata, ydim_index), fileobj%domain, &
145  xpos, ypos, isd, isc, xc_size, jsd, jsc, yc_size, buffer_includes_halos, &
146  msg="file:"//trim(fileobj%path)//" and variable:"//trim(variable_name))
147 
148  if (fileobj%use_netcdf_mpi) then
149  c = 1
150  e = shape(vdata)
151 
152  if (buffer_includes_halos) then
153  c(xdim_index) = isd
154  c(ydim_index) = jsd
155  e(xdim_index) = xc_size + 2*(isc - isd)
156  e(ydim_index) = yc_size + 2*(jsc - jsd)
157  else
158  c(xdim_index) = isc
159  c(ydim_index) = jsc
160  e(xdim_index) = xc_size
161  e(ydim_index) = yc_size
162  endif
163 
164  call netcdf_read_data(fileobj, variable_name, vdata, unlim_dim_level=unlim_dim_level, corner=c, edge_lengths=e)
165  return
166  endif
167 
168  io_domain => mpp_get_io_domain(fileobj%domain)
169  c(:) = 1
170  e(:) = shape(vdata)
171 
172  call mpp_get_global_domain(io_domain, xbegin=xgbegin, xsize=xgsize, position=xpos)
173  call mpp_get_global_domain(io_domain, ybegin=ygbegin, ysize=ygsize, position=ypos)
174 
175  !I/O root reads in the data and scatters it.
176  if (fileobj%is_root) then
177 
178  if (fileobj%adjust_indices) then
179  !< If the file is distributed, the file only contains the io global domain
180  c(xdim_index) = 1
181  c(ydim_index) = 1
182  else
183  !< If the file is not distributed read, the file contains the global domain,
184  !! so you only need to read the global io domain
185  c(xdim_index) = xgbegin
186  c(ydim_index) = ygbegin
187  endif
188 
189  e(xdim_index) = xgsize
190  e(ydim_index) = ygsize
191 
192  !Read in the global io domain
193  select type(vdata)
194  type is (integer(kind=i4_kind))
195  call allocate_array(buf_i4_kind, e)
196  call netcdf_read_data(fileobj, variable_name, buf_i4_kind, &
197  unlim_dim_level=unlim_dim_level, &
198  corner=c, edge_lengths=e, broadcast=.false.)
199  type is (integer(kind=i8_kind))
200  call allocate_array(buf_i8_kind, e)
201  call netcdf_read_data(fileobj, variable_name, buf_i8_kind, &
202  unlim_dim_level=unlim_dim_level, &
203  corner=c, edge_lengths=e, broadcast=.false.)
204  type is (real(kind=r4_kind))
205  call allocate_array(buf_r4_kind, e)
206  call netcdf_read_data(fileobj, variable_name, buf_r4_kind, &
207  unlim_dim_level=unlim_dim_level, &
208  corner=c, edge_lengths=e, broadcast=.false.)
209  type is (real(kind=r8_kind))
210  call allocate_array(buf_r8_kind, e)
211  call netcdf_read_data(fileobj, variable_name, buf_r8_kind, &
212  unlim_dim_level=unlim_dim_level, &
213  corner=c, edge_lengths=e, broadcast=.false.)
214  class default
215  call error("unsupported variable type: domain_read_2d: file: "//trim(fileobj%path)//" variable:"// &
216  & trim(variable_name))
217  end select
218 
219  endif
220 
221  c = 1
222  e = shape(vdata)
223 
224  if (buffer_includes_halos) then
225  !Adjust if the input buffer has room for halos.
226  c(xdim_index) = isc - isd + 1
227  c(ydim_index) = jsc - jsd + 1
228  else
229  c(xdim_index) = 1
230  c(ydim_index) = 1
231  endif
232 
233  e(xdim_index) = xc_size
234  e(ydim_index) = yc_size
235 
236  dim_order = (/xdim_index, ydim_index/)
237 
238  select type(vdata)
239  type is (integer(kind=i4_kind))
240  call allocate_array(buf_i4_kind_pe, e)
241  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, fileobj%pelist, &
242  buf_i4_kind_pe, buf_i4_kind, dim_order, fileobj%is_root)
243  call put_array_section(buf_i4_kind_pe, vdata, c, e)
244  deallocate(buf_i4_kind_pe)
245  type is (integer(kind=i8_kind))
246  call allocate_array(buf_i8_kind_pe, e)
247  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, fileobj%pelist, &
248  buf_i8_kind_pe, buf_i8_kind, dim_order, fileobj%is_root)
249  call put_array_section(buf_i8_kind_pe, vdata, c, e)
250  deallocate(buf_i8_kind_pe)
251  type is (real(kind=r4_kind))
252  call allocate_array(buf_r4_kind_pe, e)
253  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, fileobj%pelist, &
254  buf_r4_kind_pe, buf_r4_kind, dim_order, fileobj%is_root)
255  call put_array_section(buf_r4_kind_pe, vdata, c, e)
256  deallocate(buf_r4_kind_pe)
257  type is (real(kind=r8_kind))
258  call allocate_array(buf_r8_kind_pe, e)
259  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, fileobj%pelist, &
260  buf_r8_kind_pe, buf_r8_kind, dim_order, fileobj%is_root)
261  call put_array_section(buf_r8_kind_pe, vdata, c, e)
262  deallocate(buf_r8_kind_pe)
263  class default
264  call error("unsupported variable type: domain_read_2d: file: "//trim(fileobj%path)//" variable:"// &
265  & trim(variable_name))
266  end select
267 
268  if (fileobj%is_root) then
269  if (allocated(buf_i4_kind)) deallocate(buf_i4_kind)
270  if (allocated(buf_i8_kind)) deallocate(buf_i8_kind)
271  if (allocated(buf_r4_kind)) deallocate(buf_r4_kind)
272  if (allocated(buf_r8_kind)) deallocate(buf_r8_kind)
273  endif
274 end subroutine domain_read_2d
275 
276 
277 !> @brief I/O domain root reads in a domain decomposed variable at a
278 !! specific unlimited dimension level and scatters the data to the
279 !! rest of the ranks using its I/O compute domain indices. This
280 !! routine may only be used with variables that are "domain
281 !! decomposed".
282 subroutine domain_read_3d(fileobj, variable_name, vdata, unlim_dim_level, &
283  corner, edge_lengths)
284  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
285  character(len=*), intent(in) :: variable_name !< Variable name.
286  class(*), contiguous, target, intent(inout) :: vdata(:,:,:) !< Data that will
287  !! be read out
288  !! to the netcdf file.
289  integer, intent(in), optional :: unlim_dim_level !< Level for the unlimited
290  !! dimension.
291  integer, dimension(3), intent(in), optional :: corner !< Array of starting
292  !! indices describing
293  !! where the data
294  !! will be read to.
295  integer, dimension(3), intent(in), optional :: edge_lengths !< The number of
296  !! elements that
297  !! will be read
298  !! in each dimension.
299 
300  integer :: xdim_index !< The index of the variable that is the x dimension
301  integer :: ydim_index !< The index of the variable that is the y dimension
302  integer :: zdim_index !< The index of the variable that is the z dimension
303  integer :: xpos !< The position of the x axis
304  integer :: ypos !< The position of the y axis
305  integer :: i !< For do loops
306  integer :: isd !< The starting x position of the data io_domain
307  integer :: isc !< The starting x position of the compute io_domain
308  integer :: xc_size !< The size of the x compute io_domain
309  integer :: yc_size !< The size of the y compute io_domain
310  integer :: jsd !< The ending x position of the data io_domain
311  integer :: jsc !< The ending y position of the compute io_domain
312  integer :: c(3) !< The corners of the data
313  integer :: e(3) !< The number of points (edges)
314  logical :: buffer_includes_halos !< .True. if vdata includes halo points
315  integer :: xgbegin !< Starting x index of global io domain
316  integer :: xgsize !< Size of global x io domain
317  integer :: ygbegin !< Starting y index of global io domain
318  integer :: ygsize !< Size of global y io domain
319  integer :: dim_order(3) !< Order of the dimensions
320  type(domain2d), pointer :: io_domain !< pointer to the io_domain
321 
322  !< The global data is only allocated by the io root PEs
323  integer(kind=i4_kind), dimension(:,:,:), allocatable :: buf_i4_kind_pe !< PES section of the data
324  integer(kind=i8_kind), dimension(:,:,:), allocatable :: buf_i8_kind_pe !< PES section of the data
325  real(kind=r4_kind), dimension(:,:,:), allocatable :: buf_r4_kind_pe !< PES section of the data
326  real(kind=r8_kind), dimension(:,:,:), allocatable :: buf_r8_kind_pe !< PES section of the data
327  integer(kind=i4_kind), dimension(:,:,:), allocatable :: buf_i4_kind !< Global section of the data
328  integer(kind=i8_kind), dimension(:,:,:), allocatable :: buf_i8_kind !< Global section of the data
329  real(kind=r4_kind), dimension(:,:,:), allocatable :: buf_r4_kind !< Global section of the data
330  real(kind=r8_kind), dimension(:,:,:), allocatable :: buf_r8_kind !< Global section of the data
331  class(*), dimension(:,:,:,:), pointer :: vdata_dummy !< Vdata remapped as 4D
332 
333  if (.not. is_variable_domain_decomposed(fileobj, variable_name, .true., &
334  xdim_index, ydim_index, xpos, ypos)) then
335  call netcdf_read_data(fileobj, variable_name, vdata, &
336  unlim_dim_level=unlim_dim_level, corner=corner, &
337  edge_lengths=edge_lengths, broadcast=.true.)
338  return
339  endif
340 
341  call domain_offsets(size(vdata, xdim_index), size(vdata, ydim_index), fileobj%domain, &
342  xpos, ypos, isd, isc, xc_size, jsd, jsc, yc_size, buffer_includes_halos, &
343  msg="file:"//trim(fileobj%path)//" and variable:"//trim(variable_name))
344 
345  if (fileobj%use_netcdf_mpi) then
346  c = 1
347  e = shape(vdata)
348 
349  if (buffer_includes_halos) then
350  c(xdim_index) = isd
351  c(ydim_index) = jsd
352  e(xdim_index) = xc_size + 2*(isc - isd)
353  e(ydim_index) = yc_size + 2*(jsc - jsd)
354  else
355  c(xdim_index) = isc
356  c(ydim_index) = jsc
357  e(xdim_index) = xc_size
358  e(ydim_index) = yc_size
359  endif
360 
361  call netcdf_read_data(fileobj, variable_name, vdata, unlim_dim_level=unlim_dim_level, corner=c, edge_lengths=e)
362  return
363  endif
364 
365  io_domain => mpp_get_io_domain(fileobj%domain)
366  c(:) = 1
367  if (present(corner)) c = corner
368 
369  e(:) = shape(vdata)
370  if (present(edge_lengths)) e = edge_lengths
371 
372  call mpp_get_global_domain(io_domain, xbegin=xgbegin, xsize=xgsize, position=xpos)
373  call mpp_get_global_domain(io_domain, ybegin=ygbegin, ysize=ygsize, position=ypos)
374 
375  !I/O root reads in the data and scatters it.
376  if (fileobj%is_root) then
377 
378  if (fileobj%adjust_indices) then
379  !< If the file is distributed, the file only contains the io global domain
380  c(xdim_index) = 1
381  c(ydim_index) = 1
382  else
383  !< If the file is not distributed read, the file contains the global domain,
384  !! so you only need to read the global io domain
385  c(xdim_index) = xgbegin
386  c(ydim_index) = ygbegin
387  endif
388 
389  e(xdim_index) = xgsize
390  e(ydim_index) = ygsize
391 
392  !Read in the global io domain
393  select type(vdata)
394  type is (integer(kind=i4_kind))
395  call allocate_array(buf_i4_kind, e)
396  call netcdf_read_data(fileobj, variable_name, buf_i4_kind, &
397  unlim_dim_level=unlim_dim_level, &
398  corner=c, edge_lengths=e, broadcast=.false.)
399  type is (integer(kind=i8_kind))
400  call allocate_array(buf_i8_kind, e)
401  call netcdf_read_data(fileobj, variable_name, buf_i8_kind, &
402  unlim_dim_level=unlim_dim_level, &
403  corner=c, edge_lengths=e, broadcast=.false.)
404  type is (real(kind=r4_kind))
405  call allocate_array(buf_r4_kind, e)
406  call netcdf_read_data(fileobj, variable_name, buf_r4_kind, &
407  unlim_dim_level=unlim_dim_level, &
408  corner=c, edge_lengths=e, broadcast=.false.)
409  type is (real(kind=r8_kind))
410  call allocate_array(buf_r8_kind, e)
411  call netcdf_read_data(fileobj, variable_name, buf_r8_kind, &
412  unlim_dim_level=unlim_dim_level, &
413  corner=c, edge_lengths=e, broadcast=.false.)
414  class default
415  call error("unsupported variable type: domain_read_2d: file: "//trim(fileobj%path)//" variable:"// &
416  & trim(variable_name))
417  end select
418 
419  endif
420 
421  c = 1
422  e = shape(vdata)
423 
424  if (buffer_includes_halos) then
425  !Adjust if the input buffer has room for halos.
426  c(xdim_index) = isc - isd + 1
427  c(ydim_index) = jsc - jsd + 1
428  else
429  c(xdim_index) = 1
430  c(ydim_index) = 1
431  endif
432 
433  e(xdim_index) = xc_size
434  e(ydim_index) = yc_size
435 
436  ! Calculate the index of the z dimension
437  zdim_index = 6 - xdim_index - ydim_index
438 
439  dim_order = (/xdim_index, ydim_index, zdim_index/)
440 
441  select type(vdata)
442  type is (integer(kind=i4_kind))
443  call allocate_array(buf_i4_kind_pe, e)
444  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, e(zdim_index), &
445  fileobj%pelist, buf_i4_kind_pe, buf_i4_kind, dim_order, fileobj%is_root)
446  call put_array_section(buf_i4_kind_pe, vdata, c, e)
447  deallocate(buf_i4_kind_pe)
448  type is (integer(kind=i8_kind))
449  call allocate_array(buf_i8_kind_pe, e)
450  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, e(zdim_index), &
451  fileobj%pelist, buf_i8_kind_pe, buf_i8_kind, dim_order, fileobj%is_root)
452  call put_array_section(buf_i8_kind_pe, vdata, c, e)
453  deallocate(buf_i8_kind_pe)
454  type is (real(kind=r4_kind))
455  call allocate_array(buf_r4_kind_pe, e)
456  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, e(zdim_index), &
457  fileobj%pelist, buf_r4_kind_pe, buf_r4_kind, dim_order, fileobj%is_root)
458  call put_array_section(buf_r4_kind_pe, vdata, c, e)
459  deallocate(buf_r4_kind_pe)
460  type is (real(kind=r8_kind))
461  call allocate_array(buf_r8_kind_pe, e)
462  call mpp_scatter(isc-xgbegin+1, isc+xc_size-xgbegin, jsc-ygbegin+1, jsc+yc_size-ygbegin, e(zdim_index), &
463  fileobj%pelist, buf_r8_kind_pe, buf_r8_kind, dim_order, fileobj%is_root)
464  call put_array_section(buf_r8_kind_pe, vdata, c, e)
465  deallocate(buf_r8_kind_pe)
466  class default
467  call error("unsupported variable type: domain_read_2d: file: "//trim(fileobj%path)//" variable:"// &
468  & trim(variable_name))
469  end select
470 
471  if (fileobj%is_root) then
472  if (allocated(buf_i4_kind)) deallocate(buf_i4_kind)
473  if (allocated(buf_i8_kind)) deallocate(buf_i8_kind)
474  if (allocated(buf_r4_kind)) deallocate(buf_r4_kind)
475  if (allocated(buf_r8_kind)) deallocate(buf_r8_kind)
476  endif
477 
478 end subroutine domain_read_3d
479 
480 
481 !> @brief I/O domain root reads in a domain decomposed variable at a
482 !! specific unlimited dimension level and scatters the data to the
483 !! rest of the ranks using its I/O compute domain indices. This
484 !! routine may only be used with variables that are "domain
485 !! decomposed".
486 subroutine domain_read_4d(fileobj, variable_name, vdata, unlim_dim_level, &
487  corner, edge_lengths)
488 
489  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
490  character(len=*), intent(in) :: variable_name !< Variable name.
491  class(*), dimension(:,:,:,:), intent(inout) :: vdata !< Data that will
492  !! be read out
493  !! to the netcdf file.
494  integer, intent(in), optional :: unlim_dim_level !< Level for the unlimited
495  !! dimension.
496  integer, dimension(4), intent(in), optional :: corner !< Array of starting
497  !! indices describing
498  !! where the data
499  !! will be read to.
500  integer, dimension(4), intent(in), optional :: edge_lengths !< The number of
501  !! elements that
502  !! will be read
503  !! in each dimension.
504 
505  integer :: xdim_index
506  integer :: ydim_index
507  type(domain2d), pointer :: io_domain
508  integer :: xpos
509  integer :: ypos
510  integer :: i
511  integer :: isd
512  integer :: isc
513  integer :: xc_size
514  integer :: jsd
515  integer :: jsc
516  integer :: yc_size
517  integer, dimension(:), allocatable :: pe_isc
518  integer, dimension(:), allocatable :: pe_icsize
519  integer, dimension(:), allocatable :: pe_jsc
520  integer, dimension(:), allocatable :: pe_jcsize
521  integer, dimension(4) :: c
522  integer, dimension(4) :: e
523  integer(kind=i4_kind), dimension(:,:,:,:), allocatable :: buf_i4_kind
524  integer(kind=i8_kind), dimension(:,:,:,:), allocatable :: buf_i8_kind
525  real(kind=r4_kind), dimension(:,:,:,:), allocatable :: buf_r4_kind
526  real(kind=r8_kind), dimension(:,:,:,:), allocatable :: buf_r8_kind
527  logical :: buffer_includes_halos
528  integer :: xgmin !< Starting x index of global io domain
529  integer :: ygmin !< Starting y index of global io domain
530 
531  if (.not. is_variable_domain_decomposed(fileobj, variable_name, .true., &
532  xdim_index, ydim_index, xpos, ypos)) then
533  call netcdf_read_data(fileobj, variable_name, vdata, &
534  unlim_dim_level=unlim_dim_level, corner=corner, &
535  edge_lengths=edge_lengths, broadcast=.true.)
536  return
537  endif
538 
539  call domain_offsets(size(vdata, xdim_index), size(vdata, ydim_index), fileobj%domain, &
540  xpos, ypos, isd, isc, xc_size, jsd, jsc, yc_size, buffer_includes_halos, &
541  msg="file:"//trim(fileobj%path)//" and variable:"//trim(variable_name))
542 
543  if (fileobj%use_netcdf_mpi) then
544  c = 1
545  e = shape(vdata)
546 
547  if (buffer_includes_halos) then
548  c(xdim_index) = isd
549  c(ydim_index) = jsd
550  e(xdim_index) = xc_size + 2*(isc - isd)
551  e(ydim_index) = yc_size + 2*(jsc - jsd)
552  else
553  c(xdim_index) = isc
554  c(ydim_index) = jsc
555  e(xdim_index) = xc_size
556  e(ydim_index) = yc_size
557  endif
558 
559  call netcdf_read_data(fileobj, variable_name, vdata, unlim_dim_level=unlim_dim_level, corner=c, edge_lengths=e)
560  return
561  endif
562 
563  io_domain => mpp_get_io_domain(fileobj%domain)
564  c(:) = 1
565  e(:) = shape(vdata)
566  if (present(edge_lengths)) e = edge_lengths
567 
568  !I/O root reads in the data and scatters it.
569  if (fileobj%is_root) then
570  allocate(pe_isc(size(fileobj%pelist)))
571  allocate(pe_icsize(size(fileobj%pelist)))
572  allocate(pe_jsc(size(fileobj%pelist)))
573  allocate(pe_jcsize(size(fileobj%pelist)))
574  call mpp_get_compute_domains(io_domain, xbegin=pe_isc, xsize=pe_icsize, position=xpos)
575  call mpp_get_compute_domains(io_domain, ybegin=pe_jsc, ysize=pe_jcsize, position=ypos)
576  call mpp_get_global_domain(io_domain, xbegin=xgmin, position=xpos)
577  call mpp_get_global_domain(io_domain, ybegin=ygmin, position=ypos)
578  do i = 1, size(fileobj%pelist)
579  if (present(corner)) c = corner
580  c(xdim_index) = pe_isc(i)
581  c(ydim_index) = pe_jsc(i)
582  if (fileobj%adjust_indices) then
583  c(xdim_index) = c(xdim_index) - xgmin + 1
584  c(ydim_index) = c(ydim_index) - ygmin + 1
585  endif
586  e(xdim_index) = pe_icsize(i)
587  e(ydim_index) = pe_jcsize(i)
588  select type(vdata)
589  type is (integer(kind=i4_kind))
590  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
591  call allocate_array(buf_i4_kind, e)
592  call netcdf_read_data(fileobj, variable_name, buf_i4_kind, &
593  unlim_dim_level=unlim_dim_level, &
594  corner=c, edge_lengths=e, broadcast=.false.)
595  if (i .eq. 1) then
596  !Root rank stores data directly.
597  c = 1
598  if (buffer_includes_halos) then
599  !Adjust if the input buffer has room for halos.
600  c(xdim_index) = isc - isd + 1
601  c(ydim_index) = jsc - jsd + 1
602  endif
603  call put_array_section(buf_i4_kind, vdata, c, e)
604  else
605  !Send data to non-root ranks.
606  call mpp_send(buf_i4_kind, size(buf_i4_kind), fileobj%pelist(i))
607  call mpp_sync_self(check=event_send)
608  endif
609  deallocate(buf_i4_kind)
610  type is (integer(kind=i8_kind))
611  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
612  call allocate_array(buf_i8_kind, e)
613  call netcdf_read_data(fileobj, variable_name, buf_i8_kind, &
614  unlim_dim_level=unlim_dim_level, &
615  corner=c, edge_lengths=e, broadcast=.false.)
616  if (i .eq. 1) then
617  !Root rank stores data directly.
618  c = 1
619  if (buffer_includes_halos) then
620  !Adjust if the input buffer has room for halos.
621  c(xdim_index) = isc - isd + 1
622  c(ydim_index) = jsc - jsd + 1
623  endif
624  call put_array_section(buf_i8_kind, vdata, c, e)
625  else
626  !Send data to non-root ranks.
627  call mpp_send(buf_i8_kind, size(buf_i8_kind), fileobj%pelist(i))
628  call mpp_sync_self(check=event_send)
629  endif
630  deallocate(buf_i8_kind)
631  type is (real(kind=r4_kind))
632  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
633  call allocate_array(buf_r4_kind, e)
634  call netcdf_read_data(fileobj, variable_name, buf_r4_kind, &
635  unlim_dim_level=unlim_dim_level, &
636  corner=c, edge_lengths=e, broadcast=.false.)
637  if (i .eq. 1) then
638  !Root rank stores data directly.
639  c = 1
640  if (buffer_includes_halos) then
641  !Adjust if the input buffer has room for halos.
642  c(xdim_index) = isc - isd + 1
643  c(ydim_index) = jsc - jsd + 1
644  endif
645  call put_array_section(buf_r4_kind, vdata, c, e)
646  else
647  !Send data to non-root ranks.
648  call mpp_send(buf_r4_kind, size(buf_r4_kind), fileobj%pelist(i))
649  call mpp_sync_self(check=event_send)
650  endif
651  deallocate(buf_r4_kind)
652  type is (real(kind=r8_kind))
653  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
654  call allocate_array(buf_r8_kind, e)
655  call netcdf_read_data(fileobj, variable_name, buf_r8_kind, &
656  unlim_dim_level=unlim_dim_level, &
657  corner=c, edge_lengths=e, broadcast=.false.)
658  if (i .eq. 1) then
659  !Root rank stores data directly.
660  c = 1
661  if (buffer_includes_halos) then
662  !Adjust if the input buffer has room for halos.
663  c(xdim_index) = isc - isd + 1
664  c(ydim_index) = jsc - jsd + 1
665  endif
666  call put_array_section(buf_r8_kind, vdata, c, e)
667  else
668  !Send data to non-root ranks.
669  call mpp_send(buf_r8_kind, size(buf_r8_kind), fileobj%pelist(i))
670  call mpp_sync_self(check=event_send)
671  endif
672  deallocate(buf_r8_kind)
673  class default
674  call error("unsupported variable type: domain_read_4d: file: "//trim(fileobj%path)//" variable:"// &
675  & trim(variable_name))
676  end select
677  enddo
678  deallocate(pe_isc)
679  deallocate(pe_icsize)
680  deallocate(pe_jsc)
681  deallocate(pe_jcsize)
682  else
683  c = 1
684  if (buffer_includes_halos) then
685  c(xdim_index) = isc - isd + 1
686  c(ydim_index) = jsc - jsd + 1
687  endif
688  e(xdim_index) = xc_size
689  e(ydim_index) = yc_size
690  select type(vdata)
691  type is (integer(kind=i4_kind))
692  call allocate_array(buf_i4_kind, e)
693  call mpp_recv(buf_i4_kind, size(buf_i4_kind), fileobj%io_root, block=.true.)
694  call put_array_section(buf_i4_kind, vdata, c, e)
695  deallocate(buf_i4_kind)
696  type is (integer(kind=i8_kind))
697  call allocate_array(buf_i8_kind, e)
698  call mpp_recv(buf_i8_kind, size(buf_i8_kind), fileobj%io_root, block=.true.)
699  call put_array_section(buf_i8_kind, vdata, c, e)
700  deallocate(buf_i8_kind)
701  type is (real(kind=r4_kind))
702  call allocate_array(buf_r4_kind, e)
703  call mpp_recv(buf_r4_kind, size(buf_r4_kind), fileobj%io_root, block=.true.)
704  call put_array_section(buf_r4_kind, vdata, c, e)
705  deallocate(buf_r4_kind)
706  type is (real(kind=r8_kind))
707  call allocate_array(buf_r8_kind, e)
708  call mpp_recv(buf_r8_kind, size(buf_r8_kind), fileobj%io_root, block=.true.)
709  call put_array_section(buf_r8_kind, vdata, c, e)
710  deallocate(buf_r8_kind)
711  class default
712  call error("unsupported variable type: domain_read_4d: file: "//trim(fileobj%path)//" variable:"// &
713  & trim(variable_name))
714  end select
715  endif
716 end subroutine domain_read_4d
717 
718 
719 !> @brief I/O domain root reads in a domain decomposed variable at a
720 !! specific unlimited dimension level and scatters the data to the
721 !! rest of the ranks using its I/O compute domain indices. This
722 !! routine may only be used with variables that are "domain
723 !! decomposed".
724 subroutine domain_read_5d(fileobj, variable_name, vdata, unlim_dim_level, &
725  corner, edge_lengths)
726 
727  type(fmsnetcdfdomainfile_t), intent(in) :: fileobj !< File object.
728  character(len=*), intent(in) :: variable_name !< Variable name.
729  class(*), dimension(:,:,:,:,:), intent(inout) :: vdata !< Data that will
730  !! be read out
731  !! to the netcdf file.
732  integer, intent(in), optional :: unlim_dim_level !< Level for the unlimited
733  !! dimension.
734  integer, dimension(5), intent(in), optional :: corner !< Array of starting
735  !! indices describing
736  !! where the data
737  !! will be read to.
738  integer, dimension(5), intent(in), optional :: edge_lengths !< The number of
739  !! elements that
740  !! will be read
741  !! in each dimension.
742 
743  integer :: xdim_index
744  integer :: ydim_index
745  type(domain2d), pointer :: io_domain
746  integer :: xpos
747  integer :: ypos
748  integer :: i
749  integer :: isd
750  integer :: isc
751  integer :: xc_size
752  integer :: jsd
753  integer :: jsc
754  integer :: yc_size
755  integer, dimension(:), allocatable :: pe_isc
756  integer, dimension(:), allocatable :: pe_icsize
757  integer, dimension(:), allocatable :: pe_jsc
758  integer, dimension(:), allocatable :: pe_jcsize
759  integer, dimension(5) :: c
760  integer, dimension(5) :: e
761  integer(kind=i4_kind), dimension(:,:,:,:,:), allocatable :: buf_i4_kind
762  integer(kind=i8_kind), dimension(:,:,:,:,:), allocatable :: buf_i8_kind
763  real(kind=r4_kind), dimension(:,:,:,:,:), allocatable :: buf_r4_kind
764  real(kind=r8_kind), dimension(:,:,:,:,:), allocatable :: buf_r8_kind
765  logical :: buffer_includes_halos
766  integer :: xgmin !< Starting x index of global io domain
767  integer :: ygmin !< Starting y index of global io domain
768 
769  if (.not. is_variable_domain_decomposed(fileobj, variable_name, .true., &
770  xdim_index, ydim_index, xpos, ypos)) then
771  call netcdf_read_data(fileobj, variable_name, vdata, &
772  unlim_dim_level=unlim_dim_level, corner=corner, &
773  edge_lengths=edge_lengths, broadcast=.true.)
774  return
775  endif
776 
777  call domain_offsets(size(vdata, xdim_index), size(vdata, ydim_index), fileobj%domain, &
778  xpos, ypos, isd, isc, xc_size, jsd, jsc, yc_size, buffer_includes_halos, &
779  msg="file:"//trim(fileobj%path)//" and variable:"//trim(variable_name))
780 
781  if (fileobj%use_netcdf_mpi) then
782  c = 1
783  e = shape(vdata)
784 
785  if (buffer_includes_halos) then
786  c(xdim_index) = isd
787  c(ydim_index) = jsd
788  e(xdim_index) = xc_size + 2*(isc - isd)
789  e(ydim_index) = yc_size + 2*(jsc - jsd)
790  else
791  c(xdim_index) = isc
792  c(ydim_index) = jsc
793  e(xdim_index) = xc_size
794  e(ydim_index) = yc_size
795  endif
796 
797  call netcdf_read_data(fileobj, variable_name, vdata, unlim_dim_level=unlim_dim_level, corner=c, edge_lengths=e)
798  return
799  endif
800 
801  io_domain => mpp_get_io_domain(fileobj%domain)
802  c(:) = 1
803  e(:) = shape(vdata)
804  if (present(edge_lengths)) e = edge_lengths
805 
806  !I/O root reads in the data and scatters it.
807  if (fileobj%is_root) then
808  allocate(pe_isc(size(fileobj%pelist)))
809  allocate(pe_icsize(size(fileobj%pelist)))
810  allocate(pe_jsc(size(fileobj%pelist)))
811  allocate(pe_jcsize(size(fileobj%pelist)))
812  call mpp_get_compute_domains(io_domain, xbegin=pe_isc, xsize=pe_icsize, position=xpos)
813  call mpp_get_compute_domains(io_domain, ybegin=pe_jsc, ysize=pe_jcsize, position=ypos)
814  call mpp_get_global_domain(io_domain, xbegin=xgmin, position=xpos)
815  call mpp_get_global_domain(io_domain, ybegin=ygmin, position=ypos)
816  do i = 1, size(fileobj%pelist)
817  !Calculate the indices of the domain-decomposed chunk relative to its position in the file.
818  if (present(corner)) c = corner
819  c(xdim_index) = pe_isc(i)
820  c(ydim_index) = pe_jsc(i)
821  if (fileobj%adjust_indices) then
822  c(xdim_index) = c(xdim_index) - xgmin + 1
823  c(ydim_index) = c(ydim_index) - ygmin + 1
824  endif
825  e(xdim_index) = pe_icsize(i)
826  e(ydim_index) = pe_jcsize(i)
827  select type(vdata)
828  type is (integer(kind=i4_kind))
829  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
830  call allocate_array(buf_i4_kind, e)
831  call netcdf_read_data(fileobj, variable_name, buf_i4_kind, &
832  unlim_dim_level=unlim_dim_level, &
833  corner=c, edge_lengths=e, broadcast=.false.)
834  if (i .eq. 1) then
835  !Root rank stores data directly. Re-adjust the indicies relative
836  !to the input buffer vdata.
837  c = 1
838  if (buffer_includes_halos) then
839  !Adjust if the input buffer has room for halos.
840  c(xdim_index) = isc - isd + 1
841  c(ydim_index) = jsc - jsd + 1
842  endif
843  call put_array_section(buf_i4_kind, vdata, c, e)
844  else
845  !Send data to non-root ranks.
846  call mpp_send(buf_i4_kind, size(buf_i4_kind), fileobj%pelist(i))
847  call mpp_sync_self(check=event_send)
848  endif
849  deallocate(buf_i4_kind)
850  type is (integer(kind=i8_kind))
851  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
852  call allocate_array(buf_i8_kind, e)
853  call netcdf_read_data(fileobj, variable_name, buf_i8_kind, &
854  unlim_dim_level=unlim_dim_level, &
855  corner=c, edge_lengths=e, broadcast=.false.)
856  if (i .eq. 1) then
857  !Root rank stores data directly.
858  c = 1
859  if (buffer_includes_halos) then
860  !Adjust if the input buffer has room for halos.
861  c(xdim_index) = isc - isd + 1
862  c(ydim_index) = jsc - jsd + 1
863  endif
864  call put_array_section(buf_i8_kind, vdata, c, e)
865  else
866  !Send data to non-root ranks.
867  call mpp_send(buf_i8_kind, size(buf_i8_kind), fileobj%pelist(i))
868  call mpp_sync_self(check=event_send)
869  endif
870  deallocate(buf_i8_kind)
871  type is (real(kind=r4_kind))
872  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
873  call allocate_array(buf_r4_kind, e)
874  call netcdf_read_data(fileobj, variable_name, buf_r4_kind, &
875  unlim_dim_level=unlim_dim_level, &
876  corner=c, edge_lengths=e, broadcast=.false.)
877  if (i .eq. 1) then
878  !Root rank stores data directly.
879  c = 1
880  if (buffer_includes_halos) then
881  !Adjust if the input buffer has room for halos.
882  c(xdim_index) = isc - isd + 1
883  c(ydim_index) = jsc - jsd + 1
884  endif
885  call put_array_section(buf_r4_kind, vdata, c, e)
886  else
887  !Send data to non-root ranks.
888  call mpp_send(buf_r4_kind, size(buf_r4_kind), fileobj%pelist(i))
889  call mpp_sync_self(check=event_send)
890  endif
891  deallocate(buf_r4_kind)
892  type is (real(kind=r8_kind))
893  !Read in the data for fileobj%pelist(i)'s portion of the compute domain.
894  call allocate_array(buf_r8_kind, e)
895  call netcdf_read_data(fileobj, variable_name, buf_r8_kind, &
896  unlim_dim_level=unlim_dim_level, &
897  corner=c, edge_lengths=e, broadcast=.false.)
898  if (i .eq. 1) then
899  !Root rank stores data directly.
900  c = 1
901  if (buffer_includes_halos) then
902  !Adjust if the input buffer has room for halos.
903  c(xdim_index) = isc - isd + 1
904  c(ydim_index) = jsc - jsd + 1
905  endif
906  call put_array_section(buf_r8_kind, vdata, c, e)
907  else
908  !Send data to non-root ranks.
909  call mpp_send(buf_r8_kind, size(buf_r8_kind), fileobj%pelist(i))
910  call mpp_sync_self(check=event_send)
911  endif
912  deallocate(buf_r8_kind)
913  class default
914  call error("unsupported variable type: domain_read_5d: file: "//trim(fileobj%path)//" variable:"// &
915  & trim(variable_name))
916  end select
917  enddo
918  deallocate(pe_isc)
919  deallocate(pe_icsize)
920  deallocate(pe_jsc)
921  deallocate(pe_jcsize)
922  else
923  c = 1
924  if (buffer_includes_halos) then
925  c(xdim_index) = isc - isd + 1
926  c(ydim_index) = jsc - jsd + 1
927  endif
928  e(xdim_index) = xc_size
929  e(ydim_index) = yc_size
930  select type(vdata)
931  type is (integer(kind=i4_kind))
932  call allocate_array(buf_i4_kind, e)
933  call mpp_recv(buf_i4_kind, size(buf_i4_kind), fileobj%io_root, block=.true.)
934  call put_array_section(buf_i4_kind, vdata, c, e)
935  deallocate(buf_i4_kind)
936  type is (integer(kind=i8_kind))
937  call allocate_array(buf_i8_kind, e)
938  call mpp_recv(buf_i8_kind, size(buf_i8_kind), fileobj%io_root, block=.true.)
939  call put_array_section(buf_i8_kind, vdata, c, e)
940  deallocate(buf_i8_kind)
941  type is (real(kind=r4_kind))
942  call allocate_array(buf_r4_kind, e)
943  call mpp_recv(buf_r4_kind, size(buf_r4_kind), fileobj%io_root, block=.true.)
944  call put_array_section(buf_r4_kind, vdata, c, e)
945  deallocate(buf_r4_kind)
946  type is (real(kind=r8_kind))
947  call allocate_array(buf_r8_kind, e)
948  call mpp_recv(buf_r8_kind, size(buf_r8_kind), fileobj%io_root, block=.true.)
949  call put_array_section(buf_r8_kind, vdata, c, e)
950  deallocate(buf_r8_kind)
951  class default
952  call error("unsupported variable type: domain_read_5d: file: "//trim(fileobj%path)//" variable:"// &
953  & trim(variable_name))
954  end select
955  endif
956 end subroutine domain_read_5d
957 !> @}
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_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 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...
type(domain2d) function, pointer mpp_get_io_domain(domain)
Set user stack size.
subroutine mpp_sync_self(pelist, check, request, msg_size, msg_type)
This is to check if current PE's outstanding puts are complete but we can't use shmem_fence because w...