FMS  2026.01.01-dev
Flexible Modeling System
gather_data_bc.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 Routines for the @ref gather_data_bc interface
20 
21 !> @addtogroup netcdf_io_mod
22 !> @{
23 
24 !> @brief gathers the 2d vdata from all of the relevant pes into the root_pe and saves it to a
25 !! buffer.
26 subroutine gather_data_bc_2d(fileobj, vdata, bc_info)
27  class(fmsnetcdffile_t), intent(inout) :: fileobj !< Fms2io netcdf fileobj
28  class(*), dimension(:,:), intent(in) :: vdata !< Data to be gather
29  type(bc_information), intent(inout) :: bc_info !< information about the boundary condition variable
30 
31  integer :: i_glob !< Size of the global domain in x
32  integer :: j_glob !< Size of the global domain in y
33 
34  integer :: isc, iec, jsc, jec !< current PE's indices
35  integer :: i1, i2, j1, j2 !< current PE's indices relative to the global domain
36  integer :: i_add, j_add !< current PE's shift
37 
38  real(kind=r4_kind), dimension(:,:), allocatable, target :: global_buf_r4_kind !< buffer with a data gathered
39  real(kind=r4_kind), dimension(:,:), allocatable, target :: local_buf_r4_kind !< current PEs data
40  real(kind=r8_kind), dimension(:,:), allocatable, target :: global_buf_r8_kind !< buffer with a data gathered
41  real(kind=r8_kind), dimension(:,:), allocatable, target :: local_buf_r8_kind !< current PEs data
42 
43  integer(kind=i8_kind) :: chksum_val !< Checksum value calculated from the gathered data
44  character(len=32) :: chksum !< Cheksum value converted to a string
45 
46  !> Set the indices
47  isc = bc_info%indices(1)
48  iec = bc_info%indices(2)
49  jsc = bc_info%indices(3)
50  jec = bc_info%indices(4)
51 
52  !> This is the section of the PE that will actually be added to the global_buffer
53  i1 = 1 + bc_info%x_halo
54  i2 = i1 + (iec-isc)
55  j1 = 1 + bc_info%y_halo
56  j2 = j1 + (jec-jsc)
57 
58  !> Set up index shifts for global array
59  i_add = bc_info%ishift
60  j_add = bc_info%jshift
61 
62  !> Only root allocates a global_buffer that will be written
63  if (fileobj%is_root) then
64  i_glob = bc_info%global_size(1)
65  j_glob = bc_info%global_size(2)
66  endif
67 
68  !> Gather the data and calculate the checksum for the resulting array.
69  select type(vdata)
70  type is (real(kind=r4_kind))
71  !> If the fileobj's root does not have data for this variable
72  if (fileobj%is_root .and. .not. bc_info%data_on_file_root) then
73  !> Allocate global_buf_r4_kind to be one size bigger, global_buf_r4_kind(i_glob+1,,:) is just dummy data
74  allocate(global_buf_r4_kind(i_glob+1, j_glob))
75  !> Allocate a temp local buffer to the fileobj's root. This is needed because the data needs to be send
76  !! to the fileobj's root, but because fileobj's root doesn't have any data, we just create dummy data and
77  !! not write it later
78  allocate(local_buf_r4_kind(1,1))
79  local_buf_r4_kind = 0.
80  isc = 1+i_glob; i_add=0; iec=1+i_glob; jsc=j_glob; j_add=0; jec=j_glob
81  i1=1; i2=1; j1=1; j2=1
82  else
83  !! In this case there is data in fileobj's root, so there is no need for the dummy data
84  if(fileobj%is_root) then
85  allocate(global_buf_r4_kind(i_glob, j_glob))
86  else
87  allocate(global_buf_r4_kind(1, 1))
88  endif
89  allocate(local_buf_r4_kind(size(vdata,1), size(vdata,2)))
90  local_buf_r4_kind = vdata
91  endif
92 
93  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, bc_info%pelist, &
94  local_buf_r4_kind(i1:i2,j1:j2), &
95  global_buf_r4_kind, fileobj%is_root)
96 
97  deallocate(local_buf_r4_kind)
98  !> If you are on fileobj's root, calculate the checksum and save the gathered data in a buffer
99  if (fileobj%is_root) then
100  chksum_val = mpp_chksum(global_buf_r4_kind(1:i_glob,1:j_glob), (/mpp_pe()/))
101  allocate(bc_info%globaldata2d_r4(i_glob, j_glob))
102  bc_info%globaldata2d_r4=global_buf_r4_kind(1:i_glob,1:j_glob)
103  deallocate(global_buf_r4_kind)
104  endif
105  type is (real(kind=r8_kind))
106  !> If the fileobj's root does not have data for this variable
107  if (fileobj%is_root .and. .not. bc_info%data_on_file_root) then
108  !> Allocate global_buf_r8_kind to be one size bigger, global_buf_r8_kind(i_glob+1,,:) is just dummy data
109  allocate(global_buf_r8_kind(i_glob+1, j_glob))
110  !> Allocate a temp local buffer to the fileobj's root. This is needed because the data needs to be send
111  !! to the fileobj's root, but because fileobj's root doesn't have any data, we just create dummy data and
112  !! not write it later
113  allocate(local_buf_r8_kind(1,1))
114  local_buf_r8_kind = 0.
115  isc = 1+i_glob; i_add=0; iec=1+i_glob; jsc=j_glob; j_add=0; jec=j_glob
116  i1=1; i2=1; j1=1; j2=1
117  else
118  !! In this case there is data in fileobj's root, so there is no need for the dummy data
119  if(fileobj%is_root) then
120  allocate(global_buf_r8_kind(i_glob, j_glob))
121  else
122  allocate(global_buf_r8_kind(1, 1))
123  endif
124  allocate(local_buf_r8_kind(size(vdata,1), size(vdata,2)))
125  local_buf_r8_kind = vdata
126  endif
127 
128  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, bc_info%pelist, &
129  local_buf_r8_kind(i1:i2,j1:j2), &
130  global_buf_r8_kind, fileobj%is_root)
131  deallocate(local_buf_r8_kind)
132  !> If you are on fileobj's root, calculate the checksum and save the gathered data in a buffer
133  if (fileobj%is_root) then
134  chksum_val = mpp_chksum(global_buf_r8_kind(1:i_glob,1:j_glob), (/mpp_pe()/))
135  allocate(bc_info%globaldata2d_r8(i_glob, j_glob))
136  bc_info%globaldata2d_r8=global_buf_r8_kind(1:i_glob,1:j_glob)
137  deallocate(global_buf_r8_kind)
138  endif
139  class default
140  call error("gather_data_bc_2d: unsupported type. Currently only r8_kind and r4_kinds are supported")
141  end select
142 
143  !> Save the checksum, so you can write it later
144  if (fileobj%is_root) then
145  chksum = ""
146  write(chksum, "(Z16)") chksum_val
147  bc_info%chksum = chksum
148  endif
149 
150 end subroutine gather_data_bc_2d
151 
152 !> @brief gathers the 2d vdata from all of the relevant pes into the root_pe and saves it to a
153 !! buffer.
154 subroutine gather_data_bc_3d(fileobj, vdata, bc_info)
155  class(fmsnetcdffile_t), intent(inout) :: fileobj !< Fms2io netcdf fileobj
156  class(*), dimension(:,:,:), intent(in) :: vdata !< Data to be gather
157  type(bc_information), intent(inout) :: bc_info !< information about the boundary condition variable
158 
159  integer :: i_glob !< Size of the global domain in x
160  integer :: j_glob !< Size of the global domain in y
161  integer :: k_glob !< Size of the z axis
162 
163  integer :: isc, iec, jsc, jec !< current PE's indices
164  integer :: i1, i2, j1, j2 !< current PE's indices relative to the global domain
165  integer :: i_add, j_add !< current PE's shift
166 
167  real(kind=r4_kind), dimension(:,:,:), allocatable, target :: global_buf_r4_kind !< buffer with a data gathered
168  real(kind=r4_kind), dimension(:,:,:), allocatable, target :: local_buf_r4_kind !< current PEs data
169  real(kind=r8_kind), dimension(:,:,:), allocatable, target :: global_buf_r8_kind !< buffer with a data gathered
170  real(kind=r8_kind), dimension(:,:,:), allocatable, target :: local_buf_r8_kind !< current PEs data
171 
172  integer(kind=i8_kind) :: chksum_val !< Checksum value calculated from the gathered data
173  character(len=32) :: chksum !< Cheksum value converted to a string
174 
175  !> Set the indices
176  isc = bc_info%indices(1)
177  iec = bc_info%indices(2)
178  jsc = bc_info%indices(3)
179  jec = bc_info%indices(4)
180 
181  !> This is the section of the PE that will actually be added to the global_buffer
182  i1 = 1 + bc_info%x_halo
183  i2 = i1 + (iec-isc)
184  j1 = 1 + bc_info%y_halo
185  j2 = j1 + (jec-jsc)
186 
187  !> Set up index shifts for global array
188  i_add = bc_info%ishift
189  j_add = bc_info%jshift
190 
191  !> Allocate a global_buffer that will be written
192  if (fileobj%is_root) then
193  i_glob = bc_info%global_size(1)
194  j_glob = bc_info%global_size(2)
195  endif
196 
197  k_glob=bc_info%global_size(3)
198  !> Gather the data and calculate the checksum for the resulting array.
199  select type(vdata)
200  type is (real(kind=r4_kind))
201  !> If the fileobj's root does not have data for this variable
202  if (fileobj%is_root .and. .not. bc_info%data_on_file_root) then
203  !> Allocate global_buf_r8_kind to be one size bigger, global_buf_r8_kind(i_glob+1,,:) is just dummy data
204  allocate(global_buf_r4_kind(i_glob+1, j_glob, bc_info%global_size(3)))
205  !> Allocate a temp local buffer to the fileobj's root. This is needed because the data needs to be send
206  !! to the fileobj's root, but because fileobj's root doesn't have any data, we just create dummy data and
207  !! not write it later
208  allocate(local_buf_r4_kind(1,1,1))
209  local_buf_r4_kind = 0.
210  isc = 1+i_glob; i_add=0; iec=1+i_glob; jsc=j_glob; j_add=0; jec=j_glob
211  i1=1; i2=1; j1=1; j2=1
212  else
213  !! In this case there is data in fileobj's root, so there is no need for the dummy data
214  if(fileobj%is_root) then
215  allocate(global_buf_r4_kind(i_glob, j_glob, k_glob))
216  else
217  allocate(global_buf_r4_kind(1, 1, 1))
218  endif
219  allocate(local_buf_r4_kind(size(vdata,1), size(vdata,2), size(vdata,3)))
220  local_buf_r4_kind = vdata
221  endif
222 
223  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, k_glob, bc_info%pelist, &
224  local_buf_r4_kind(i1:i2,j1:j2,:), &
225  global_buf_r4_kind, fileobj%is_root)
226  deallocate(local_buf_r4_kind)
227  !> If you are on fileobj's root, calculate the checksum and save the gathered data in a buffer
228  if (fileobj%is_root) then
229  chksum_val = mpp_chksum(global_buf_r4_kind(1:i_glob,1:j_glob, :), (/mpp_pe()/))
230  allocate(bc_info%globaldata3d_r4(i_glob, j_glob, bc_info%global_size(3)))
231  bc_info%globaldata3d_r4=global_buf_r4_kind(1:i_glob,1:j_glob,:)
232  deallocate(global_buf_r4_kind)
233  endif
234  type is (real(kind=r8_kind))
235  !> If the fileobj's root does not have data for this variable
236  if (fileobj%is_root .and. .not. bc_info%data_on_file_root) then
237  !> Allocate global_buf_r8_kind to be one size bigger, global_buf_r8_kind(i_glob+1,,:) is just dummy data
238  allocate(global_buf_r8_kind(i_glob+1, j_glob, bc_info%global_size(3)))
239  !> Allocate a temp local buffer to the fileobj's root. This is needed because the data needs to be send
240  !! to the fileobj's root, but because fileobj's root doesn't have any data, we just create dummy data and
241  !! not write it later
242  allocate(local_buf_r8_kind(1,1,1))
243  local_buf_r8_kind = 0.
244  isc = 1+i_glob; i_add=0; iec=1+i_glob; jsc=j_glob; j_add=0; jec=j_glob
245  i1=1; i2=1; j1=1; j2=1
246  else
247  !! In this case there is data in fileobj's root, so there is no need for the dummy data
248  if(fileobj%is_root) then
249  allocate(global_buf_r8_kind(i_glob, j_glob, k_glob))
250  else
251  allocate(global_buf_r8_kind(1, 1, 1))
252  endif
253  allocate(local_buf_r8_kind(size(vdata,1), size(vdata,2), size(vdata,3)))
254  local_buf_r8_kind = vdata
255  endif
256 
257  call mpp_gather(isc+i_add, iec+i_add, jsc+j_add, jec+j_add, k_glob, bc_info%pelist, &
258  local_buf_r8_kind(i1:i2,j1:j2,:), &
259  global_buf_r8_kind, fileobj%is_root)
260  deallocate(local_buf_r8_kind)
261  !> If you are on fileobj's root, calculate the checksum and save the gathered data in a buffer
262  if (fileobj%is_root) then
263  chksum_val = mpp_chksum(global_buf_r8_kind(1:i_glob,1:j_glob, :), (/mpp_pe()/))
264  allocate(bc_info%globaldata3d_r8(i_glob, j_glob, bc_info%global_size(3)))
265  bc_info%globaldata3d_r8=global_buf_r8_kind(1:i_glob,1:j_glob,:)
266  deallocate(global_buf_r8_kind)
267  endif
268  class default
269  call error("gather_data_bc_3d: unsupported type. Currently only r8_kind and r4_kinds are supported")
270  end select
271 
272  !> Save the checksum, so you can write it later
273  if (fileobj%is_root) then
274  chksum = ""
275  write(chksum, "(Z16)") chksum_val
276  bc_info%chksum = chksum
277  endif
278 
279 end subroutine gather_data_bc_3d
280 !> @}
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:406
subroutine gather_data_bc_3d(fileobj, vdata, bc_info)
gathers the 2d vdata from all of the relevant pes into the root_pe and saves it to a buffer.
subroutine gather_data_bc_2d(fileobj, vdata, bc_info)
gathers the 2d vdata from all of the relevant pes into the root_pe and saves it to a buffer.