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