FMS  2024.03
Flexible Modeling System
mpp_domains_util.inc
1 ! -*-f90-*-
2 
3 !***********************************************************************
4 !* GNU Lesser General Public License
5 !*
6 !* This file is part of the GFDL Flexible Modeling System (FMS).
7 !*
8 !* FMS is free software: you can redistribute it and/or modify it under
9 !* the terms of the GNU Lesser General Public License as published by
10 !* the Free Software Foundation, either version 3 of the License, or (at
11 !* your option) any later version.
12 !*
13 !* FMS is distributed in the hope that it will be useful, but WITHOUT
14 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 !* for more details.
17 !*
18 !* You should have received a copy of the GNU Lesser General Public
19 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
20 !***********************************************************************
21 
22 !> @file
23 !> @brief Utility routines for getting and setting values in @ref mpp_domains_mod
24 
25 !> @ingroup mpp_domains_mod
26 !> @{
27 
28  !> @brief Set user stack size.
29  !!
30  !> This sets the size of an array that is used for internal storage by
31  !! <TT>mpp_domains</TT>. This array is used, for instance, to buffer the
32  !! data sent and received in halo updates.<br>
33  !! This call has implied global synchronization. It should be
34  !! placed somewhere where all PEs can call it.
36  !set the mpp_domains_stack variable to be at least n LONG words long
37  integer, intent(in) :: n
38  character(len=8) :: text
39 
40  if( n.LE.mpp_domains_stack_size )return
41  if( allocated(mpp_domains_stack) )deallocate(mpp_domains_stack)
42  allocate( mpp_domains_stack(n) )
43  if( allocated(mpp_domains_stack_nonblock) )deallocate(mpp_domains_stack_nonblock)
44  allocate( mpp_domains_stack_nonblock(n) )
45 
46  mpp_domains_stack_size = n
47  write( text,'(i8)' )n
48  if( mpp_pe().EQ.mpp_root_pe() )call mpp_error( note, 'MPP_DOMAINS_SET_STACK_SIZE: stack size set to '//text//'.' )
49 
50  return
51  end subroutine mpp_domains_set_stack_size
52 
53 
54 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
55  ! !
56  ! MPP_DOMAINS: overloaded operators (==, /=) !
57  ! !
58 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
59 
60  function mpp_domain1d_eq( a, b )
61  logical :: mpp_domain1d_eq
62  type(domain1d), intent(in) :: a, b
63 
64  mpp_domain1d_eq = ( a%compute%begin.EQ.b%compute%begin .AND. &
65  a%compute%end .EQ.b%compute%end .AND. &
66  a%domain_data%begin .EQ.b%domain_data%begin .AND. &
67  a%domain_data%end .EQ.b%domain_data%end .AND. &
68  a%global%begin .EQ.b%global%begin .AND. &
69  a%global%end .EQ.b%global%end )
70  !compare pelists
71  ! if( mpp_domain1D_eq )mpp_domain1D_eq = ASSOCIATED(a%list) .AND. ASSOCIATED(b%list)
72  ! if( mpp_domain1D_eq )mpp_domain1D_eq = size(a%list(:)).EQ.size(b%list(:))
73  ! if( mpp_domain1D_eq )mpp_domain1D_eq = ALL(a%list%pe.EQ.b%list%pe)
74 
75  return
76  end function mpp_domain1d_eq
77 
78  function mpp_domain1d_ne( a, b )
79  logical :: mpp_domain1d_ne
80  type(domain1d), intent(in) :: a, b
81 
82  mpp_domain1d_ne = .NOT. ( a.EQ.b )
83  return
84  end function mpp_domain1d_ne
85 
86  function mpp_domain2d_eq( a, b )
87  logical :: mpp_domain2d_eq
88  type(domain2d), intent(in) :: a, b
89  integer :: nt, n
90 
91  mpp_domain2d_eq = size(a%x(:)) .EQ. size(b%x(:))
92  nt = size(a%x(:))
93  do n = 1, nt
94  if(mpp_domain2d_eq) mpp_domain2d_eq = a%x(n).EQ.b%x(n) .AND. a%y(n).EQ.b%y(n)
95  end do
96 
97  if( mpp_domain2d_eq .AND. ((a%pe.EQ.null_pe).OR.(b%pe.EQ.null_pe)) )return !NULL_DOMAIN2D
98  !compare pelists
99  if( mpp_domain2d_eq )mpp_domain2d_eq = ASSOCIATED(a%list) .AND. ASSOCIATED(b%list)
100  if( mpp_domain2d_eq )mpp_domain2d_eq = size(a%list(:)).EQ.size(b%list(:))
101  if( mpp_domain2d_eq )mpp_domain2d_eq = all(a%list%pe.EQ.b%list%pe)
102  if( mpp_domain2d_eq )mpp_domain2d_eq = all(a%io_layout .EQ. b%io_layout)
103  if( mpp_domain2d_eq )mpp_domain2d_eq = a%symmetry .eqv. b%symmetry
104 
105  return
106  end function mpp_domain2d_eq
107 
108  !#####################################################################
109 
110  function mpp_domain2d_ne( a, b )
111  logical :: mpp_domain2d_ne
112  type(domain2d), intent(in) :: a, b
113 
114  mpp_domain2d_ne = .NOT. ( a.EQ.b )
115  return
116  end function mpp_domain2d_ne
117 
118 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
119  ! !
120  ! MPP_GET and SET routiness: retrieve various components of domains !
121  ! !
122 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
123 
124  subroutine mpp_get_compute_domain1d( domain, begin, end, size, max_size, is_global )
125  type(domain1d), intent(in) :: domain
126  integer, intent(out), optional :: begin, end, size, max_size
127  logical, intent(out), optional :: is_global
128 
129  if( PRESENT(begin) )begin = domain%compute%begin
130  if( PRESENT(end) )end = domain%compute%end
131  if( PRESENT(size) )size = domain%compute%size
132  if( PRESENT(max_size) )max_size = domain%compute%max_size
133  if( PRESENT(is_global) )is_global = domain%compute%is_global
134  return
135  end subroutine mpp_get_compute_domain1d
136 
137  !#####################################################################
138  subroutine mpp_get_data_domain1d( domain, begin, end, size, max_size, is_global )
139  type(domain1d), intent(in) :: domain
140  integer, intent(out), optional :: begin, end, size, max_size
141  logical, intent(out), optional :: is_global
142 
143  if( PRESENT(begin) )begin = domain%domain_data%begin
144  if( PRESENT(end) )end = domain%domain_data%end
145  if( PRESENT(size) )size = domain%domain_data%size
146  if( PRESENT(max_size) )max_size = domain%domain_data%max_size
147  if( PRESENT(is_global) )is_global = domain%domain_data%is_global
148  return
149  end subroutine mpp_get_data_domain1d
150 
151  !#####################################################################
152  subroutine mpp_get_global_domain1d( domain, begin, end, size, max_size )
153  type(domain1d), intent(in) :: domain
154  integer, intent(out), optional :: begin, end, size, max_size
155 
156  if( PRESENT(begin) )begin = domain%global%begin
157  if( PRESENT(end) )end = domain%global%end
158  if( PRESENT(size) )size = domain%global%size
159  if( PRESENT(max_size) )max_size = domain%global%max_size
160  return
161  end subroutine mpp_get_global_domain1d
162 
163  !#####################################################################
164  subroutine mpp_get_memory_domain1d( domain, begin, end, size, max_size, is_global )
165  type(domain1d), intent(in) :: domain
166  integer, intent(out), optional :: begin, end, size, max_size
167  logical, intent(out), optional :: is_global
168 
169  if( PRESENT(begin) )begin = domain%memory%begin
170  if( PRESENT(end) )end = domain%memory%end
171  if( PRESENT(size) )size = domain%memory%size
172  if( PRESENT(max_size) )max_size = domain%memory%max_size
173  if( PRESENT(is_global) )is_global = domain%memory%is_global
174  return
175  end subroutine mpp_get_memory_domain1d
176 
177  !#####################################################################
178  subroutine mpp_get_compute_domain2d( domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, &
179  x_is_global, y_is_global, tile_count, position )
180  type(domain2d), intent(in) :: domain
181  integer, intent(out), optional :: xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size
182  logical, intent(out), optional :: x_is_global, y_is_global
183  integer, intent(in), optional :: tile_count, position
184  integer :: tile, ishift, jshift
185 
186  tile = 1
187  if(present(tile_count)) tile = tile_count
188 
189  call mpp_get_compute_domain( domain%x(tile), xbegin, xend, xsize, xmax_size, x_is_global )
190  call mpp_get_compute_domain( domain%y(tile), ybegin, yend, ysize, ymax_size, y_is_global )
191  call mpp_get_domain_shift( domain, ishift, jshift, position )
192  if( PRESENT(xend) ) xend = xend + ishift
193  if( PRESENT(yend) ) yend = yend + jshift
194  if( PRESENT(xsize)) xsize = xsize + ishift
195  if( PRESENT(ysize)) ysize = ysize + jshift
196  if(PRESENT(xmax_size))xmax_size = xmax_size + ishift
197  if(PRESENT(ymax_size))ymax_size = ymax_size + jshift
198 
199  return
200  end subroutine mpp_get_compute_domain2d
201 
202  !#####################################################################
203  subroutine mpp_get_data_domain2d( domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, &
204  x_is_global, y_is_global, tile_count, position )
205  type(domain2d), intent(in) :: domain
206  integer, intent(out), optional :: xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size
207  logical, intent(out), optional :: x_is_global, y_is_global
208  integer, intent(in), optional :: tile_count, position
209  integer :: tile, ishift, jshift
210 
211  tile = 1
212  if(present(tile_count)) tile = tile_count
213 
214  call mpp_get_data_domain( domain%x(tile), xbegin, xend, xsize, xmax_size, x_is_global )
215  call mpp_get_data_domain( domain%y(tile), ybegin, yend, ysize, ymax_size, y_is_global )
216  call mpp_get_domain_shift( domain, ishift, jshift, position )
217  if( PRESENT(xend) ) xend = xend + ishift
218  if( PRESENT(yend) ) yend = yend + jshift
219  if( PRESENT(xsize)) xsize = xsize + ishift
220  if( PRESENT(ysize)) ysize = ysize + jshift
221  if(PRESENT(xmax_size))xmax_size = xmax_size + ishift
222  if(PRESENT(ymax_size))ymax_size = ymax_size + jshift
223 
224  return
225  end subroutine mpp_get_data_domain2d
226 
227  !#####################################################################
228  subroutine mpp_get_global_domain2d( domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, &
229  tile_count, position )
230  type(domain2d), intent(in) :: domain
231  integer, intent(out), optional :: xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size
232  integer, intent(in), optional :: tile_count, position
233  integer :: tile, ishift, jshift
234 
235  tile = 1
236  if(present(tile_count)) tile = tile_count
237 
238  call mpp_get_global_domain( domain%x(tile), xbegin, xend, xsize, xmax_size )
239  call mpp_get_global_domain( domain%y(tile), ybegin, yend, ysize, ymax_size )
240  call mpp_get_domain_shift( domain, ishift, jshift, position )
241  if( PRESENT(xend) ) xend = xend + ishift
242  if( PRESENT(yend) ) yend = yend + jshift
243  if( PRESENT(xsize)) xsize = xsize + ishift
244  if( PRESENT(ysize)) ysize = ysize + jshift
245  if(PRESENT(xmax_size))xmax_size = xmax_size + ishift
246  if(PRESENT(ymax_size))ymax_size = ymax_size + jshift
247 
248  return
249  end subroutine mpp_get_global_domain2d
250 
251  !#####################################################################
252  subroutine mpp_get_memory_domain2d( domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, &
253  x_is_global, y_is_global, position)
254  type(domain2d), intent(in) :: domain
255  integer, intent(out), optional :: xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size
256  logical, intent(out), optional :: x_is_global, y_is_global
257  integer, intent(in), optional :: position
258  integer :: tile, ishift, jshift
259 
260  tile = 1
261 
262  call mpp_get_memory_domain( domain%x(tile), xbegin, xend, xsize, xmax_size, x_is_global )
263  call mpp_get_memory_domain( domain%y(tile), ybegin, yend, ysize, ymax_size, y_is_global )
264  call mpp_get_domain_shift( domain, ishift, jshift, position )
265  if( PRESENT(xend) ) xend = xend + ishift
266  if( PRESENT(yend) ) yend = yend + jshift
267  if( PRESENT(xsize)) xsize = xsize + ishift
268  if( PRESENT(ysize)) ysize = ysize + jshift
269  if(PRESENT(xmax_size))xmax_size = xmax_size + ishift
270  if(PRESENT(ymax_size))ymax_size = ymax_size + jshift
271 
272  return
273  end subroutine mpp_get_memory_domain2d
274 
275  !> @brief Modifies the indices in the domain_axis_spec type to those of the supergrid
276  subroutine mpp_set_super_grid_indices(grid)
277  type(domain_axis_spec), intent(inout) :: grid !< domain_axis_spec type
278 
279  grid%begin = 2*grid%begin-1
280  grid%end = 2*grid%end+1
281  grid%size = grid%end-grid%begin+1
282 
283  end subroutine mpp_set_super_grid_indices
284 
285  !> @brief Modifies the indices of the input domain to create the supergrid domain
286  !!
287  !> This is an example of how to use mpp_create_super_grid_domain
288  !! @code{.F90}
289  !! call mpp_copy_domain(domain_in, domain_out)
290  !! call super_grid_domain(domain_out)
291  !! @endcode
292  !! domain_in is the original domain, domain_out is the domain with the supergrid indices.
293  subroutine mpp_create_super_grid_domain(domain)
294  type(domain2d), intent(inout) :: domain !< Input domain
295 
296  integer :: xbegin !< Begining x indices
297  integer :: ybegin !< Begining y indices
298  integer :: xend !< Ending x indices
299  integer :: yend !< Ending y indices
300  integer :: xsize !< Size of the x domain
301  integer :: ysize !< Size of the y domain
302  integer :: i !< For loops
303 
304  call mpp_get_global_domain(domain, xbegin=xbegin, xend=xend, ybegin=ybegin, yend=yend, xsize=xsize, ysize=ysize)
305  call mpp_set_global_domain (domain, 2*xbegin-1, 2*xend+1, 2*ybegin-1, 2*yend+1, 2*(xend-xbegin)+3, &
306  & 2*(yend-ybegin)+3)
307 
308  call mpp_get_compute_domain(domain, xbegin=xbegin, xend=xend, ybegin=ybegin, yend=yend, xsize=xsize, ysize=ysize)
309  call mpp_set_compute_domain (domain, 2*xbegin-1, 2*xend+1, 2*ybegin-1, 2*yend+1, 2*(xend-xbegin)+3, &
310  & 2*(yend-ybegin)+3)
311 
312  call mpp_get_data_domain(domain, xbegin=xbegin, xend=xend, ybegin=ybegin, yend=yend, xsize=xsize, ysize=ysize)
313  call mpp_set_data_domain (domain, 2*xbegin-1, 2*xend+1, 2*ybegin-1, 2*yend+1, 2*(xend-xbegin)+3, 2*(yend-ybegin)+3)
314 
315  do i=1, size(domain%list(:))
316  call mpp_set_super_grid_indices(domain%list(i-1)%x(1)%global)
317  call mpp_set_super_grid_indices(domain%list(i-1)%y(1)%global)
318 
319  call mpp_set_super_grid_indices(domain%list(i-1)%x(1)%compute)
320  call mpp_set_super_grid_indices(domain%list(i-1)%y(1)%compute)
321 
322  !< There is no data domain in domain%list
323  !call mpp_set_super_grid_indices(domain%list(i-1)%x(1)%domain_data)
324  !call mpp_set_super_grid_indices(domain%list(i-1)%y(1)%domain_data)
325  enddo
326 
327  do i=1, size(domain%x(1)%list)
328  call mpp_set_super_grid_indices(domain%x(1)%list(i-1)%compute)
329  enddo
330 
331  do i=1, size(domain%y(1)%list)
332  call mpp_set_super_grid_indices(domain%y(1)%list(i-1)%compute)
333  enddo
334 
335  end subroutine mpp_create_super_grid_domain
336 
337  !#####################################################################
338  subroutine mpp_set_compute_domain1d( domain, begin, end, size, is_global )
339  type(domain1d), intent(inout) :: domain
340  integer, intent(in), optional :: begin, end, size
341  logical, intent(in), optional :: is_global
342 
343  if(present(begin)) domain%compute%begin = begin
344  if(present(end)) domain%compute%end = end
345  if(present(size)) domain%compute%size = size
346  if(present(is_global)) domain%compute%is_global = is_global
347 
348  end subroutine mpp_set_compute_domain1d
349 
350  !#####################################################################
351  subroutine mpp_set_compute_domain2d( domain, xbegin, xend, ybegin, yend, xsize, ysize, &
352  x_is_global, y_is_global, tile_count )
353  type(domain2d), intent(inout) :: domain
354  integer, intent(in), optional :: xbegin, xend, ybegin, yend, xsize, ysize
355  logical, intent(in), optional :: x_is_global, y_is_global
356  integer, intent(in), optional :: tile_count
357  integer :: tile
358 
359  tile = 1
360  if(present(tile_count)) tile = tile_count
361 
362  call mpp_set_compute_domain(domain%x(tile), xbegin, xend, xsize, x_is_global)
363  call mpp_set_compute_domain(domain%y(tile), ybegin, yend, ysize, y_is_global)
364 
365  end subroutine mpp_set_compute_domain2d
366 
367  !#####################################################################
368  subroutine mpp_set_data_domain1d( domain, begin, end, size, is_global )
369  type(domain1d), intent(inout) :: domain
370  integer, intent(in), optional :: begin, end, size
371  logical, intent(in), optional :: is_global
372 
373  if(present(begin)) domain%domain_data%begin = begin
374  if(present(end)) domain%domain_data%end = end
375  if(present(size)) domain%domain_data%size = size
376  if(present(is_global)) domain%domain_data%is_global = is_global
377 
378  end subroutine mpp_set_data_domain1d
379 
380  !#####################################################################
381  subroutine mpp_set_data_domain2d( domain, xbegin, xend, ybegin, yend, xsize, ysize, &
382  x_is_global, y_is_global, tile_count )
383  type(domain2d), intent(inout) :: domain
384  integer, intent(in), optional :: xbegin, xend, ybegin, yend, xsize, ysize
385  logical, intent(in), optional :: x_is_global, y_is_global
386  integer, intent(in), optional :: tile_count
387  integer :: tile
388 
389  tile = 1
390  if(present(tile_count)) tile = tile_count
391 
392  call mpp_set_data_domain(domain%x(tile), xbegin, xend, xsize, x_is_global)
393  call mpp_set_data_domain(domain%y(tile), ybegin, yend, ysize, y_is_global)
394 
395  end subroutine mpp_set_data_domain2d
396 
397  !#####################################################################
398  subroutine mpp_set_global_domain1d( domain, begin, end, size)
399  type(domain1d), intent(inout) :: domain
400  integer, intent(in), optional :: begin, end, size
401 
402  if(present(begin)) domain%global%begin = begin
403  if(present(end)) domain%global%end = end
404  if(present(size)) domain%global%size = size
405 
406  end subroutine mpp_set_global_domain1d
407 
408  !#####################################################################
409  subroutine mpp_set_global_domain2d( domain, xbegin, xend, ybegin, yend, xsize, ysize, tile_count )
410  type(domain2d), intent(inout) :: domain
411  integer, intent(in), optional :: xbegin, xend, ybegin, yend, xsize, ysize
412  integer, intent(in), optional :: tile_count
413  integer :: tile
414 
415  tile = 1
416  if(present(tile_count)) tile = tile_count
417  call mpp_set_global_domain(domain%x(tile), xbegin, xend, xsize)
418  call mpp_set_global_domain(domain%y(tile), ybegin, yend, ysize)
419 
420  end subroutine mpp_set_global_domain2d
421 
422  !#####################################################################
423 
424  !> @brief Retrieve 1D components of 2D decomposition.
425  !!
426  !! It is sometime necessary to have direct recourse to the domain1D types
427  !! that compose a domain2D object. This call retrieves them.
428  !! @code{.F90}
429  !! call mpp_get_domain_components( domain, x, y )
430  !! @endcode
431  subroutine mpp_get_domain_components( domain, x, y, tile_count )
432  type(domain2d), intent(in) :: domain
433  type(domain1d), intent(inout), optional :: x, y
434  integer, intent(in), optional :: tile_count
435  integer :: tile
436 
437  tile = 1
438  if(present(tile_count)) tile = tile_count
439  if( PRESENT(x) )x = domain%x(tile)
440  if( PRESENT(y) )y = domain%y(tile)
441  return
442  end subroutine mpp_get_domain_components
443 
444  !#####################################################################
445  subroutine mpp_get_compute_domains1d( domain, begin, end, size )
446  type(domain1d), intent(in) :: domain
447  integer, intent(out), optional, dimension(:) :: begin, end, size
448 
449  if( .NOT.module_is_initialized ) &
450  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: must first call mpp_domains_init.' )
451  !we use shape instead of size for error checks because size is used as an argument
452  if( PRESENT(begin) )then
453  if( any(shape(begin).NE.shape(domain%list)) ) &
454  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: begin array size does not match domain.' )
455  begin(:) = domain%list(:)%compute%begin
456  end if
457  if( PRESENT(end) )then
458  if( any(shape(end).NE.shape(domain%list)) ) &
459  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: end array size does not match domain.' )
460  end(:) = domain%list(:)%compute%end
461  end if
462  if( PRESENT(size) )then
463  if( any(shape(size).NE.shape(domain%list)) ) &
464  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: size array size does not match domain.' )
465  size(:) = domain%list(:)%compute%size
466  end if
467  return
468 end subroutine mpp_get_compute_domains1d
469 
470 !#####################################################################
471 subroutine mpp_get_compute_domains2d( domain, xbegin, xend, xsize, ybegin, yend, ysize, position )
472  type(domain2d), intent(in) :: domain
473  integer, intent(out), optional, dimension(:) :: xbegin, xend, xsize, ybegin, yend, ysize
474  integer, intent(in ), optional :: position
475 
476  integer :: i, ishift, jshift
477 
478  call mpp_get_domain_shift( domain, ishift, jshift, position )
479 
480 
481  if( .NOT.module_is_initialized ) &
482  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: must first call mpp_domains_init.' )
483 
484  if( PRESENT(xbegin) )then
485  if( size(xbegin(:)).NE.size(domain%list(:)) ) &
486  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: xbegin array size does not match domain.' )
487  do i = 1, size(xbegin(:))
488  xbegin(i) = domain%list(i-1)%x(1)%compute%begin
489  end do
490  end if
491  if( PRESENT(xend) )then
492  if( size(xend(:)).NE.size(domain%list(:)) ) &
493  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: xend array size does not match domain.' )
494  do i = 1, size(xend(:))
495  xend(i) = domain%list(i-1)%x(1)%compute%end + ishift
496  end do
497  end if
498  if( PRESENT(xsize) )then
499  if( size(xsize(:)).NE.size(domain%list(:)) ) &
500  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: xsize array size does not match domain.' )
501  do i = 1, size(xsize(:))
502  xsize(i) = domain%list(i-1)%x(1)%compute%size + ishift
503  end do
504  end if
505  if( PRESENT(ybegin) )then
506  if( size(ybegin(:)).NE.size(domain%list(:)) ) &
507  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: ybegin array size does not match domain.' )
508  do i = 1, size(ybegin(:))
509  ybegin(i) = domain%list(i-1)%y(1)%compute%begin
510  end do
511  end if
512  if( PRESENT(yend) )then
513  if( size(yend(:)).NE.size(domain%list(:)) ) &
514  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: yend array size does not match domain.' )
515  do i = 1, size(yend(:))
516  yend(i) = domain%list(i-1)%y(1)%compute%end + jshift
517  end do
518  end if
519  if( PRESENT(ysize) )then
520  if( size(ysize(:)).NE.size(domain%list(:)) ) &
521  call mpp_error( fatal, 'MPP_GET_COMPUTE_DOMAINS: ysize array size does not match domain.' )
522  do i = 1, size(ysize(:))
523  ysize(i) = domain%list(i-1)%y(1)%compute%size + jshift
524  end do
525  end if
526  return
527 end subroutine mpp_get_compute_domains2d
528 
529  !#####################################################################
530  subroutine mpp_get_global_domains1d( domain, begin, end, size )
531  type(domain1d), intent(in) :: domain
532  integer, intent(out), optional, dimension(:) :: begin, end, size
533 
534  if( .NOT.module_is_initialized ) &
535  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: must first call mpp_domains_init.' )
536  !we use shape instead of size for error checks because size is used as an argument
537  if( PRESENT(begin) )then
538  if( any(shape(begin).NE.shape(domain%list)) ) &
539  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: begin array size does not match domain.' )
540  begin(:) = domain%list(:)%global%begin
541  end if
542  if( PRESENT(end) )then
543  if( any(shape(end).NE.shape(domain%list)) ) &
544  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: end array size does not match domain.' )
545  end(:) = domain%list(:)%global%end
546  end if
547  if( PRESENT(size) )then
548  if( any(shape(size).NE.shape(domain%list)) ) &
549  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: size array size does not match domain.' )
550  size(:) = domain%list(:)%global%size
551  end if
552  return
553  end subroutine mpp_get_global_domains1d
554 
555 
556 !#####################################################################
557 subroutine mpp_get_global_domains2d( domain, xbegin, xend, xsize, ybegin, yend, ysize, position )
558  type(domain2d), intent(in) :: domain
559  integer, intent(out), optional, dimension(:) :: xbegin, xend, xsize, ybegin, yend, ysize
560  integer, intent(in ), optional :: position
561 
562  integer :: i, ishift, jshift
563 
564  call mpp_get_domain_shift( domain, ishift, jshift, position )
565 
566 
567  if( .NOT.module_is_initialized ) &
568  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: must first call mpp_domains_init.' )
569 
570  if( PRESENT(xbegin) )then
571  if( size(xbegin(:)).NE.size(domain%list(:)) ) &
572  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: xbegin array size does not match domain.' )
573  do i = 1, size(xbegin(:))
574  xbegin(i) = domain%list(i-1)%x(1)%global%begin
575  end do
576  end if
577  if( PRESENT(xend) )then
578  if( size(xend(:)).NE.size(domain%list(:)) ) &
579  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: xend array size does not match domain.' )
580  do i = 1, size(xend(:))
581  xend(i) = domain%list(i-1)%x(1)%global%end + ishift
582  end do
583  end if
584  if( PRESENT(xsize) )then
585  if( size(xsize(:)).NE.size(domain%list(:)) ) &
586  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: xsize array size does not match domain.' )
587  do i = 1, size(xsize(:))
588  xsize(i) = domain%list(i-1)%x(1)%global%size + ishift
589  end do
590  end if
591  if( PRESENT(ybegin) )then
592  if( size(ybegin(:)).NE.size(domain%list(:)) ) &
593  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: ybegin array size does not match domain.' )
594  do i = 1, size(ybegin(:))
595  ybegin(i) = domain%list(i-1)%y(1)%global%begin
596  end do
597  end if
598  if( PRESENT(yend) )then
599  if( size(yend(:)).NE.size(domain%list(:)) ) &
600  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: yend array size does not match domain.' )
601  do i = 1, size(yend(:))
602  yend(i) = domain%list(i-1)%y(1)%global%end + jshift
603  end do
604  end if
605  if( PRESENT(ysize) )then
606  if( size(ysize(:)).NE.size(domain%list(:)) ) &
607  call mpp_error( fatal, 'MPP_GET_GLOBAL_DOMAINS: ysize array size does not match domain.' )
608  do i = 1, size(ysize(:))
609  ysize(i) = domain%list(i-1)%y(1)%global%size + jshift
610  end do
611  end if
612  return
613 end subroutine mpp_get_global_domains2d
614 
615 
616 !#####################################################################
617 subroutine mpp_get_domain_extents1d(domain, xextent, yextent)
618  type(domain2d), intent(in) :: domain
619  integer, dimension(0:), intent(inout) :: xextent, yextent
620  integer :: n
621 
622  if(domain%ntiles .NE. 1) call mpp_error(fatal,"mpp_domains_util.inc(mpp_get_domain_extents1D): "// &
623  "ntiles is more than 1, please use mpp_get_domain_extents2D")
624  if(size(xextent) .NE. size(domain%x(1)%list(:))) call mpp_error(fatal, &
625  & "mpp_domains_util.inc(mpp_get_domain_extents1D): "// &
626  & "size(xextent) does not equal to size(domain%x(1)%list(:)))")
627  if(size(yextent) .NE. size(domain%y(1)%list(:))) call mpp_error(fatal, &
628  & "mpp_domains_util.inc(mpp_get_domain_extents1D): "// &
629  & "size(yextent) does not equal to size(domain%y(1)%list(:)))")
630  do n = 0, size(domain%x(1)%list(:))-1
631  xextent(n) = domain%x(1)%list(n)%compute%size
632  enddo
633  do n = 0, size(domain%y(1)%list(:))-1
634  yextent(n) = domain%y(1)%list(n)%compute%size
635  enddo
636 
637 end subroutine mpp_get_domain_extents1d
638 
639 !#####################################################################
640 !> This will return xextent and yextent for each tile
641 subroutine mpp_get_domain_extents2d(domain, xextent, yextent)
642  type(domain2d), intent(in) :: domain
643  integer, dimension(:,:), intent(inout) :: xextent, yextent
644  integer :: ntile, nlist, n, m, ndivx, ndivy, tile, pos
645 
646  ntile = domain%ntiles
647  nlist = size(domain%list(:))
648  if(size(xextent,2) .ne. ntile .or. size(yextent,2) .ne. ntile) call mpp_error(fatal, &
649  "mpp_domains_utile.inc: the second dimension size of xextent/yextent is not correct")
650  ndivx = size(xextent,1); ndivy = size(yextent,1)
651  do n = 0, nlist-1
652  if(any(domain%list(n)%x(:)%pos>ndivx-1) ) call mpp_error(fatal, &
653  "mpp_domains_utile.inc: first dimension size of xextent is less than the x-layout in some tile")
654  if(any(domain%list(n)%y(:)%pos>ndivy-1) ) call mpp_error(fatal, &
655  "mpp_domains_utile.inc: first dimension size of yextent is less than the y-layout in some tile")
656  end do
657 
658  xextent = 0; yextent=0
659 
660  do n = 0, nlist-1
661  do m = 1, size(domain%list(n)%tile_id(:))
662  tile = domain%list(n)%tile_id(m)
663  pos = domain%list(n)%x(m)%pos+1
664  if(xextent(pos, tile) == 0) xextent(pos,tile) = domain%list(n)%x(m)%compute%size
665  pos = domain%list(n)%y(m)%pos+1
666  if(yextent(pos, tile) == 0) yextent(pos,tile) = domain%list(n)%y(m)%compute%size
667  end do
668  end do
669 
670 
671 end subroutine mpp_get_domain_extents2d
672 
673 !#####################################################################
674 function mpp_get_domain_pe(domain)
675  type(domain2d), intent(in) :: domain
676  integer :: mpp_get_domain_pe
677 
678  mpp_get_domain_pe = domain%pe
679 
680 
681 end function mpp_get_domain_pe
682 
683 
685  type(domain2d), intent(in) :: domain
686  integer :: mpp_get_domain_tile_root_pe
687 
688  mpp_get_domain_tile_root_pe = domain%tile_root_pe
689 
690 end function mpp_get_domain_tile_root_pe
691 
692 
694  type(domain2d), intent(in) :: domain !> domain you are querying for information
695  integer :: mpp_get_domain_tile_commid !> declaration of the return tile communicator
696 
697  mpp_get_domain_tile_commid = domain%tile_comm_id
698 
699 end function mpp_get_domain_tile_commid
700 
701 
702 function mpp_get_domain_commid(domain)
703  type(domain2d), intent(in) :: domain !> domain you are querying for information
704  integer :: mpp_get_domain_commid !> declaration of the return domain communicator
705 
706  mpp_get_domain_commid = domain%comm_id
707 
708 end function mpp_get_domain_commid
709 
710 
711 function mpp_get_io_domain(domain)
712  type(domain2d), intent(in) :: domain
713  type(domain2d), pointer :: mpp_get_io_domain
714 
715  if(ASSOCIATED(domain%io_domain)) then
716  mpp_get_io_domain => domain%io_domain
717  else
718  mpp_get_io_domain => null()
719  endif
720 
721 end function mpp_get_io_domain
722 
723 !#####################################################################
724 ! <SUBROUTINE NAME="mpp_get_pelist1D" INTERFACE="mpp_get_pelist">
725 ! <IN NAME="domain" TYPE="type(domain1D)"></IN>
726 ! <OUT NAME="pelist" TYPE="integer" DIM="(:)"></OUT>
727 ! <OUT NAME="pos" TYPE="integer"></OUT>
728 ! </SUBROUTINE>
729 subroutine mpp_get_pelist1d( domain, pelist, pos )
730  type(domain1d), intent(in) :: domain
731  integer, intent(out) :: pelist(:)
732  integer, intent(out), optional :: pos
733  integer :: ndivs
734 
735  if( .NOT.module_is_initialized ) &
736  call mpp_error( fatal, 'MPP_GET_PELIST: must first call mpp_domains_init.' )
737  ndivs = size(domain%list(:))
738 
739  if( size(pelist(:)).NE.ndivs ) &
740  call mpp_error( fatal, 'MPP_GET_PELIST: pelist array size does not match domain.' )
741 
742  pelist(:) = domain%list(0:ndivs-1)%pe
743  if( PRESENT(pos) )pos = domain%pos
744  return
745 end subroutine mpp_get_pelist1d
746 
747 !#####################################################################
748 ! <SUBROUTINE NAME="mpp_get_pelist2D" INTERFACE="mpp_get_pelist">
749 ! <IN NAME="domain" TYPE="type(domain2D)"></IN>
750 ! <OUT NAME="pelist" TYPE="integer" DIM="(:)"></OUT>
751 ! <OUT NAME="pos" TYPE="integer"></OUT>
752 ! </SUBROUTINE>
753 subroutine mpp_get_pelist2d( domain, pelist, pos )
754  type(domain2d), intent(in) :: domain
755  integer, intent(out) :: pelist(:)
756  integer, intent(out), optional :: pos
757 
758  if( .NOT.module_is_initialized ) &
759  call mpp_error( fatal, 'MPP_GET_PELIST: must first call mpp_domains_init.' )
760  if( size(pelist(:)).NE.size(domain%list(:)) ) &
761  call mpp_error( fatal, 'MPP_GET_PELIST: pelist array size does not match domain.' )
762 
763  pelist(:) = domain%list(:)%pe
764  if( PRESENT(pos) )pos = domain%pos
765  return
766 end subroutine mpp_get_pelist2d
767 
768 !#####################################################################
769 ! <SUBROUTINE NAME="mpp_get_layout1D" INTERFACE="mpp_get_layout">
770 ! <IN NAME="domain" TYPE="type(domain1D)"></IN>
771 ! <OUT NAME="layout" TYPE="integer"></OUT>
772 ! </SUBROUTINE>
773 subroutine mpp_get_layout1d( domain, layout )
774  type(domain1d), intent(in) :: domain
775  integer, intent(out) :: layout
776 
777  if( .NOT.module_is_initialized ) &
778  call mpp_error( fatal, 'MPP_GET_LAYOUT: must first call mpp_domains_init.' )
779 
780  layout = size(domain%list(:))
781  return
782 end subroutine mpp_get_layout1d
783 
784 !#####################################################################
785 ! <SUBROUTINE NAME="mpp_get_layout2D" INTERFACE="mpp_get_layout">
786 ! <IN NAME="domain" TYPE="type(domain2D)"></IN>
787 ! <OUT NAME="layout" TYPE="integer" DIM="(2)"></OUT>
788 ! </SUBROUTINE>
789 subroutine mpp_get_layout2d( domain, layout )
790  type(domain2d), intent(in) :: domain
791  integer, intent(out) :: layout(2)
792 
793  if( .NOT.module_is_initialized ) &
794  call mpp_error( fatal, 'MPP_GET_LAYOUT: must first call mpp_domains_init.' )
795 
796  layout(1) = size(domain%x(1)%list(:))
797  layout(2) = size(domain%y(1)%list(:))
798  return
799 end subroutine mpp_get_layout2d
800 
801 !#####################################################################
802 
803  !> @brief Returns the shift value in x and y-direction according to domain position..
804  !!
805  !> When domain is symmetry, one extra point maybe needed in
806  !! x- and/or y-direction. This routine will return the shift value based
807  !! on the position
808  !! @code{.F90}
809  !! call mpp_get_domain_shift( domain, ishift, jshift, position )
810  !! @endcode
811 subroutine mpp_get_domain_shift(domain, ishift, jshift, position)
812  type(domain2d), intent(in) :: domain!> predefined data contains 2-d domain decomposition.
813  integer, intent(out) :: ishift, jshift!< return value will be 0 or 1.
814  integer, optional, intent(in) :: position!< position of data. Its value can be CENTER, EAST, NORTH or CORNER.
815  integer :: pos
816 
817  ishift = 0 ; jshift = 0
818  pos = center
819  if(present(position)) pos = position
820 
821  if(domain%symmetry) then ! shift is non-zero only when the domain is symmetry.
822  select case(pos)
823  case(corner)
824  ishift = 1; jshift = 1
825  case(east)
826  ishift = 1
827  case(north)
828  jshift = 1
829  end select
830  end if
831 
832 end subroutine mpp_get_domain_shift
833 
834 !#####################################################################
835 
836  !> Return PE to the righ/left of this PE-domain.
837  subroutine mpp_get_neighbor_pe_1d(domain, direction, pe)
838  type(domain1d), intent(inout) :: domain
839  integer, intent(in) :: direction
840  integer, intent(out) :: pe
841 
842  integer ipos, ipos2, npx
843 
844  pe = null_pe
845  npx = size(domain%list(:)) ! 0..npx-1
846  ipos = domain%pos
847 
848  select case (direction)
849 
850  case (:-1)
851  ! neighbor on the left
852  ipos2 = ipos - 1
853  if(ipos2 < 0) then
854  if(domain%cyclic) then
855  ipos2 = npx-1
856  else
857  ipos2 = -999
858  endif
859  endif
860 
861  case (0)
862  ! identity
863  ipos2 = ipos
864 
865  case (1:)
866  ! neighbor on the right
867  ipos2 = ipos + 1
868  if(ipos2 > npx-1) then
869  if(domain%cyclic) then
870  ipos2 = 0
871  else
872  ipos2 = -999
873  endif
874  endif
875 
876  end select
877 
878  if(ipos2 >= 0) pe = domain%list(ipos2)%pe
879 
880  end subroutine mpp_get_neighbor_pe_1d
881 !#####################################################################
882 
883  !> Return PE North/South/East/West of this PE-domain.
884  !! direction must be NORTH, SOUTH, EAST or WEST.
885  subroutine mpp_get_neighbor_pe_2d(domain, direction, pe)
886  type(domain2d), intent(inout) :: domain
887  integer, intent(in) :: direction
888  integer, intent(out) :: pe
889 
890  integer ipos, jpos, npx, npy, ix, iy, ipos0, jpos0
891 
892  pe = null_pe
893  npx = size(domain%x(1)%list(:)) ! 0..npx-1
894  npy = size(domain%y(1)%list(:)) ! 0..npy-1
895  ipos0 = domain%x(1)%pos
896  jpos0 = domain%y(1)%pos
897 
898  select case (direction)
899  case (north)
900  ix = 0
901  iy = 1
902  case (north_east)
903  ix = 1
904  iy = 1
905  case (east)
906  ix = 1
907  iy = 0
908  case (south_east)
909  ix = 1
910  iy =-1
911  case (south)
912  ix = 0
913  iy =-1
914  case (south_west)
915  ix =-1
916  iy =-1
917  case (west)
918  ix =-1
919  iy = 0
920  case (north_west)
921  ix =-1
922  iy = 1
923 
924  case default
925  call mpp_error( fatal, &
926  & 'MPP_GET_NEIGHBOR_PE_2D: direction must be either NORTH, ' &
927  & // 'SOUTH, EAST, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST or NORTH_WEST')
928  end select
929 
930  ipos = ipos0 + ix
931  jpos = jpos0 + iy
932 
933 
934  if( (ipos < 0 .or. ipos > npx-1) .and. domain%x(1)%cyclic ) then
935  ! E/W cyclic domain
936  ipos = modulo(ipos, npx)
937  endif
938 
939  if( (ipos < 0 .and. btest(domain%fold,west)) .or. &
940  & (ipos > npx-1 .and. btest(domain%fold,east)) ) then
941  ! E or W folded domain
942  ipos = ipos0
943  jpos = npy-jpos-1
944  endif
945 
946  if( (jpos < 0 .or. jpos > npy-1) .and. domain%y(1)%cyclic ) then
947  ! N/S cyclic
948  jpos = modulo(jpos, npy)
949  endif
950 
951  if( (jpos < 0 .and. btest(domain%fold,south)) .or. &
952  & (jpos > npy-1 .and. btest(domain%fold,north)) ) then
953  ! N or S folded
954  ipos = npx-ipos-1
955  jpos = jpos0
956  endif
957 
958  ! get the PE number
959  pe = null_pe
960  if(ipos >= 0 .and. ipos <= npx-1 .and. jpos >= 0 .and. jpos <= npy-1) then
961  pe = domain%pearray(ipos, jpos)
962  endif
963 
964 
965  end subroutine mpp_get_neighbor_pe_2d
966 
967 
968 !#######################################################################
969 
970  subroutine nullify_domain2d_list(domain)
971  type(domain2d), intent(inout) :: domain
972 
973  domain%list =>null()
974 
975  end subroutine nullify_domain2d_list
976 
977 !#######################################################################
978  function mpp_domain_is_symmetry(domain)
979  type(domain2d), intent(in) :: domain
980  logical :: mpp_domain_is_symmetry
981 
982  mpp_domain_is_symmetry = domain%symmetry
983  return
984 
985  end function mpp_domain_is_symmetry
986 
987 !#######################################################################
988  function mpp_domain_is_initialized(domain)
989  type(domain2d), intent(in) :: domain
990  logical :: mpp_domain_is_initialized
991 
992  mpp_domain_is_initialized = domain%initialized
993 
994  return
995 
996  end function mpp_domain_is_initialized
997 
998 !#######################################################################
999  !--- private routine used only for mpp_update_domains. This routine will
1000  !--- compare whalo, ehalo, shalo, nhalo with the halo size when defining "domain"
1001  !--- to decide if update is needed. Also it check the sign of whalo, ehalo, shalo and nhalo.
1002  function domain_update_is_needed(domain, whalo, ehalo, shalo, nhalo)
1003  type(domain2d), intent(in) :: domain
1004  integer, intent(in) :: whalo, ehalo, shalo, nhalo
1005  logical :: domain_update_is_needed
1006 
1007  domain_update_is_needed = .true.
1008 
1009  if(whalo == 0 .AND. ehalo==0 .AND. shalo == 0 .AND. nhalo==0 ) then
1010  domain_update_is_needed = .false.
1011  if( debug )call mpp_error(note, &
1012  'mpp_domains_util.inc: halo size to be updated are all zero, no update will be done')
1013  return
1014  end if
1015  if( (whalo == -domain%whalo .AND. domain%whalo .NE. 0) .or. &
1016  (ehalo == -domain%ehalo .AND. domain%ehalo .NE. 0) .or. &
1017  (shalo == -domain%shalo .AND. domain%shalo .NE. 0) .or. &
1018  (nhalo == -domain%nhalo .AND. domain%nhalo .NE. 0) ) then
1019  domain_update_is_needed = .false.
1020  call mpp_error(note, 'mpp_domains_util.inc: at least one of w/e/s/n halo size to be updated '// &
1021  'is the inverse of the original halo when defining domain, no update will be done')
1022  return
1023  end if
1024 
1025  end function domain_update_is_needed
1026 !#######################################################################
1027  !> this routine found the domain has the same halo size with the input
1028  !! whalo, ehalo,
1029  function search_update_overlap(domain, whalo, ehalo, shalo, nhalo, position)
1030  type(domain2d), intent(inout) :: domain
1031  integer, intent(in) :: whalo, ehalo, shalo, nhalo
1032  integer, intent(in) :: position
1033  type(overlapspec), pointer :: search_update_overlap
1034  type(overlapspec), pointer :: update_ref
1035  type(overlapspec), pointer :: check => null()
1036  integer :: ishift, jshift, shift
1037 
1038  shift = 0; if(domain%symmetry) shift = 1
1039  select case(position)
1040  case (center)
1041  update_ref => domain%update_T
1042  ishift = 0; jshift = 0
1043  case (corner)
1044  update_ref => domain%update_C
1045  ishift = shift; jshift = shift
1046  case (north)
1047  update_ref => domain%update_N
1048  ishift = 0; jshift = shift
1049  case (east)
1050  update_ref => domain%update_E
1051  ishift = shift; jshift = 0
1052  case default
1053  call mpp_error(fatal,"mpp_domains_util.inc(search_update_overlap): position should be CENTER|CORNER|EAST|NORTH")
1054  end select
1055 
1056  search_update_overlap => update_ref
1057 
1058  do
1059  if(whalo == search_update_overlap%whalo .AND. ehalo == search_update_overlap%ehalo .AND. &
1060  shalo == search_update_overlap%shalo .AND. nhalo == search_update_overlap%nhalo ) then
1061  exit ! found domain
1062  endif
1063  !--- if not found, switch to next
1064  if(.NOT. ASSOCIATED(search_update_overlap%next)) then
1065  allocate(search_update_overlap%next)
1067  if(domain%fold .NE. 0) then
1068  call compute_overlaps(domain, position, search_update_overlap, check, &
1069  ishift, jshift, 0, 0, whalo, ehalo, shalo, nhalo)
1070  else
1071  call set_overlaps(domain, update_ref, search_update_overlap, whalo, ehalo, shalo, nhalo )
1072  endif
1073  exit
1074  else
1076  end if
1077 
1078  end do
1079 
1080  update_ref => null()
1081 
1082  end function search_update_overlap
1083 
1084 !#######################################################################
1085  !> this routine finds the check at certain position
1086  function search_check_overlap(domain, position)
1087  type(domain2d), intent(in) :: domain
1088  integer, intent(in) :: position
1089  type(overlapspec), pointer :: search_check_overlap
1090 
1091  select case(position)
1092  case (center)
1093  search_check_overlap => null()
1094  case (corner)
1095  search_check_overlap => domain%check_C
1096  case (north)
1097  search_check_overlap => domain%check_N
1098  case (east)
1099  search_check_overlap => domain%check_E
1100  case default
1101  call mpp_error(fatal,"mpp_domains_util.inc(search_check_overlap): position should be CENTER|CORNER|EAST|NORTH")
1102  end select
1103 
1104  end function search_check_overlap
1105 
1106 !#######################################################################
1107  !> This routine finds the bound at certain position
1108  function search_bound_overlap(domain, position)
1109  type(domain2d), intent(in) :: domain
1110  integer, intent(in) :: position
1111  type(overlapspec), pointer :: search_bound_overlap
1112 
1113  select case(position)
1114  case (center)
1115  search_bound_overlap => null()
1116  case (corner)
1117  search_bound_overlap => domain%bound_C
1118  case (north)
1119  search_bound_overlap => domain%bound_N
1120  case (east)
1121  search_bound_overlap => domain%bound_E
1122  case default
1123  call mpp_error(fatal,"mpp_domains_util.inc(search_bound_overlap): position should be CENTER|CORNER|EAST|NORTH")
1124  end select
1125 
1126  end function search_bound_overlap
1127 
1128  !########################################################################
1129  !> Returns the tile_id on current pe
1130  function mpp_get_tile_id(domain)
1131  type(domain2d), intent(in) :: domain
1132  integer, dimension(size(domain%tile_id(:))) :: mpp_get_tile_id
1133 
1134  mpp_get_tile_id = domain%tile_id
1135  return
1136 
1137  end function mpp_get_tile_id
1138 
1139  !#######################################################################
1140  !> Return the tile_id on current pelist. one-tile-per-pe is assumed.
1141  subroutine mpp_get_tile_list(domain, tiles)
1142  type(domain2d), intent(in) :: domain
1143  integer, intent(inout) :: tiles(:)
1144  integer :: i
1145 
1146  if( size(tiles(:)).NE.size(domain%list(:)) ) &
1147  call mpp_error( fatal, 'mpp_get_tile_list: tiles array size does not match domain.' )
1148  do i = 1, size(tiles(:))
1149  if(size(domain%list(i-1)%tile_id(:)) > 1) call mpp_error( fatal, &
1150  'mpp_get_tile_list: only support one-tile-per-pe now, contact developer');
1151  tiles(i) = domain%list(i-1)%tile_id(1)
1152  end do
1153 
1154  end subroutine mpp_get_tile_list
1155 
1156  !########################################################################
1157  !> Returns number of tiles in mosaic
1158  function mpp_get_ntile_count(domain)
1159  type(domain2d), intent(in) :: domain
1160  integer :: mpp_get_ntile_count
1161 
1162  mpp_get_ntile_count = domain%ntiles
1163  return
1164 
1165  end function mpp_get_ntile_count
1166 
1167  !########################################################################
1168  !> Returns number of tile on current pe
1169  function mpp_get_current_ntile(domain)
1170  type(domain2d), intent(in) :: domain
1171  integer :: mpp_get_current_ntile
1172 
1173  mpp_get_current_ntile = size(domain%tile_id(:))
1174  return
1175 
1176  end function mpp_get_current_ntile
1177 
1178  !#######################################################################
1179  !> Returns if current pe is the root pe of the tile, if number of tiles on current pe
1180  !! is greater than 1, will return true, if isc==isg and jsc==jsg also will return true,
1181  !! otherwise false will be returned.
1183  type(domain2d), intent(in) :: domain
1184  logical :: mpp_domain_is_tile_root_pe
1185 
1186  mpp_domain_is_tile_root_pe = domain%pe == domain%tile_root_pe;
1187 
1188  end function mpp_domain_is_tile_root_pe
1189 
1190  !#########################################################################
1191  !> Returns number of processors used on current tile.
1192  function mpp_get_tile_npes(domain)
1193  type(domain2d), intent(in) :: domain
1194  integer :: mpp_get_tile_npes
1195  integer :: i, tile
1196 
1197  !--- When there is more than one tile on this pe, we assume each tile will be
1198  !--- limited to this pe.
1199  if(size(domain%tile_id(:)) > 1) then
1200  mpp_get_tile_npes = 1
1201  else
1202  mpp_get_tile_npes = 0
1203  tile = domain%tile_id(1)
1204  do i = 0, size(domain%list(:))-1
1205  if(tile == domain%list(i)%tile_id(1) ) mpp_get_tile_npes = mpp_get_tile_npes + 1
1206  end do
1207  endif
1208 
1209  end function mpp_get_tile_npes
1210 
1211  !########################################################################
1212  !> Get the processors list used on current tile.
1213  subroutine mpp_get_tile_pelist(domain, pelist)
1214  type(domain2d), intent(in) :: domain
1215  integer, intent(inout) :: pelist(:)
1216  integer :: npes_on_tile
1217  integer :: i, tile, pos
1218 
1219  npes_on_tile = mpp_get_tile_npes(domain)
1220  if(size(pelist(:)) .NE. npes_on_tile) call mpp_error(fatal, &
1221  "mpp_domains_util.inc(mpp_get_tile_pelist): size(pelist) does not equal npes on current tile")
1222  tile = domain%tile_id(1)
1223  pos = 0
1224  do i = 0, size(domain%list(:))-1
1225  if(tile == domain%list(i)%tile_id(1)) then
1226  pos = pos+1
1227  pelist(pos) = domain%list(i)%pe
1228  endif
1229  enddo
1230 
1231  return
1232 
1233  end subroutine mpp_get_tile_pelist
1234 
1235 !#####################################################################
1236 subroutine mpp_get_tile_compute_domains( domain, xbegin, xend, ybegin, yend, position )
1237  type(domain2d), intent(in) :: domain
1238  integer, intent(out), dimension(:) :: xbegin, xend, ybegin, yend
1239  integer, intent(in ), optional :: position
1240 
1241  integer :: i, ishift, jshift
1242  integer :: npes_on_tile, pos, tile
1243 
1244  call mpp_get_domain_shift( domain, ishift, jshift, position )
1245 
1246 
1247  if( .NOT.module_is_initialized ) &
1248  call mpp_error( fatal, 'mpp_get_compute_domains2D: must first call mpp_domains_init.' )
1249 
1250  npes_on_tile = mpp_get_tile_npes(domain)
1251  if(size(xbegin(:)) .NE. npes_on_tile) call mpp_error(fatal, &
1252  "mpp_domains_util.inc(mpp_get_compute_domains2D): size(xbegin) does not equal npes on current tile")
1253  if(size(xend(:)) .NE. npes_on_tile) call mpp_error(fatal, &
1254  "mpp_domains_util.inc(mpp_get_compute_domains2D): size(xend) does not equal npes on current tile")
1255  if(size(ybegin(:)) .NE. npes_on_tile) call mpp_error(fatal, &
1256  "mpp_domains_util.inc(mpp_get_compute_domains2D): size(ybegin) does not equal npes on current tile")
1257  if(size(yend(:)) .NE. npes_on_tile) call mpp_error(fatal, &
1258  "mpp_domains_util.inc(mpp_get_compute_domains2D): size(yend) does not equal npes on current tile")
1259 
1260  tile = domain%tile_id(1)
1261  pos = 0
1262  do i = 0, size(domain%list(:))-1
1263  if(tile == domain%list(i)%tile_id(1)) then
1264  pos = pos+1
1265  xbegin(pos) = domain%list(i)%x(1)%compute%begin
1266  xend(pos) = domain%list(i)%x(1)%compute%end + ishift
1267  ybegin(pos) = domain%list(i)%y(1)%compute%begin
1268  yend(pos) = domain%list(i)%y(1)%compute%end + jshift
1269  endif
1270  enddo
1271 
1272  return
1273 
1274 end subroutine mpp_get_tile_compute_domains
1275 
1276 
1277 
1278  !#############################################################################
1279  function mpp_get_num_overlap(domain, action, p, position)
1280  type(domain2d), intent(in) :: domain
1281  integer, intent(in) :: action
1282  integer, intent(in) :: p
1283  integer, optional, intent(in) :: position
1284  integer :: mpp_get_num_overlap
1285  type(overlapspec), pointer :: update => null()
1286  integer :: pos
1287 
1288  pos = center
1289  if(present(position)) pos = position
1290  select case(pos)
1291  case (center)
1292  update => domain%update_T
1293  case (corner)
1294  update => domain%update_C
1295  case (east)
1296  update => domain%update_E
1297  case (north)
1298  update => domain%update_N
1299  case default
1300  call mpp_error( fatal, "mpp_domains_mod(mpp_get_num_overlap): invalid option of position")
1301  end select
1302 
1303  if(action == event_send) then
1304  if(p< 1 .OR. p > update%nsend) call mpp_error( fatal, &
1305  "mpp_domains_mod(mpp_get_num_overlap): p should be between 1 and update%nsend")
1306  mpp_get_num_overlap = update%send(p)%count
1307  else if(action == event_recv) then
1308  if(p< 1 .OR. p > update%nrecv) call mpp_error( fatal, &
1309  "mpp_domains_mod(mpp_get_num_overlap): p should be between 1 and update%nrecv")
1310  mpp_get_num_overlap = update%recv(p)%count
1311  else
1312  call mpp_error( fatal, "mpp_domains_mod(mpp_get_num_overlap): invalid option of action")
1313  end if
1314 
1315  end function mpp_get_num_overlap
1316 
1317  !#############################################################################
1318  subroutine mpp_get_update_size(domain, nsend, nrecv, position)
1319  type(domain2d), intent(in) :: domain
1320  integer, intent(out) :: nsend, nrecv
1321  integer, optional, intent(in) :: position
1322  integer :: pos
1323 
1324  pos = center
1325  if(present(position)) pos = position
1326  select case(pos)
1327  case (center)
1328  nsend = domain%update_T%nsend
1329  nrecv = domain%update_T%nrecv
1330  case (corner)
1331  nsend = domain%update_C%nsend
1332  nrecv = domain%update_C%nrecv
1333  case (east)
1334  nsend = domain%update_E%nsend
1335  nrecv = domain%update_E%nrecv
1336  case (north)
1337  nsend = domain%update_N%nsend
1338  nrecv = domain%update_N%nrecv
1339  case default
1340  call mpp_error( fatal, "mpp_domains_mod(mpp_get_update_size): invalid option of position")
1341  end select
1342 
1343  end subroutine mpp_get_update_size
1344 
1345  !#############################################################################
1346  subroutine mpp_get_update_pelist(domain, action, pelist, position)
1347  type(domain2d), intent(in) :: domain
1348  integer, intent(in) :: action
1349  integer, intent(inout) :: pelist(:)
1350  integer, optional, intent(in) :: position
1351  type(overlapspec), pointer :: update => null()
1352  integer :: pos, p
1353 
1354  pos = center
1355  if(present(position)) pos = position
1356  select case(pos)
1357  case (center)
1358  update => domain%update_T
1359  case (corner)
1360  update => domain%update_C
1361  case (east)
1362  update => domain%update_E
1363  case (north)
1364  update => domain%update_N
1365  case default
1366  call mpp_error( fatal, "mpp_domains_mod(mpp_get_update_pelist): invalid option of position")
1367  end select
1368 
1369  if(action == event_send) then
1370  if(size(pelist) .NE. update%nsend) call mpp_error( fatal, &
1371  "mpp_domains_mod(mpp_get_update_pelist): size of pelist does not match update%nsend")
1372  do p = 1, update%nsend
1373  pelist(p) = update%send(p)%pe
1374  enddo
1375  else if(action == event_recv) then
1376  if(size(pelist) .NE. update%nrecv) call mpp_error( fatal, &
1377  "mpp_domains_mod(mpp_get_update_pelist): size of pelist does not match update%nrecv")
1378  do p = 1, update%nrecv
1379  pelist(p) = update%recv(p)%pe
1380  enddo
1381  else
1382  call mpp_error( fatal, "mpp_domains_mod(mpp_get_update_pelist): invalid option of action")
1383  end if
1384 
1385  end subroutine mpp_get_update_pelist
1386 
1387  !#############################################################################
1388  subroutine mpp_get_overlap(domain, action, p, is, ie, js, je, dir, rot, position)
1389  type(domain2d), intent(in) :: domain
1390  integer, intent(in) :: action
1391  integer, intent(in) :: p
1392  integer, dimension(:), intent(out) :: is, ie, js, je
1393  integer, dimension(:), intent(out) :: dir, rot
1394  integer, optional, intent(in) :: position
1395  type(overlapspec), pointer :: update => null()
1396  type(overlap_type), pointer :: overlap => null()
1397  integer :: count, pos
1398 
1399  pos = center
1400  if(present(position)) pos = position
1401  select case(pos)
1402  case (center)
1403  update => domain%update_T
1404  case (corner)
1405  update => domain%update_C
1406  case (east)
1407  update => domain%update_E
1408  case (north)
1409  update => domain%update_N
1410  case default
1411  call mpp_error( fatal, "mpp_domains_mod(mpp_get_overlap): invalid option of position")
1412  end select
1413 
1414  if(action == event_send) then
1415  overlap => update%send(p)
1416  else if(action == event_recv) then
1417  overlap => update%recv(p)
1418  else
1419  call mpp_error( fatal, "mpp_domains_mod(mpp_get_overlap): invalid option of action")
1420  end if
1421 
1422  count = overlap%count
1423  if(size(is(:)) .NE. count .OR. size(ie(:)) .NE. count .OR. size(js(:)) .NE. count .OR. &
1424  size(je(:)) .NE. count .OR. size(dir(:)) .NE. count .OR. size(rot(:)) .NE. count ) &
1425  call mpp_error( fatal, &
1426  & "mpp_domains_mod(mpp_get_overlap): size mismatch between number of overlap and array size")
1427 
1428  is = overlap%is (1:count)
1429  ie = overlap%ie (1:count)
1430  js = overlap%js (1:count)
1431  je = overlap%je (1:count)
1432  dir = overlap%dir (1:count)
1433  rot = overlap%rotation(1:count)
1434 
1435  update => null()
1436  overlap => null()
1437 
1438  end subroutine mpp_get_overlap
1439 
1440  !##################################################################
1441  function mpp_get_domain_name(domain)
1442  type(domain2d), intent(in) :: domain
1443  character(len=NAME_LENGTH) :: mpp_get_domain_name
1444 
1445  mpp_get_domain_name = domain%name
1446 
1447  end function mpp_get_domain_name
1448 
1449  !#################################################################
1450  function mpp_get_domain_root_pe(domain)
1451  type(domain2d), intent(in) :: domain
1452  integer :: mpp_get_domain_root_pe
1453 
1454  mpp_get_domain_root_pe = domain%list(0)%pe
1455 
1456  end function mpp_get_domain_root_pe
1457  !#################################################################
1458  function mpp_get_domain_npes(domain)
1459  type(domain2d), intent(in) :: domain
1460  integer :: mpp_get_domain_npes
1461 
1462  mpp_get_domain_npes = size(domain%list(:))
1463 
1464  return
1465 
1466  end function mpp_get_domain_npes
1467 
1468  !################################################################
1469  subroutine mpp_get_domain_pelist(domain, pelist)
1470  type(domain2d), intent(in) :: domain
1471  integer, intent(out) :: pelist(:)
1472  integer :: p
1473 
1474  if(size(pelist(:)) .NE. size(domain%list(:)) ) then
1475  call mpp_error(fatal, .NE."mpp_get_domain_pelist: size(pelist(:)) size(domain%list(:)) ")
1476  endif
1477 
1478  do p = 0, size(domain%list(:))-1
1479  pelist(p+1) = domain%list(p)%pe
1480  enddo
1481 
1482  return
1483 
1484  end subroutine mpp_get_domain_pelist
1485 
1486  !#################################################################
1487  function mpp_get_io_domain_layout(domain)
1488  type(domain2d), intent(in) :: domain
1489  integer, dimension(2) :: mpp_get_io_domain_layout
1490 
1491  mpp_get_io_domain_layout = domain%io_layout
1492 
1493  end function mpp_get_io_domain_layout
1494 
1495  !################################################################
1496  function get_rank_send(domain, overlap_x, overlap_y, rank_x, rank_y, ind_x, ind_y)
1497  type(domain2d), intent(in) :: domain
1498  type(overlapspec), intent(in) :: overlap_x, overlap_y
1499  integer, intent(out) :: rank_x, rank_y, ind_x, ind_y
1500  integer :: get_rank_send
1501  integer :: nlist, nsend_x, nsend_y
1502 
1503  nlist = size(domain%list(:))
1504  nsend_x = overlap_x%nsend
1505  nsend_y = overlap_y%nsend
1506  rank_x = nlist+1
1507  rank_y = nlist+1
1508  if(nsend_x>0) rank_x = overlap_x%send(1)%pe - domain%pe
1509  if(nsend_y>0) rank_y = overlap_y%send(1)%pe - domain%pe
1510  if(rank_x .LT. 0) rank_x = rank_x + nlist
1511  if(rank_y .LT. 0) rank_y = rank_y + nlist
1512  get_rank_send = min(rank_x, rank_y)
1513  ind_x = nsend_x + 1
1514  ind_y = nsend_y + 1
1515  if(get_rank_send < nlist+1) then
1516  if(nsend_x>0) ind_x = 1
1517  if(nsend_y>0) ind_y = 1
1518  endif
1519 
1520  end function get_rank_send
1521 
1522  !############################################################################
1523  function get_rank_recv(domain, overlap_x, overlap_y, rank_x, rank_y, ind_x, ind_y)
1524  type(domain2d), intent(in) :: domain
1525  type(overlapspec), intent(in) :: overlap_x, overlap_y
1526  integer, intent(out) :: rank_x, rank_y, ind_x, ind_y
1527  integer :: get_rank_recv
1528  integer :: nlist, nrecv_x, nrecv_y
1529 
1530  nlist = size(domain%list(:))
1531  nrecv_x = overlap_x%nrecv
1532  nrecv_y = overlap_y%nrecv
1533  rank_x = -1
1534  rank_y = -1
1535  if(nrecv_x>0) then
1536  rank_x = overlap_x%recv(1)%pe - domain%pe
1537  if(rank_x .LE. 0) rank_x = rank_x + nlist
1538  endif
1539  if(nrecv_y>0) then
1540  rank_y = overlap_y%recv(1)%pe - domain%pe
1541  if(rank_y .LE. 0) rank_y = rank_y + nlist
1542  endif
1543  get_rank_recv = max(rank_x, rank_y)
1544  ind_x = nrecv_x + 1
1545  ind_y = nrecv_y + 1
1546  if(get_rank_recv < nlist+1) then
1547  if(nrecv_x>0) ind_x = 1
1548  if(nrecv_y>0) ind_y = 1
1549  endif
1550 
1551  end function get_rank_recv
1552 
1553  function get_vector_recv(domain, update_x, update_y, ind_x, ind_y, start_pos, pelist)
1554  type(domain2d), intent(in) :: domain
1555  type(overlapspec), intent(in) :: update_x, update_y
1556  integer, intent(out) :: ind_x(:), ind_y(:)
1557  integer, intent(out) :: start_pos(:)
1558  integer, intent(out) :: pelist(:)
1559  integer :: nlist, nrecv_x, nrecv_y, ntot, n
1560  integer :: ix, iy, rank_x, rank_y, cur_pos
1561  integer :: get_vector_recv
1562 
1563  nlist = size(domain%list(:))
1564  nrecv_x = update_x%nrecv
1565  nrecv_y = update_y%nrecv
1566 
1567  ntot = nrecv_x + nrecv_y
1568 
1569  n = 1
1570  ix = 1
1571  iy = 1
1572  ind_x = -1
1573  ind_y = -1
1574  get_vector_recv = 0
1575  cur_pos = 0
1576  do while (n<=ntot)
1577  if(ix <= nrecv_x ) then
1578  rank_x = update_x%recv(ix)%pe-domain%pe
1579  if(rank_x .LE. 0) rank_x = rank_x + nlist
1580  else
1581  rank_x = -1
1582  endif
1583  if(iy <= nrecv_y ) then
1584  rank_y = update_y%recv(iy)%pe-domain%pe
1585  if(rank_y .LE. 0) rank_y = rank_y + nlist
1586  else
1587  rank_y = -1
1588  endif
1590  start_pos(get_vector_recv) = cur_pos
1591  if( rank_x == rank_y ) then
1592  n = n+2
1593  ind_x(get_vector_recv) = ix
1594  ind_y(get_vector_recv) = iy
1595  cur_pos = cur_pos + update_x%recv(ix)%totsize + update_y%recv(iy)%totsize
1596  pelist(get_vector_recv) = update_x%recv(ix)%pe
1597  ix = ix + 1
1598  iy = iy + 1
1599  else if ( rank_x > rank_y ) then
1600  n = n+1
1601  ind_x(get_vector_recv) = ix
1602  ind_y(get_vector_recv) = -1
1603  cur_pos = cur_pos + update_x%recv(ix)%totsize
1604  pelist(get_vector_recv) = update_x%recv(ix)%pe
1605  ix = ix + 1
1606  else if ( rank_y > rank_x ) then
1607  n = n+1
1608  ind_x(get_vector_recv) = -1
1609  ind_y(get_vector_recv) = iy
1610  cur_pos = cur_pos + update_y%recv(iy)%totsize
1611  pelist(get_vector_recv) = update_y%recv(iy)%pe
1612  iy = iy+1
1613  endif
1614  end do
1615 
1616 
1617  end function get_vector_recv
1618 
1619  function get_vector_send(domain, update_x, update_y, ind_x, ind_y, start_pos, pelist)
1620  type(domain2d), intent(in) :: domain
1621  type(overlapspec), intent(in) :: update_x, update_y
1622  integer, intent(out) :: ind_x(:), ind_y(:)
1623  integer, intent(out) :: start_pos(:)
1624  integer, intent(out) :: pelist(:)
1625  integer :: nlist, nsend_x, nsend_y, ntot, n
1626  integer :: ix, iy, rank_x, rank_y, cur_pos
1627  integer :: get_vector_send
1628 
1629  nlist = size(domain%list(:))
1630  nsend_x = update_x%nsend
1631  nsend_y = update_y%nsend
1632 
1633  ntot = nsend_x + nsend_y
1634  n = 1
1635  ix = 1
1636  iy = 1
1637  ind_x = -1
1638  ind_y = -1
1639  get_vector_send = 0
1640  cur_pos = 0
1641  do while (n<=ntot)
1642  if(ix <= nsend_x ) then
1643  rank_x = update_x%send(ix)%pe-domain%pe
1644  if(rank_x .LT. 0) rank_x = rank_x + nlist
1645  else
1646  rank_x = nlist+1
1647  endif
1648  if(iy <= nsend_y ) then
1649  rank_y = update_y%send(iy)%pe-domain%pe
1650  if(rank_y .LT. 0) rank_y = rank_y + nlist
1651  else
1652  rank_y = nlist+1
1653  endif
1655  start_pos(get_vector_send) = cur_pos
1656 
1657  if( rank_x == rank_y ) then
1658  n = n+2
1659  ind_x(get_vector_send) = ix
1660  ind_y(get_vector_send) = iy
1661  cur_pos = cur_pos + update_x%send(ix)%totsize + update_y%send(iy)%totsize
1662  pelist(get_vector_send) = update_x%send(ix)%pe
1663  ix = ix + 1
1664  iy = iy + 1
1665  else if ( rank_x < rank_y ) then
1666  n = n+1
1667  ind_x(get_vector_send) = ix
1668  ind_y(get_vector_send) = -1
1669  cur_pos = cur_pos + update_x%send(ix)%totsize
1670  pelist(get_vector_send) = update_x%send(ix)%pe
1671  ix = ix + 1
1672  else if ( rank_y < rank_x ) then
1673  n = n+1
1674  ind_x(get_vector_send) = -1
1675  ind_y(get_vector_send) = iy
1676  cur_pos = cur_pos + update_y%send(iy)%totsize
1677  pelist(get_vector_send) = update_y%send(iy)%pe
1678  iy = iy+1
1679  endif
1680  end do
1681 
1682 
1683  end function get_vector_send
1684 
1685 
1686  !############################################################################
1687  function get_rank_unpack(domain, overlap_x, overlap_y, rank_x, rank_y, ind_x, ind_y)
1688  type(domain2d), intent(in) :: domain
1689  type(overlapspec), intent(in) :: overlap_x, overlap_y
1690  integer, intent(out) :: rank_x, rank_y, ind_x, ind_y
1691  integer :: get_rank_unpack
1692  integer :: nlist, nrecv_x, nrecv_y
1693 
1694  nlist = size(domain%list(:))
1695  nrecv_x = overlap_x%nrecv
1696  nrecv_y = overlap_y%nrecv
1697 
1698  rank_x = nlist+1
1699  rank_y = nlist+1
1700  if(nrecv_x>0) rank_x = overlap_x%recv(nrecv_x)%pe - domain%pe
1701  if(nrecv_y>0) rank_y = overlap_y%recv(nrecv_y)%pe - domain%pe
1702  if(rank_x .LE.0) rank_x = rank_x + nlist
1703  if(rank_y .LE.0) rank_y = rank_y + nlist
1704 
1705  get_rank_unpack = min(rank_x, rank_y)
1706  ind_x = 0
1707  ind_y = 0
1708  if(get_rank_unpack < nlist+1) then
1709  if(nrecv_x >0) ind_x = nrecv_x
1710  if(nrecv_y >0) ind_y = nrecv_y
1711  endif
1712 
1713  end function get_rank_unpack
1714 
1715  function get_mesgsize(overlap, do_dir)
1716  type(overlap_type), intent(in) :: overlap
1717  logical, intent(in) :: do_dir(:)
1718  integer :: get_mesgsize
1719  integer :: n, dir
1720 
1721  get_mesgsize = 0
1722  do n = 1, overlap%count
1723  dir = overlap%dir(n)
1724  if(do_dir(dir)) then
1725  get_mesgsize = get_mesgsize + overlap%msgsize(n)
1726  end if
1727  end do
1728 
1729  end function get_mesgsize
1730 
1731  !#############################################################################
1732  subroutine mpp_set_domain_symmetry(domain, symmetry)
1733  type(domain2d), intent(inout) :: domain
1734  logical, intent(in ) :: symmetry
1735 
1736  domain%symmetry = symmetry
1737 
1738  end subroutine mpp_set_domain_symmetry
1739 
1740  !> @brief Copies input 1d domain to the output 1d domain
1741  recursive subroutine mpp_copy_domain1d(domain_in, domain_out)
1742  type(domain1d), intent(in) :: domain_in !< Input domain
1743  type(domain1d), intent(inout) :: domain_out !< Output domain
1744 
1745  integer :: i !< For loop
1746  integer :: starting !< Starting bounds
1747  integer :: ending !< Ending bounds
1748 
1749  domain_out%compute = domain_in%compute
1750  domain_out%domain_data = domain_in%domain_data
1751  domain_out%global = domain_in%global
1752  domain_out%memory = domain_in%memory
1753  domain_out%cyclic = domain_in%cyclic
1754  domain_out%pe = domain_in%pe
1755  domain_out%pos = domain_in%pos
1756 
1757  if (associated(domain_in%list)) then
1758  starting = lbound(domain_in%list, 1)
1759  ending = ubound(domain_in%list, 1)
1760  if (associated(domain_out%list)) deallocate(domain_out%list) !< Check if allocated
1761  allocate(domain_out%list(starting:ending))
1762 
1763  do i = starting, ending
1764  call mpp_copy_domain1d(domain_in%list(i), domain_out%list(i))
1765  enddo
1766 
1767  endif
1768 
1769  end subroutine mpp_copy_domain1d
1770 
1771  !#################################################################
1772  !> @brief Copies input 2d domain to the output 2d domain
1773  subroutine mpp_copy_domain2d(domain_in, domain_out)
1774  type(domain2d), intent(in) :: domain_in !< Input domain
1775  type(domain2d), intent(inout) :: domain_out !< Output domain
1776 
1777  integer :: n,i !< For loops
1778  integer :: ntiles !< Number of tiles
1779  integer :: starting(2) !< Starting bounds
1780  integer :: ending(2) !< Ending bounds
1781 
1782  if (associated(domain_out%x)) then
1783  call mpp_error(fatal, "mpp_copy_domain: domain_out is already set")
1784  endif
1785 
1786  domain_out%id = domain_in%id
1787  domain_out%pe = domain_in%pe
1788  domain_out%fold = domain_in%fold
1789  domain_out%pos = domain_in%pos
1790  domain_out%symmetry = domain_in%symmetry
1791  domain_out%whalo = domain_in%whalo
1792  domain_out%ehalo = domain_in%ehalo
1793  domain_out%shalo = domain_in%shalo
1794  domain_out%nhalo = domain_in%nhalo
1795  domain_out%ntiles = domain_in%ntiles
1796  domain_out%max_ntile_pe = domain_in%max_ntile_pe
1797  domain_out%ncontacts = domain_in%ncontacts
1798  domain_out%rotated_ninety = domain_in%rotated_ninety
1799  domain_out%initialized = domain_in%initialized
1800  domain_out%tile_root_pe = domain_in%tile_root_pe
1801  domain_out%io_layout = domain_in%io_layout
1802  domain_out%name = domain_in%name
1803 
1804  ntiles = size(domain_in%x(:))
1805  allocate(domain_out%x(ntiles), domain_out%y(ntiles), domain_out%tile_id(ntiles) )
1806  do n = 1, ntiles
1807  call mpp_copy_domain1d(domain_in%x(n), domain_out%x(n))
1808  call mpp_copy_domain1d(domain_in%y(n), domain_out%y(n))
1809  enddo
1810 
1811  if (associated(domain_in%pearray)) then
1812  starting = lbound(domain_in%pearray)
1813  ending = ubound(domain_in%pearray)
1814 
1815  allocate(domain_out%pearray(starting(1):ending(1), starting(2):ending(2)))
1816  domain_out%pearray=domain_in%pearray
1817  endif
1818 
1819  if (associated(domain_in%tile_id)) then
1820  starting(1) = lbound(domain_in%tile_id,1)
1821  ending(1) = ubound(domain_in%tile_id,1)
1822 
1823  allocate(domain_out%tile_id(starting(1):ending(1)))
1824  domain_out%tile_id = domain_in%tile_id
1825  endif
1826 
1827  if (associated(domain_in%tile_id_all)) then
1828  starting(1) = lbound(domain_in%tile_id_all,1)
1829  ending(1) = ubound(domain_in%tile_id_all,1)
1830 
1831  allocate(domain_out%tile_id_all(starting(1):ending(1)))
1832  domain_out%tile_id_all = domain_in%tile_id_all
1833  endif
1834 
1835  if (associated(domain_in%list)) then
1836  starting(1) = lbound(domain_in%list,1)
1837  ending(1) = ubound(domain_in%list,1)
1838 
1839  allocate(domain_out%list(starting(1):ending(1)))
1840  do i = starting(1), ending(1)
1841  call mpp_copy_domain2d_spec(domain_in%list(i),domain_out%list(i))
1842  enddo
1843  endif
1844 
1845  return
1846 
1847  end subroutine mpp_copy_domain2d
1848 
1849  !> @brief Copies input 2d domain spec to the output 2d domain spec
1850  subroutine mpp_copy_domain2d_spec(domain2D_spec_in, domain2d_spec_out)
1851  type(domain2d_spec), intent(in) :: domain2D_spec_in !< Input
1852  type(domain2d_spec), intent(out) :: domain2D_spec_out !< Output
1853 
1854  integer :: starting !< Starting bounds
1855  integer :: ending !< Ending bounds
1856  integer :: i !< For loop
1857 
1858  domain2d_spec_out%pe = domain2d_spec_in%pe
1859  domain2d_spec_out%pos = domain2d_spec_in%pos
1860  domain2d_spec_out%tile_root_pe = domain2d_spec_in%tile_root_pe
1861 
1862  if (associated(domain2d_spec_in%tile_id)) then
1863  starting = lbound(domain2d_spec_in%tile_id,1)
1864  ending = ubound(domain2d_spec_in%tile_id,1)
1865 
1866  if (associated(domain2d_spec_out%tile_id)) deallocate(domain2d_spec_out%tile_id) !< Check if allocated
1867  allocate(domain2d_spec_out%tile_id(starting:ending))
1868  domain2d_spec_out%tile_id = domain2d_spec_in%tile_id
1869  endif
1870 
1871  if (associated(domain2d_spec_in%x)) then
1872  starting = lbound(domain2d_spec_in%x,1)
1873  ending = ubound(domain2d_spec_in%x,1)
1874 
1875  if (associated(domain2d_spec_out%x)) deallocate(domain2d_spec_out%x) !< Check if allocated
1876  allocate(domain2d_spec_out%x(starting:ending))
1877  do i = starting, ending
1878  call mpp_copy_domain1d_spec(domain2d_spec_in%x(i), domain2d_spec_out%x(i))
1879  enddo
1880  endif
1881 
1882  if (associated(domain2d_spec_in%y)) then
1883  starting = lbound(domain2d_spec_in%y,1)
1884  ending = ubound(domain2d_spec_in%y,1)
1885 
1886  if (associated(domain2d_spec_out%y)) deallocate(domain2d_spec_out%y) !< Check if allocated
1887  allocate(domain2d_spec_out%y(starting:ending))
1888  do i = starting, ending
1889  call mpp_copy_domain1d_spec(domain2d_spec_in%y(i), domain2d_spec_out%y(i))
1890  enddo
1891  endif
1892 
1893  end subroutine mpp_copy_domain2d_spec
1894 
1895  !> @brief Copies input 1d domain spec to the output 1d domain spec
1896  subroutine mpp_copy_domain1d_spec(domain1D_spec_in, domain1D_spec_out)
1897  type(domain1d_spec), intent(in) :: domain1D_spec_in !< Input
1898  type(domain1d_spec), intent(out) :: domain1D_spec_out !< Output
1899 
1900  domain1d_spec_out%pos = domain1d_spec_in%pos
1901 
1902  call mpp_copy_domain_axis_spec(domain1d_spec_in%compute, domain1d_spec_out%compute)
1903  call mpp_copy_domain_axis_spec(domain1d_spec_in%global, domain1d_spec_out%global)
1904  end subroutine mpp_copy_domain1d_spec
1905 
1906  !> @brief Copies input domain_axis_spec to the output domain_axis_spec
1907  subroutine mpp_copy_domain_axis_spec(domain_axis_spec_in, domain_axis_spec_out)
1908  type(domain_axis_spec), intent(in) :: domain_axis_spec_in !< Input
1909  type(domain_axis_spec), intent(out) :: domain_axis_spec_out !< Output
1910 
1911  domain_axis_spec_out%begin = domain_axis_spec_in%begin
1912  domain_axis_spec_out%end = domain_axis_spec_in%end
1913  domain_axis_spec_out%size = domain_axis_spec_in%size
1914  domain_axis_spec_out%max_size = domain_axis_spec_in%max_size
1915  domain_axis_spec_out%is_global = domain_axis_spec_in%is_global
1916  end subroutine mpp_copy_domain_axis_spec
1917 
1918  !######################################################################
1919  subroutine set_group_update(group, domain)
1920  type(mpp_group_update_type), intent(inout) :: group
1921  type(domain2d), intent(inout) :: domain
1922  integer :: nscalar, nvector, nlist
1923  integer :: nsend, nrecv, nsend_old, nrecv_old
1924  integer :: nsend_s, nsend_x, nsend_y
1925  integer :: nrecv_s, nrecv_x, nrecv_y
1926  integer :: update_buffer_pos, tot_recv_size, tot_send_size
1927  integer :: msgsize_s, msgsize_x, msgsize_y, msgsize
1928  logical :: recv_s(8), send_s(8)
1929  logical :: recv_x(8), send_x(8), recv_y(8), send_y(8)
1930  integer :: ntot, n, l, m, ksize
1931  integer :: i_s, i_x, i_y, rank_s, rank_x, rank_y, rank
1932  integer :: ind_s(3*MAXOVERLAP)
1933  integer :: ind_x(3*MAXOVERLAP)
1934  integer :: ind_y(3*MAXOVERLAP)
1935  integer :: pelist(3*MAXOVERLAP)
1936  integer :: send_size(3*MAXOVERLAP)
1937  integer :: position_x, position_y, npack, nunpack, dir
1938  integer :: pack_buffer_pos, unpack_buffer_pos
1939  integer :: omp_get_num_threads, nthreads
1940  character(len=8) :: text
1941  type(overlap_type), pointer :: overPtr => null()
1942  type(overlapspec), pointer :: update_s => null()
1943  type(overlapspec), pointer :: update_x => null()
1944  type(overlapspec), pointer :: update_y => null()
1945 
1946  nscalar = group%nscalar
1947  nvector = group%nvector
1948 
1949  !--- get the overlap data type
1950  select case(group%gridtype)
1951  case (agrid)
1952  position_x = center
1953  position_y = center
1954  case (bgrid_ne, bgrid_sw)
1955  position_x = corner
1956  position_y = corner
1957  case (cgrid_ne, cgrid_sw)
1958  position_x = east
1959  position_y = north
1960  case (dgrid_ne, dgrid_sw)
1961  position_x = north
1962  position_y = east
1963  case default
1964  call mpp_error(fatal, "set_group_update: invalid value of gridtype")
1965  end select
1966  if(nscalar>0) then
1967  update_s => search_update_overlap(domain, group%whalo_s, group%ehalo_s, &
1968  group%shalo_s, group%nhalo_s, group%position)
1969  endif
1970  if(nvector>0) then
1971  update_x => search_update_overlap(domain, group%whalo_v, group%ehalo_v, &
1972  group%shalo_v, group%nhalo_v, position_x)
1973  update_y => search_update_overlap(domain, group%whalo_v, group%ehalo_v, &
1974  group%shalo_v, group%nhalo_v, position_y)
1975  endif
1976 
1977  if(nscalar > 0) then
1978  recv_s = group%recv_s
1979  send_s = recv_s
1980  endif
1981  if(nvector > 0) then
1982  recv_x = group%recv_x
1983  send_x = recv_x
1984  recv_y = group%recv_y
1985  send_y = recv_y
1986  end if
1987  nlist = size(domain%list(:))
1988  group%initialized = .true.
1989  nsend_s = 0; nsend_x = 0; nsend_y = 0
1990  nrecv_s = 0; nrecv_x = 0; nrecv_y = 0
1991 
1992  if(nscalar > 0) then
1993  !--- This check could not be done because of memory domain
1994 ! if( group%isize_s .NE. (group%ie_s-group%is_s+1) .OR. group%jsize_s .NE. (group%je_s-group%js_s+1)) &
1995 ! call mpp_error(FATAL, "set_group_update: mismatch of size of the field and domain memory domain")
1996  nsend_s = update_s%nsend
1997  nrecv_s = update_s%nrecv
1998  endif
1999 
2000  !--- ksize_s must equal ksize_v
2001  if(nvector > 0 .AND. nscalar > 0) then
2002  if(group%ksize_s .NE. group%ksize_v) then
2003  call mpp_error(fatal, "set_group_update: ksize_s and ksize_v are not equal")
2004  endif
2005  ksize = group%ksize_s
2006  else if (nscalar > 0) then
2007  ksize = group%ksize_s
2008  else if (nvector > 0) then
2009  ksize = group%ksize_v
2010  else
2011  call mpp_error(fatal, "set_group_update: nscalar and nvector are all 0")
2012  endif
2013 
2014  nthreads = 1
2015 !$OMP PARALLEL
2016 !$ nthreads = omp_get_num_threads()
2017 !$OMP END PARALLEL
2018  if( nthreads > nthread_control_loop ) then
2019  group%k_loop_inside = .false.
2020  else
2021  group%k_loop_inside = .true.
2022  endif
2023 
2024  if(nvector > 0) then
2025  !--- This check could not be done because of memory domain
2026 ! if( group%isize_x .NE. (group%ie_x-group%is_x+1) .OR. group%jsize_x .NE. (group%je_x-group%js_x+1)) &
2027 ! call mpp_error(FATAL, "set_group_update: mismatch of size of the fieldx and domain memory domain")
2028 ! if( group%isize_y .NE. (group%ie_y-group%is_y+1) .OR. group%jsize_y .NE. (group%je_y-group%js_y+1)) &
2029 ! call mpp_error(FATAL, "set_group_update: mismatch of size of the fieldy and domain memory domain")
2030  nsend_x = update_x%nsend
2031  nrecv_x = update_x%nrecv
2032  nsend_y = update_y%nsend
2033  nrecv_y = update_y%nrecv
2034  endif
2035 
2036  !figure out message size for each processor.
2037  ntot = nrecv_s + nrecv_x + nrecv_y
2038  if(ntot > 3*maxoverlap) call mpp_error(fatal, "set_group_update: ntot is greater than 3*MAXOVERLAP")
2039  n = 1
2040  i_s = 1
2041  i_x = 1
2042  i_y = 1
2043  ind_s = -1
2044  ind_x = -1
2045  ind_y = -1
2046  nrecv = 0
2047  do while(n<=ntot)
2048  if( i_s <= nrecv_s ) then
2049  rank_s = update_s%recv(i_s)%pe-domain%pe
2050  if(rank_s .LE. 0) rank_s = rank_s + nlist
2051  else
2052  rank_s = -1
2053  endif
2054  if( i_x <= nrecv_x ) then
2055  rank_x = update_x%recv(i_x)%pe-domain%pe
2056  if(rank_x .LE. 0) rank_x = rank_x + nlist
2057  else
2058  rank_x = -1
2059  endif
2060  if( i_y <= nrecv_y ) then
2061  rank_y = update_y%recv(i_y)%pe-domain%pe
2062  if(rank_y .LE. 0) rank_y = rank_y + nlist
2063  else
2064  rank_y = -1
2065  endif
2066  nrecv = nrecv + 1
2067  rank = maxval((/rank_s, rank_x, rank_y/))
2068  if(rank == rank_s) then
2069  n = n + 1
2070  ind_s(nrecv) = i_s
2071  pelist(nrecv) = update_s%recv(i_s)%pe
2072  i_s = i_s + 1
2073  endif
2074  if(rank == rank_x) then
2075  n = n + 1
2076  ind_x(nrecv) = i_x
2077  pelist(nrecv) = update_x%recv(i_x)%pe
2078  i_x = i_x + 1
2079  endif
2080  if(rank == rank_y) then
2081  n = n + 1
2082  ind_y(nrecv) = i_y
2083  pelist(nrecv) = update_y%recv(i_y)%pe
2084  i_y = i_y + 1
2085  endif
2086  enddo
2087 
2088  nrecv_old = nrecv
2089  nrecv = 0
2090  update_buffer_pos = 0
2091  tot_recv_size = 0
2092 
2093  !--- setup for recv
2094  do l = 1, nrecv_old
2095  msgsize_s = 0
2096  msgsize_x = 0
2097  msgsize_y = 0
2098  m = ind_s(l)
2099  if(m>0) msgsize_s = get_mesgsize(update_s%recv(m), recv_s)*ksize*nscalar
2100  m = ind_x(l)
2101  if(m>0) msgsize_x = get_mesgsize(update_x%recv(m), recv_x)*ksize*nvector
2102  m = ind_y(l)
2103  if(m>0) msgsize_y = get_mesgsize(update_y%recv(m), recv_y)*ksize*nvector
2104  msgsize = msgsize_s + msgsize_x + msgsize_y
2105  if( msgsize.GT.0 )then
2106  tot_recv_size = tot_recv_size + msgsize
2107  nrecv = nrecv + 1
2108  if(nrecv > maxoverlap) then
2109  call mpp_error(fatal, "set_group_update: nrecv is greater than MAXOVERLAP, increase MAXOVERLAP")
2110  endif
2111  group%from_pe(nrecv) = pelist(l)
2112  group%recv_size(nrecv) = msgsize
2113  group%buffer_pos_recv(nrecv) = update_buffer_pos
2114  update_buffer_pos = update_buffer_pos + msgsize
2115  end if
2116  end do
2117  group%nrecv = nrecv
2118 
2119  !--- setup for unpack
2120  nunpack = 0
2121  unpack_buffer_pos = 0
2122  do l = 1, nrecv_old
2123  m = ind_s(l)
2124  if(m>0) then
2125  overptr => update_s%recv(m)
2126  do n = 1, overptr%count
2127  dir = overptr%dir(n)
2128  if(recv_s(dir)) then
2129  nunpack = nunpack + 1
2130  if(nunpack > maxoverlap) call mpp_error(fatal, &
2131  "set_group_update: nunpack is greater than MAXOVERLAP, increase MAXOVERLAP 1")
2132  group%unpack_type(nunpack) = field_s
2133  group%unpack_buffer_pos(nunpack) = unpack_buffer_pos
2134  group%unpack_rotation(nunpack) = overptr%rotation(n)
2135  group%unpack_is(nunpack) = overptr%is(n)
2136  group%unpack_ie(nunpack) = overptr%ie(n)
2137  group%unpack_js(nunpack) = overptr%js(n)
2138  group%unpack_je(nunpack) = overptr%je(n)
2139  group%unpack_size(nunpack) = overptr%msgsize(n)*nscalar
2140  unpack_buffer_pos = unpack_buffer_pos + group%unpack_size(nunpack)*ksize
2141  end if
2142  end do
2143  end if
2144 
2145  m = ind_x(l)
2146  if(m>0) then
2147  overptr => update_x%recv(m)
2148  do n = 1, overptr%count
2149  dir = overptr%dir(n)
2150  if(recv_x(dir)) then
2151  nunpack = nunpack + 1
2152  if(nunpack > maxoverlap) call mpp_error(fatal, &
2153  "set_group_update: nunpack is greater than MAXOVERLAP, increase MAXOVERLAP 2")
2154  group%unpack_type(nunpack) = field_x
2155  group%unpack_buffer_pos(nunpack) = unpack_buffer_pos
2156  group%unpack_rotation(nunpack) = overptr%rotation(n)
2157  group%unpack_is(nunpack) = overptr%is(n)
2158  group%unpack_ie(nunpack) = overptr%ie(n)
2159  group%unpack_js(nunpack) = overptr%js(n)
2160  group%unpack_je(nunpack) = overptr%je(n)
2161  group%unpack_size(nunpack) = overptr%msgsize(n)*nvector
2162  unpack_buffer_pos = unpack_buffer_pos + group%unpack_size(nunpack)*ksize
2163  end if
2164  end do
2165  end if
2166 
2167  m = ind_y(l)
2168  if(m>0) then
2169  overptr => update_y%recv(m)
2170  do n = 1, overptr%count
2171  dir = overptr%dir(n)
2172  if(recv_y(dir)) then
2173  nunpack = nunpack + 1
2174  if(nunpack > maxoverlap) call mpp_error(fatal, &
2175  "set_group_update: nunpack is greater than MAXOVERLAP, increase MAXOVERLAP 3")
2176  group%unpack_type(nunpack) = field_y
2177  group%unpack_buffer_pos(nunpack) = unpack_buffer_pos
2178  group%unpack_rotation(nunpack) = overptr%rotation(n)
2179  group%unpack_is(nunpack) = overptr%is(n)
2180  group%unpack_ie(nunpack) = overptr%ie(n)
2181  group%unpack_js(nunpack) = overptr%js(n)
2182  group%unpack_je(nunpack) = overptr%je(n)
2183  group%unpack_size(nunpack) = overptr%msgsize(n)*nvector
2184  unpack_buffer_pos = unpack_buffer_pos + group%unpack_size(nunpack)*ksize
2185  end if
2186  end do
2187  end if
2188  end do
2189  group%nunpack = nunpack
2190 
2191  if(update_buffer_pos .NE. unpack_buffer_pos ) call mpp_error(fatal, &
2192  .NE."set_group_update: update_buffer_pos unpack_buffer_pos")
2193 
2194  !figure out message size for each processor.
2195  ntot = nsend_s + nsend_x + nsend_y
2196  n = 1
2197  i_s = 1
2198  i_x = 1
2199  i_y = 1
2200  ind_s = -1
2201  ind_x = -1
2202  ind_y = -1
2203  nsend = 0
2204  do while(n<=ntot)
2205  if( i_s <= nsend_s ) then
2206  rank_s = update_s%send(i_s)%pe-domain%pe
2207  if(rank_s .LT. 0) rank_s = rank_s + nlist
2208  else
2209  rank_s = nlist+1
2210  endif
2211  if( i_x <= nsend_x ) then
2212  rank_x = update_x%send(i_x)%pe-domain%pe
2213  if(rank_x .LT. 0) rank_x = rank_x + nlist
2214  else
2215  rank_x = nlist+1
2216  endif
2217  if( i_y <= nsend_y ) then
2218  rank_y = update_y%send(i_y)%pe-domain%pe
2219  if(rank_y .LT. 0) rank_y = rank_y + nlist
2220  else
2221  rank_y = nlist+1
2222  endif
2223  nsend = nsend + 1
2224  rank = minval((/rank_s, rank_x, rank_y/))
2225  if(rank == rank_s) then
2226  n = n + 1
2227  ind_s(nsend) = i_s
2228  pelist(nsend) = update_s%send(i_s)%pe
2229  i_s = i_s + 1
2230  endif
2231  if(rank == rank_x) then
2232  n = n + 1
2233  ind_x(nsend) = i_x
2234  pelist(nsend) = update_x%send(i_x)%pe
2235  i_x = i_x + 1
2236  endif
2237  if(rank == rank_y) then
2238  n = n + 1
2239  ind_y(nsend) = i_y
2240  pelist(nsend) = update_y%send(i_y)%pe
2241  i_y = i_y + 1
2242  endif
2243  enddo
2244 
2245  nsend_old = nsend
2246  nsend = 0
2247  tot_send_size = 0
2248  do l = 1, nsend_old
2249  msgsize_s = 0
2250  msgsize_x = 0
2251  msgsize_y = 0
2252  m = ind_s(l)
2253  if(m>0) msgsize_s = get_mesgsize(update_s%send(m), send_s)*ksize*nscalar
2254  m = ind_x(l)
2255  if(m>0) msgsize_x = get_mesgsize(update_x%send(m), send_x)*ksize*nvector
2256  m = ind_y(l)
2257  if(m>0) msgsize_y = get_mesgsize(update_y%send(m), send_y)*ksize*nvector
2258  msgsize = msgsize_s + msgsize_x + msgsize_y
2259  if( msgsize.GT.0 )then
2260  tot_send_size = tot_send_size + msgsize
2261  nsend = nsend + 1
2262  if(nsend > maxoverlap) then
2263  call mpp_error(fatal, "set_group_update: nsend is greater than MAXOVERLAP, increase MAXOVERLAP")
2264  endif
2265  send_size(nsend) = msgsize
2266  group%to_pe(nsend) = pelist(l)
2267  group%buffer_pos_send(nsend) = update_buffer_pos
2268  group%send_size(nsend) = msgsize
2269  update_buffer_pos = update_buffer_pos + msgsize
2270  end if
2271  end do
2272  group%nsend = nsend
2273 
2274  !--- setup for pack
2275  npack = 0
2276  pack_buffer_pos = unpack_buffer_pos
2277  do l = 1, nsend_old
2278  m = ind_s(l)
2279  if(m>0) then
2280  overptr => update_s%send(m)
2281  do n = 1, overptr%count
2282  dir = overptr%dir(n)
2283  if(send_s(dir)) then
2284  npack = npack + 1
2285  if(npack > maxoverlap) call mpp_error(fatal, &
2286  "set_group_update: npack is greater than MAXOVERLAP, increase MAXOVERLAP 1")
2287  group%pack_type(npack) = field_s
2288  group%pack_buffer_pos(npack) = pack_buffer_pos
2289  group%pack_rotation(npack) = overptr%rotation(n)
2290  group%pack_is(npack) = overptr%is(n)
2291  group%pack_ie(npack) = overptr%ie(n)
2292  group%pack_js(npack) = overptr%js(n)
2293  group%pack_je(npack) = overptr%je(n)
2294  group%pack_size(npack) = overptr%msgsize(n)*nscalar
2295  pack_buffer_pos = pack_buffer_pos + group%pack_size(npack)*ksize
2296  end if
2297  end do
2298  end if
2299 
2300  m = ind_x(l)
2301  if(m>0) then
2302  overptr => update_x%send(m)
2303  do n = 1, overptr%count
2304  dir = overptr%dir(n)
2305  !--- nonsym_edge update is not for rotation of 90 or -90 degree ( cubic sphere grid )
2306  if( group%nonsym_edge .and. (overptr%rotation(n)==ninety .or. &
2307  overptr%rotation(n)==minus_ninety) ) then
2308  call mpp_error(fatal, 'set_group_update: flags=NONSYMEDGEUPDATE is not compatible '// &
2309  'with 90 or -90 degree rotation (normally cubic sphere grid' )
2310  endif
2311  if(send_x(dir)) then
2312  npack = npack + 1
2313  if(npack > maxoverlap) call mpp_error(fatal, &
2314  "set_group_update: npack is greater than MAXOVERLAP, increase MAXOVERLAP 2")
2315  group%pack_type(npack) = field_x
2316  group%pack_buffer_pos(npack) = pack_buffer_pos
2317  group%pack_rotation(npack) = overptr%rotation(n)
2318  group%pack_is(npack) = overptr%is(n)
2319  group%pack_ie(npack) = overptr%ie(n)
2320  group%pack_js(npack) = overptr%js(n)
2321  group%pack_je(npack) = overptr%je(n)
2322  group%pack_size(npack) = overptr%msgsize(n)*nvector
2323  pack_buffer_pos = pack_buffer_pos + group%pack_size(npack)*ksize
2324  end if
2325  end do
2326  end if
2327 
2328  m = ind_y(l)
2329  if(m>0) then
2330  overptr => update_y%send(m)
2331  do n = 1, overptr%count
2332  dir = overptr%dir(n)
2333  if( group%nonsym_edge .and. (overptr%rotation(n)==ninety .or. &
2334  overptr%rotation(n)==minus_ninety) ) then
2335  call mpp_error(fatal, 'set_group_update: flags=NONSYMEDGEUPDATE is not compatible '// &
2336  'with 90 or -90 degree rotation (normally cubic sphere grid' )
2337  endif
2338  if(send_y(dir)) then
2339  npack = npack + 1
2340  if(npack > maxoverlap) call mpp_error(fatal, &
2341  "set_group_update: npack is greater than MAXOVERLAP, increase MAXOVERLAP 3")
2342  group%pack_type(npack) = field_y
2343  group%pack_buffer_pos(npack) = pack_buffer_pos
2344  group%pack_rotation(npack) = overptr%rotation(n)
2345  group%pack_is(npack) = overptr%is(n)
2346  group%pack_ie(npack) = overptr%ie(n)
2347  group%pack_js(npack) = overptr%js(n)
2348  group%pack_je(npack) = overptr%je(n)
2349  group%pack_size(npack) = overptr%msgsize(n)*nvector
2350  pack_buffer_pos = pack_buffer_pos + group%pack_size(npack)*ksize
2351  end if
2352  end do
2353  end if
2354  end do
2355  group%npack = npack
2356  if(update_buffer_pos .NE. pack_buffer_pos ) call mpp_error(fatal, &
2357  .NE."set_group_update: update_buffer_pos pack_buffer_pos")
2358 
2359  !--- make sure the buffer is large enough
2360  mpp_domains_stack_hwm = max( mpp_domains_stack_hwm, tot_recv_size+tot_send_size )
2361 
2362  if( mpp_domains_stack_hwm.GT.mpp_domains_stack_size )then
2363  write( text,'(i8)' )mpp_domains_stack_hwm
2364  call mpp_error( fatal, 'set_group_update: mpp_domains_stack overflow, '// &
2365  'call mpp_domains_set_stack_size('//trim(text)//') from all PEs.' )
2366  end if
2367 
2368  group%tot_msgsize = tot_recv_size+tot_send_size
2369 
2370 end subroutine set_group_update
2371 
2372 
2373 !######################################################################
2374  subroutine mpp_clear_group_update(group)
2375  type(mpp_group_update_type), intent(inout) :: group
2376 
2377  group%nscalar = 0
2378  group%nvector = 0
2379  group%nsend = 0
2380  group%nrecv = 0
2381  group%npack = 0
2382  group%nunpack = 0
2383  group%initialized = .false.
2384 
2385  end subroutine mpp_clear_group_update
2386 
2387 !#####################################################################
2389  type(mpp_group_update_type), intent(in) :: group
2390  logical :: mpp_group_update_initialized
2391 
2392  mpp_group_update_initialized = group%initialized
2393 
2394  end function mpp_group_update_initialized
2395 
2396 !#####################################################################
2397  function mpp_group_update_is_set(group)
2398  type(mpp_group_update_type), intent(in) :: group
2399  logical :: mpp_group_update_is_set
2400 
2401  mpp_group_update_is_set = (group%nscalar > 0 .OR. group%nvector > 0)
2402 
2403  end function mpp_group_update_is_set
2404 !> @}
subroutine mpp_get_overlap(domain, action, p, is, ie, js, je, dir, rot, position)
Set user stack size.
subroutine mpp_get_neighbor_pe_2d(domain, direction, pe)
Return PE North/South/East/West of this PE-domain. direction must be NORTH, SOUTH,...
subroutine mpp_get_global_domains1d(domain, begin, end, size)
Set user stack size.
type(overlapspec) function, pointer search_bound_overlap(domain, position)
This routine finds the bound at certain position.
subroutine mpp_set_super_grid_indices(grid)
Modifies the indices in the domain_axis_spec type to those of the supergrid.
integer function mpp_get_domain_npes(domain)
Set user stack size.
logical function mpp_domain2d_eq(a, b)
Set user stack size.
integer function mpp_get_tile_npes(domain)
Returns number of processors used on current tile.
integer function get_rank_send(domain, overlap_x, overlap_y, rank_x, rank_y, ind_x, ind_y)
Set user stack size.
subroutine set_group_update(group, domain)
Set user stack size.
subroutine mpp_get_global_domain2d(domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, tile_count, position)
Set user stack size.
subroutine mpp_get_pelist1d(domain, pelist, pos)
Set user stack size.
subroutine mpp_set_global_domain1d(domain, begin, end, size)
Set user stack size.
subroutine mpp_get_layout2d(domain, layout)
Set user stack size.
subroutine mpp_get_tile_pelist(domain, pelist)
Get the processors list used on current tile.
subroutine mpp_get_domain_components(domain, x, y, tile_count)
Retrieve 1D components of 2D decomposition.
subroutine mpp_get_domain_extents1d(domain, xextent, yextent)
Set user stack size.
logical function mpp_group_update_is_set(group)
Set user stack size.
integer function get_vector_send(domain, update_x, update_y, ind_x, ind_y, start_pos, pelist)
Set user stack size.
subroutine mpp_copy_domain_axis_spec(domain_axis_spec_in, domain_axis_spec_out)
Copies input domain_axis_spec to the output domain_axis_spec.
integer function mpp_get_domain_tile_commid(domain)
Set user stack size.
subroutine mpp_set_global_domain2d(domain, xbegin, xend, ybegin, yend, xsize, ysize, tile_count)
Set user stack size.
logical function mpp_domain1d_eq(a, b)
Set user stack size.
integer function get_rank_recv(domain, overlap_x, overlap_y, rank_x, rank_y, ind_x, ind_y)
Set user stack size.
integer function, dimension(size(domain%tile_id(:))) mpp_get_tile_id(domain)
Returns the tile_id on current pe.
logical function mpp_domain_is_symmetry(domain)
Set user stack size.
subroutine mpp_create_super_grid_domain(domain)
Modifies the indices of the input domain to create the supergrid domain.
integer function mpp_get_num_overlap(domain, action, p, position)
Set user stack size.
type(overlapspec) function, pointer search_check_overlap(domain, position)
this routine finds the check at certain position
integer function mpp_get_current_ntile(domain)
Returns number of tile on current pe.
subroutine mpp_set_domain_symmetry(domain, symmetry)
Set user stack size.
integer function mpp_get_ntile_count(domain)
Returns number of tiles in mosaic.
subroutine mpp_get_domain_extents2d(domain, xextent, yextent)
This will return xextent and yextent for each tile.
subroutine mpp_get_global_domain1d(domain, begin, end, size, max_size)
Set user stack size.
logical function domain_update_is_needed(domain, whalo, ehalo, shalo, nhalo)
Set user stack size.
integer function, dimension(2) mpp_get_io_domain_layout(domain)
Set user stack size.
subroutine mpp_get_neighbor_pe_1d(domain, direction, pe)
Return PE to the righ/left of this PE-domain.
subroutine mpp_get_tile_compute_domains(domain, xbegin, xend, ybegin, yend, position)
Set user stack size.
subroutine mpp_get_compute_domain2d(domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, x_is_global, y_is_global, tile_count, position)
Set user stack size.
subroutine mpp_get_compute_domain1d(domain, begin, end, size, max_size, is_global)
Set user stack size.
subroutine mpp_copy_domain1d_spec(domain1D_spec_in, domain1D_spec_out)
Copies input 1d domain spec to the output 1d domain spec.
logical function mpp_domain1d_ne(a, b)
Set user stack size.
subroutine mpp_get_layout1d(domain, layout)
Set user stack size.
subroutine mpp_copy_domain2d_spec(domain2D_spec_in, domain2d_spec_out)
Copies input 2d domain spec to the output 2d domain spec.
subroutine mpp_get_update_pelist(domain, action, pelist, position)
Set user stack size.
subroutine mpp_set_data_domain2d(domain, xbegin, xend, ybegin, yend, xsize, ysize, x_is_global, y_is_global, tile_count)
Set user stack size.
type(overlapspec) function, pointer search_update_overlap(domain, whalo, ehalo, shalo, nhalo, position)
this routine found the domain has the same halo size with the input whalo, ehalo,
subroutine mpp_get_compute_domains1d(domain, begin, end, size)
Set user stack size.
integer function mpp_get_domain_tile_root_pe(domain)
Set user stack size.
subroutine mpp_get_pelist2d(domain, pelist, pos)
Set user stack size.
subroutine mpp_get_memory_domain2d(domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, x_is_global, y_is_global, position)
Set user stack size.
integer function get_mesgsize(overlap, do_dir)
Set user stack size.
subroutine mpp_set_compute_domain1d(domain, begin, end, size, is_global)
Set user stack size.
integer function mpp_get_domain_pe(domain)
Set user stack size.
integer function get_vector_recv(domain, update_x, update_y, ind_x, ind_y, start_pos, pelist)
Set user stack size.
subroutine mpp_get_tile_list(domain, tiles)
Return the tile_id on current pelist. one-tile-per-pe is assumed.
logical function mpp_group_update_initialized(group)
Set user stack size.
subroutine mpp_set_compute_domain2d(domain, xbegin, xend, ybegin, yend, xsize, ysize, x_is_global, y_is_global, tile_count)
Set user stack size.
type(domain2d) function, pointer mpp_get_io_domain(domain)
Set user stack size.
subroutine mpp_get_compute_domains2d(domain, xbegin, xend, xsize, ybegin, yend, ysize, position)
Set user stack size.
subroutine compute_overlaps(domain, position, update, check, ishift, jshift, x_cyclic_offset, y_cyclic_offset, whalo, ehalo, shalo, nhalo)
Computes remote domain overlaps.
subroutine mpp_copy_domain2d(domain_in, domain_out)
Copies input 2d domain to the output 2d domain.
subroutine mpp_get_memory_domain1d(domain, begin, end, size, max_size, is_global)
Set user stack size.
subroutine mpp_get_domain_shift(domain, ishift, jshift, position)
Returns the shift value in x and y-direction according to domain position..
logical function mpp_domain2d_ne(a, b)
Set user stack size.
logical function mpp_domain_is_initialized(domain)
Set user stack size.
subroutine nullify_domain2d_list(domain)
Set user stack size.
logical function mpp_domain_is_tile_root_pe(domain)
Returns if current pe is the root pe of the tile, if number of tiles on current pe is greater than 1,...
character(len=name_length) function mpp_get_domain_name(domain)
Set user stack size.
subroutine mpp_get_global_domains2d(domain, xbegin, xend, xsize, ybegin, yend, ysize, position)
Set user stack size.
integer function mpp_get_domain_commid(domain)
Set user stack size.
subroutine mpp_get_data_domain2d(domain, xbegin, xend, ybegin, yend, xsize, xmax_size, ysize, ymax_size, x_is_global, y_is_global, tile_count, position)
Set user stack size.
subroutine mpp_get_domain_pelist(domain, pelist)
Set user stack size.
subroutine mpp_domains_set_stack_size(n)
Set user stack size.
subroutine mpp_clear_group_update(group)
Set user stack size.
subroutine mpp_get_update_size(domain, nsend, nrecv, position)
Set user stack size.
integer function get_rank_unpack(domain, overlap_x, overlap_y, rank_x, rank_y, ind_x, ind_y)
Set user stack size.
integer function mpp_get_domain_root_pe(domain)
Set user stack size.
subroutine mpp_set_data_domain1d(domain, begin, end, size, is_global)
Set user stack size.
recursive subroutine mpp_copy_domain1d(domain_in, domain_out)
Copies input 1d domain to the output 1d domain.
subroutine set_overlaps(domain, overlap_in, overlap_out, whalo_out, ehalo_out, shalo_out, nhalo_out)
this routine sets up the overlapping for mpp_update_domains for arbitrary halo update....
subroutine mpp_get_data_domain1d(domain, begin, end, size, max_size, is_global)
Set user stack size.
integer function mpp_pe()
Returns processor ID.
Definition: mpp_util.inc:407