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