FMS  2025.02.01
Flexible Modeling System
block_control.F90
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 !> @defgroup block_control_mod block_control_mod
20 !> @ingroup block_control
21 !> @brief Routines for "blocks" used for OpenMP threading of column-based
22 !! calculations
23 
24 module block_control_mod
25 
26 use mpp_mod, only: mpp_error, note, warning, fatal, mpp_sum, mpp_npes
27 use mpp_domains_mod, only: mpp_compute_extent
28 use fms_string_utils_mod, only: string
29 implicit none
30 
31 public block_control_type
32 
33 !> Type to dereference packed index from global index.
34 !> @ingroup block_control_mod
35 type :: ix_type
36  integer, dimension(:,:), allocatable :: ix
37 end type ix_type
38 
39 !> Type to dereference packed index from global indices.
40 !> @ingroup block_control_mod
41 type :: pk_type
42  integer, dimension(:), allocatable :: ii
43  integer, dimension(:), allocatable :: jj
44 end type pk_type
45 
46 !> @brief Block data and extents for OpenMP threading of column-based calculations
47 !> @ingroup block_control_mod
49  integer :: nx_block, ny_block !< blocking factor using mpp-style decomposition
50  integer :: nblks !< number of blocks cover MPI domain
51  integer :: isc, iec, jsc, jec !< MPI domain global extents
52  integer :: npz !< vertical extent
53  integer, dimension(:), allocatable :: ibs , & !< block extents for mpp-style
54  ibe , & !! decompositions
55  jbs , &
56  jbe
57  type(ix_type), dimension(:), allocatable :: ix !< dereference packed index from global index
58  !--- packed blocking fields
59  integer, dimension(:), allocatable :: blksz !< number of points in each individual block
60  !! blocks are not required to be uniforom in size
61  integer, dimension(:,:), allocatable :: blkno !< dereference block number using global indices
62  integer, dimension(:,:), allocatable :: ixp !< dereference packed index from global indices
63  !! must be used in conjuction with blkno
64  type(pk_type), dimension(:), allocatable :: index !< dereference global indices from
65  !! block/ixp combo
66 end type block_control_type
67 
68 !> @addtogroup block_control_mod
69 !> @{
70 
72 
73 contains
74 
75 !###############################################################################
76 !> @brief Sets up "blocks" used for OpenMP threading of column-based
77 !! calculations using rad_n[x/y]xblock from coupler_nml
78 !!
79  subroutine define_blocks (component, Block, isc, iec, jsc, jec, kpts, &
80  nx_block, ny_block, message)
81  character(len=*), intent(in) :: component !< Component name string
82  type(block_control_type), intent(inout) :: block !< Returns instantiated @ref block_control_type
83  integer, intent(in) :: isc, iec, jsc, jec, kpts
84  integer, intent(in) :: nx_block, ny_block
85  logical, intent(inout) :: message !< flag for outputting debug message
86 
87 !-------------------------------------------------------------------------------
88 ! Local variables:
89 ! blocks
90 ! i1
91 ! i2
92 ! j1
93 ! j2
94 ! text
95 ! i
96 ! j
97 ! nblks
98 ! ix
99 ! ii
100 ! jj
101 !-------------------------------------------------------------------------------
102 
103  integer :: blocks
104  integer, dimension(nx_block) :: i1, i2
105  integer, dimension(ny_block) :: j1, j2
106  character(len=256) :: text
107  integer :: i, j, nblks, ix, ii, jj
108  integer :: non_uniform_blocks !< Number of non uniform blocks
109 
110  if (message) then
111  non_uniform_blocks = 0
112  if ((mod(iec-isc+1,nx_block) .ne. 0) .or. (mod(jec-jsc+1,ny_block) .ne. 0)) then
113  non_uniform_blocks = 1
114  endif
115  call mpp_sum(non_uniform_blocks)
116  if (non_uniform_blocks > 0 ) then
117  call mpp_error(note, string(non_uniform_blocks)//" out of "//string(mpp_npes())//" total domains "//&
118  "have non-uniform blocks for block size ("//string(nx_block)//","//string(ny_block)//")")
119  message = .false.
120  endif
121  endif
122 
123 !--- set up blocks
124  if (iec-isc+1 .lt. nx_block) &
125  call mpp_error(fatal, 'block_control: number of '//trim(component)//.gt.' nxblocks &
126  &number of elements in MPI-domain size')
127  if (jec-jsc+1 .lt. ny_block) &
128  call mpp_error(fatal, 'block_control: number of '//trim(component)//.gt.' nyblocks &
129  &number of elements in MPI-domain size')
130  call mpp_compute_extent(isc,iec,nx_block,i1,i2)
131  call mpp_compute_extent(jsc,jec,ny_block,j1,j2)
132 
133  nblks = nx_block*ny_block
134  block%isc = isc
135  block%iec = iec
136  block%jsc = jsc
137  block%jec = jec
138  block%npz = kpts
139  block%nx_block = nx_block
140  block%ny_block = ny_block
141  block%nblks = nblks
142 
143  if (.not.allocated(block%ibs)) &
144  allocate (block%ibs(nblks), &
145  block%ibe(nblks), &
146  block%jbs(nblks), &
147  block%jbe(nblks), &
148  block%ix(nblks) )
149 
150  blocks=0
151  do j = 1, ny_block
152  do i = 1, nx_block
153  blocks = blocks + 1
154  block%ibs(blocks) = i1(i)
155  block%jbs(blocks) = j1(j)
156  block%ibe(blocks) = i2(i)
157  block%jbe(blocks) = j2(j)
158  allocate(block%ix(blocks)%ix(i1(i):i2(i),j1(j):j2(j)) )
159  ix = 0
160  do jj = j1(j), j2(j)
161  do ii = i1(i), i2(i)
162  ix = ix+1
163  block%ix(blocks)%ix(ii,jj) = ix
164  enddo
165  enddo
166  enddo
167  enddo
168 
169  end subroutine define_blocks
170 
171 
172 
173 !###############################################################################
174 !> @brief Creates and populates a data type which is used for defining the
175 !! sub-blocks of the MPI-domain to enhance OpenMP and memory performance.
176 !! Uses a packed concept.
177 !!
178  subroutine define_blocks_packed (component, Block, isc, iec, jsc, jec, &
179  kpts, blksz, message)
180  character(len=*), intent(in) :: component !< Component name string
181  type(block_control_type), intent(inout) :: block !< Returns instantiated @ref block_control_type
182  integer, intent(in) :: isc, iec, jsc, jec, kpts
183  integer, intent(inout) :: blksz !< block size
184  logical, intent(inout) :: message !< flag for outputting debug message
185 
186 !-------------------------------------------------------------------------------
187 ! Local variables:
188 ! nblks
189 ! lblksz
190 ! tot_pts
191 ! nb
192 ! ix
193 ! ii
194 ! jj
195 ! text
196 !-------------------------------------------------------------------------------
197 
198  integer :: nblks, lblksz, tot_pts, nb, ix, ii, jj
199  character(len=256) :: text
200 
201  tot_pts = (iec - isc + 1) * (jec - jsc + 1)
202  if (blksz < 0) then
203  nblks = 1
204  blksz = tot_pts
205  else
206  nblks = tot_pts/blksz
207  if (mod(tot_pts,blksz) .gt. 0) then
208  nblks = nblks + 1
209  endif
210  endif
211 
212  if (message) then
213  if (mod(tot_pts,blksz) .ne. 0) then
214  write( text,'(a,a,2i4,a,i4,a,i4)' ) trim(component),'define_blocks_packed: domain (',&
215  (iec-isc+1), (jec-jsc+1),') is not an even divisor with definition (',&
216  blksz,') - blocks will not be uniform with a remainder of ',mod(tot_pts,blksz)
217  call mpp_error (warning, trim(text))
218  endif
219  message = .false.
220  endif
221 
222  block%isc = isc
223  block%iec = iec
224  block%jsc = jsc
225  block%jec = jec
226  block%npz = kpts
227  block%nblks = nblks
228  if (.not. allocated(block%blksz)) &
229  allocate (block%blksz(nblks), &
230  block%index(nblks), &
231  block%blkno(isc:iec,jsc:jec), &
232  block%ixp(isc:iec,jsc:jec))
233 
234 !--- set up blocks
235  do nb = 1, nblks
236  lblksz = blksz
237  if (nb .EQ. nblks) lblksz = tot_pts - (nb-1) * blksz
238  block%blksz(nb) = lblksz
239  allocate (block%index(nb)%ii(lblksz), &
240  block%index(nb)%jj(lblksz))
241  enddo
242 
243 !--- set up packed indices
244  nb = 1
245  ix = 0
246  do jj = jsc, jec
247  do ii = isc, iec
248  ix = ix + 1
249  if (ix .GT. blksz) then
250  ix = 1
251  nb = nb + 1
252  endif
253  block%ixp(ii,jj) = ix
254  block%blkno(ii,jj) = nb
255  block%index(nb)%ii(ix) = ii
256  block%index(nb)%jj(ix) = jj
257  enddo
258  enddo
259 
260  end subroutine define_blocks_packed
261 
262 end module block_control_mod
263 !> @}
264 ! close documentation grouping
subroutine, public define_blocks_packed(component, Block, isc, iec, jsc, jec, kpts, blksz, message)
Creates and populates a data type which is used for defining the sub-blocks of the MPI-domain to enha...
subroutine, public define_blocks(component, Block, isc, iec, jsc, jec, kpts, nx_block, ny_block, message)
Sets up "blocks" used for OpenMP threading of column-based calculations using rad_n[x/y]xblock from c...
Block data and extents for OpenMP threading of column-based calculations.
Type to dereference packed index from global index.
Type to dereference packed index from global indices.
character(:) function, allocatable, public string(v, fmt)
Converts a number or a Boolean value to a string.
subroutine mpp_compute_extent(isg, ieg, ndivs, ibegin, iend, extent)
Computes extents for a grid decomposition with the given indices and divisions.
integer function mpp_npes()
Returns processor count for current pelist.
Definition: mpp_util.inc:421
Error handler.
Definition: mpp.F90:382
Reduction operation.
Definition: mpp.F90:597