FV3 Bundle
test_mpp_domains.F90
Go to the documentation of this file.
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 #ifdef test_mpp_domains
20 program test
21  use mpp_mod, only : fatal, warning, mpp_debug, note, mpp_clock_sync,mpp_clock_detailed
22  use mpp_mod, only : mpp_pe, mpp_npes, mpp_node, mpp_root_pe, mpp_error, mpp_set_warn_level
23  use mpp_mod, only : mpp_declare_pelist, mpp_set_current_pelist, mpp_sync, mpp_sync_self
24  use mpp_mod, only : mpp_clock_begin, mpp_clock_end, mpp_clock_id
25  use mpp_mod, only : mpp_init, mpp_exit, mpp_chksum, stdout, stderr
26  use mpp_mod, only : input_nml_file
27  use mpp_mod, only : mpp_get_current_pelist, mpp_broadcast
28  use mpp_domains_mod, only : global_data_domain, bitwise_exact_sum, bgrid_ne, cgrid_ne, dgrid_ne, agrid
29  use mpp_domains_mod, only : fold_south_edge, fold_north_edge, fold_west_edge, fold_east_edge
30  use mpp_domains_mod, only : mpp_domain_time, cyclic_global_domain, nupdate,eupdate, xupdate, yupdate, scalar_pair
31  use mpp_domains_mod, only : domain1d, domain2d, domaincommunicator2d, bitwise_efp_sum
32  use mpp_domains_mod, only : mpp_get_compute_domain, mpp_get_data_domain, mpp_domains_set_stack_size
34  use mpp_domains_mod, only : mpp_domains_init, mpp_domains_exit, mpp_broadcast_domain
37  use mpp_domains_mod, only : mpp_get_neighbor_pe, mpp_define_mosaic, mpp_nullify_domain_list
38  use mpp_domains_mod, only : north, north_east, east, south_east, corner, center
39  use mpp_domains_mod, only : south, south_west, west, north_west, mpp_define_mosaic_pelist
40  use mpp_domains_mod, only : mpp_get_global_domain, zero, ninety, minus_ninety
42  use mpp_domains_mod, only : mpp_define_nest_domains, nest_domain_type
43  use mpp_domains_mod, only : mpp_get_c2f_index, mpp_update_nest_fine
44  use mpp_domains_mod, only : mpp_get_f2c_index, mpp_update_nest_coarse
45  use mpp_domains_mod, only : mpp_get_domain_shift, edgeupdate, mpp_deallocate_domain
47  use mpp_domains_mod, only : mpp_do_group_update, mpp_clear_group_update
49  use mpp_domains_mod, only : wupdate, supdate, mpp_get_compute_domains, nonsymedgeupdate
50  use mpp_domains_mod, only : domainug, mpp_define_unstruct_domain, mpp_get_ug_domain_tile_id
51  use mpp_domains_mod, only : mpp_get_ug_compute_domain, mpp_pass_sg_to_ug, mpp_pass_ug_to_sg
52  use mpp_domains_mod, only : mpp_get_ug_global_domain, mpp_global_field_ug
54 
55  implicit none
56 #include <fms_platform.h>
57  integer :: pe, npes
58  integer :: nx=128, ny=128, nz=40, stackmax=4000000
59  integer :: unit=7
60  integer :: stdunit = 6
61  logical :: debug=.false., opened
62 
63  integer :: mpes = 0
64  integer :: whalo = 2, ehalo = 2, shalo = 2, nhalo = 2
65  integer :: x_cyclic_offset = 3 ! to be used in test_cyclic_offset
66  integer :: y_cyclic_offset = -4 ! to be used in test_cyclic_offset
67  character(len=32) :: warn_level = "fatal"
68  integer :: wide_halo_x = 0, wide_halo_y = 0
69  integer :: nx_cubic = 0, ny_cubic = 0
70  logical :: test_performance = .false.
71  logical :: test_interface = .true.
72  logical :: test_nest_domain = .false.
73  logical :: test_edge_update = .false.
74  logical :: test_nonsym_edge = .false.
75  logical :: test_group = .false.
76  logical :: test_cubic_grid_redistribute = .false.
77  logical :: check_parallel = .false. ! when check_parallel set to false,
78  logical :: test_get_nbr = .false.
79  logical :: test_boundary = .false.
80  logical :: test_global_sum = .false.
81  logical :: test_halosize_performance = .false.
82  integer :: ensemble_size = 1
83  integer :: layout_cubic(2) = (/0,0/)
84  integer :: layout_tripolar(2) = (/0,0/)
85  integer :: layout_ensemble(2) = (/0,0/)
86  logical :: do_sleep = .false.
87  integer :: num_iter = 1
88  integer :: num_fields = 4
89 
90  !--- namelist variable for nest domain
91  integer :: tile_fine = 1
92  integer :: tile_coarse = 1
93  integer :: istart_fine = 0, iend_fine = -1, jstart_fine = 0, jend_fine = -1
94  integer :: istart_coarse = 0, iend_coarse = -1, jstart_coarse = 0, jend_coarse = -1
95  integer :: npes_coarse = 0
96  integer :: npes_fine = 0
97  integer :: extra_halo = 0
98  logical :: mix_2D_3D = .false.
99  logical :: test_subset = .false.
100  logical :: test_unstruct = .false.
101  integer :: nthreads = 1
102  logical :: test_adjoint = .false.
103  logical :: wide_halo = .false.
104 
105  namelist / test_mpp_domains_nml / nx, ny, nz, stackmax, debug, mpes, check_parallel, &
106  whalo, ehalo, shalo, nhalo, x_cyclic_offset, y_cyclic_offset, &
107  warn_level, wide_halo_x, wide_halo_y, nx_cubic, ny_cubic, &
108  test_performance, test_interface, num_fields, do_sleep, num_iter, &
109  test_nest_domain, tile_fine, tile_coarse, istart_fine, iend_fine, &
110  jstart_fine, jend_fine, istart_coarse, iend_coarse, jstart_coarse, &
111  jend_coarse, extra_halo, npes_fine, npes_coarse, mix_2d_3d, test_get_nbr, &
112  test_edge_update, test_cubic_grid_redistribute, ensemble_size, &
113  layout_cubic, layout_ensemble, nthreads, test_boundary, &
114  layout_tripolar, test_group, test_global_sum, test_subset, test_unstruct, &
115  test_nonsym_edge, test_halosize_performance, test_adjoint, wide_halo
116  integer :: i, j, k
117  integer :: layout(2)
118  integer :: id
119  integer :: outunit, errunit, io_status
120  integer :: get_cpu_affinity, base_cpu, omp_get_num_threads, omp_get_thread_num
121 
122  call mpp_memuse_begin()
123  call mpp_init()
124 
125  outunit = stdout()
126  errunit = stderr()
127 #ifdef INTERNAL_FILE_NML
128  read (input_nml_file, test_mpp_domains_nml, status=io_status)
129 #else
130  do
131  inquire( unit=unit, opened=opened )
132  if( .NOT.opened )exit
133  unit = unit + 1
134  if( unit.EQ.100 )call mpp_error( fatal, 'Unable to locate unit number.' )
135  end do
136  open( unit=unit, file='input.nml', iostat=io_status )
137  read( unit,test_mpp_domains_nml, iostat=io_status )
138  close(unit)
139 #endif
140 
141  if (io_status > 0) then
142  call mpp_error(fatal,'=>test_mpp_domains: Error reading input.nml')
143  endif
144 
145  select case(trim(warn_level))
146  case("fatal")
147  call mpp_set_warn_level(fatal)
148  case("warning")
149  call mpp_set_warn_level(warning)
150  case default
151  call mpp_error(fatal, "test_mpp_domains: warn_level should be fatal or warning")
152  end select
153 
154  pe = mpp_pe()
155  npes = mpp_npes()
156 
157  if( debug )then
158  call mpp_domains_init(mpp_debug)
159  else
160  call mpp_domains_init(mpp_domain_time)
161  end if
162  call mpp_domains_set_stack_size(stackmax)
163 
164 !$ call omp_set_num_threads(nthreads)
165 !$ base_cpu = get_cpu_affinity()
166 !$OMP PARALLEL
167 !$ call set_cpu_affinity( base_cpu + omp_get_thread_num() )
168 !$OMP END PARALLEL
169 
170  if( pe.EQ.mpp_root_pe() )print '(a,9i6)', 'npes, mpes, nx, ny, nz, whalo, ehalo, shalo, nhalo =', &
171  npes, mpes, nx, ny, nz, whalo, ehalo, shalo, nhalo
172  call mpp_memuse_end("in the begining", outunit)
173 
174  !--- wide_halo_x and wide_halo_y must be either both 0 or both positive.
175  if( wide_halo_x < 0 .OR. wide_halo_y < 0) call mpp_error(fatal, &
176  "test_mpp_domain: both wide_halo_x and wide_halo_y should be non-negative")
177  if( wide_halo_x == 0 .NEQV. wide_halo_y == 0) call mpp_error(fatal, &
178  "test_mpp_domain: wide_halo_x and wide_halo_y should be both zero or both positive")
179 
180  !--- nx_cubic and ny_cubic must be either both 0 or both positive.
181  if( nx_cubic < 0 .OR. ny_cubic < 0) call mpp_error(fatal, &
182  "test_mpp_domain: both nx_cubic and ny_cubic should be non-negative")
183  if( nx_cubic == 0 .NEQV. ny_cubic == 0) call mpp_error(fatal, &
184  "test_mpp_domain: nx_cubic and ny_cubic should be both zero or both positive")
185 
186  if( test_nest_domain ) then
187  if( istart_fine > iend_fine .OR. jstart_fine > jend_fine ) call mpp_error(fatal, &
188  "test_mpp_domain: check the setting of namelist variable istart_fine, iend_fine, jstart_fine, jend_fine")
189  if( istart_coarse > iend_coarse .OR. jstart_coarse > jend_coarse ) call mpp_error(fatal, &
190  "test_mpp_domain: check the setting of namelist variable istart_coarse, iend_coarse, jstart_coarse, jend_coarse")
191 
192  call test_update_nest_domain('Cubic-Grid')
193  endif
194 
195  if(test_subset) then
196  call test_subset_update()
197  endif
198 
199  if( test_halosize_performance ) then
200  call test_halosize_update( 'Folded-north' )
201  call test_halosize_update( 'Folded-north symmetry' )
202  call test_halosize_update( 'Cubic-Grid' )
203  endif
204 
205  if( test_edge_update ) then
206  call test_update_edge( 'Cyclic' )
207  call test_update_edge( 'Folded-north' ) !includes vector field test
208  call test_update_edge( 'Folded-north symmetry' )
209  endif
210 
211  if( test_nonsym_edge ) then
212  call test_update_nonsym_edge( 'Folded-north' ) !includes vector field test
213  call test_update_nonsym_edge( 'Folded-north symmetry' )
214  endif
215 
216  if( test_performance) then
217  call update_domains_performance('Folded-north')
218  call update_domains_performance('Cubic-Grid')
219  endif
220 
221  if( test_global_sum ) then
222  call test_mpp_global_sum('Folded-north')
223  endif
224 
225  if( test_cubic_grid_redistribute ) then
226  call cubic_grid_redistribute()
227  endif
228 
229  if(test_boundary) then
230  call test_get_boundary('torus')
231  call test_get_boundary('Four-Tile')
232  call test_get_boundary('Cubic-Grid')
233  call test_get_boundary('Folded-north')
234  endif
235 
236 ! Adjoint Dot Test ------------------------------------------
237  if (test_adjoint) then
238  call test_get_boundary_ad('Four-Tile')
239  call test_halo_update_ad( 'Simple' )
240  call test_global_reduce_ad( 'Simple')
241  endif
242 
243  if( test_unstruct) then
244  call test_unstruct_update( 'Cubic-Grid' )
245  endif
246 
247  if( test_group) then
248  call test_group_update( 'Folded-north' )
249  call test_group_update( 'Cubic-Grid' )
250  endif
251 
252  if( test_interface ) then
253  call test_modify_domain()
254 !!$ call test_cyclic_offset('x_cyclic_offset')
255 !!$ call test_cyclic_offset('y_cyclic_offset')
256 !!$ call test_cyclic_offset('torus_x_offset')
257 !!$ call test_cyclic_offset('torus_y_offset')
258  if(.not. wide_halo) call test_uniform_mosaic('Single-Tile')
259  call test_uniform_mosaic('Folded-north mosaic') ! one-tile tripolar grid
260  call test_uniform_mosaic('Folded-north symmetry mosaic') ! one-tile tripolar grid
261  if(.not. wide_halo) then
262  call test_uniform_mosaic('Folded-south symmetry mosaic') ! one-tile tripolar grid
263  call test_uniform_mosaic('Folded-west symmetry mosaic') ! one-tile tripolar grid
264  call test_uniform_mosaic('Folded-east symmetry mosaic') ! one-tile tripolar grid
265  call test_uniform_mosaic('Four-Tile')
266  endif
267  call test_uniform_mosaic('Cubic-Grid') ! 6 tiles.
268  call test_nonuniform_mosaic('Five-Tile')
269 
270  call test_halo_update( 'Simple' ) !includes global field, global sum tests
271  call test_halo_update( 'Cyclic' )
272  call test_halo_update( 'Folded-north' ) !includes vector field test
273 ! call test_halo_update( 'Masked' ) !includes vector field test
274  call test_halo_update( 'Folded xy_halo' ) !
275  if(.not. wide_halo) then
276  call test_halo_update( 'Simple symmetry' ) !includes global field, global sum tests
277  call test_halo_update( 'Cyclic symmetry' )
278  endif
279  call test_halo_update( 'Folded-north symmetry' ) !includes vector field test
280  if(.not. wide_halo) then
281  call test_halo_update( 'Folded-south symmetry' ) !includes vector field test
282  call test_halo_update( 'Folded-west symmetry' ) !includes vector field test
283  call test_halo_update( 'Folded-east symmetry' ) !includes vector field test
284  endif
285 
286  !--- z1l: The following will not work due to symmetry and domain%x is cyclic.
287  !--- Will solve this problem in the future if needed.
288  ! call test_halo_update( 'Masked symmetry' ) !includes vector field test
289 
290  call test_global_field( 'Non-symmetry' )
291  call test_global_field( 'Symmetry center' )
292  call test_global_field( 'Symmetry corner' )
293  call test_global_field( 'Symmetry east' )
294  call test_global_field( 'Symmetry north' )
295 
296  if(.not. wide_halo) then
297  call test_global_reduce( 'Simple')
298  call test_global_reduce( 'Simple symmetry center')
299  call test_global_reduce( 'Simple symmetry corner')
300  call test_global_reduce( 'Simple symmetry east')
301  call test_global_reduce( 'Simple symmetry north')
302  call test_global_reduce( 'Cyclic symmetry center')
303  call test_global_reduce( 'Cyclic symmetry corner')
304  call test_global_reduce( 'Cyclic symmetry east')
305  call test_global_reduce( 'Cyclic symmetry north')
306  endif
307 
308  call test_redistribute( 'Complete pelist' )
309 ! call test_redistribute( 'Overlap pelist' )
310 ! call test_redistribute( 'Disjoint pelist' )
311  if(.not. wide_halo) then
312  call test_define_mosaic_pelist('One tile', 1)
313  call test_define_mosaic_pelist('Two uniform tile', 2)
314  call test_define_mosaic_pelist('Two nonuniform tile', 2)
315  call test_define_mosaic_pelist('Ten tile', 10)
316  call test_define_mosaic_pelist('Ten tile with nonuniform cost', 10)
317  endif
318  endif
319 
320  if( check_parallel) then
321  call test_parallel( )
322  endif
323 
324 !!$!Balaji adding openMP tests
325 !!$ call test_openmp()
326 !!$! Alewxander.Pletzer get_neighbor tests
327  if( test_get_nbr ) then
328  call test_get_neighbor_1d
329  call test_get_neighbor_non_cyclic
330  call test_get_neighbor_cyclic
331  call test_get_neighbor_folded_north
332  call test_get_neighbor_mask
333  endif
334 
335  call mpp_domains_exit()
336  call mpp_exit()
337 
338 contains
339  subroutine test_openmp()
340 #ifdef _OPENMP_TEST
341  integer :: omp_get_num_thread, omp_get_max_threads, omp_get_thread_num
342  real, allocatable :: a(:,:,:)
343  type(domain2D) :: domain
344  integer :: layout(2)
345  integer :: i,j,k, jthr
346  integer :: thrnum, maxthr
347  integer(LONG_KIND) :: sum1, sum2
348 
349  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
350  call mpp_define_domains( (/1,nx,1,ny/), layout, domain )
351  call mpp_get_compute_domain( domain, is, ie, js, je )
352  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
353  allocate( a(isd:ied,jsd:jed,nz) )
354  maxthr = omp_get_max_threads()
355  write( outunit,'(a,4i6)' )'pe,js,je,maxthr=', pe, js, je, maxthr
356  if( mod(je-js+1,maxthr).NE.0 ) &
357  call mpp_error( fatal, 'maxthr must divide domain (TEMPORARY).' )
358  jthr = (je-js+1)/maxthr
359 !$OMP PARALLEL PRIVATE(i,j,k,thrnum)
360  thrnum = omp_get_thread_num()
361  write( outunit,'(a,4i6)' )'pe,thrnum,js,je=', &
362  pe, thrnum, js+thrnum*jthr,js+(thrnum+1)*jthr-1
363  write( outunit,'(a,3i6)' )'pe,thrnum,node=', pe, thrnum, mpp_node()
364 !!$OMP DO
365  do k = 1,nz
366 !when omp DO is commented out, user must compute j loop limits
367 !with omp DO, let OMP figure it out
368  do j = js+thrnum*jthr,js+(thrnum+1)*jthr-1
369 ! do j = js,je
370  do i = is,ie
371  a(i,j,k) = global(i,j,k)
372  end do
373  end do
374  end do
375 !!$OMP END DO
376 !$OMP END PARALLEL
377  sum1 = mpp_chksum( a(is:ie,js:je,:) )
378  sum2 = mpp_chksum( global(is:ie,js:je,:) )
379  if( sum1.EQ.sum2 )then
380  call mpp_error( note, 'OMP parallel test OK.' )
381  else
382  if( mpp_pe().EQ.mpp_root_pe() )write( errunit,'(a,2z18)' )'OMP checksums: ', sum1, sum2
383  call mpp_error( fatal, 'OMP parallel test failed.' )
384  end if
385 #endif
386  return
387  end subroutine test_openmp
388 
389  subroutine test_redistribute( type )
390 !test redistribute between two domains
391  character(len=*), intent(in) :: type
392  type(domain2D) :: domainx, domainy
393  type(DomainCommunicator2D), pointer, save :: dch =>null()
394  real, allocatable, dimension(:,:,:) :: gcheck, global
395  real, allocatable, dimension(:,:,:), save :: x, y
396  real, allocatable, dimension(:,:,:), save :: x2, y2
397  real, allocatable, dimension(:,:,:), save :: x3, y3
398  real, allocatable, dimension(:,:,:), save :: x4, y4
399  real, allocatable, dimension(:,:,:), save :: x5, y5
400  real, allocatable, dimension(:,:,:), save :: x6, y6
401  integer, allocatable :: pelist(:)
402  integer :: pemax
403  integer :: is, ie, js, je, isd, ied, jsd, jed
404 
405  pemax = npes/2 !the partial pelist will run from 0...pemax
406  !--- nullify domain list otherwise it retains memory between calls.
407  call mpp_nullify_domain_list(domainx)
408  call mpp_nullify_domain_list(domainy)
409 
410  allocate( gcheck(nx,ny,nz), global(nx,ny,nz) )
411  !fill in global array: with k.iiijjj
412  do k = 1,nz
413  do j = 1,ny
414  do i = 1,nx
415  global(i,j,k) = k + i*1e-3 + j*1e-6
416  end do
417  end do
418  end do
419 
420 !select pelists
421  select case(type)
422  case( 'Complete pelist' )
423 !both pelists run from 0...npes-1
424  if(nx < npes) then
425  call mpp_error(note, &
426  "test_mpp_domains(test_redistribute): nx is less than npes, no test will be done for complete pelist")
427  return
428  endif
429  allocate( pelist(0:npes-1) )
430  pelist = (/ (i,i=0,npes-1) /)
431  call mpp_declare_pelist( pelist )
432  case( 'Overlap pelist' )
433 !one pelist from 0...pemax, other from 0...npes-1
434  allocate( pelist(0:pemax) )
435  pelist = (/ (i,i=0,pemax) /)
436  call mpp_declare_pelist( pelist )
437  case( 'Disjoint pelist' )
438 !one pelist from 0...pemax, other from pemax+1...npes-1
439  if( pemax+1.GE.npes )return
440  allocate( pelist(0:pemax) )
441  pelist = (/ (i,i=0,pemax) /)
442 
443  call mpp_declare_pelist( pelist )
444  ! z1l: the follwing will cause deadlock will happen
445  ! for npes = 6, x- mpp_global_field will call mpp_sync
446  call mpp_declare_pelist( (/ (i,i=pemax+1,npes-1) /))
447  case default
448  call mpp_error( fatal, 'TEST_REDISTRIBUTE: no such test: '//type )
449  end select
450 
451 !set up x and y arrays
452  select case(type)
453  case( 'Complete pelist' )
454 !set up x array
455  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
456  call mpp_define_domains( (/1,nx,1,ny/), layout, domainx, name=type )
457  call mpp_get_compute_domain( domainx, is, ie, js, je )
458  call mpp_get_data_domain ( domainx, isd, ied, jsd, jed )
459  allocate( x(isd:ied,jsd:jed,nz) )
460  allocate( x2(isd:ied,jsd:jed,nz) )
461  allocate( x3(isd:ied,jsd:jed,nz) )
462  allocate( x4(isd:ied,jsd:jed,nz) )
463  allocate( x5(isd:ied,jsd:jed,nz) )
464  allocate( x6(isd:ied,jsd:jed,nz) )
465  x = 0.
466  x(is:ie,js:je,:) = global(is:ie,js:je,:)
467  x2 = x; x3 = x; x4 = x; x5 = x; x6 = x
468 !set up y array
469  call mpp_define_domains( (/1,nx,1,ny/), (/npes,1/), domainy, name=type )
470  call mpp_get_compute_domain( domainy, is, ie, js, je )
471  call mpp_get_data_domain ( domainy, isd, ied, jsd, jed )
472  allocate( y(isd:ied,jsd:jed,nz) )
473  allocate( y2(isd:ied,jsd:jed,nz) )
474  allocate( y3(isd:ied,jsd:jed,nz) )
475  allocate( y4(isd:ied,jsd:jed,nz) )
476  allocate( y5(isd:ied,jsd:jed,nz) )
477  allocate( y6(isd:ied,jsd:jed,nz) )
478  y = 0.
479  y2 = 0.;y3 = 0.;y4 = 0.;y5 = 0.;y6 = 0.
480  case( 'Overlap pelist' )
481 !one pelist from 0...pemax, other from 0...npes-1
482 !set up x array
483  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
484  call mpp_define_domains( (/1,nx,1,ny/), layout, domainx, name=type )
485  call mpp_get_compute_domain( domainx, is, ie, js, je )
486  call mpp_get_data_domain ( domainx, isd, ied, jsd, jed )
487  allocate( x(isd:ied,jsd:jed,nz) )
488  allocate( x2(isd:ied,jsd:jed,nz) )
489  allocate( x3(isd:ied,jsd:jed,nz) )
490  allocate( x4(isd:ied,jsd:jed,nz) )
491  allocate( x5(isd:ied,jsd:jed,nz) )
492  allocate( x6(isd:ied,jsd:jed,nz) )
493  x = 0.
494  x(is:ie,js:je,:) = global(is:ie,js:je,:)
495  x2 = x; x3 = x; x4 = x; x5 = x; x6 = x
496 !set up y array
497  if( any(pelist.EQ.pe) )then
498  call mpp_set_current_pelist(pelist)
499  call mpp_define_layout( (/1,nx,1,ny/), mpp_npes(), layout )
500  call mpp_define_domains( (/1,nx,1,ny/), layout, domainy, name=type )
501  call mpp_get_compute_domain( domainy, is, ie, js, je )
502  call mpp_get_data_domain ( domainy, isd, ied, jsd, jed )
503  allocate( y(isd:ied,jsd:jed,nz) )
504  allocate( y2(isd:ied,jsd:jed,nz) )
505  allocate( y3(isd:ied,jsd:jed,nz) )
506  allocate( y4(isd:ied,jsd:jed,nz) )
507  allocate( y5(isd:ied,jsd:jed,nz) )
508  allocate( y6(isd:ied,jsd:jed,nz) )
509  y = 0.
510  y2 = 0.;y3 = 0.;y4 = 0.;y5 = 0.;y6 = 0.
511  end if
512  case( 'Disjoint pelist' )
513 !one pelist from 0...pemax, other from pemax+1...npes-1
514 
515 !set up y array
516  if( any(pelist.EQ.pe) )then
517  call mpp_set_current_pelist(pelist)
518  call mpp_define_layout( (/1,nx,1,ny/), mpp_npes(), layout )
519  call mpp_define_domains( (/1,nx,1,ny/), layout, domainy, name=type )
520  call mpp_get_compute_domain( domainy, is, ie, js, je )
521  call mpp_get_data_domain ( domainy, isd, ied, jsd, jed )
522  allocate( y(isd:ied,jsd:jed,nz) )
523  allocate( y2(isd:ied,jsd:jed,nz) )
524  allocate( y3(isd:ied,jsd:jed,nz) )
525  allocate( y4(isd:ied,jsd:jed,nz) )
526  allocate( y5(isd:ied,jsd:jed,nz) )
527  allocate( y6(isd:ied,jsd:jed,nz) )
528  y = 0.
529  y2 = 0.;y3 = 0.;y4 = 0.;y5 = 0.;y6 = 0.
530  else
531 !set up x array
532  call mpp_set_current_pelist( (/ (i,i=pemax+1,npes-1) /) )
533  call mpp_define_layout( (/1,nx,1,ny/), mpp_npes(), layout )
534  call mpp_define_domains( (/1,nx,1,ny/), layout, domainx, name=type )
535  call mpp_get_compute_domain( domainx, is, ie, js, je )
536  call mpp_get_data_domain ( domainx, isd, ied, jsd, jed )
537  allocate( x(isd:ied,jsd:jed,nz) )
538  allocate( x2(isd:ied,jsd:jed,nz) )
539  allocate( x3(isd:ied,jsd:jed,nz) )
540  allocate( x4(isd:ied,jsd:jed,nz) )
541  allocate( x5(isd:ied,jsd:jed,nz) )
542  allocate( x6(isd:ied,jsd:jed,nz) )
543  x = 0.
544  x(is:ie,js:je,:) = global(is:ie,js:je,:)
545  x2 = x; x3 = x; x4 = x; x5 = x; x6 = x
546  end if
547  end select
548 
549 !go global and redistribute
550  call mpp_set_current_pelist()
551  call mpp_broadcast_domain(domainx)
552  call mpp_broadcast_domain(domainy)
553 
554  id = mpp_clock_id( type, flags=mpp_clock_sync+mpp_clock_detailed )
555  call mpp_clock_begin(id)
556  call mpp_redistribute( domainx, x, domainy, y )
557  call mpp_clock_end (id)
558 
559 !check answers on pelist
560  if( any(pelist.EQ.pe) )then
561  call mpp_set_current_pelist(pelist)
562  call mpp_global_field( domainy, y, gcheck )
563  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
564  end if
565 
566  call mpp_set_current_pelist()
567 
568  call mpp_clock_begin(id)
569  if(ALLOCATED(y))y=0.
570  call mpp_redistribute( domainx, x, domainy, y, complete=.false. )
571  call mpp_redistribute( domainx, x2, domainy, y2, complete=.false. )
572  call mpp_redistribute( domainx, x3, domainy, y3, complete=.false. )
573  call mpp_redistribute( domainx, x4, domainy, y4, complete=.false. )
574  call mpp_redistribute( domainx, x5, domainy, y5, complete=.false. )
575  call mpp_redistribute( domainx, x6, domainy, y6, complete=.true., dc_handle=dch )
576  call mpp_clock_end (id)
577 
578 !check answers on pelist
579  if( any(pelist.EQ.pe) )then
580  call mpp_set_current_pelist(pelist)
581  call mpp_global_field( domainy, y, gcheck )
582  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
583  call mpp_global_field( domainy, y2, gcheck )
584  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
585  call mpp_global_field( domainy, y3, gcheck )
586  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
587  call mpp_global_field( domainy, y4, gcheck )
588  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
589  call mpp_global_field( domainy, y5, gcheck )
590  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
591  call mpp_global_field( domainy, y6, gcheck )
592  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
593  end if
594 
595  call mpp_set_current_pelist()
596 
597  if(type == 'Complete pelist')then
598  write(outunit,*) 'Use domain communicator handle'
599  call mpp_clock_begin(id)
600  if(ALLOCATED(y))then
601  y=0.; y2=0.; y3=0.; y4=0.; y5=0.; y6=0.
602  endif
603  call mpp_redistribute( domainx, x, domainy, y, complete=.false. )
604  call mpp_redistribute( domainx, x2, domainy, y2, complete=.false. )
605  call mpp_redistribute( domainx, x3, domainy, y3, complete=.false. )
606  call mpp_redistribute( domainx, x4, domainy, y4, complete=.false. )
607  call mpp_redistribute( domainx, x5, domainy, y5, complete=.false. )
608  call mpp_redistribute( domainx, x6, domainy, y6, complete=.true., dc_handle=dch )
609  call mpp_clock_end (id)
610 
611 !check answers on pelist
612  if( any(pelist.EQ.pe) )then
613  call mpp_set_current_pelist(pelist)
614  call mpp_global_field( domainy, y, gcheck )
615  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
616  call mpp_global_field( domainy, y2, gcheck )
617  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
618  call mpp_global_field( domainy, y3, gcheck )
619  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
620  call mpp_global_field( domainy, y4, gcheck )
621  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
622  call mpp_global_field( domainy, y5, gcheck )
623  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
624  call mpp_global_field( domainy, y6, gcheck )
625  call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
626  end if
627  endif
628  dch =>null()
629 
630  call mpp_set_current_pelist()
631 
632  deallocate(gcheck, global)
633  if(ALLOCATED(pelist)) deallocate(pelist)
634 
635  if(ALLOCATED(x))then
636  call mpp_redistribute( domainx, x, domainy, y, free=.true.,list_size=6 )
637  deallocate(x,x2,x3,x4,x5,x6)
638  endif
639  if(ALLOCATED(y))deallocate(y,y2,y3,y4,y5,y6)
640  end subroutine test_redistribute
641 
642  subroutine cubic_grid_redistribute
643 
644  integer :: npes, npes_per_ensemble, npes_per_tile
645  integer :: ensemble_id, tile_id, ensemble_tile_id
646  integer :: i, j, p, n, ntiles, my_root_pe
647  integer :: isc_ens, iec_ens, jsc_ens, jec_ens
648  integer :: isd_ens, ied_ens, jsd_ens, jed_ens
649  integer :: isc, iec, jsc, jec
650  integer :: isd, ied, jsd, jed
651  integer, allocatable :: my_ensemble_pelist(:), pe_start(:), pe_end(:)
652  integer, allocatable :: global_indices(:,:), layout2D(:,:)
653  real, allocatable :: x(:,:,:,:), x_ens(:,:,:), y(:,:,:)
654  integer :: layout(2)
655  type(domain2D) :: domain
656  type(domain2D), allocatable :: domain_ensemble(:)
657  character(len=128) :: mesg
658 
659  ! --- set up pelist
660  npes = mpp_npes()
661  if(mod(npes, ensemble_size) .NE. 0) call mpp_error(fatal, &
662  "test_mpp_domains: npes is not divisible by ensemble_size")
663  npes_per_ensemble = npes/ensemble_size
664  allocate(my_ensemble_pelist(0:npes_per_ensemble-1))
665  ensemble_id = mpp_pe()/npes_per_ensemble + 1
666  do p = 0, npes_per_ensemble-1
667  my_ensemble_pelist(p) = (ensemble_id-1)*npes_per_ensemble + p
668  enddo
669 
670  call mpp_declare_pelist(my_ensemble_pelist)
671 
672  !--- define a mosaic use all the pelist
673  ntiles = 6
674 
675 
676  if( mod(npes, ntiles) .NE. 0 ) call mpp_error(fatal, &
677  "test_mpp_domains: npes is not divisible by ntiles")
678 
679  npes_per_tile = npes/ntiles
680  tile_id = mpp_pe()/npes_per_tile + 1
681  if( npes_per_tile == layout_cubic(1) * layout_cubic(2) ) then
682  layout = layout_cubic
683  else
684  call mpp_define_layout( (/1,nx_cubic,1,ny_cubic/), npes_per_tile, layout )
685  endif
686  allocate(global_indices(4, ntiles))
687  allocate(layout2d(2, ntiles))
688  allocate(pe_start(ntiles), pe_end(ntiles))
689  do n = 1, ntiles
690  global_indices(:,n) = (/1,nx_cubic,1,ny_cubic/)
691  layout2d(:,n) = layout
692  end do
693 
694  do n = 1, ntiles
695  pe_start(n) = (n-1)*npes_per_tile
696  pe_end(n) = n*npes_per_tile-1
697  end do
698 
699  call define_cubic_mosaic("cubic_grid", domain, (/nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic/), &
700  (/ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic/), &
701  global_indices, layout2d, pe_start, pe_end )
702 
703  allocate(domain_ensemble(ensemble_size))
704  !-- define domain for each ensemble
705  call mpp_set_current_pelist( my_ensemble_pelist )
706  if( mod(npes_per_ensemble, ntiles) .NE. 0 ) call mpp_error(fatal, &
707  "test_mpp_domains: npes_per_ensemble is not divisible by ntiles")
708  npes_per_tile = npes_per_ensemble/ntiles
709  my_root_pe = my_ensemble_pelist(0)
710  ensemble_tile_id = (mpp_pe() - my_root_pe)/npes_per_tile + 1
711 
712  if( npes_per_tile == layout_ensemble(1) * layout_ensemble(2) ) then
713  layout = layout_ensemble
714  else
715  call mpp_define_layout( (/1,nx_cubic,1,ny_cubic/), npes_per_tile, layout )
716  endif
717  do n = 1, ntiles
718  global_indices(:,n) = (/1,nx_cubic,1,ny_cubic/)
719  layout2d(:,n) = layout
720  end do
721 
722  do n = 1, ntiles
723  pe_start(n) = my_root_pe + (n-1)*npes_per_tile
724  pe_end(n) = my_root_pe + n*npes_per_tile-1
725  end do
726 
727  call define_cubic_mosaic("cubic_grid", domain_ensemble(ensemble_id), (/nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic/), &
728  (/ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic/), &
729  global_indices, layout2d, pe_start, pe_end )
730 
731  call mpp_set_current_pelist()
732  do n = 1, ensemble_size
733  call mpp_broadcast_domain(domain_ensemble(n))
734  enddo
735 
736  call mpp_get_data_domain( domain_ensemble(ensemble_id), isd_ens, ied_ens, jsd_ens, jed_ens)
737  call mpp_get_compute_domain( domain_ensemble(ensemble_id), isc_ens, iec_ens, jsc_ens, jec_ens)
738  call mpp_get_data_domain( domain, isd, ied, jsd, jed)
739  call mpp_get_compute_domain( domain, isc, iec, jsc, jec)
740 
741  allocate(x_ens(isd_ens:ied_ens, jsd_ens:jed_ens, nz))
742  allocate(x(isd:ied, jsd:jed, nz, ensemble_size))
743  allocate(y(isd:ied, jsd:jed, nz))
744 
745  x = 0
746  do k = 1, nz
747  do j = jsc_ens, jec_ens
748  do i = isc_ens, iec_ens
749  x_ens(i,j,k) = ensemble_id *1e6 + ensemble_tile_id*1e3 + i + j * 1.e-3 + k * 1.e-6
750  enddo
751  enddo
752  enddo
753 
754  do n = 1, ensemble_size
755  x = 0
756  call mpp_redistribute( domain_ensemble(n), x_ens, domain, x(:,:,:,n) )
757  y = 0
758  do k = 1, nz
759  do j = jsc, jec
760  do i = isc, iec
761  y(i,j,k) = n *1e6 + tile_id*1e3 + i + j * 1.e-3 + k * 1.e-6
762  enddo
763  enddo
764  enddo
765  write(mesg,'(a,i4)') "cubic_grid redistribute from ensemble", n
766  call compare_checksums( x(isc:iec,jsc:jec,:,n), y(isc:iec,jsc:jec,:), trim(mesg) )
767  enddo
768 
769  ! redistribute data to each ensemble.
770  deallocate(x,y,x_ens)
771  allocate(x(isd:ied, jsd:jed, nz, ensemble_size))
772  allocate(x_ens(isd_ens:ied_ens, jsd_ens:jed_ens, nz))
773  allocate(y(isd_ens:ied_ens, jsd_ens:jed_ens, nz))
774 
775  y = 0
776  do k = 1, nz
777  do j = jsc, jec
778  do i = isc, iec
779  x(i,j,k,:) = i + j * 1.e-3 + k * 1.e-6
780  enddo
781  enddo
782  enddo
783 
784  do n = 1, ensemble_size
785  x_ens = 0
786  call mpp_redistribute(domain, x(:,:,:,n), domain_ensemble(n), x_ens)
787  y = 0
788  if( ensemble_id == n ) then
789  do k = 1, nz
790  do j = jsc_ens, jec_ens
791  do i = isc_ens, iec_ens
792  y(i,j,k) = i + j * 1.e-3 + k * 1.e-6
793  enddo
794  enddo
795  enddo
796  endif
797  write(mesg,'(a,i4)') "cubic_grid redistribute to ensemble", n
798  call compare_checksums( x_ens(isc_ens:iec_ens,jsc_ens:jec_ens,:), y(isc_ens:iec_ens,jsc_ens:jec_ens,:), trim(mesg) )
799  enddo
800 
801  deallocate(x, y, x_ens)
802  call mpp_deallocate_domain(domain)
803  do n = 1, ensemble_size
804  call mpp_deallocate_domain(domain_ensemble(n))
805  enddo
806  deallocate(domain_ensemble)
807 
808  end subroutine cubic_grid_redistribute
809 
810 
811  subroutine test_uniform_mosaic( type )
812  character(len=*), intent(in) :: type
813 
814  type(domain2D) :: domain
815  integer :: num_contact, ntiles, npes_per_tile, ntile_per_pe, update_flags
816  integer :: i, j, k, l, n, shift, tw, te, ts, tn, tsw, tnw, tse, tne
817  integer :: ism, iem, jsm, jem, wh, eh, sh, nh
818  integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
819  real :: gsum, lsum
820 
821  integer, allocatable, dimension(:) :: tile
822  integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
823  integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
824  integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
825  integer, allocatable, dimension(:,:) :: layout2D, global_indices
826  real, allocatable, dimension(:,:) :: global2D
827  real, allocatable, dimension(:,:,:) :: local1, local2
828  real, allocatable, dimension(:,:,:,:) :: x, y, x1, x2, x3, x4, y1, y2, y3, y4
829  real, allocatable, dimension(:,:,:,:) :: global1, global2, gcheck
830  real, allocatable, dimension(:,:,:,:) :: global1_all, global2_all, global_all
831  character(len=256) :: type2, type3
832  logical :: folded_north, folded_north_sym, folded_north_nonsym
833  logical :: folded_south_sym, folded_west_sym, folded_east_sym
834  logical :: cubic_grid, single_tile, four_tile
835  integer :: whalo_save, ehalo_save, nhalo_save, shalo_save
836  integer :: nx_save, ny_save
837  logical :: same_layout = .false.
838 
839 
840  nx_save = nx
841  ny_save = ny
842  if(type == 'Cubic-Grid' .and. nx_cubic >0) then
843  nx = nx_cubic
844  ny = ny_cubic
845  endif
846 
847  if(wide_halo_x > 0) then
848  whalo_save = whalo
849  ehalo_save = ehalo
850  shalo_save = shalo
851  nhalo_save = nhalo
852  if(type == 'Single-Tile' .OR. type == 'Folded-north mosaic' .OR. type == 'Cubic-Grid') then
853  whalo = wide_halo_x
854  ehalo = wide_halo_x
855  shalo = wide_halo_y
856  nhalo = wide_halo_y
857  endif
858  endif
859 
860  folded_north_nonsym = .false.
861  folded_north_sym = .false.
862  folded_north = .false.
863  folded_south_sym = .false.
864  folded_west_sym = .false.
865  folded_east_sym = .false.
866  cubic_grid = .false.
867  single_tile = .false.
868  four_tile = .false.
869  !--- check the type
870  select case(type)
871  case ( 'Single-Tile' ) !--- single with cyclic along x- and y-direction
872  single_tile = .true.
873  ntiles = 1
874  num_contact = 2
875  case ( 'Folded-north mosaic' )
876  ntiles = 1
877  num_contact = 2
878  folded_north_nonsym = .true.
879  case ( 'Folded-north symmetry mosaic' )
880  ntiles = 1
881  num_contact = 2
882  folded_north_sym = .true.
883  case ( 'Folded-south symmetry mosaic' )
884  ntiles = 1
885  num_contact = 2
886  folded_south_sym = .true.
887  case ( 'Folded-west symmetry mosaic' )
888  ntiles = 1
889  num_contact = 2
890  folded_west_sym = .true.
891  case ( 'Folded-east symmetry mosaic' )
892  ntiles = 1
893  num_contact = 2
894  folded_east_sym = .true.
895  case ( 'Four-Tile' ) !--- cyclic along both x- and y-direction.
896  ntiles = 4
897  num_contact = 8
898  four_tile = .true.
899  case ( 'Cubic-Grid' )
900  ntiles = 6
901  num_contact = 12
902  cubic_grid = .true.
903  if( nx .NE. ny) then
904  call mpp_error(note,'TEST_MPP_DOMAINS: for Cubic_grid mosaic, nx should equal ny, '//&
905  'No test is done for Cubic-Grid mosaic. ' )
906  if(wide_halo_x > 0) then
907  whalo = whalo_save
908  ehalo = ehalo_save
909  shalo = shalo_save
910  nhalo = nhalo_save
911  nx = nx_save
912  ny = ny_save
913  endif
914  return
915  end if
916  case default
917  call mpp_error(fatal, 'TEST_MPP_DOMAINS: no such test: '//type)
918  end select
919 
920  folded_north = folded_north_nonsym .OR. folded_north_sym
921 
922  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
923  if( mod(npes, ntiles) == 0 ) then
924  npes_per_tile = npes/ntiles
925  write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
926  '", each tile will be distributed over ', npes_per_tile, ' processors.'
927  ntile_per_pe = 1
928  allocate(tile(ntile_per_pe))
929  tile = pe/npes_per_tile+1
930  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
931  do n = 1, ntiles
932  pe_start(n) = (n-1)*npes_per_tile
933  pe_end(n) = n*npes_per_tile-1
934  end do
935  else if ( mod(ntiles, npes) == 0 ) then
936  ntile_per_pe = ntiles/npes
937  write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
938  '", there will be ', ntile_per_pe, ' tiles on each processor.'
939  allocate(tile(ntile_per_pe))
940  do n = 1, ntile_per_pe
941  tile(n) = pe*ntile_per_pe + n
942  end do
943  do n = 1, ntiles
944  pe_start(n) = (n-1)/ntile_per_pe
945  pe_end(n) = pe_start(n)
946  end do
947  layout = 1
948  else
949  call mpp_error(note,'TEST_MPP_DOMAINS: npes should be multiple of ntiles or ' // &
950  'ntiles should be multiple of npes. No test is done for '//trim(type) )
951  nx = nx_save
952  ny = ny_save
953  if(wide_halo_x > 0) then
954  whalo = whalo_save
955  ehalo = ehalo_save
956  shalo = shalo_save
957  nhalo = nhalo_save
958  endif
959  return
960  end if
961 
962  do n = 1, ntiles
963  global_indices(:,n) = (/1,nx,1,ny/)
964  layout2d(:,n) = layout
965  end do
966  same_layout = .false.
967  if(layout(1) == layout(2)) same_layout = .true.
968 
969  allocate(tile1(num_contact), tile2(num_contact) )
970  allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
971  allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
972 
973  call mpp_memuse_begin()
974  !--- define domain
975  if(single_tile) then
976  !--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST)
977  tile1(1) = 1; tile2(1) = 1
978  istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
979  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
980  !--- Contact line 2, between tile 1 (SOUTH) and tile 1 (NORTH) --- cyclic
981  tile1(2) = 1; tile2(2) = 1
982  istart1(2) = 1; iend1(2) = nx; jstart1(2) = 1; jend1(2) = 1
983  istart2(2) = 1; iend2(2) = nx; jstart2(2) = ny; jend2(2) = ny
984  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
985  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
986  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
987  name = type, symmetry = .false. )
988  else if(folded_north) then
989  !--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
990  tile1(1) = 1; tile2(1) = 1
991  istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
992  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
993  !--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
994  tile1(2) = 1; tile2(2) = 1
995  istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
996  istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
997  if(folded_north_nonsym) then
998  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
999  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
1000  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
1001  name = type, symmetry = .false. )
1002  else
1003  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
1004  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
1005  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
1006  name = type, symmetry = .true. )
1007  endif
1008  else if(folded_south_sym) then
1009  !--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
1010  tile1(1) = 1; tile2(1) = 1
1011  istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
1012  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
1013  !--- Contact line 2, between tile 1 (SOUTH) and tile 1 (SOUTH) --- folded-south-edge
1014  tile1(2) = 1; tile2(2) = 1
1015  istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = 1; jend1(2) = 1
1016  istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = 1; jend2(2) = 1
1017  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
1018  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
1019  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
1020  name = type, symmetry = .true. )
1021  else if(folded_west_sym) then
1022  !--- Contact line 1, between tile 1 (NORTH) and tile 1 (SOUTH) --- cyclic
1023  tile1(1) = 1; tile2(1) = 1
1024  istart1(1) = 1; iend1(1) = nx; jstart1(1) = ny; jend1(1) = ny
1025  istart2(1) = 1; iend2(1) = nx; jstart2(1) = 1; jend2(1) = 1
1026  !--- Contact line 2, between tile 1 (WEST) and tile 1 (WEST) --- folded-west-edge
1027  tile1(2) = 1; tile2(2) = 1
1028  istart1(2) = 1; iend1(2) = 1; jstart1(2) = 1; jend1(2) = ny/2
1029  istart2(2) = 1; iend2(2) = 1; jstart2(2) = ny; jend2(2) = ny/2+1
1030  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
1031  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
1032  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
1033  name = type, symmetry = .true. )
1034  else if(folded_east_sym) then
1035  !--- Contact line 1, between tile 1 (NORTH) and tile 1 (SOUTH) --- cyclic
1036  tile1(1) = 1; tile2(1) = 1
1037  istart1(1) = 1; iend1(1) = nx; jstart1(1) = ny; jend1(1) = ny
1038  istart2(1) = 1; iend2(1) = nx; jstart2(1) = 1; jend2(1) = 1
1039  !--- Contact line 2, between tile 1 (EAST) and tile 1 (EAST) --- folded-west-edge
1040  tile1(2) = 1; tile2(2) = 1
1041  istart1(2) = nx; iend1(2) = nx; jstart1(2) = 1; jend1(2) = ny/2
1042  istart2(2) = nx; iend2(2) = nx; jstart2(2) = ny; jend2(2) = ny/2+1
1043  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
1044  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
1045  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
1046  name = type, symmetry = .true. )
1047  else if( four_tile ) then
1048  call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
1049  layout2D, pe_start, pe_end, symmetry = .false. )
1050  else if( cubic_grid ) then
1051  call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
1052  global_indices, layout2D, pe_start, pe_end )
1053  endif
1054  call mpp_memuse_end(trim(type)//" mpp_define_mosaic", outunit )
1055 
1056  !--- setup data
1057  allocate(global2(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz, ntile_per_pe) )
1058  allocate(global_all(1:nx,1:ny,nz, ntiles) )
1059  global2 = 0
1060  do l = 1, ntiles
1061  do k = 1, nz
1062  do j = 1, ny
1063  do i = 1, nx
1064  global_all(i,j,k,l) = l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1065  end do
1066  end do
1067  end do
1068  end do
1069 
1070  do n = 1, ntile_per_pe
1071  global2(1:nx,1:ny,:,n) = global_all(:,:,:,tile(n))
1072  end do
1073 
1074  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
1075  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
1076  call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
1077  allocate( gcheck(nx, ny, nz, ntile_per_pe) )
1078  allocate( x(ism:iem,jsm:jem,nz, ntile_per_pe) )
1079  allocate( x1(ism:iem,jsm:jem,nz, ntile_per_pe) )
1080  allocate( x2(ism:iem,jsm:jem,nz, ntile_per_pe) )
1081  allocate( x3(ism:iem,jsm:jem,nz, ntile_per_pe) )
1082  allocate( x4(ism:iem,jsm:jem,nz, ntile_per_pe) )
1083  x = 0.
1084  x(isc:iec,jsc:jec,:,:) = global2(isc:iec,jsc:jec,:,:)
1085  x1 = x; x2 = x; x3 = x; x4 = x;
1086 
1087  !--- test mpp_global_sum
1088  gsum = 0
1089  allocate(global2d(nx,ny))
1090  do n = 1, ntiles
1091  do j = 1, ny
1092  do i = 1, nx
1093  global2d(i,j) = sum(global_all(i,j,:,n))
1094  end do
1095  end do
1096  gsum = gsum + sum(global2d)
1097  end do
1098 
1099  do n = 1, ntile_per_pe
1100  lsum = mpp_global_sum( domain, x(:,:,:,n), tile_count=n )
1101  end do
1102  if( pe.EQ.mpp_root_pe() )print '(a,2es15.8,a,es12.4)', type//' Fast sum=', lsum, gsum
1103 
1104  !test exact mpp_global_sum
1105  do n = 1, ntile_per_pe
1106  lsum = mpp_global_sum( domain, x(:,:,:,n), bitwise_exact_sum, tile_count=n)
1107  end do
1108  call compare_data_scalar(lsum, gsum, fatal, type//' mpp_global_exact_sum')
1109 
1110  !--- test mpp_global_field
1111  gcheck = 0.
1112  id = mpp_clock_id( type//' global field ', flags=mpp_clock_sync+mpp_clock_detailed )
1113  call mpp_clock_begin(id)
1114  do n = 1, ntile_per_pe
1115  call mpp_global_field( domain, x(:,:,:,n), gcheck(:,:,:,n), tile_count=n)
1116  end do
1117  call mpp_clock_end (id)
1118  !compare checksums between global and x arrays
1119  do n = 1, ntile_per_pe
1120  call compare_checksums( global2(1:nx,1:ny,:,n), gcheck(:,:,:,n), type//' mpp_global_field ' )
1121  end do
1122 
1123  id = mpp_clock_id( type, flags=mpp_clock_sync+mpp_clock_detailed )
1124  do n = 1, ntile_per_pe
1125  !--- fill up the value at halo points.
1126  if(single_tile) then
1127  call fill_regular_mosaic_halo(global2(:,:,:,n), global_all, 1, 1, 1, 1, 1, 1, 1, 1)
1128  else if(folded_north) then
1129  call fill_folded_north_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
1130  else if(folded_south_sym) then
1131  call fill_folded_south_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
1132  else if(folded_west_sym) then
1133  call fill_folded_west_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
1134  else if(folded_east_sym) then
1135  call fill_folded_east_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
1136  else if(four_tile) then
1137  select case ( tile(n) )
1138  case (1)
1139  tw = 2; ts = 3; tsw = 4
1140  case (2)
1141  tw = 1; ts = 4; tsw = 3
1142  case (3)
1143  tw = 4; ts = 1; tsw = 2
1144  case (4)
1145  tw = 3; ts = 2; tsw = 1
1146  end select
1147  te = tw; tn = ts; tse = tsw; tnw = tsw; tne = tsw
1148  call fill_regular_mosaic_halo(global2(:,:,:,n), global_all, te, tse, ts, tsw, tw, tnw, tn, tne )
1149  else if(cubic_grid) then
1150  call fill_cubic_grid_halo(global2(:,:,:,n), global_all, global_all, tile(n), 0, 0, 1, 1 )
1151  endif
1152 
1153  !full update
1154  call mpp_clock_begin(id)
1155  if(ntile_per_pe == 1) then
1156  call mpp_update_domains( x(:,:,:,n), domain )
1157  else
1158  call mpp_update_domains( x(:,:,:,n), domain, tile_count = n )
1159  end if
1160  call mpp_clock_end (id)
1161  end do
1162  type2 = type
1163  do n = 1, ntile_per_pe
1164  if(ntile_per_pe>1) write(type2, *)type, " at tile_count = ",n
1165  call compare_checksums( x(ism:ism+ied-isd,jsm:jsm+jed-jsd,:,n), global2(isd:ied,jsd:jed,:,n), trim(type2) )
1166  end do
1167 
1168  !partial update only be done when there is at most one tile on each pe
1169  if(ntile_per_pe == 1 ) then
1170  id = mpp_clock_id( type//' partial', flags=mpp_clock_sync+mpp_clock_detailed )
1171  call mpp_clock_begin(id)
1172  call mpp_update_domains( x1, domain, nupdate+eupdate, complete=.false. )
1173  call mpp_update_domains( x2, domain, nupdate+eupdate, complete=.false. )
1174  call mpp_update_domains( x3, domain, nupdate+eupdate, complete=.false. )
1175  call mpp_update_domains( x4, domain, nupdate+eupdate, complete=.true. )
1176  call mpp_clock_end (id)
1177  call compare_checksums( x1(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x1' )
1178  call compare_checksums( x2(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x2' )
1179  call compare_checksums( x3(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x3' )
1180  call compare_checksums( x4(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x4' )
1181 
1182  !arbitrary halo update. not for tripolar grid
1183  if(wide_halo_x == 0) then
1184  if(single_tile .or. four_tile .or. (cubic_grid .and. same_layout) .or. folded_north ) then
1185  allocate(local2(isd:ied,jsd:jed,nz) )
1186  do wh = 1, whalo
1187  do eh = 1, ehalo
1188  if(wh .NE. eh) cycle
1189  do sh = 1, shalo
1190  do nh = 1, nhalo
1191  if(sh .NE. nh) cycle
1192  local2(isd:ied,jsd:jed,:) = global2(isd:ied,jsd:jed,:,1)
1193  x = 0.
1194  x(isc:iec,jsc:jec,:,1) = local2(isc:iec,jsc:jec,:)
1195  call fill_halo_zero(local2, wh, eh, sh, nh, 0, 0, isc, iec, jsc, jec, isd, ied, jsd, jed)
1196  write(type2,'(a,a,i2,a,i2,a,i2,a,i2)') trim(type), ' with whalo = ', wh, &
1197  ', ehalo = ',eh, ', shalo = ', sh, ', nhalo = ', nh
1198  call mpp_update_domains( x, domain, whalo=wh, ehalo=eh, shalo=sh, nhalo=nh, name = type2 )
1199  call compare_checksums( x(isd:ied,jsd:jed,:,1), local2, trim(type2) )
1200  end do
1201  end do
1202  end do
1203  end do
1204  deallocate(local2)
1205  end if
1206  endif
1207  end if
1208 
1209  deallocate(global2, global_all, x, x1, x2, x3, x4)
1210  !------------------------------------------------------------------
1211  ! vector update : BGRID_NE, one extra point in each direction for cubic-grid
1212  !------------------------------------------------------------------
1213  !--- setup data
1214  shift = 0
1215  if(single_tile .or. four_tile .or. folded_north_nonsym) then
1216  shift = 0
1217  else
1218  shift = 1
1219  endif
1220 
1221  allocate(global1(1-whalo:nx+shift+ehalo,1-shalo:ny+shift+nhalo,nz,ntile_per_pe) )
1222  allocate(global2(1-whalo:nx+shift+ehalo,1-shalo:ny+shift+nhalo,nz,ntile_per_pe) )
1223  allocate(global1_all(nx+shift,ny+shift,nz, ntiles), global2_all(nx+shift,ny+shift,nz, ntiles))
1224  global1 = 0; global2 = 0
1225  do l = 1, ntiles
1226  do k = 1, nz
1227  do j = 1, ny+shift
1228  do i = 1, nx+shift
1229  global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1230  global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1231  end do
1232  end do
1233  end do
1234  end do
1235 
1236  !-----------------------------------------------------------------------
1237  !--- make sure consistency on the boundary for cubic grid
1238  !--- east boundary will take the value of neighbor tile ( west/south),
1239  !--- north boundary will take the value of neighbor tile ( south/west).
1240  !--- for the point on the corner, the 12 corner take the following value
1241  !--- corner between 1, 2, 3 takes the value at 3,
1242  !--- corner between 1, 3, 5 takes the value at 3
1243  !-----------------------------------------------------------------------
1244  if( cubic_grid ) then
1245  do l = 1, ntiles
1246  if(mod(l,2) == 0) then ! tile 2, 4, 6
1247  te = l + 2
1248  tn = l + 1
1249  if(te>6) te = te - 6
1250  if(tn > 6) tn = tn - 6
1251  global1_all(nx+shift,1:ny+1,:,l) = global2_all(nx+shift:1:-1,1,:,te) ! east
1252  global2_all(nx+shift,1:ny+1,:,l) = global1_all(nx+shift:1:-1,1,:,te) ! east
1253  global1_all(1:nx,ny+shift,:,l) = global1_all(1:nx,1,:,tn) ! north
1254  global2_all(1:nx,ny+shift,:,l) = global2_all(1:nx,1,:,tn) ! north
1255  else ! tile 1, 3, 5
1256  te = l + 1
1257  tn = l + 2
1258  if(tn > 6) tn = tn - 6
1259  global1_all(nx+shift,:,:,l) = global1_all(1,:,:,te) ! east
1260  global2_all(nx+shift,:,:,l) = global2_all(1,:,:,te) ! east
1261  global1_all(1:nx+1,ny+shift,:,l) = global2_all(1,ny+shift:1:-1,:,tn) ! north
1262  global2_all(1:nx+1,ny+shift,:,l) = global1_all(1,ny+shift:1:-1,:,tn) ! north
1263  end if
1264  end do
1265  ! set the corner value to 0
1266  global1_all(1,ny+1,:,:) = 0; global1_all(nx+1,1,:,:) = 0; global1_all(1,1,:,:) = 0; global1_all(nx+1,ny+1,:,:) = 0
1267  global2_all(1,ny+1,:,:) = 0; global2_all(nx+1,1,:,:) = 0; global2_all(1,1,:,:) = 0; global2_all(nx+1,ny+1,:,:) = 0
1268  end if
1269 
1270  do n = 1, ntile_per_pe
1271  global1(1:nx+shift,1:ny+shift,:,n) = global1_all(:,:,:,tile(n))
1272  global2(1:nx+shift,1:ny+shift,:,n) = global2_all(:,:,:,tile(n))
1273  end do
1274 
1275  if(folded_north) then
1276  call fill_folded_north_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
1277  call fill_folded_north_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
1278  else if(folded_south_sym) then
1279  call fill_folded_south_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
1280  call fill_folded_south_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
1281  else if(folded_west_sym) then
1282  call fill_folded_west_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
1283  call fill_folded_west_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
1284  else if(folded_east_sym) then
1285  call fill_folded_east_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
1286  call fill_folded_east_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
1287  endif
1288 
1289  allocate( x(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1290  allocate( y(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1291  allocate( x1(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1292  allocate( x2(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1293  allocate( x3(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1294  allocate( x4(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1295  allocate( y1(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1296  allocate( y2(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1297  allocate( y3(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1298  allocate( y4(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1299 
1300  x = 0.; y = 0
1301  x(isc:iec+shift,jsc:jec+shift,:,:) = global1(isc:iec+shift,jsc:jec+shift,:,:)
1302  y(isc:iec+shift,jsc:jec+shift,:,:) = global2(isc:iec+shift,jsc:jec+shift,:,:)
1303  x1 = x; x2 = x; x3 = x; x4 = x
1304  y1 = y; y2 = y; y3 = y; y4 = y
1305 
1306  !-----------------------------------------------------------------------
1307  ! fill up the value at halo points.
1308  !-----------------------------------------------------------------------
1309  if(cubic_grid) then
1310  type2 = type//' paired-scalar BGRID_NE'
1311  update_flags = scalar_pair
1312  else
1313  type2 = type//' vector BGRID_NE'
1314  update_flags = xupdate + yupdate
1315  endif
1316 
1317  id = mpp_clock_id( trim(type2), flags=mpp_clock_sync+mpp_clock_detailed )
1318  type3 = type2
1319 
1320  do n = 1, ntile_per_pe
1321  if(single_tile) then
1322  call fill_regular_mosaic_halo(global1(:,:,:,n), global1_all, 1, 1, 1, 1, 1, 1, 1, 1)
1323  call fill_regular_mosaic_halo(global2(:,:,:,n), global2_all, 1, 1, 1, 1, 1, 1, 1, 1)
1324  else if(folded_north) then
1325  !redundant points must be equal and opposite for tripolar grid
1326  global1(nx/2+shift, ny+shift,:,:) = 0. !pole points must have 0 velocity
1327  global1(nx+shift , ny+shift,:,:) = 0. !pole points must have 0 velocity
1328  global1(nx/2+1+shift:nx-1+shift, ny+shift,:,:) = -global1(nx/2-1+shift:1+shift:-1, ny+shift,:,:)
1329  global1(1-whalo:shift, ny+shift,:,:) = -global1(nx-whalo+1:nx+shift, ny+shift,:,:)
1330  global1(nx+1+shift:nx+ehalo+shift, ny+shift,:,:) = -global1(1+shift:ehalo+shift, ny+shift,:,:)
1331  global2(nx/2+shift, ny+shift,:,:) = 0. !pole points must have 0 velocity
1332  global2(nx+shift , ny+shift,:,:) = 0. !pole points must have 0 velocity
1333  global2(nx/2+1+shift:nx-1+shift, ny+shift,:,:) = -global2(nx/2-1+shift:1+shift:-1, ny+shift,:,:)
1334  global2(1-whalo:shift, ny+shift,:,:) = -global2(nx-whalo+1:nx+shift, ny+shift,:,:)
1335  global2(nx+1+shift:nx+ehalo+shift, ny+shift,:,:) = -global2(1+shift:ehalo+shift, ny+shift,:,:)
1336  !--- the following will fix the +0/-0 problem on altix
1337  if(nhalo >0) then
1338  global1(shift,ny+shift,:,:) = 0. !pole points must have 0 velocity
1339  global2(shift,ny+shift,:,:) = 0. !pole points must have 0 velocity
1340  end if
1341  else if(folded_south_sym) then
1342  global1(nx/2+shift, 1,:,:) = 0. !pole points must have 0 velocity
1343  global1(nx+shift , 1,:,:) = 0. !pole points must have 0 velocity
1344  global1(nx/2+1+shift:nx-1+shift, 1,:,:) = -global1(nx/2-1+shift:1+shift:-1, 1,:,:)
1345  global1(1-whalo:shift, 1,:,:) = -global1(nx-whalo+1:nx+shift, 1,:,:)
1346  global1(nx+1+shift:nx+ehalo+shift, 1,:,:) = -global1(1+shift:ehalo+shift, 1,:,:)
1347  global2(nx/2+shift, 1,:,:) = 0. !pole points must have 0 velocity
1348  global2(nx+shift , 1,:,:) = 0. !pole points must have 0 velocity
1349  global2(nx/2+1+shift:nx-1+shift, 1,:,:) = -global2(nx/2-1+shift:1+shift:-1, 1,:,:)
1350  global2(1-whalo:shift, 1,:,:) = -global2(nx-whalo+1:nx+shift, 1,:,:)
1351  global2(nx+1+shift:nx+ehalo+shift, 1,:,:) = -global2(1+shift:ehalo+shift, 1,:,:)
1352  !--- the following will fix the +0/-0 problem on altix
1353  if(shalo >0) then
1354  global1(shift,1,:,:) = 0. !pole points must have 0 velocity
1355  global2(shift,1,:,:) = 0. !pole points must have 0 velocity
1356  endif
1357  else if(folded_west_sym) then
1358  global1(1, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
1359  global1(1, ny+shift, :,:) = 0. !pole points must have 0 velocity
1360  global1(1, ny/2+1+shift:ny-1+shift, :,:) = -global1(1, ny/2-1+shift:1+shift:-1, :,:)
1361  global1(1, 1-shalo:shift, :,:) = -global1(1, ny-shalo+1:ny+shift, :,:)
1362  global1(1, ny+1+shift:ny+nhalo+shift, :,:) = -global1(1, 1+shift:nhalo+shift, :,:)
1363  global2(1, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
1364  global2(1, ny+shift, :,:) = 0. !pole points must have 0 velocity
1365  global2(1, ny/2+1+shift:ny-1+shift, :,:) = -global2(1, ny/2-1+shift:1+shift:-1, :,:)
1366  global2(1, 1-shalo:shift, :,:) = -global2(1, ny-shalo+1:ny+shift, :,:)
1367  global2(1, ny+1+shift:ny+nhalo+shift, :,:) = -global2(1, 1+shift:nhalo+shift, :,:)
1368  !--- the following will fix the +0/-0 problem on altix
1369  if(whalo>0) then
1370  global1(1, shift, :, :) = 0. !pole points must have 0 velocity
1371  global2(1, shift, :, :) = 0. !pole points must have 0 velocity
1372  endif
1373  else if(folded_east_sym) then
1374  global1(nx+shift, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
1375  global1(nx+shift, ny+shift, :,:) = 0. !pole points must have 0 velocity
1376  global1(nx+shift, ny/2+1+shift:ny-1+shift, :,:) = -global1(nx+shift, ny/2-1+shift:1+shift:-1, :,:)
1377  global1(nx+shift, 1-shalo:shift, :,:) = -global1(nx+shift, ny-shalo+1:ny+shift, :,:)
1378  global1(nx+shift, ny+1+shift:ny+nhalo+shift, :,:) = -global1(nx+shift, 1+shift:nhalo+shift, :,:)
1379  global2(nx+shift, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
1380  global2(nx+shift, ny+shift, :,:) = 0. !pole points must have 0 velocity
1381  global2(nx+shift, ny/2+1+shift:ny-1+shift, :,:) = -global2(nx+shift, ny/2-1+shift:1+shift:-1, :,:)
1382  global2(nx+shift, 1-shalo:shift, :,:) = -global2(nx+shift, ny-shalo+1:ny+shift, :,:)
1383  global2(nx+shift, ny+1+shift:ny+nhalo+shift, :,:) = -global2(nx+shift, 1+shift:nhalo+shift, :,:)
1384  !--- the following will fix the +0/-0 problem on altix
1385  if(ehalo >0) then
1386  global1(nx+shift, shift, :,:) = 0. !pole points must have 0 velocity
1387  global2(nx+shift, shift, :,:) = 0. !pole points must have 0 velocity
1388  end if
1389  else if(four_tile) then
1390  select case ( tile(n) )
1391  case (1)
1392  tw = 2; ts = 3; tsw = 4
1393  case (2)
1394  tw = 1; ts = 4; tsw = 3
1395  case (3)
1396  tw = 4; ts = 1; tsw = 2
1397  case (4)
1398  tw = 3; ts = 2; tsw = 1
1399  end select
1400  te = tw; tn = ts; tse = tsw; tnw = tsw; tne = tsw
1401  call fill_regular_mosaic_halo(global1(:,:,:,n), global1_all, te, tse, ts, tsw, tw, tnw, tn, tne )
1402  call fill_regular_mosaic_halo(global2(:,:,:,n), global2_all, te, tse, ts, tsw, tw, tnw, tn, tne )
1403  else if(cubic_grid) then
1404  call fill_cubic_grid_halo(global1(:,:,:,n), global1_all, global2_all, tile(n), 1, 1, 1, 1 )
1405  call fill_cubic_grid_halo(global2(:,:,:,n), global2_all, global1_all, tile(n), 1, 1, 1, 1 )
1406  endif
1407 
1408  if(ntile_per_pe > 1) write(type3, *)trim(type2), " at tile_count = ",n
1409  call mpp_clock_begin(id)
1410  if(ntile_per_pe == 1) then
1411  call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, flags=update_flags, gridtype=bgrid_ne, name=type3)
1412  else
1413  call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, flags=update_flags, gridtype=bgrid_ne, &
1414  name=type3, tile_count = n)
1415  end if
1416  call mpp_clock_end (id)
1417  end do
1418 
1419  do n = 1, ntile_per_pe
1420  if(ntile_per_pe > 1) write(type3, *)trim(type2), " at tile_count = ", n
1421  call compare_checksums( x(isd:ied+shift,jsd:jed+shift,:,n), global1(isd:ied+shift,jsd:jed+shift,:,n), trim(type3)//' X' )
1422  call compare_checksums( y(isd:ied+shift,jsd:jed+shift,:,n), global2(isd:ied+shift,jsd:jed+shift,:,n), trim(type3)//' Y' )
1423  end do
1424 
1425  if(ntile_per_pe == 1) then
1426  call mpp_clock_begin(id)
1427  call mpp_update_domains( x1, y1, domain, flags=update_flags, gridtype=bgrid_ne, complete=.false., name=type2)
1428  call mpp_update_domains( x2, y2, domain, flags=update_flags, gridtype=bgrid_ne, complete=.false., name=type2)
1429  call mpp_update_domains( x3, y3, domain, flags=update_flags, gridtype=bgrid_ne, complete=.false., name=type2)
1430  call mpp_update_domains( x4, y4, domain, flags=update_flags, gridtype=bgrid_ne, complete=.true., name=type2)
1431  call mpp_clock_end (id)
1432 
1433  call compare_checksums( x1(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X1')
1434  call compare_checksums( x2(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X2')
1435  call compare_checksums( x3(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X3')
1436  call compare_checksums( x4(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X4')
1437  call compare_checksums( y1(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y1')
1438  call compare_checksums( y2(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y2')
1439  call compare_checksums( y3(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y3')
1440  call compare_checksums( y4(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y4')
1441 
1442  !--- arbitrary halo updates ---------------------------------------
1443  if(wide_halo_x == 0) then
1444  if(single_tile .or. four_tile .or. (cubic_grid .and. same_layout) .or. folded_north) then
1445  allocate(local1(isd:ied+shift,jsd:jed+shift,nz) )
1446  allocate(local2(isd:ied+shift,jsd:jed+shift,nz) )
1447  do wh = 1, whalo
1448  do eh = 1, ehalo
1449  if(wh .NE. eh) cycle
1450  do sh = 1, shalo
1451  do nh = 1, nhalo
1452  if(nh .NE. sh) cycle
1453 
1454  local1(isd:ied+shift,jsd:jed+shift,:) = global1(isd:ied+shift,jsd:jed+shift,:,1)
1455  local2(isd:ied+shift,jsd:jed+shift,:) = global2(isd:ied+shift,jsd:jed+shift,:,1)
1456  x = 0.; y = 0.
1457  x(isc:iec+shift,jsc:jec+shift,:,1) = global1(isc:iec+shift,jsc:jec+shift,:,1)
1458  y(isc:iec+shift,jsc:jec+shift,:,1) = global2(isc:iec+shift,jsc:jec+shift,:,1)
1459 
1460  call fill_halo_zero(local1, wh, eh, sh, nh, shift, shift, isc, iec, jsc, jec, isd, ied, jsd, jed)
1461  call fill_halo_zero(local2, wh, eh, sh, nh, shift, shift, isc, iec, jsc, jec, isd, ied, jsd, jed)
1462  write(type3,'(a,a,i2,a,i2,a,i2,a,i2)') trim(type2), ' with whalo = ', wh, &
1463  ', ehalo = ',eh, ', shalo = ', sh, ', nhalo = ', nh
1464  call mpp_update_domains( x, y, domain, flags=update_flags, gridtype=bgrid_ne, &
1465  whalo=wh, ehalo=eh, shalo=sh, nhalo=nh, name=type3)
1466  call compare_checksums( x(isd:ied+shift,jsd:jed+shift,:,1), local1, trim(type3)//' X' )
1467  call compare_checksums( y(isd:ied+shift,jsd:jed+shift,:,1), local2, trim(type3)//' Y' )
1468  end do
1469  end do
1470  end do
1471  end do
1472  deallocate(local1, local2)
1473  end if
1474  endif
1475  end if
1476  !------------------------------------------------------------------
1477  ! vector update : CGRID_NE
1478  !------------------------------------------------------------------
1479  !--- setup data
1480  if(cubic_grid .or. folded_north .or. folded_south_sym .or. folded_west_sym .or. folded_east_sym ) then
1481  deallocate(global1_all, global2_all)
1482  allocate(global1_all(nx+shift,ny,nz, ntiles), global2_all(nx,ny+shift,nz, ntiles))
1483  deallocate(global1, global2, x, y, x1, x2, x3, x4, y1, y2, y3, y4)
1484  allocate(global1(1-whalo:nx+shift+ehalo,1-shalo:ny +nhalo,nz,ntile_per_pe) )
1485  allocate( x(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
1486  allocate( y(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
1487  allocate( x1(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
1488  allocate( x2(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
1489  allocate( x3(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
1490  allocate( x4(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
1491  allocate( y1(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
1492  allocate( y2(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
1493  allocate( y3(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
1494  allocate( y4(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
1495  allocate(global2(1-whalo:nx +ehalo,1-shalo:ny+shift+nhalo,nz,ntile_per_pe) )
1496  global1 = 0; global2 = 0
1497  do l = 1, ntiles
1498  do k = 1, nz
1499  do j = 1, ny
1500  do i = 1, nx+shift
1501  global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1502  end do
1503  end do
1504  do j = 1, ny+shift
1505  do i = 1, nx
1506  global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1507  end do
1508  end do
1509  end do
1510  end do
1511  endif
1512  if( folded_north .or. folded_south_sym .or. folded_west_sym .or. folded_east_sym ) then
1513  do n = 1, ntile_per_pe
1514  global1(1:nx+shift,1:ny ,:,n) = global1_all(1:nx+shift,1:ny, :,tile(n))
1515  global2(1:nx ,1:ny+shift,:,n) = global2_all(1:nx ,1:ny+shift,:,tile(n))
1516  end do
1517  endif
1518 
1519  if( cubic_grid ) then
1520  !-----------------------------------------------------------------------
1521  !--- make sure consistency on the boundary for cubic grid
1522  !--- east boundary will take the value of neighbor tile ( west/south),
1523  !--- north boundary will take the value of neighbor tile ( south/west).
1524  !-----------------------------------------------------------------------
1525  do l = 1, ntiles
1526  if(mod(l,2) == 0) then ! tile 2, 4, 6
1527  te = l + 2
1528  tn = l + 1
1529  if(te>6) te = te - 6
1530  if(tn > 6) tn = tn - 6
1531  global1_all(nx+shift,1:ny,:,l) = global2_all(nx:1:-1,1,:,te) ! east
1532  global2_all(1:nx,ny+shift,:,l) = global2_all(1:nx,1,:,tn) ! north
1533  else ! tile 1, 3, 5
1534  te = l + 1
1535  tn = l + 2
1536  if(tn > 6) tn = tn - 6
1537  global1_all(nx+shift,:,:,l) = global1_all(1,:,:,te) ! east
1538  global2_all(1:nx,ny+shift,:,l) = global1_all(1,ny:1:-1,:,tn) ! north
1539  end if
1540  end do
1541  do n = 1, ntile_per_pe
1542  global1(1:nx+shift,1:ny ,:,n) = global1_all(1:nx+shift,1:ny, :,tile(n))
1543  global2(1:nx ,1:ny+shift,:,n) = global2_all(1:nx ,1:ny+shift,:,tile(n))
1544  end do
1545  else if( folded_north ) then
1546  call fill_folded_north_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
1547  call fill_folded_north_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
1548  else if(folded_south_sym ) then
1549  call fill_folded_south_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
1550  call fill_folded_south_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
1551  else if(folded_west_sym ) then
1552  call fill_folded_west_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
1553  call fill_folded_west_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
1554  else if(folded_east_sym ) then
1555  call fill_folded_east_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
1556  call fill_folded_east_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
1557  endif
1558  x = 0.; y = 0.
1559  x(isc:iec+shift,jsc:jec ,:,:) = global1(isc:iec+shift,jsc:jec ,:,:)
1560  y(isc:iec ,jsc:jec+shift,:,:) = global2(isc:iec ,jsc:jec+shift,:,:)
1561  x1 = x; x2 = x; x3 = x; x4 = x
1562  y1 = y; y2 = y; y3 = y; y4 = y
1563 
1564  !-----------------------------------------------------------------------
1565  ! fill up the value at halo points for cubic-grid.
1566  ! On the contact line, the following relation will be used to
1567  ! --- fill the value on contact line ( balance send and recv).
1568  ! 2W --> 1E, 1S --> 6N, 3W --> 1N, 4S --> 2E
1569  ! 4W --> 3E, 3S --> 2N, 1W --> 5N, 2S --> 6E
1570  ! 6W --> 5E, 5S --> 4N, 5W --> 3N, 6S --> 4E
1571  !---------------------------------------------------------------------------
1572  id = mpp_clock_id( type//' vector CGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
1573  type2 = type
1574  do n = 1, ntile_per_pe
1575  if( cubic_grid ) then
1576  call fill_cubic_grid_halo(global1(:,:,:,n), global1_all, global2_all, tile(n), 1, 0, 1, -1 )
1577  call fill_cubic_grid_halo(global2(:,:,:,n), global2_all, global1_all, tile(n), 0, 1, -1, 1 )
1578  else if( folded_north ) then
1579  !redundant points must be equal and opposite
1580  global2(nx/2+1:nx, ny+shift,:,:) = -global2(nx/2:1:-1, ny+shift,:,:)
1581  global2(1-whalo:0, ny+shift,:,:) = -global2(nx-whalo+1:nx, ny+shift,:,:)
1582  global2(nx+1:nx+ehalo, ny+shift,:,:) = -global2(1:ehalo, ny+shift,:,:)
1583  else if( folded_south_sym ) then
1584  global2(nx/2+1:nx, 1,:,:) = -global2(nx/2:1:-1, 1,:,:)
1585  global2(1-whalo:0, 1,:,:) = -global2(nx-whalo+1:nx, 1, :,:)
1586  global2(nx+1:nx+ehalo, 1,:,:) = -global2(1:ehalo, 1, :,:)
1587  else if( folded_west_sym ) then
1588  global1(1, ny/2+1:ny, :,:) = -global1(1, ny/2:1:-1, :,:)
1589  global1(1, 1-shalo:0, :,:) = -global1(1, ny-shalo+1:ny, :,:)
1590  global1(1, ny+1:ny+nhalo, :,:) = -global1(1, 1:nhalo, :,:)
1591  else if( folded_east_sym ) then
1592  global1(nx+shift, ny/2+1:ny, :,:) = -global1(nx+shift, ny/2:1:-1, :,:)
1593  global1(nx+shift, 1-shalo:0, :,:) = -global1(nx+shift, ny-shalo+1:ny, :,:)
1594  global1(nx+shift, ny+1:ny+nhalo, :,:) = -global1(nx+shift, 1:nhalo, :,:)
1595  end if
1596 
1597  if(ntile_per_pe > 1) write(type2, *)type, " at tile_count = ",n
1598  call mpp_clock_begin(id)
1599  if(ntile_per_pe == 1) then
1600  call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=cgrid_ne, name=type2//' vector CGRID_NE')
1601  else
1602  call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=cgrid_ne, &
1603  name=type2//' vector CGRID_NE', tile_count = n)
1604  end if
1605  call mpp_clock_end (id)
1606  end do
1607 
1608 
1609 
1610  do n = 1, ntile_per_pe
1611  if(ntile_per_pe > 1) write(type2, *)type, " at tile_count = ",n
1612  call compare_checksums( x(isd:ied+shift,jsd:jed,:,n), global1(isd:ied+shift,jsd:jed, :,n), &
1613  trim(type2)//' CGRID_NE X')
1614  call compare_checksums( y(isd:ied,jsd:jed+shift,:,n), global2(isd:ied, jsd:jed+shift,:,n), &
1615  trim(type2)//' CGRID_NE Y')
1616  end do
1617 
1618  if(ntile_per_pe == 1) then
1619  call mpp_clock_begin(id)
1620  call mpp_update_domains( x1, y1, domain, gridtype=cgrid_ne, complete=.false., name=type//' vector CGRID_NE' )
1621  call mpp_update_domains( x2, y2, domain, gridtype=cgrid_ne, complete=.false., name=type//' vector CGRID_NE')
1622  call mpp_update_domains( x3, y3, domain, gridtype=cgrid_ne, complete=.false., name=type//' vector CGRID_NE' )
1623  call mpp_update_domains( x4, y4, domain, gridtype=cgrid_ne, complete=.true. , name=type//' vector CGRID_NE')
1624  call mpp_clock_end (id)
1625 
1626  call compare_checksums( x1(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X1')
1627  call compare_checksums( x2(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X2')
1628  call compare_checksums( x3(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X3')
1629  call compare_checksums( x4(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X4')
1630  call compare_checksums( y1(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y1')
1631  call compare_checksums( y2(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y2')
1632  call compare_checksums( y3(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y3')
1633  call compare_checksums( y4(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y4')
1634 
1635  !--- arbitrary halo updates ---------------------------------------
1636  if(wide_halo_x ==0) then
1637  if(single_tile .or. four_tile .or. (cubic_grid .and. same_layout) .or. folded_north ) then
1638  allocate(local1(isd:ied+shift,jsd:jed, nz) )
1639  allocate(local2(isd:ied, jsd:jed+shift,nz) )
1640 
1641  do wh = 1, whalo
1642  do eh = 1, ehalo
1643  if(wh .NE. eh) cycle
1644  do sh = 1, shalo
1645  do nh = 1, nhalo
1646  if(sh .NE. nh) cycle
1647  local1(isd:ied+shift,jsd:jed, :) = global1(isd:ied+shift,jsd:jed, :,1)
1648  local2(isd:ied, jsd:jed+shift,:) = global2(isd:ied, jsd:jed+shift,:,1)
1649  x = 0.; y = 0.
1650  x(isc:iec+shift,jsc:jec, :,1) = global1(isc:iec+shift,jsc:jec, :,1)
1651  y(isc:iec, jsc:jec+shift,:,1) = global2(isc:iec, jsc:jec+shift,:,1)
1652  call fill_halo_zero(local1, wh, eh, sh, nh, shift, 0, isc, iec, jsc, jec, isd, ied, jsd, jed)
1653  call fill_halo_zero(local2, wh, eh, sh, nh, 0, shift, isc, iec, jsc, jec, isd, ied, jsd, jed)
1654 
1655  write(type3,'(a,a,i2,a,i2,a,i2,a,i2)') trim(type), ' vector CGRID_NE with whalo = ', &
1656  wh, ', ehalo = ',eh, ', shalo = ', sh, ', nhalo = ', nh
1657  call mpp_update_domains( x, y, domain, gridtype=cgrid_ne, whalo=wh, ehalo=eh, &
1658  shalo=sh, nhalo=nh, name=type3)
1659  call compare_checksums( x(isd:ied+shift,jsd:jed, :,1), local1, trim(type3)//' X' )
1660  call compare_checksums( y(isd:ied,jsd:jed+shift, :,1), local2, trim(type3)//' Y' )
1661  end do
1662  end do
1663  end do
1664  end do
1665  deallocate(local1, local2)
1666  end if
1667  endif
1668  end if
1669 
1670  deallocate(global1, global2, x, y, x1, x2, x3, x4, y1, y2, y3, y4, global1_all, global2_all)
1671  deallocate(layout2d, global_indices, pe_start, pe_end, tile1, tile2)
1672  deallocate(istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2 )
1673 
1674  if(wide_halo_x > 0) then
1675  whalo = whalo_save
1676  ehalo = ehalo_save
1677  shalo = shalo_save
1678  nhalo = nhalo_save
1679  endif
1680  nx = nx_save
1681  ny = ny_save
1682 
1683  end subroutine test_uniform_mosaic
1684 
1685  !#################################################################################
1686  subroutine update_domains_performance( type )
1687  character(len=*), intent(in) :: type
1688 
1689  type(domain2D) :: domain
1690  integer :: num_contact, ntiles, npes_per_tile, ntile_per_pe
1691  integer :: i, j, k, l, n, shift
1692  integer :: ism, iem, jsm, jem
1693  integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
1694 
1695  integer, allocatable, dimension(:) :: tile
1696  integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
1697  integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
1698  integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
1699  integer, allocatable, dimension(:,:) :: layout2D, global_indices
1700  real, allocatable, dimension(:,:,:,:) :: x, x1, y, y1, x_save, y_save
1701  real, allocatable, dimension(:,:,:,:) :: a, a1, b, b1
1702  real, allocatable, dimension(:,:,: ) :: a1_2D, b1_2D
1703  integer :: id_update
1704  integer :: id1, id2
1705  logical :: folded_north
1706  logical :: cubic_grid, single_tile, four_tile
1707  character(len=3) :: text
1708  integer :: nx_save, ny_save
1709  integer :: id_single, id_update_single
1710 
1711  folded_north = .false.
1712  cubic_grid = .false.
1713  single_tile = .false.
1714  four_tile = .false.
1715  nx_save = nx
1716  ny_save = ny
1717  !--- check the type
1718  select case(type)
1719  case ( 'Single-Tile' ) !--- single with cyclic along x- and y-direction
1720  single_tile = .true.
1721  ntiles = 1
1722  num_contact = 2
1723  case ( 'Folded-north' )
1724  ntiles = 1
1725  num_contact = 2
1726  folded_north = .true.
1727  case ( 'Four-Tile' ) !--- cyclic along both x- and y-direction.
1728  ntiles = 4
1729  num_contact = 8
1730  four_tile = .true.
1731  case ( 'Cubic-Grid' )
1732  if( nx_cubic == 0 ) then
1733  call mpp_error(note,'update_domains_performance: for Cubic_grid mosaic, nx_cubic is zero, '//&
1734  'No test is done for Cubic-Grid mosaic. ' )
1735  return
1736  endif
1737  if( nx_cubic .NE. ny_cubic ) then
1738  call mpp_error(note,'update_domains_performance: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
1739  'No test is done for Cubic-Grid mosaic. ' )
1740  return
1741  endif
1742 
1743  nx = nx_cubic
1744  ny = ny_cubic
1745  ntiles = 6
1746  num_contact = 12
1747  cubic_grid = .true.
1748 
1749  case default
1750  call mpp_error(fatal, 'update_domains_performance: no such test: '//type)
1751  end select
1752 
1753  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
1754  if( mod(npes, ntiles) == 0 ) then
1755  npes_per_tile = npes/ntiles
1756  write(outunit,*)'NOTE from update_domains_performance ==> For Mosaic "', trim(type), &
1757  '", each tile will be distributed over ', npes_per_tile, ' processors.'
1758  ntile_per_pe = 1
1759  allocate(tile(ntile_per_pe))
1760  tile = pe/npes_per_tile+1
1761  if(cubic_grid) then
1762  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
1763  else
1764  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
1765  endif
1766  do n = 1, ntiles
1767  pe_start(n) = (n-1)*npes_per_tile
1768  pe_end(n) = n*npes_per_tile-1
1769  end do
1770  else if ( mod(ntiles, npes) == 0 ) then
1771  ntile_per_pe = ntiles/npes
1772  write(outunit,*)'NOTE from update_domains_performance ==> For Mosaic "', trim(type), &
1773  '", there will be ', ntile_per_pe, ' tiles on each processor.'
1774  allocate(tile(ntile_per_pe))
1775  do n = 1, ntile_per_pe
1776  tile(n) = pe*ntile_per_pe + n
1777  end do
1778  do n = 1, ntiles
1779  pe_start(n) = (n-1)/ntile_per_pe
1780  pe_end(n) = pe_start(n)
1781  end do
1782  layout = 1
1783  else
1784  call mpp_error(note,'update_domains_performance: npes should be multiple of ntiles or ' // &
1785  'ntiles should be multiple of npes. No test is done for '//trim(type) )
1786  return
1787  end if
1788 
1789  do n = 1, ntiles
1790  global_indices(:,n) = (/1,nx,1,ny/)
1791  layout2d(:,n) = layout
1792  end do
1793 
1794  allocate(tile1(num_contact), tile2(num_contact) )
1795  allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
1796  allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
1797 
1798  !--- define domain
1799  if(single_tile) then
1800  !--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST)
1801  tile1(1) = 1; tile2(1) = 1
1802  istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
1803  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
1804  !--- Contact line 2, between tile 1 (SOUTH) and tile 1 (NORTH) --- cyclic
1805  tile1(2) = 1; tile2(2) = 1
1806  istart1(2) = 1; iend1(2) = nx; jstart1(2) = 1; jend1(2) = 1
1807  istart2(2) = 1; iend2(2) = nx; jstart2(2) = ny; jend2(2) = ny
1808  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
1809  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
1810  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
1811  name = type, symmetry = .false. )
1812  else if(folded_north) then
1813  !--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
1814  tile1(1) = 1; tile2(1) = 1
1815  istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
1816  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
1817  !--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
1818  tile1(2) = 1; tile2(2) = 1
1819  istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
1820  istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
1821  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
1822  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
1823  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
1824  name = type, symmetry = .false. )
1825  else if( four_tile ) then
1826  call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
1827  layout2D, pe_start, pe_end, symmetry = .false. )
1828  else if( cubic_grid ) then
1829  call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
1830  global_indices, layout2D, pe_start, pe_end )
1831  endif
1832 
1833  !--- setup data
1834  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
1835  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
1836  call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
1837  allocate( x(ism:iem,jsm:jem,nz, ntile_per_pe) )
1838  allocate( x_save(ism:iem,jsm:jem,nz, ntile_per_pe) )
1839  allocate( a(ism:iem,jsm:jem,nz, ntile_per_pe) )
1840  x = 0
1841  do l = 1, ntile_per_pe
1842  do k = 1, nz
1843  do j = jsc, jec
1844  do i = isc, iec
1845  x(i, j, k, l) = tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1846  enddo
1847  enddo
1848  enddo
1849  enddo
1850 
1851  a = x
1852  x_save = x
1853 
1854  if(num_fields<1) then
1855  call mpp_error(fatal, "test_mpp_domains: num_fields must be a positive integer")
1856  endif
1857 
1858  id1 = mpp_clock_id( type, flags=mpp_clock_sync)
1859  id_single = mpp_clock_id( type//' non-blocking', flags=mpp_clock_sync)
1860 
1861 
1862  call mpp_clock_begin(id1)
1863  call mpp_update_domains( x, domain)
1864  call mpp_clock_end (id1)
1865 
1866  call mpp_clock_begin(id_single)
1867  id_update_single = mpp_start_update_domains(a, domain)
1868  call mpp_clock_end (id_single)
1869 
1870  !---- sleep some time for non-blocking.
1871  if(do_sleep) call sleep(1)
1872 
1873  id1 = mpp_clock_id( type//' group', flags=mpp_clock_sync )
1874  id2 = mpp_clock_id( type//' group non-blocking', flags=mpp_clock_sync )
1875 
1876 
1877  if(ntile_per_pe == 1) then
1878  allocate( x1(ism:iem,jsm:jem,nz, num_fields) )
1879  allocate( a1(ism:iem,jsm:jem,nz, num_fields) )
1880  if(mix_2d_3d) allocate( a1_2d(ism:iem,jsm:jem,num_fields) )
1881 
1882  do n = 1, num_iter
1883  do l = 1, num_fields
1884  x1(:,:,:,l) = x_save(:,:,:,1)
1885  a1(:,:,:,l) = x_save(:,:,:,1)
1886  if(mix_2d_3d) a1_2d(:,:,l) = x_save(:,:,1,1)
1887  enddo
1888 
1889  call mpp_clock_begin(id1)
1890  do l = 1, num_fields
1891  call mpp_update_domains( x1(:,:,:,l), domain, complete=l==num_fields )
1892  enddo
1893  call mpp_clock_end (id1)
1894 
1895  ! non-blocking update
1896  call mpp_clock_begin(id2)
1897  if( n == 1 ) then
1898  do l = 1, num_fields
1899  if(mix_2d_3d) id_update = mpp_start_update_domains(a1_2d(:,:,l), domain, complete=.false.)
1900  id_update = mpp_start_update_domains(a1(:,:,:,l), domain, complete=l==num_fields)
1901  enddo
1902  else
1903  do l = 1, num_fields
1904  if(mix_2d_3d) id_update = mpp_start_update_domains(a1_2d(:,:,l), domain, update_id=id_update, complete=.false.)
1905  id_update = mpp_start_update_domains(a1(:,:,:,l), domain, update_id=id_update, complete=l==num_fields)
1906  enddo
1907  endif
1908  call mpp_clock_end (id2)
1909 
1910  !---- sleep some time for non-blocking.
1911  if(do_sleep) call sleep(1)
1912 
1913  call mpp_clock_begin(id2)
1914  do l = 1, num_fields
1915  if(mix_2d_3d) call mpp_complete_update_domains(id_update, a1_2d(:,:,l), domain, complete=.false.)
1916  call mpp_complete_update_domains(id_update, a1(:,:,:,l), domain, complete=l==num_fields)
1917  enddo
1918  call mpp_clock_end (id2)
1919 
1920 
1921  !--- compare checksum
1922  do l = 1, num_fields
1923  write(text, '(i3.3)') l
1924  call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' X'//text)
1925  enddo
1926  if(mix_2d_3d)call compare_checksums( x1(:,:,1,:), a1_2d(:,:,:), type//' X 2D')
1927  enddo
1928  deallocate(x1, a1)
1929  if(mix_2d_3d) deallocate(a1_2d)
1930  endif
1931 
1932  call mpp_clock_begin(id_single)
1933  call mpp_complete_update_domains(id_update_single, a, domain)
1934  call mpp_clock_end (id_single)
1935  call compare_checksums( x(:,:,:,1), a(:,:,:,1), type)
1936  deallocate(x, a, x_save)
1937 
1938 
1939  !------------------------------------------------------------------
1940  ! vector update : BGRID_NE, one extra point in each direction for cubic-grid
1941  !------------------------------------------------------------------
1942  !--- setup data
1943  shift = 0
1944  if(single_tile .or. four_tile .or. folded_north) then
1945  shift = 0
1946  else
1947  shift = 1
1948  endif
1949 
1950  allocate( x(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1951  allocate( y(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1952  allocate( x_save(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1953  allocate( y_save(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1954  allocate( a(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1955  allocate( b(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
1956  x = 0
1957  y = 0
1958  do l = 1, ntile_per_pe
1959  do k = 1, nz
1960  do j = jsc, jec+shift
1961  do i = isc, iec+shift
1962  x(i,j,k,l) = 1.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1963  y(i,j,k,l) = 2.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
1964  end do
1965  end do
1966  end do
1967  enddo
1968  a = x; b = y
1969  x_save = x; y_save = y
1970 
1971  id1 = mpp_clock_id( trim(type)//' BGRID', flags=mpp_clock_sync )
1972  id_single = mpp_clock_id( trim(type)//' BGRID non-blocking', flags=mpp_clock_sync )
1973 
1974  call mpp_clock_begin(id1)
1975  call mpp_update_domains( x, y, domain, gridtype=bgrid_ne)
1976  call mpp_clock_end (id1)
1977 
1978  !--- non-blocking update
1979  call mpp_clock_begin(id_single)
1980  id_update_single = mpp_start_update_domains(a, b, domain, gridtype=bgrid_ne)
1981  call mpp_clock_end (id_single)
1982 
1983  !---- sleep some time for non-blocking.
1984  if(do_sleep) call sleep(1)
1985 
1986  id1 = mpp_clock_id( trim(type)//' BGRID group', flags=mpp_clock_sync)
1987  id2 = mpp_clock_id( trim(type)//' BGRID group non-blocking', flags=mpp_clock_sync)
1988  if(ntile_per_pe == 1) then
1989  allocate( x1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
1990  allocate( y1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
1991  allocate( a1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
1992  allocate( b1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
1993  if(mix_2d_3d) then
1994  allocate( a1_2d(ism:iem+shift,jsm:jem+shift,num_fields) )
1995  allocate( b1_2d(ism:iem+shift,jsm:jem+shift,num_fields) )
1996  endif
1997 
1998  do n = 1, num_iter
1999  do l = 1, num_fields
2000  x1(:,:,:,l) = x_save(:,:,:,1)
2001  a1(:,:,:,l) = x_save(:,:,:,1)
2002  y1(:,:,:,l) = y_save(:,:,:,1)
2003  b1(:,:,:,l) = y_save(:,:,:,1)
2004  if(mix_2d_3d) then
2005  a1_2d(:,:,l) = x_save(:,:,1,1)
2006  b1_2d(:,:,l) = y_save(:,:,1,1)
2007  endif
2008  enddo
2009 
2010  call mpp_clock_begin(id1)
2011  do l = 1, num_fields
2012  call mpp_update_domains( x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=bgrid_ne, complete=l==num_fields )
2013  enddo
2014  call mpp_clock_end (id1)
2015 
2016  !--- non-blocking update
2017  call mpp_clock_begin(id2)
2018  if( n == 1 ) then
2019  do l = 1, num_fields
2020  if(mix_2d_3d) id_update = mpp_start_update_domains(a1_2d(:,:,l), b1_2d(:,:,l), domain, &
2021  gridtype=bgrid_ne, complete=.false.)
2022  id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, &
2023  gridtype=bgrid_ne, complete=l==num_fields)
2024  enddo
2025  else
2026  do l = 1, num_fields
2027  if(mix_2d_3d) id_update = mpp_start_update_domains(a1_2d(:,:,l), b1_2d(:,:,l), domain, gridtype=bgrid_ne, &
2028  update_id=id_update, complete=.false.)
2029  id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, gridtype=bgrid_ne, &
2030  update_id=id_update, complete=l==num_fields)
2031  enddo
2032  endif
2033  call mpp_clock_end (id2)
2034 
2035  !---- sleep some time for non-blocking.
2036  if(do_sleep) call sleep(1)
2037 
2038  call mpp_clock_begin(id2)
2039  do l = 1, num_fields
2040  if(mix_2d_3d)call mpp_complete_update_domains(id_update, a1_2d(:,:,l), b1_2d(:,:,l), domain, &
2041  gridtype=bgrid_ne, complete=.false.)
2042  call mpp_complete_update_domains(id_update, a1(:,:,:,l), b1(:,:,:,l), domain, &
2043  gridtype=bgrid_ne, complete=l==num_fields)
2044  enddo
2045  call mpp_clock_end (id2)
2046 
2047  !--- compare checksum
2048  do l = 1, num_fields
2049  write(text, '(i3.3)') l
2050  call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' BGRID X'//text)
2051  call compare_checksums( y1(:,:,:,l), b1(:,:,:,l), type//' BGRID Y'//text)
2052  if(mix_2d_3d) then
2053  call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' BGRID X'//text)
2054  call compare_checksums( y1(:,:,:,1), b1(:,:,:,1), type//' BGRID Y'//text)
2055  endif
2056  enddo
2057  if(mix_2d_3d) then
2058  call compare_checksums( x1(:,:,1,:), a1_2d(:,:,:), type//' BGRID X 2D')
2059  call compare_checksums( y1(:,:,1,:), b1_2d(:,:,:), type//' BGRID Y 2D')
2060  endif
2061  enddo
2062  deallocate(x1, y1, a1, b1)
2063  if(mix_2d_3d) deallocate(a1_2d, b1_2d)
2064  endif
2065 
2066  call mpp_clock_begin(id_single)
2067  call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=bgrid_ne)
2068  call mpp_clock_end (id_single)
2069 
2070 
2071  !--- compare checksum
2072 
2073  call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' BGRID X')
2074  call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' BGRID Y')
2075 
2076 
2077  deallocate(x, y, a, b, x_save, y_save)
2078  !------------------------------------------------------------------
2079  ! vector update : CGRID_NE, one extra point in each direction for cubic-grid
2080  !------------------------------------------------------------------
2081  allocate( x(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
2082  allocate( y(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
2083  allocate( a(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
2084  allocate( b(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
2085  allocate( x_save(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
2086  allocate( y_save(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
2087 
2088 
2089  x = 0
2090  y = 0
2091  do l = 1, ntile_per_pe
2092  do k = 1, nz
2093  do j = jsc, jec
2094  do i = isc, iec+shift
2095  x(i,j,k,l) = 1.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
2096  end do
2097  end do
2098  do j = jsc, jec+shift
2099  do i = isc, iec
2100  y(i,j,k,l) = 2.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
2101  end do
2102  end do
2103  end do
2104  enddo
2105 
2106  a = x; b = y
2107  x_save = x; y_save = y
2108 
2109  id1 = mpp_clock_id( trim(type)//' CGRID', flags=mpp_clock_sync )
2110  id_single = mpp_clock_id( trim(type)//' CGRID non-blocking', flags=mpp_clock_sync )
2111 
2112  call mpp_clock_begin(id1)
2113  call mpp_update_domains( x, y, domain, gridtype=cgrid_ne)
2114  call mpp_clock_end (id1)
2115 
2116  !--- non-blocking update
2117  call mpp_clock_begin(id_single)
2118  id_update_single = mpp_start_update_domains(a, b, domain, gridtype=cgrid_ne)
2119  call mpp_clock_end (id_single)
2120 
2121  !---- sleep some time for non-blocking.
2122  if(do_sleep) call sleep(1)
2123 
2124  id1 = mpp_clock_id( trim(type)//' CGRID group', flags=mpp_clock_sync )
2125  id2 = mpp_clock_id( trim(type)//' CGRID group non-blocking', flags=mpp_clock_sync )
2126 
2127  if(ntile_per_pe == 1) then
2128  allocate( x1(ism:iem+shift,jsm:jem ,nz,num_fields) )
2129  allocate( y1(ism:iem ,jsm:jem+shift,nz,num_fields) )
2130  allocate( a1(ism:iem+shift,jsm:jem ,nz,num_fields) )
2131  allocate( b1(ism:iem ,jsm:jem+shift,nz,num_fields) )
2132  if(mix_2d_3d) then
2133  allocate( a1_2d(ism:iem+shift,jsm:jem ,num_fields) )
2134  allocate( b1_2d(ism:iem ,jsm:jem+shift,num_fields) )
2135  endif
2136 
2137  do n = 1, num_iter
2138  do l = 1, num_fields
2139  x1(:,:,:,l) = x_save(:,:,:,1)
2140  a1(:,:,:,l) = x_save(:,:,:,1)
2141  y1(:,:,:,l) = y_save(:,:,:,1)
2142  b1(:,:,:,l) = y_save(:,:,:,1)
2143  if(mix_2d_3d) then
2144  a1_2d(:,:,l) = x_save(:,:,1,1)
2145  b1_2d(:,:,l) = y_save(:,:,1,1)
2146  endif
2147  enddo
2148 
2149  call mpp_clock_begin(id1)
2150  do l = 1, num_fields
2151  call mpp_update_domains( x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=cgrid_ne, complete=l==num_fields )
2152  enddo
2153  call mpp_clock_end (id1)
2154 
2155  !--- non-blocking update
2156  call mpp_clock_begin(id2)
2157  if( n == 1 ) then
2158  do l = 1, num_fields
2159  if(mix_2d_3d) id_update = mpp_start_update_domains(a1_2d(:,:,l), b1_2d(:,:,l), domain, &
2160  gridtype=cgrid_ne, complete=.false.)
2161  id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, &
2162  gridtype=cgrid_ne, complete=l==num_fields)
2163  enddo
2164  else
2165  do l = 1, num_fields
2166  if(mix_2d_3d)id_update = mpp_start_update_domains(a1_2d(:,:,l), b1_2d(:,:,l), domain, gridtype=cgrid_ne, &
2167  update_id=id_update, complete=.false.)
2168  id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, gridtype=cgrid_ne, &
2169  update_id=id_update, complete=l==num_fields)
2170  enddo
2171  endif
2172  call mpp_clock_end (id2)
2173 
2174  !---- sleep some time for non-blocking.
2175  if(do_sleep) call sleep(1)
2176 
2177  call mpp_clock_begin(id2)
2178  do l = 1, num_fields
2179  if(mix_2d_3d)call mpp_complete_update_domains(id_update, a1_2d(:,:,l), b1_2d(:,:,l), domain, &
2180  gridtype=cgrid_ne, complete=.false.)
2181  call mpp_complete_update_domains(id_update, a1(:,:,:,l), b1(:,:,:,l), domain, &
2182  gridtype=cgrid_ne, complete=l==num_fields)
2183  enddo
2184  call mpp_clock_end (id2)
2185 
2186  !--- compare checksum
2187  do l = 1, num_fields
2188  write(text, '(i3.3)') l
2189  call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' CGRID X'//text)
2190  call compare_checksums( y1(:,:,:,l), b1(:,:,:,l), type//' CGRID Y'//text)
2191  enddo
2192  if(mix_2d_3d) then
2193  call compare_checksums( x1(:,:,1,:), a1_2d(:,:,:), type//' BGRID X 2D')
2194  call compare_checksums( y1(:,:,1,:), b1_2d(:,:,:), type//' BGRID Y 2D')
2195  endif
2196  enddo
2197  deallocate(x1, y1, a1, b1)
2198  if(mix_2d_3d) deallocate(a1_2d, b1_2d)
2199  endif
2200 
2201  call mpp_clock_begin(id_single)
2202  call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=cgrid_ne)
2203  call mpp_clock_end (id_single)
2204 
2205  !--- compare checksum
2206 
2207  call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' CGRID X')
2208  call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' CGRID Y')
2209 
2210  deallocate(x, y, a, b, x_save, y_save)
2211 
2212 
2213  !------------------------------------------------------------------
2214  ! vector update : AGRID vector and scalar pair
2215  !------------------------------------------------------------------
2216  allocate( x(ism:iem,jsm:jem,nz,ntile_per_pe) )
2217  allocate( y(ism:iem,jsm:jem,nz,ntile_per_pe) )
2218  allocate( a(ism:iem,jsm:jem,nz,ntile_per_pe) )
2219  allocate( b(ism:iem,jsm:jem,nz,ntile_per_pe) )
2220  allocate( x_save(ism:iem,jsm:jem,nz,ntile_per_pe) )
2221  allocate( y_save(ism:iem,jsm:jem,nz,ntile_per_pe) )
2222 
2223 
2224  x = 0
2225  y = 0
2226  do l = 1, ntile_per_pe
2227  do k = 1, nz
2228  do j = jsc, jec
2229  do i = isc, iec+shift
2230  x(i,j,k,l) = 1.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
2231  end do
2232  end do
2233  do j = jsc, jec+shift
2234  do i = isc, iec
2235  y(i,j,k,l) = 2.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
2236  end do
2237  end do
2238  end do
2239  enddo
2240 
2241  a = x; b = y
2242  x_save = x; y_save = y
2243 
2244  call mpp_update_domains( x, y, domain, gridtype=agrid)
2245 
2246  id_update_single = mpp_start_update_domains(a, b, domain, gridtype=agrid)
2247  call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=agrid)
2248 
2249  !--- compare checksum
2250  call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' AGRID X')
2251  call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' AGRID Y')
2252 
2253  x = x_save; y = y_save
2254  a = x_save; b = y_save
2255 
2256  call mpp_update_domains( x, y, domain, gridtype=agrid, flags = scalar_pair)
2257 
2258  id_update_single = mpp_start_update_domains(a, b, domain, gridtype=agrid, flags = scalar_pair)
2259  call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=agrid, flags = scalar_pair)
2260 
2261  !--- compare checksum
2262  call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' AGRID SCALAR-PAIR X')
2263  call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' AGRID SCALAR-PAIR Y')
2264 
2265  deallocate(x, y, a, b, x_save, y_save)
2266 
2267  nx = nx_save
2268  ny = ny_save
2269 
2270  deallocate(layout2d, global_indices, pe_start, pe_end, tile1, tile2)
2271  deallocate(istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2 )
2272 
2273 
2274  end subroutine update_domains_performance
2275 
2276 
2277  !###############################################################
2278  subroutine test_mpp_global_sum( type )
2279  character(len=*), intent(in) :: type
2280 
2281  type(domain2D) :: domain
2282  integer :: num_contact, ntiles, npes_per_tile
2283  integer :: i, j, k, l, n, shift
2284  integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
2285  integer :: ism, iem, jsm, jem
2286 
2287  integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
2288  integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
2289  integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
2290  integer, allocatable, dimension(:,:) :: layout2D, global_indices
2291  real, allocatable, dimension(:,:,:) :: data_3D
2292  real, allocatable, dimension(:,:) :: data_2D
2293 
2294  integer(kind=8) :: mold
2295  logical :: folded_north, cubic_grid
2296  character(len=3) :: text
2297  integer :: nx_save, ny_save
2298  integer :: id1, id2, id3, id4
2299  real :: gsum1, gsum2, gsum3, gsum4
2300 
2301  folded_north = .false.
2302  cubic_grid = .false.
2303 
2304  nx_save = nx
2305  ny_save = ny
2306  !--- check the type
2307  select case(type)
2308  case ( 'Folded-north' )
2309  ntiles = 1
2310  shift = 0
2311  num_contact = 2
2312  folded_north = .true.
2313  npes_per_tile = npes
2314  if(layout_tripolar(1)*layout_tripolar(2) == npes ) then
2315  layout = layout_tripolar
2316  else
2317  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
2318  endif
2319  case ( 'Cubic-Grid' )
2320  if( nx_cubic == 0 ) then
2321  call mpp_error(note,'test_group_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
2322  'No test is done for Cubic-Grid mosaic. ' )
2323  return
2324  endif
2325  if( nx_cubic .NE. ny_cubic ) then
2326  call mpp_error(note,'test_group_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
2327  'No test is done for Cubic-Grid mosaic. ' )
2328  return
2329  endif
2330  shift = 1
2331  nx = nx_cubic
2332  ny = ny_cubic
2333  ntiles = 6
2334  num_contact = 12
2335  cubic_grid = .true.
2336  if( mod(npes, ntiles) == 0 ) then
2337  npes_per_tile = npes/ntiles
2338  write(outunit,*)'NOTE from test_mpp_global_sum ==> For Mosaic "', trim(type), &
2339  '", each tile will be distributed over ', npes_per_tile, ' processors.'
2340  else
2341  call mpp_error(note,'test_group_update: npes should be multiple of ntiles No test is done for '//trim(type))
2342  return
2343  endif
2344  if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
2345  layout = layout_cubic
2346  else
2347  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
2348  endif
2349  case default
2350  call mpp_error(fatal, 'test_mpp_global_sum: no such test: '//type)
2351  end select
2352 
2353  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
2354  do n = 1, ntiles
2355  pe_start(n) = (n-1)*npes_per_tile
2356  pe_end(n) = n*npes_per_tile-1
2357  end do
2358 
2359  do n = 1, ntiles
2360  global_indices(:,n) = (/1,nx,1,ny/)
2361  layout2d(:,n) = layout
2362  end do
2363 
2364  allocate(tile1(num_contact), tile2(num_contact) )
2365  allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
2366  allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
2367 
2368  !--- define domain
2369  if(folded_north) then
2370  !--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
2371  tile1(1) = 1; tile2(1) = 1
2372  istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
2373  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
2374  !--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
2375  tile1(2) = 1; tile2(2) = 1
2376  istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
2377  istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
2378  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
2379  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
2380  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
2381  name = type, symmetry = .false. )
2382  else if( cubic_grid ) then
2383  call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
2384  global_indices, layout2D, pe_start, pe_end )
2385  endif
2386 
2387  !--- setup data
2388  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
2389  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
2390 
2391  allocate(data_2d(isd:ied,jsd:jed))
2392  allocate(data_3d(isd:ied,jsd:jed,nz))
2393 
2394  do k = 1, nz
2395  do j = jsd, jed
2396  do i = isd, ied
2397  data_3d(i,j,k) = k*1e3 + i + j*1e-3
2398  enddo
2399  enddo
2400  enddo
2401 
2402  do j = jsd, jed
2403  do i = isd, ied
2404  data_2d(i,j) = i*1e3 + j*1e-3
2405  enddo
2406  enddo
2407 
2408  id1 = mpp_clock_id( type//' bitwise sum 3D', flags=mpp_clock_sync )
2409  id2 = mpp_clock_id( type//' EFP sum 3D', flags=mpp_clock_sync )
2410  id3 = mpp_clock_id( type//' EFP sum 3D check', flags=mpp_clock_sync )
2411  id4 = mpp_clock_id( type//' non-bitwise sum 3D', flags=mpp_clock_sync )
2412 
2413  call mpp_clock_begin(id1)
2414  do n = 1, num_iter
2415  gsum1 = mpp_global_sum(domain, data_3d, flags=bitwise_exact_sum)
2416  enddo
2417  call mpp_clock_end(id1)
2418 
2419  call mpp_clock_begin(id2)
2420  do n = 1, num_iter
2421  gsum2 = mpp_global_sum(domain, data_3d, flags=bitwise_efp_sum)
2422  enddo
2423  call mpp_clock_end(id2)
2424 
2425  call mpp_clock_begin(id3)
2426  do n = 1, num_iter
2427  gsum3 = mpp_global_sum(domain, data_3d, flags=bitwise_efp_sum, overflow_check=.true. )
2428  enddo
2429  call mpp_clock_end(id3)
2430 
2431  call mpp_clock_begin(id4)
2432  do n = 1, num_iter
2433  gsum4= mpp_global_sum(domain, data_3d)
2434  enddo
2435  call mpp_clock_end(id4)
2436 
2437  write(outunit, *) " ********************************************************************************"
2438  write(outunit, *) " global sum for "//type//' bitwise exact sum 3D = ', gsum1
2439  write(outunit, *) " global sum for "//type//' bitwise EFP sum 3D = ', gsum2
2440  write(outunit, *) " global sum for "//type//' bitwise EFP sum 3D with overflow_check = ', gsum3
2441  write(outunit, *) " global sum for "//type//' non-bitwise sum 3D = ', gsum4
2442  write(outunit, *) " "
2443  write(outunit, *) " chksum for "//type//' bitwise exact sum 3D = ', transfer(gsum1, mold)
2444  write(outunit, *) " chksum for "//type//' bitwise EFP sum 3D = ', transfer(gsum2, mold)
2445  write(outunit, *) " chksum for "//type//' bitwise EFP sum 3D with overflow_check = ', transfer(gsum3, mold)
2446  write(outunit, *) " chksum for "//type//' non-bitwise sum 3D = ', transfer(gsum4, mold)
2447  write(outunit, *) " ********************************************************************************"
2448 
2449  id1 = mpp_clock_id( type//' bitwise sum 2D', flags=mpp_clock_sync )
2450  id2 = mpp_clock_id( type//' EFP sum 2D', flags=mpp_clock_sync )
2451  id3 = mpp_clock_id( type//' EFP sum 2D check', flags=mpp_clock_sync )
2452  id4 = mpp_clock_id( type//' non-bitwise sum 2D', flags=mpp_clock_sync )
2453 
2454  call mpp_clock_begin(id1)
2455  do n = 1, num_iter
2456  gsum1 = mpp_global_sum(domain, data_2d, flags=bitwise_exact_sum)
2457  enddo
2458  call mpp_clock_end(id1)
2459 
2460  call mpp_clock_begin(id2)
2461  do n = 1, num_iter
2462  gsum2 = mpp_global_sum(domain, data_2d, flags=bitwise_efp_sum)
2463  enddo
2464  call mpp_clock_end(id2)
2465 
2466  call mpp_clock_begin(id3)
2467  do n = 1, num_iter
2468  gsum3 = mpp_global_sum(domain, data_2d, flags=bitwise_efp_sum, overflow_check=.true. )
2469  enddo
2470  call mpp_clock_end(id3)
2471 
2472  call mpp_clock_begin(id4)
2473  do n = 1, num_iter
2474  gsum4= mpp_global_sum(domain, data_2d)
2475  enddo
2476  call mpp_clock_end(id4)
2477 
2478  write(outunit, *) " ********************************************************************************"
2479  write(outunit, *) " global sum for "//type//' bitwise exact sum 2D = ', gsum1
2480  write(outunit, *) " global sum for "//type//' bitwise EFP sum 2D = ', gsum2
2481  write(outunit, *) " global sum for "//type//' bitwise EFP sum 2D with overflow_check = ', gsum3
2482  write(outunit, *) " global sum for "//type//' non-bitwise sum 2D = ', gsum4
2483  write(outunit, *) " "
2484  write(outunit, *) " chksum for "//type//' bitwise exact sum 2D = ', transfer(gsum1, mold)
2485  write(outunit, *) " chksum for "//type//' bitwise EFP sum 2D = ', transfer(gsum2, mold)
2486  write(outunit, *) " chksum for "//type//' bitwise EFP sum 2D with overflow_check = ', transfer(gsum3, mold)
2487  write(outunit, *) " chksum for "//type//' non-bitwise sum 2D = ', transfer(gsum4, mold)
2488  write(outunit, *) " ********************************************************************************"
2489 
2490 
2491 
2492  nx = nx_save
2493  ny = ny_save
2494 
2495  end subroutine test_mpp_global_sum
2496 
2497  !###############################################################
2498  subroutine test_group_update( type )
2499  character(len=*), intent(in) :: type
2500 
2501  type(domain2D) :: domain
2502  integer :: num_contact, ntiles, npes_per_tile
2503  integer :: i, j, k, l, n, shift
2504  integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
2505  integer :: ism, iem, jsm, jem
2506 
2507  integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
2508  integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
2509  integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
2510  integer, allocatable, dimension(:,:) :: layout2D, global_indices
2511  real, allocatable, dimension(:,:,:,:) :: x1, y1, x2, y2
2512  real, allocatable, dimension(:,:,:,:) :: a1, a2
2513  real, allocatable, dimension(:,:,:) :: base
2514  integer :: id1, id2, id3
2515  logical :: folded_north
2516  logical :: cubic_grid
2517  character(len=3) :: text
2518  integer :: nx_save, ny_save
2519  type(mpp_group_update_type) :: group_update
2520  type(mpp_group_update_type), allocatable :: update_list(:)
2521 
2522  folded_north = .false.
2523  cubic_grid = .false.
2524 
2525  nx_save = nx
2526  ny_save = ny
2527  !--- check the type
2528  select case(type)
2529  case ( 'Folded-north' )
2530  ntiles = 1
2531  shift = 0
2532  num_contact = 2
2533  folded_north = .true.
2534  npes_per_tile = npes
2535  if(layout_tripolar(1)*layout_tripolar(2) == npes ) then
2536  layout = layout_tripolar
2537  else
2538  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
2539  endif
2540  case ( 'Cubic-Grid' )
2541  if( nx_cubic == 0 ) then
2542  call mpp_error(note,'test_group_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
2543  'No test is done for Cubic-Grid mosaic. ' )
2544  return
2545  endif
2546  if( nx_cubic .NE. ny_cubic ) then
2547  call mpp_error(note,'test_group_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
2548  'No test is done for Cubic-Grid mosaic. ' )
2549  return
2550  endif
2551  shift = 1
2552  nx = nx_cubic
2553  ny = ny_cubic
2554  ntiles = 6
2555  num_contact = 12
2556  cubic_grid = .true.
2557  if( mod(npes, ntiles) == 0 ) then
2558  npes_per_tile = npes/ntiles
2559  write(outunit,*)'NOTE from update_domains_performance ==> For Mosaic "', trim(type), &
2560  '", each tile will be distributed over ', npes_per_tile, ' processors.'
2561  else
2562  call mpp_error(note,'test_group_update: npes should be multiple of ntiles No test is done for '//trim(type))
2563  return
2564  endif
2565  if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
2566  layout = layout_cubic
2567  else
2568  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
2569  endif
2570  case default
2571  call mpp_error(fatal, 'test_group_update: no such test: '//type)
2572  end select
2573 
2574  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
2575  do n = 1, ntiles
2576  pe_start(n) = (n-1)*npes_per_tile
2577  pe_end(n) = n*npes_per_tile-1
2578  end do
2579 
2580  do n = 1, ntiles
2581  global_indices(:,n) = (/1,nx,1,ny/)
2582  layout2d(:,n) = layout
2583  end do
2584 
2585  allocate(tile1(num_contact), tile2(num_contact) )
2586  allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
2587  allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
2588 
2589  !--- define domain
2590  if(folded_north) then
2591  !--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
2592  tile1(1) = 1; tile2(1) = 1
2593  istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
2594  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
2595  !--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
2596  tile1(2) = 1; tile2(2) = 1
2597  istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
2598  istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
2599  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
2600  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
2601  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
2602  name = type, symmetry = .false. )
2603  else if( cubic_grid ) then
2604  call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
2605  global_indices, layout2D, pe_start, pe_end )
2606  endif
2607 
2608  !--- setup data
2609  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
2610  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
2611  call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
2612 
2613  if(num_fields<1) then
2614  call mpp_error(fatal, "test_mpp_domains: num_fields must be a positive integer")
2615  endif
2616 
2617  allocate(update_list(num_fields))
2618 
2619  id1 = mpp_clock_id( type//' group 2D', flags=mpp_clock_sync )
2620  id2 = mpp_clock_id( type//' non-group 2D', flags=mpp_clock_sync )
2621  id3 = mpp_clock_id( type//' non-block group 2D', flags=mpp_clock_sync )
2622 
2623  allocate( a1(ism:iem, jsm:jem, nz, num_fields) )
2624  allocate( x1(ism:iem+shift,jsm:jem, nz, num_fields) )
2625  allocate( y1(ism:iem, jsm:jem+shift, nz, num_fields) )
2626  allocate( a2(ism:iem, jsm:jem, nz, num_fields) )
2627  allocate( x2(ism:iem+shift,jsm:jem, nz, num_fields) )
2628  allocate( y2(ism:iem, jsm:jem+shift, nz, num_fields) )
2629  allocate( base(isc:iec+shift,jsc:jec+shift,nz) )
2630  a1 = 0; x1 = 0; y1 = 0
2631 
2632  base = 0
2633  do k = 1,nz
2634  do j = jsc, jec+shift
2635  do i = isc, iec+shift
2636  base(i,j,k) = k + i*1e-3 + j*1e-6
2637  end do
2638  end do
2639  end do
2640 
2641  !--- Test for partial direction update
2642  do l =1, num_fields
2643  call mpp_create_group_update(group_update, a1(:,:,:,l), domain, flags=wupdate+supdate)
2644  end do
2645 
2646  do l = 1, num_fields
2647  a1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3
2648  do k=1,nz
2649  do i=isc-1,iec+1
2650  a1(i,jsc-1,k,l) = 999;
2651  a1(i,jec+1,k,l) = 999;
2652  enddo
2653  do j=jsc,jec
2654  a1(isc-1,j,k,l) = 999
2655  a1(iec+1,j,k,l) = 999
2656  enddo
2657  enddo
2658  enddo
2659 
2660  a2 = a1
2661  call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
2662 
2663  do l = 1, num_fields
2664  call mpp_update_domains( a2(:,:,:,l), domain, flags=wupdate+supdate, complete=l==num_fields )
2665  enddo
2666 
2667  do l = 1, num_fields
2668  write(text, '(i3.3)') l
2669  call compare_checksums(a1(isd:ied,jsd:jed,:,l),a2(isd:ied,jsd:jed,:,l),type//' CENTER South West '//text)
2670  enddo
2671 
2672  call mpp_clear_group_update(group_update)
2673 
2674  !--- Test for DGRID update
2675  if(type == 'Cubic-Grid' ) then
2676  x1 = 0; y1 = 0
2677  do l =1, num_fields
2678  call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=dgrid_ne)
2679  end do
2680 
2681  do l = 1, num_fields
2682  y1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
2683  x1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
2684  enddo
2685  x2 = x1; y2 = y1
2686  call mpp_start_group_update(group_update, domain, x1(isc,jsc,1,1))
2687  call mpp_complete_group_update(group_update, domain, x1(isc,jsc,1,1))
2688 
2689  do l = 1, num_fields
2690  call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=dgrid_ne, complete=l==num_fields )
2691  enddo
2692 
2693  !--- compare checksum
2694  do l = 1, num_fields
2695  write(text, '(i3.3)') l
2696  call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l),type//' DGRID X'//text)
2697  call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l),type//' DGRID Y'//text)
2698  enddo
2699 
2700  call mpp_clear_group_update(group_update)
2701  endif
2702  !--- Test for CGRID
2703  a1 = 0; x1 = 0; y1 = 0
2704  do l =1, num_fields
2705  call mpp_create_group_update(group_update, a1(:,:,:,l), domain)
2706  call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=cgrid_ne)
2707  end do
2708 
2709  do n = 1, num_iter
2710  a1 = 0; x1 = 0; y1 = 0
2711  do l = 1, num_fields
2712  a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
2713  x1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
2714  y1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
2715  enddo
2716  a2 = a1; x2 = x1; y2 = y1
2717  call mpp_clock_begin(id1)
2718  call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
2719  call mpp_clock_end (id1)
2720 
2721  call mpp_clock_begin(id2)
2722  do l = 1, num_fields
2723  call mpp_update_domains( a2(:,:,:,l), domain, complete=l==num_fields )
2724  enddo
2725  do l = 1, num_fields
2726  call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=cgrid_ne, complete=l==num_fields )
2727  enddo
2728  call mpp_clock_end(id2)
2729 
2730  !--- compare checksum
2731  if( n == num_iter ) then
2732  do l = 1, num_fields
2733  write(text, '(i3.3)') l
2734  call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l),type//' CENTER '//text)
2735  call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l),type//' CGRID X'//text)
2736  call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l),type//' CGRID Y'//text)
2737  enddo
2738  endif
2739  a1 = 0; x1 = 0; y1 = 0
2740  do l = 1, num_fields
2741  a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
2742  x1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
2743  y1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
2744  enddo
2745  call mpp_clock_begin(id3)
2746  call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
2747  call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
2748  call mpp_clock_end (id3)
2749  !--- compare checksum
2750  if( n == num_iter ) then
2751  do l = 1, num_fields
2752  write(text, '(i3.3)') l
2753  call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l), &
2754  type//' nonblock CENTER '//text)
2755  call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l), &
2756  type//' nonblock CGRID X'//text)
2757  call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l), &
2758  type//' nonblock CGRID Y'//text)
2759  enddo
2760  endif
2761  enddo
2762 
2763  call mpp_clear_group_update(group_update)
2764 
2765  !--- The following is to test overlapping start and complete
2766  if( num_fields > 1 ) then
2767  do l =1, num_fields
2768  call mpp_create_group_update(update_list(l), a1(:,:,:,l), domain)
2769  call mpp_create_group_update(update_list(l), x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=cgrid_ne)
2770  end do
2771 
2772  do n = 1, num_iter
2773 
2774  a1 = 0; x1 = 0; y1 = 0
2775  do l = 1, num_fields
2776  a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
2777  x1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
2778  y1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
2779  enddo
2780  do l = 1, num_fields-1
2781  call mpp_start_group_update(update_list(l), domain, a1(isc,jsc,1,1))
2782  enddo
2783 
2784  call mpp_complete_group_update(update_list(1), domain, a1(isc,jsc,1,1))
2785  call mpp_start_group_update(update_list(num_fields), domain, a1(isc,jsc,1,1))
2786  do l = 2, num_fields
2787  call mpp_complete_group_update(update_list(l), domain, a1(isc,jsc,1,1))
2788  enddo
2789  !--- compare checksum
2790  if( n == num_iter ) then
2791  do l = 1, num_fields
2792  write(text, '(i3.3)') l
2793  call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l), &
2794  type//' multiple nonblock CENTER '//text)
2795  call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l), &
2796  type//' multiple nonblock CGRID X'//text)
2797  call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l), &
2798  type//' multiple nonblock CGRID Y'//text)
2799  enddo
2800  endif
2801  enddo
2802  endif
2803 
2804  do l =1, num_fields
2805  call mpp_clear_group_update(update_list(l))
2806  enddo
2807  deallocate(update_list)
2808 
2809  !--- test scalar 4-D variable
2810  call mpp_create_group_update(group_update, a1(:,:,:,:), domain)
2811 
2812  a1 = 0; x1 = 0; y1 = 0
2813  do l = 1, num_fields
2814  a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
2815  enddo
2816  a2 = a1; x2 = x1; y2 = y1
2817  call mpp_clock_begin(id1)
2818  call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
2819  call mpp_clock_end (id1)
2820 
2821  call mpp_clock_begin(id2)
2822  call mpp_update_domains( a2(:,:,:,:), domain )
2823  call mpp_clock_end(id2)
2824 
2825  !--- compare checksum
2826  do l = 1, num_fields
2827  write(text, '(i3.3)') l
2828  call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l),type//' 4D CENTER '//text)
2829  enddo
2830 
2831  a1 = 0
2832  do l = 1, num_fields
2833  a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
2834  enddo
2835  call mpp_clock_begin(id3)
2836  call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
2837  call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
2838  call mpp_clock_end (id3)
2839 
2840  !--- compare checksum
2841  do l = 1, num_fields
2842  write(text, '(i3.3)') l
2843  call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l), &
2844  type//' nonblock 4D CENTER '//text)
2845  enddo
2846 
2847 
2848 
2849  !--- test for BGRID.
2850  deallocate(a1, x1, y1)
2851  deallocate(a2, x2, y2)
2852  call mpp_clear_group_update(group_update)
2853 
2854  allocate( a1(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
2855  allocate( x1(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
2856  allocate( y1(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
2857  allocate( a2(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
2858  allocate( x2(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
2859  allocate( y2(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
2860 
2861  do l =1, num_fields
2862  call mpp_create_group_update(group_update, a1(:,:,:,l), domain, position=corner)
2863  call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=bgrid_ne)
2864  end do
2865 
2866  do n = 1, num_iter
2867  a1 = 0; x1 = 0; y1 = 0
2868  do l = 1, num_fields
2869  a1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3
2870  x1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 1e6
2871  y1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 2*1e6
2872  enddo
2873  a2 = a1; x2 = x1; y2 = y1
2874  call mpp_clock_begin(id1)
2875  call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
2876  call mpp_clock_end (id1)
2877 
2878  call mpp_clock_begin(id2)
2879  do l = 1, num_fields
2880  call mpp_update_domains( a2(:,:,:,l), domain, position=corner, complete=l==num_fields )
2881  enddo
2882  do l = 1, num_fields
2883  call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=bgrid_ne, complete=l==num_fields )
2884  enddo
2885  call mpp_clock_end(id2)
2886 
2887  !--- compare checksum
2888  if( n == num_iter ) then
2889  do l = 1, num_fields
2890  write(text, '(i3.3)') l
2891  call compare_checksums(a1(isd:ied+shift,jsd:jed+shift,:,l),a2(isd:ied+shift,jsd:jed+shift,:,l),type//' CORNER '//text)
2892  call compare_checksums(x1(isd:ied+shift,jsd:jed+shift,:,l),x2(isd:ied+shift,jsd:jed+shift,:,l),type//' BGRID X'//text)
2893  call compare_checksums(y1(isd:ied+shift,jsd:jed+shift,:,l),y2(isd:ied+shift,jsd:jed+shift,:,l),type//' BGRID Y'//text)
2894  enddo
2895  endif
2896 
2897  a1 = 0; x1 = 0; y1 = 0
2898  do l = 1, num_fields
2899  a1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3
2900  x1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 1e6
2901  y1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 2*1e6
2902  enddo
2903  call mpp_clock_begin(id3)
2904  call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
2905  call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
2906  call mpp_clock_end (id3)
2907  !--- compare checksum
2908  if( n == num_iter ) then
2909  do l = 1, num_fields
2910  write(text, '(i3.3)') l
2911  call compare_checksums(a1(isd:ied+shift,jsd:jed+shift,:,l),a2(isd:ied+shift,jsd:jed+shift,:,l), &
2912  type//' nonblockCORNER '//text)
2913  call compare_checksums(x1(isd:ied+shift,jsd:jed+shift,:,l),x2(isd:ied+shift,jsd:jed+shift,:,l), &
2914  type//' nonblock BGRID X'//text)
2915  call compare_checksums(y1(isd:ied+shift,jsd:jed+shift,:,l),y2(isd:ied+shift,jsd:jed+shift,:,l), &
2916  type//' nonblock BGRID Y'//text)
2917  enddo
2918  endif
2919  enddo
2920 
2921  call mpp_clear_group_update(group_update)
2922 
2923  !-----------------------------------------------------------------------------
2924  ! test for AGRID vector and scalar pair
2925  !-----------------------------------------------------------------------------
2926  deallocate(x1, y1)
2927  deallocate(x2, y2)
2928 
2929  allocate( x1(ism:iem,jsm:jem, nz, num_fields) )
2930  allocate( y1(ism:iem,jsm:jem, nz, num_fields) )
2931  allocate( x2(ism:iem,jsm:jem, nz, num_fields) )
2932  allocate( y2(ism:iem,jsm:jem, nz, num_fields) )
2933 
2934  x1 = 0; y1 = 0
2935  do l = 1, num_fields
2936  x1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 1e6
2937  y1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 2*1e6
2938  enddo
2939  x2 = x1; y2 = y1
2940 
2941  do l =1, num_fields
2942  call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=agrid)
2943  end do
2944 
2945  do l = 1, num_fields
2946  call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=agrid, complete=l==num_fields )
2947  enddo
2948 
2949  call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
2950  call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
2951 
2952  !--- compare checksum
2953  do l = 1, num_fields
2954  write(text, '(i3.3)') l
2955  call compare_checksums(x1(isd:ied,jsd:jed,:,l),x2(isd:ied,jsd:jed,:,l),type//' AGRID X'//text)
2956  call compare_checksums(y1(isd:ied,jsd:jed,:,l),y2(isd:ied,jsd:jed,:,l),type//' AGRID Y'//text)
2957  enddo
2958 
2959  call mpp_clear_group_update(group_update)
2960 
2961  x1 = 0; y1 = 0
2962  do l = 1, num_fields
2963  x1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 1e6
2964  y1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 2*1e6
2965  enddo
2966  x2 = x1; y2 = y1
2967 
2968  do l =1, num_fields
2969  call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=agrid, flags=scalar_pair)
2970  end do
2971 
2972  do l = 1, num_fields
2973  call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=agrid, flags=scalar_pair, complete=l==num_fields)
2974  enddo
2975 
2976  call mpp_start_group_update(group_update, domain, x1(isc,jsc,1,1))
2977  call mpp_complete_group_update(group_update, domain, x1(isc,jsc,1,1))
2978 
2979  !--- compare checksum
2980  do l = 1, num_fields
2981  write(text, '(i3.3)') l
2982  call compare_checksums(x1(isd:ied,jsd:jed,:,l),x2(isd:ied,jsd:jed,:,l),type//' AGRID SCALAR_PAIR X'//text)
2983  call compare_checksums(y1(isd:ied,jsd:jed,:,l),y2(isd:ied,jsd:jed,:,l),type//' AGRID SCALAR_PAIR Y'//text)
2984  enddo
2985 
2986  call mpp_clear_group_update(group_update)
2987 
2988  deallocate(pe_start, pe_end, tile1, tile2)
2989  deallocate(istart1, iend1, jstart1, jend1)
2990  deallocate(istart2, iend2, jstart2, jend2)
2991  deallocate(layout2d, global_indices)
2992 
2993  deallocate(a1, x1, y1)
2994  deallocate(a2, x2, y2)
2995  deallocate(base)
2996  call mpp_deallocate_domain(domain)
2997 
2998 end subroutine test_group_update
2999 
3000 
3001  !###############################################################
3002  !--- This will test scalar and CGRID performance between halo=1 and halo=3
3003  subroutine test_halosize_update( type )
3004  character(len=*), intent(in) :: type
3005 
3006  type(domain2D) :: domain
3007  integer :: ntiles, npes_per_tile
3008  integer :: i, j, k, l, n, shift
3009  integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
3010  integer :: ism, iem, jsm, jem
3011 
3012  integer, allocatable, dimension(:) :: pe_start, pe_end
3013  integer, allocatable, dimension(:,:) :: layout2D, global_indices
3014  real, allocatable, dimension(:,:,:,:) :: x1, y1, x2, y2
3015  real, allocatable, dimension(:,:,:,:) :: a1, a2
3016  real, allocatable, dimension(:,:,:,:) :: base, global_all, global
3017  real, allocatable, dimension(:,:,:,:) :: base1, global1_all, global1
3018  real, allocatable, dimension(:,:,:,:) :: base2, global2_all, global2
3019 
3020  integer :: id1, id2, id3
3021  logical :: folded_north
3022  logical :: cubic_grid, is_symmetry
3023  character(len=3) :: text
3024  character(len=1) :: halostr
3025  integer :: nx_save, ny_save
3026  integer :: mytile
3027  type(mpp_group_update_type) :: group_update1, group_update2
3028  type(mpp_group_update_type), allocatable :: update_list(:)
3029 
3030  if(whalo .ne. ehalo .or. whalo .ne. shalo .or. whalo .ne. nhalo) then
3031  call mpp_error(fatal,"test_mpp_domains: whalo, ehalo, shalo, nhalo must be the same when test_halosize_performance=true")
3032  endif
3033 
3034  folded_north = .false.
3035  cubic_grid = .false.
3036 
3037  nx_save = nx
3038  ny_save = ny
3039  !--- check the type
3040  select case(type)
3041  case ( 'Folded-north', 'Folded-north symmetry' )
3042  ntiles = 1
3043  mytile = 1
3044  folded_north = .true.
3045  npes_per_tile = npes
3046  if(layout_tripolar(1)*layout_tripolar(2) == npes ) then
3047  layout = layout_tripolar
3048  else
3049  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
3050  endif
3051  if(index(type, 'symmetry') == 0) then
3052  is_symmetry = .false.
3053  else
3054  is_symmetry = .true.
3055  end if
3056  case ( 'Cubic-Grid' )
3057  is_symmetry = .true.
3058  if( nx_cubic == 0 ) then
3059  call mpp_error(note,'test_halosize_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
3060  'No test is done for Cubic-Grid mosaic. ' )
3061  return
3062  endif
3063  if( nx_cubic .NE. ny_cubic ) then
3064  call mpp_error(note,'test_halosize_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
3065  'No test is done for Cubic-Grid mosaic. ' )
3066  return
3067  endif
3068  nx = nx_cubic
3069  ny = ny_cubic
3070  ntiles = 6
3071  if( mod(npes, ntiles) .ne. 0 ) then
3072  call mpp_error(note,'test_halosize_update: npes is not divisible by ntiles, no test is done for '//trim(type) )
3073  return
3074  endif
3075  npes_per_tile = npes/ntiles
3076  mytile = mpp_pe()/npes_per_tile + 1
3077  cubic_grid = .true.
3078  if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
3079  layout = layout_cubic
3080  else
3081  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
3082  endif
3083  case default
3084  call mpp_error(fatal, 'test_group_update: no such test: '//type)
3085  end select
3086 
3087  shift = 0
3088  if(is_symmetry) shift = 1
3089 
3090  !--- define domain
3091  if(folded_north) then
3092  call mpp_define_domains((/1,nx,1,ny/), layout, domain, &
3093  xflags=cyclic_global_domain, yflags=fold_north_edge, &
3094  whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
3095  symmetry=is_symmetry, name=type )
3096  else if( cubic_grid ) then
3097  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
3098  do n = 1, ntiles
3099  pe_start(n) = (n-1)*npes_per_tile
3100  pe_end(n) = n*npes_per_tile-1
3101  end do
3102 
3103  do n = 1, ntiles
3104  global_indices(:,n) = (/1,nx,1,ny/)
3105  layout2d(:,n) = layout
3106  end do
3107 
3108  call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
3109  global_indices, layout2D, pe_start, pe_end, use_memsize=.false.)
3110  deallocate(pe_start, pe_end)
3111  deallocate(layout2d, global_indices)
3112  endif
3113 
3114  !--- setup data
3115  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
3116  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
3117 
3118  if(num_fields<1) then
3119  call mpp_error(fatal, "test_mpp_domains: num_fields must be a positive integer")
3120  endif
3121 
3122  !--- scalar update
3123  write(halostr,'(I1)') whalo
3124  id1 = mpp_clock_id( type//' halo='//halostr//' scalar', flags=mpp_clock_sync )
3125  id2 = mpp_clock_id( type//' halo=1 scalar', flags=mpp_clock_sync )
3126 
3127  allocate( a1(isd:ied, jsd:jed, nz, num_fields) )
3128  allocate( a2(isd:ied, jsd:jed, nz, num_fields) )
3129  allocate(base(isc:iec, jsc:jec, nz, num_fields))
3130  allocate(global_all(1:nx,1:ny,nz,ntiles) )
3131  allocate(global(1-whalo:nx+ehalo, 1-shalo:ny+nhalo, nz, num_fields))
3132 
3133  do n = 1, ntiles
3134  do k = 1, nz
3135  do j = 1, ny
3136  do i = 1, nx
3137  global_all(i,j,k,n) = n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
3138  end do
3139  end do
3140  end do
3141  end do
3142  global = 0.0
3143  do l = 1, num_fields
3144  global(1:nx,1:ny,:,l) = global_all(:,:,:,mytile)
3145  enddo
3146 
3147  base(isc:iec,jsc:jec,:,:) = global(isc:iec,jsc:jec,:,:)
3148 
3149  !--- fill up the value at halo points
3150  do l = 1, num_fields
3151  if(folded_north) then
3152  call fill_folded_north_halo(global(:,:,:,l), 0, 0, 0, 0, 1)
3153  else if(cubic_grid) then
3154  call fill_cubic_grid_halo(global(:,:,:,l), global_all, global_all, mytile, 0, 0, 1, 1 )
3155  endif
3156  enddo
3157  a1 = 0.0
3158  a2(isd:ied,jsd:jed,:,:) = global(isd:ied,jsd:jed,:,:)
3159 
3160  do l =1, num_fields
3161  call mpp_create_group_update(group_update1, a1(:,:,:,l), domain)
3162  end do
3163  do l =1, num_fields
3164  call mpp_create_group_update(group_update2, a1(:,:,:,l), domain, whalo=1, ehalo=1, shalo=1, nhalo=1)
3165  end do
3166 
3167  do n = 1, num_iter
3168  a1 = 0.0
3169  a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
3170 
3171  call mpp_clock_begin(id1)
3172  call mpp_do_group_update(group_update1, domain, a1(isc,jsc,1,1))
3173  call mpp_clock_end(id1)
3174  if(n==num_iter) then
3175  do l = 1, num_fields
3176  write(text, '(i3.3)') l
3177  call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//' halo='//halostr//' scalar'//text)
3178  enddo
3179  endif
3180  enddo
3181 
3182  !--- make sure mpp_start_group_update/mpp_complete_group_update is OK
3183  a1 = 0.0
3184  a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
3185 
3186  call mpp_start_group_update(group_update1, domain, a1(isc,jsc,1,1))
3187  call mpp_complete_group_update(group_update1, domain, a1(isc,jsc,1,1))
3188  do l = 1, num_fields
3189  write(text, '(i3.3)') l
3190  call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//'nonblock halo='//halostr//' scalar'//text)
3191  enddo
3192 
3193 
3194  a2 = 0
3195  a2(isc-1:iec+1,jsc-1:jec+1,:,:) = global(isc-1:iec+1,jsc-1:jec+1,:,:)
3196 
3197  do n = 1, num_iter
3198  a1 = 0.0
3199  a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
3200  call mpp_clock_begin(id2)
3201  call mpp_do_group_update(group_update2, domain, a1(isc,jsc,1,1))
3202  call mpp_clock_end(id2)
3203  if(n==num_iter) then
3204  do l = 1, num_fields
3205  write(text, '(i3.3)') l
3206  call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//' halo=1 scalar'//text)
3207  enddo
3208  endif
3209  enddo
3210 
3211  a1 = 0.0
3212  a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
3213  call mpp_start_group_update(group_update2, domain, a1(isc,jsc,1,1))
3214  call mpp_complete_group_update(group_update2, domain, a1(isc,jsc,1,1))
3215  do l = 1, num_fields
3216  write(text, '(i3.3)') l
3217  call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//' nonblock halo=1 scalar'//text)
3218  enddo
3219 
3220  call mpp_clear_group_update(group_update1)
3221  call mpp_clear_group_update(group_update2)
3222  deallocate(a1,a2,global,global_all,base)
3223 
3224  !--- CGRID vector update -------------------------
3225  id1 = mpp_clock_id( type//' halo='//halostr//' CGRID', flags=mpp_clock_sync )
3226  id2 = mpp_clock_id( type//' halo=1 CGRID', flags=mpp_clock_sync )
3227 
3228  allocate( x1(isd:ied+shift,jsd:jed, nz, num_fields) )
3229  allocate( y1(isd:ied, jsd:jed+shift, nz, num_fields) )
3230  allocate( x2(isd:ied+shift,jsd:jed, nz, num_fields) )
3231  allocate( y2(isd:ied, jsd:jed+shift, nz, num_fields) )
3232  allocate(base1(isc:iec+shift, jsc:jec, nz, num_fields))
3233  allocate(base2(isc:iec, jsc:jec+shift, nz, num_fields))
3234  allocate(global1_all(1:nx+shift,1:ny,nz,ntiles) )
3235  allocate(global2_all(1:nx,1:ny+shift,nz,ntiles) )
3236  allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz, num_fields))
3237  allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz, num_fields))
3238  do l = 1, ntiles
3239  do k = 1, nz
3240  do j = 1, ny
3241  do i = 1, nx+shift
3242  global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
3243  end do
3244  end do
3245  do j = 1, ny+shift
3246  do i = 1, nx
3247  global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
3248  end do
3249  end do
3250  end do
3251  end do
3252 
3253  global1 = 0.0; global2 = 0.0
3254  do l = 1, num_fields
3255  global1(1:nx+shift,1:ny,:,l) = global1_all(1:nx+shift,1:ny,:,mytile)
3256  global2(1:nx,1:ny+shift,:,l) = global2_all(1:nx,1:ny+shift,:,mytile)
3257  end do
3258 
3259  if(folded_north) then
3260  do l = 1, num_fields
3261  call fill_folded_north_halo(global1(:,:,:,l), 1, 0, shift, 0, -1)
3262  call fill_folded_north_halo(global2(:,:,:,l), 0, 1, 0, shift, -1)
3263  enddo
3264  endif
3265 
3266  base1(isc:iec+shift,jsc:jec,:,:) = global1(isc:iec+shift,jsc:jec,:,:)
3267  base2(isc:iec,jsc:jec+shift,:,:) = global2(isc:iec,jsc:jec+shift,:,:)
3268 
3269  if(folded_north) then
3270  !redundant points must be equal and opposite for tripolar grid
3271  global2(nx/2+1:nx, ny+shift,:,:) = -global2(nx/2:1:-1, ny+shift,:,:)
3272  global2(1-whalo:0, ny+shift,:,:) = -global2(nx-whalo+1:nx, ny+shift,:,:)
3273  global2(nx+1:nx+ehalo, ny+shift,:,:) = -global2(1:ehalo, ny+shift,:,:)
3274  else if(cubic_grid) then
3275  do l = 1, num_fields
3276  call fill_cubic_grid_halo(global1(:,:,:,l), global1_all, global2_all, mytile, 1, 0, 1, -1 )
3277  call fill_cubic_grid_halo(global2(:,:,:,l), global2_all, global1_all, mytile, 0, 1, -1, 1 )
3278  enddo
3279  endif
3280 
3281  x1 = 0; y1 = 0
3282  do l =1, num_fields
3283  call mpp_create_group_update(group_update1, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=cgrid_ne)
3284  end do
3285  do l =1, num_fields
3286  call mpp_create_group_update(group_update2, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=cgrid_ne, &
3287  whalo=1, ehalo=1, shalo=1, nhalo=1 )
3288  end do
3289 
3290  x2(:,:,:,:) = global1(isd:ied+shift,jsd:jed,:,:)
3291  y2(:,:,:,:) = global2(isd:ied,jsd:jed+shift,:,:)
3292 
3293  do n = 1, num_iter
3294  x1 = 0.0; y1 = 0.0
3295  x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
3296  y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
3297  call mpp_clock_begin(id1)
3298  call mpp_do_group_update(group_update1, domain, x1(isc,jsc,1,1))
3299  call mpp_clock_end(id1)
3300  if(n==num_iter) then
3301  do l = 1, num_fields
3302  write(text, '(i3.3)') l
3303  call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' halo='//halostr//' CGRID X'//text)
3304  call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' halo='//halostr//' CGRID Y'//text)
3305  enddo
3306  endif
3307  enddo
3308 
3309  !--- make sure non-blocking call is OK
3310  x1 = 0.0; y1 = 0.0
3311  x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
3312  y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
3313  call mpp_start_group_update(group_update1, domain, x1(isc,jsc,1,1))
3314  call mpp_complete_group_update(group_update1, domain, x1(isc,jsc,1,1))
3315  do l = 1, num_fields
3316  write(text, '(i3.3)') l
3317  call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' nonblock halo='//halostr//' CGRID X'//text)
3318  call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' nonblock halo='//halostr//' CGRID Y'//text)
3319  enddo
3320 
3321  x2 = 0; y2 = 0
3322  x2(isc-1:iec+1+shift,jsc-1:jec+1,:,:) = global1(isc-1:iec+1+shift,jsc-1:jec+1,:,:)
3323  y2(isc-1:iec+1,jsc-1:jec+1+shift,:,:) = global2(isc-1:iec+1,jsc-1:jec+1+shift,:,:)
3324 
3325  do n = 1, num_iter
3326  x1 = 0.0; y1 = 0.0
3327  x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
3328  y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
3329  call mpp_clock_begin(id2)
3330  call mpp_do_group_update(group_update2, domain, x1(isc,jsc,1,1))
3331  call mpp_clock_end(id2)
3332  if(n==num_iter) then
3333  do l = 1, num_fields
3334  write(text, '(i3.3)') l
3335  call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' halo=1 CGRID X'//text)
3336  call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' halo=1 CGRID Y'//text)
3337  enddo
3338  endif
3339  enddo
3340 
3341  x1 = 0.0; y1 = 0.0
3342  x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
3343  y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
3344  call mpp_start_group_update(group_update2, domain, x1(isc,jsc,1,1))
3345  call mpp_complete_group_update(group_update2, domain, x1(isc,jsc,1,1))
3346  do l = 1, num_fields
3347  write(text, '(i3.3)') l
3348  call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' nonblock halo=1 CGRID X'//text)
3349  call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' nonblock halo=1 CGRID Y'//text)
3350  enddo
3351 
3352  call mpp_clear_group_update(group_update1)
3353  call mpp_clear_group_update(group_update2)
3354 
3355  deallocate(x1, y1, global1, global2)
3356  deallocate(x2, y2, global1_all, global2_all)
3357  deallocate(base1, base2)
3358  call mpp_deallocate_domain(domain)
3359 
3360 end subroutine test_halosize_update
3361 
3362  !###############################################################
3363  subroutine test_unstruct_update( type )
3364  character(len=*), intent(in) :: type
3365 
3366  type(domain2D) :: SG_domain
3367  type(domainUG) :: UG_domain
3368  integer :: num_contact, ntiles, npes_per_tile
3369  integer :: i, j, k, l, n, shift
3370  integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
3371  integer :: ism, iem, jsm, jem, lsg, leg
3372 
3373  integer, allocatable, dimension(:) :: pe_start, pe_end, npts_tile, grid_index, ntiles_grid
3374  integer, allocatable, dimension(:,:) :: layout2D, global_indices
3375  real, allocatable, dimension(:,:) :: x1, x2, g1, g2
3376  real, allocatable, dimension(:,:,:) :: a1, a2, gdata
3377  real, allocatable, dimension(:,:) :: rmask
3378  real, allocatable, dimension(:) :: frac_crit
3379  logical, allocatable, dimension(:,:,:) :: lmask
3380  integer, allocatable, dimension(:) :: isl, iel, jsl, jel
3381  logical :: cubic_grid
3382  character(len=3) :: text
3383  integer :: nx_save, ny_save, tile
3384  integer :: ntotal_land, istart, iend, pos
3385 
3386  cubic_grid = .false.
3387 
3388  nx_save = nx
3389  ny_save = ny
3390  !--- check the type
3391  select case(type)
3392  case ( 'Cubic-Grid' )
3393  if( nx_cubic == 0 ) then
3394  call mpp_error(note,'test_unstruct_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
3395  'No test is done for Cubic-Grid mosaic. ' )
3396  return
3397  endif
3398  if( nx_cubic .NE. ny_cubic ) then
3399  call mpp_error(note,'test_unstruct_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
3400  'No test is done for Cubic-Grid mosaic. ' )
3401  return
3402  endif
3403  nx = nx_cubic
3404  ny = ny_cubic
3405  ntiles = 6
3406  num_contact = 12
3407  cubic_grid = .true.
3408  if( mod(npes, ntiles) == 0 ) then
3409  npes_per_tile = npes/ntiles
3410  write(outunit,*)'NOTE from test_unstruct_update ==> For Mosaic "', trim(type), &
3411  '", each tile will be distributed over ', npes_per_tile, ' processors.'
3412  else
3413  call mpp_error(note,'test_unstruct_update: npes should be multiple of ntiles No test is done for '//trim(type))
3414  return
3415  endif
3416  if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
3417  layout = layout_cubic
3418  else
3419  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
3420  endif
3421  allocate(frac_crit(ntiles))
3422  frac_crit(1) = 0.3; frac_crit(2) = 0.1; frac_crit(3) = 0.6
3423  frac_crit(4) = 0.2; frac_crit(5) = 0.4; frac_crit(6) = 0.5
3424 
3425  case default
3426  call mpp_error(fatal, 'test_group_update: no such test: '//type)
3427  end select
3428 
3429  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
3430  do n = 1, ntiles
3431  pe_start(n) = (n-1)*npes_per_tile
3432  pe_end(n) = n*npes_per_tile-1
3433  end do
3434 
3435  do n = 1, ntiles
3436  global_indices(:,n) = (/1,nx,1,ny/)
3437  layout2d(:,n) = layout
3438  end do
3439 
3440  !--- define domain
3441  if( cubic_grid ) then
3442  call define_cubic_mosaic(type, SG_domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
3443  global_indices, layout2D, pe_start, pe_end )
3444  endif
3445 
3446  !--- setup data
3447  call mpp_get_compute_domain( sg_domain, isc, iec, jsc, jec )
3448  call mpp_get_data_domain ( sg_domain, isd, ied, jsd, jed )
3449 
3450  allocate(lmask(nx,ny,ntiles))
3451  allocate(npts_tile(ntiles))
3452  lmask = .false.
3453  if(mpp_pe() == mpp_root_pe() ) then
3454  allocate(rmask(nx,ny))
3455  !--- construct gmask.
3456  do n = 1, ntiles
3457  call random_number(rmask)
3458  do j = 1, ny
3459  do i = 1, nx
3460  if(rmask(i,j) > frac_crit(n)) then
3461  lmask(i,j,n) = .true.
3462  endif
3463  enddo
3464  enddo
3465  npts_tile(n) = count(lmask(:,:,n))
3466  enddo
3467  ntotal_land = sum(npts_tile)
3468  allocate(grid_index(ntotal_land))
3469  l = 0
3470  allocate(isl(0:mpp_npes()-1), iel(0:mpp_npes()-1))
3471  allocate(jsl(0:mpp_npes()-1), jel(0:mpp_npes()-1))
3472  call mpp_get_compute_domains(sg_domain,xbegin=isl,xend=iel,ybegin=jsl,yend=jel)
3473 
3474  do n = 1, ntiles
3475  do j = 1, ny
3476  do i = 1, nx
3477  if(lmask(i,j,n)) then
3478  l = l + 1
3479  grid_index(l) = (j-1)*nx+i
3480  endif
3481  enddo
3482  enddo
3483  enddo
3484  deallocate(rmask, isl, iel, jsl, jel)
3485  endif
3486  call mpp_broadcast(npts_tile, ntiles, mpp_root_pe())
3487  if(mpp_pe() .NE. mpp_root_pe()) then
3488  ntotal_land = sum(npts_tile)
3489  allocate(grid_index(ntotal_land))
3490  endif
3491  call mpp_broadcast(grid_index, ntotal_land, mpp_root_pe())
3492 
3493  allocate(ntiles_grid(ntotal_land))
3494  ntiles_grid = 1
3495  !--- define the unstructured grid domain
3496  call mpp_define_unstruct_domain(ug_domain, sg_domain, npts_tile, ntiles_grid, mpp_npes(), 1, grid_index, name="LAND unstruct")
3497  call mpp_get_ug_compute_domain(ug_domain, istart, iend)
3498 
3499  !--- figure out lmask according to grid_index
3500  pos = 0
3501  do n = 1, ntiles
3502  do l = 1, npts_tile(n)
3503  pos = pos + 1
3504  j = (grid_index(pos)-1)/nx + 1
3505  i = mod((grid_index(pos)-1),nx) + 1
3506  lmask(i,j,n) = .true.
3507  enddo
3508  enddo
3509 
3510  !--- set up data
3511  allocate(gdata(nx,ny,ntiles))
3512  gdata = -999
3513  do n = 1, ntiles
3514  do j = 1, ny
3515  do i = 1, nx
3516  if(lmask(i,j,n)) then
3517  gdata(i,j,n) = n*1.e+3 + i + j*1.e-3
3518  endif
3519  end do
3520  end do
3521  end do
3522 
3523  !--- test the 2-D data is on computing domain
3524  allocate( a1(isc:iec, jsc:jec,1), a2(isc:iec,jsc:jec,1 ) )
3525 
3526  tile = mpp_pe()/npes_per_tile + 1
3527  do j = jsc, jec
3528  do i = isc, iec
3529  a1(i,j,1) = gdata(i,j,tile)
3530  enddo
3531  enddo
3532  a2 = -999
3533  write(mpp_pe()+1000,*) "npts_tile = "
3534  write(mpp_pe()+1000,*) npts_tile
3535  write(mpp_pe()+1000,*) "a1 = ", isc, iec, jsc, jec
3536  do j = jsc, jec
3537  write(mpp_pe()+1000,*) a1(:,j,1)
3538  enddo
3539 
3540  allocate(x1(istart:iend,1), x2(istart:iend,1))
3541  x1 = -999
3542  x2 = -999
3543  !--- fill the value of x2
3544  tile = mpp_get_ug_domain_tile_id(ug_domain)
3545  pos = 0
3546  do n = 1, tile-1
3547  pos = pos + npts_tile(n)
3548  enddo
3549  do l = istart, iend
3550  i = mod((grid_index(pos+l)-1), nx) + 1
3551  j = (grid_index(pos+l)-1)/nx + 1
3552  x2(l,1) = gdata(i,j,tile)
3553  enddo
3554 
3555  call mpp_pass_sg_to_ug(ug_domain, a1(:,:,1), x1(:,1))
3556  call compare_checksums_2d(x1, x2, type//' SG2UG 2-D compute domain')
3557  call mpp_pass_ug_to_sg(ug_domain, x1(:,1), a2(:,:,1))
3558 
3559  call compare_checksums(a1(:,:,1:1),a2(:,:,1:1),type//' UG2SG 2-D compute domain')
3560  deallocate(a1,a2,x1,x2)
3561 
3562  !--- test the 3-D data is on computing domain
3563  allocate( a1(isc:iec, jsc:jec,nz), a2(isc:iec,jsc:jec,nz ) )
3564 
3565  tile = mpp_pe()/npes_per_tile + 1
3566  do k = 1, nz
3567  do j = jsc, jec
3568  do i = isc, iec
3569  a1(i,j,k) = gdata(i,j,tile)
3570  if(a1(i,j,k) .NE. -999) a1(i,j,k) = a1(i,j,k) + k*1.e-6
3571  enddo
3572  enddo
3573  enddo
3574  a2 = -999
3575 
3576  allocate(x1(istart:iend,nz), x2(istart:iend,nz))
3577  x1 = -999
3578  x2 = -999
3579  !--- fill the value of x2
3580  tile = mpp_get_ug_domain_tile_id(ug_domain)
3581  pos = 0
3582  do n = 1, tile-1
3583  pos = pos + npts_tile(n)
3584  enddo
3585  do l = istart, iend
3586  i = mod((grid_index(pos+l)-1), nx) + 1
3587  j = (grid_index(pos+l)-1)/nx + 1
3588  do k = 1, nz
3589  x2(l,k) = gdata(i,j,tile) + k*1.e-6
3590  enddo
3591  enddo
3592 
3593  call mpp_pass_sg_to_ug(ug_domain, a1, x1)
3594  call compare_checksums_2d(x1, x2, type//' SG2UG 3-D compute domain')
3595  write(mpp_pe()+1000,*) "x1 = ", istart, iend
3596  call mpp_pass_ug_to_sg(ug_domain, x1, a2)
3597 
3598  call compare_checksums(a1,a2,type//' UG2SG 3-D compute domain')
3599  deallocate(a1,a2,x1,x2)
3600 
3601  !--- test the 2-D data is on data domain
3602  allocate( a1(isd:ied, jsd:jed,1), a2(isd:ied,jsd:jed,1 ) )
3603  a1 = -999; a2 = -999
3604 
3605  tile = mpp_pe()/npes_per_tile + 1
3606  do j = jsc, jec
3607  do i = isc, iec
3608  a1(i,j,1) = gdata(i,j,tile)
3609  enddo
3610  enddo
3611  a2 = -999
3612  write(mpp_pe()+1000,*) "npts_tile = "
3613  write(mpp_pe()+1000,*) npts_tile
3614 
3615  allocate(x1(istart:iend,1), x2(istart:iend,1))
3616  x1 = -999
3617  x2 = -999
3618  !--- fill the value of x2
3619  tile = mpp_get_ug_domain_tile_id(ug_domain)
3620  pos = 0
3621  do n = 1, tile-1
3622  pos = pos + npts_tile(n)
3623  enddo
3624  do l = istart, iend
3625  i = mod((grid_index(pos+l)-1), nx) + 1
3626  j = (grid_index(pos+l)-1)/nx + 1
3627  x2(l,1) = gdata(i,j,tile)
3628  enddo
3629 
3630  call mpp_pass_sg_to_ug(ug_domain, a1(:,:,1), x1(:,1))
3631  call compare_checksums_2d(x1, x2, type//' SG2UG 2-D data domain')
3632  write(mpp_pe()+1000,*) "x1 = ", istart, iend
3633  write(mpp_pe()+1000,*) x1
3634  call mpp_pass_ug_to_sg(ug_domain, x1(:,1), a2(:,:,1))
3635 
3636  call compare_checksums(a1(:,:,1:1),a2(:,:,1:1),type//' UG2SG 2-D data domain')
3637  deallocate(a1,a2,x1,x2)
3638 
3639  !--- test the 3-D data is on computing domain
3640  allocate( a1(isd:ied, jsd:jed,nz), a2(isd:ied,jsd:jed,nz ) )
3641  a1 = -999; a2 = -999
3642 
3643  tile = mpp_pe()/npes_per_tile + 1
3644  do k = 1, nz
3645  do j = jsc, jec
3646  do i = isc, iec
3647  a1(i,j,k) = gdata(i,j,tile)
3648  if(a1(i,j,k) .NE. -999) a1(i,j,k) = a1(i,j,k) + k*1.e-6
3649  enddo
3650  enddo
3651  enddo
3652  a2 = -999
3653  write(mpp_pe()+1000,*) "npts_tile = "
3654  write(mpp_pe()+1000,*) npts_tile
3655  do j = jsc, jec
3656  write(mpp_pe()+1000,*) a1(:,j,1)
3657  enddo
3658 
3659  allocate(x1(istart:iend,nz), x2(istart:iend,nz))
3660  x1 = -999
3661  x2 = -999
3662  !--- fill the value of x2
3663  tile = mpp_get_ug_domain_tile_id(ug_domain)
3664  pos = 0
3665  do n = 1, tile-1
3666  pos = pos + npts_tile(n)
3667  enddo
3668  do l = istart, iend
3669  i = mod((grid_index(pos+l)-1), nx) + 1
3670  j = (grid_index(pos+l)-1)/nx + 1
3671  do k = 1, nz
3672  x2(l,k) = gdata(i,j,tile) + k*1.e-6
3673  enddo
3674  enddo
3675 
3676  call mpp_pass_sg_to_ug(ug_domain, a1, x1)
3677  call compare_checksums_2d(x1, x2, type//' SG2UG 3-D data domain')
3678  write(mpp_pe()+1000,*) "x1 = ", istart, iend
3679  call mpp_pass_ug_to_sg(ug_domain, x1, a2)
3680 
3681  call compare_checksums(a1,a2,type//' UG2SG 3-D data domain')
3682  deallocate(a1,a2,x1,x2)
3683 
3684  !----------------------------------------------------------------
3685  ! test mpp_global_field_ug
3686  !----------------------------------------------------------------
3687  call mpp_get_ug_global_domain(ug_domain, lsg, leg)
3688  tile = mpp_get_ug_domain_tile_id(ug_domain)
3689  allocate(g1(lsg:leg,nz), g2(lsg:leg,nz), x1(istart:iend,nz))
3690  g1 = 0
3691  g2 = 0
3692  x1 = 0
3693  do k = 1, nz
3694  do l = lsg, leg
3695  g1(l,k) = tile*1e6 + l + k*1.e-3
3696  enddo
3697  do l = istart, iend
3698  x1(l,k) = g1(l,k)
3699  enddo
3700  enddo
3701 
3702  call mpp_global_field_ug(ug_domain, x1, g2)
3703  call compare_checksums_2d(g1,g2,type//' global_field_ug 3-D')
3704 
3705  g2 = 0.0
3706  call mpp_global_field_ug(ug_domain, x1(:,1), g2(:,1))
3707  call compare_checksums_2d(g1(:,1:1),g2(:,1:1),type//' global_field_ug 2-D')
3708 
3709  deallocate(g1,g2,x1)
3710 
3711  end subroutine test_unstruct_update
3712 
3713 
3714 
3715  !#################################################################################
3716 
3717  subroutine fill_halo_zero(data, whalo, ehalo, shalo, nhalo, xshift, yshift, isc, iec, jsc, jec, isd, ied, jsd, jed)
3718  integer, intent(in) :: isc, iec, jsc, jec, isd, ied, jsd, jed
3719  integer, intent(in) :: whalo, ehalo, shalo, nhalo, xshift, yshift
3720  real, dimension(isd:,jsd:,:), intent(inout) :: data
3721 
3722  if(whalo >=0) then
3723  data(iec+ehalo+1+xshift:ied+xshift,jsd:jed+yshift,:) = 0
3724  data(isd:isc-whalo-1,jsd:jed+yshift,:) = 0
3725  else
3726  data(iec+1+xshift:iec-ehalo+xshift,jsc+shalo:jec-nhalo+yshift,:) = 0
3727  data(isc+whalo:isc-1,jsc+shalo:jec-nhalo+yshift,:) = 0
3728  end if
3729 
3730  if(shalo>=0) then
3731  data(isd:ied+xshift, jec+nhalo+1+yshift:jed+yshift,:) = 0
3732  data(isd:ied+xshift, jsd:jsc-shalo-1,:) = 0
3733  else
3734  data(isc+whalo:iec-ehalo+xshift,jec+1+yshift:jec-nhalo+yshift,:) = 0
3735  data(isc+whalo:iec-ehalo+xshift,jsc+shalo:jsc-1,:) = 0
3736  end if
3737 
3738  end subroutine fill_halo_zero
3739 
3740  !##############################################################################
3741  ! this routine fill the halo points for the regular mosaic.
3742  subroutine fill_regular_mosaic_halo(data, data_all, te, tse, ts, tsw, tw, tnw, tn, tne)
3743  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
3744  real, dimension(:,:,:,:), intent(in) :: data_all
3745  integer, intent(in) :: te, tse, ts, tsw, tw, tnw, tn, tne
3746 
3747  data(nx+1:nx+ehalo, 1:ny, :) = data_all(1:ehalo, 1:ny, :, te) ! east
3748  data(1:nx, 1-shalo:0, :) = data_all(1:nx, ny-shalo+1:ny, :, ts) ! south
3749  data(1-whalo:0, 1:ny, :) = data_all(nx-whalo+1:nx, 1:ny, :, tw) ! west
3750  data(1:nx, ny+1:ny+nhalo, :) = data_all(1:nx, 1:nhalo, :, tn) ! north
3751  data(nx+1:nx+ehalo, 1-shalo:0, :) = data_all(1:ehalo, ny-shalo+1:ny, :,tse) ! southeast
3752  data(1-whalo:0, 1-shalo:0, :) = data_all(nx-whalo+1:nx, ny-shalo+1:ny, :,tsw) ! southwest
3753  data(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = data_all(1:ehalo, 1:nhalo, :,tnw) ! northeast
3754  data(1-whalo:0, ny+1:ny+nhalo, :) = data_all(nx-whalo+1:nx, 1:nhalo, :,tne) ! northwest
3755 
3756 
3757 
3758  end subroutine fill_regular_mosaic_halo
3759 
3760  !################################################################################
3761  subroutine fill_folded_north_halo(data, ioff, joff, ishift, jshift, sign)
3762  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
3763  integer, intent(in ) :: ioff, joff, ishift, jshift, sign
3764  integer :: nxp, nyp, m1, m2
3765 
3766  nxp = nx+ishift
3767  nyp = ny+jshift
3768  m1 = ishift - ioff
3769  m2 = 2*ishift - ioff
3770 
3771  data(1-whalo:0, 1:nyp,:) = data(nx-whalo+1:nx, 1:ny+jshift,:) ! west
3772  data(nx+1:nx+ehalo+ishift, 1:nyp,:) = data(1:ehalo+ishift, 1:ny+jshift,:) ! east
3773  if(m1 .GE. 1-whalo) data(1-whalo:m1, nyp+1:nyp+nhalo,:) = sign*data(whalo+m2:1+ishift:-1, nyp-joff:nyp-nhalo-joff+1:-1,:)
3774  data(m1+1:nx+m2, nyp+1:nyp+nhalo,:) = sign*data(nx+ishift:1:-1, nyp-joff:nyp-nhalo-joff+1:-1,:)
3775  data(nx+m2+1:nxp+ehalo,nyp+1:nyp+nhalo,:) = sign*data(nx:nx-ehalo+m1+1:-1, nyp-joff:nyp-nhalo-joff+1:-1,:)
3776 
3777  end subroutine fill_folded_north_halo
3778 
3779  !################################################################################
3780  subroutine fill_folded_south_halo(data, ioff, joff, ishift, jshift, sign)
3781  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
3782  integer, intent(in ) :: ioff, joff, ishift, jshift, sign
3783  integer :: nxp, nyp, m1, m2
3784 
3785  nxp = nx+ishift
3786  nyp = ny+jshift
3787  m1 = ishift - ioff
3788  m2 = 2*ishift - ioff
3789 
3790 
3791  data(1-whalo:0, 1:nyp,:) = data(nx-whalo+1:nx, 1:nyp,:) ! west
3792  data(nx+1:nx+ehalo+ishift, 1:nyp,:) = data(1:ehalo+ishift, 1:nyp,:) ! east
3793  if(m1 .GE. 1-whalo)data(1-whalo:m1, 1-shalo:0,:) = sign*data(whalo+m2:1+ishift:-1, shalo+jshift:1+jshift:-1,:)
3794  data(m1+1:nx+m2, 1-shalo:0,:) = sign*data(nxp:1:-1, shalo+jshift:1+jshift:-1,:)
3795  data(nx+m2+1:nxp+ehalo,1-shalo:0,:) = sign*data(nx:nx-ehalo+m1+1:-1, shalo+jshift:1+jshift:-1,:)
3796 
3797  end subroutine fill_folded_south_halo
3798 
3799  !################################################################################
3800  subroutine fill_folded_west_halo(data, ioff, joff, ishift, jshift, sign)
3801  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
3802  integer, intent(in ) :: ioff, joff, ishift, jshift, sign
3803  integer :: nxp, nyp, m1, m2
3804 
3805  nxp = nx+ishift
3806  nyp = ny+jshift
3807  m1 = jshift - joff
3808  m2 = 2*jshift - joff
3809 
3810  data(1:nxp, 1-shalo:0, :) = data(1:nxp, ny-shalo+1:ny, :) ! south
3811  data(1:nxp, ny+1:nyp+nhalo, :) = data(1:nxp, 1:nhalo+jshift,:) ! north
3812  if(m1 .GE. 1-shalo) data(1-whalo:0, 1-shalo:m1, :) = sign*data(whalo+ishift:1+ishift:-1, shalo+m2:1+jshift:-1,:)
3813  data(1-whalo:0, m1+1:ny+m2, :) = sign*data(whalo+ishift:1+ishift:-1, nyp:1:-1, :)
3814  data(1-whalo:0, ny+m2+1:nyp+nhalo,:) = sign*data(whalo+ishift:1+ishift:-1, ny:ny-nhalo+m1+1:-1,:)
3815 
3816  end subroutine fill_folded_west_halo
3817 
3818  !################################################################################
3819  subroutine fill_folded_east_halo(data, ioff, joff, ishift, jshift, sign)
3820  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
3821  integer, intent(in ) :: ioff, joff, ishift, jshift, sign
3822  integer :: nxp, nyp, m1, m2
3823 
3824  nxp = nx+ishift
3825  nyp = ny+jshift
3826  m1 = jshift - joff
3827  m2 = 2*jshift - joff
3828 
3829  data(1:nxp, 1-shalo:0, :) = data(1:nxp, ny-shalo+1:ny, :) ! south
3830  data(1:nxp, ny+1:nyp+nhalo, :) = data(1:nxp, 1:nhalo+jshift,:) ! north
3831  if(m1 .GE. 1-shalo) data(nxp+1:nxp+ehalo, 1-shalo:m1, :) = sign*data(nxp-ioff:nxp-ehalo-ioff+1:-1, shalo+m2:1+jshift:-1,:)
3832  data(nxp+1:nxp+ehalo, m1+1:ny+m2, :) = sign*data(nxp-ioff:nxp-ehalo-ioff+1:-1, nyp:1:-1, :)
3833  data(nxp+1:nxp+ehalo, ny+m2+1:nyp+nhalo,:) = sign*data(nxp-ioff:nxp-ehalo-ioff+1:-1, ny:ny-nhalo+m1+1:-1,:)
3834 
3835  end subroutine fill_folded_east_halo
3836 
3837  !################################################################################
3838  subroutine fill_four_tile_bound(data_all, is, ie, js, je, ioff, joff, tile, &
3839  ebound, sbound, wbound, nbound )
3840  real, dimension(:,:,:,:), intent(in) :: data_all
3841  integer, intent(in) :: is, ie, js, je
3842  integer, intent(in) :: tile, ioff, joff
3843  real, dimension(:,:), optional, intent(inout) :: ebound, sbound, wbound, nbound
3844  integer :: tw, te, ts, tn
3845 
3846  if(tile == 1 .OR. tile == 3) te = tile + 1
3847  if(tile == 2 .OR. tile == 4) te = tile - 1
3848  if(tile == 1 .OR. tile == 2) ts = tile + 2
3849  if(tile == 3 .OR. tile == 4) ts = tile - 2
3850  tw = te; tn = ts
3851  if(present(ebound)) then
3852  if( ie == nx ) then
3853  ebound(:,:) = data_all(1, js:je+joff, :, te)
3854  else
3855  ebound(:,:) = data_all(ie+ioff, js:je+joff, :, tile)
3856  end if
3857  end if
3858 
3859  if(present(wbound)) then
3860  if( is == 1 ) then
3861  wbound(:,:) = data_all(nx+ioff, js:je+joff, :, tw)
3862  else
3863  wbound(:,:) = data_all(is, js:je+joff, :, tile)
3864  end if
3865  end if
3866 
3867  if(present(sbound)) then
3868  if( js == 1 ) then
3869  sbound(:,:) = data_all(is:ie+ioff, ny+joff, :, ts)
3870  else
3871  sbound(:,:) = data_all(is:ie+ioff, js, :, tile)
3872  end if
3873  end if
3874 
3875  if(present(nbound)) then
3876  if( je == ny ) then
3877  nbound(:,:) = data_all(is:ie+ioff, 1, :, tn)
3878  else
3879  nbound(:,:) = data_all(is:ie+ioff, je+joff, :, tile)
3880  end if
3881  end if
3882 
3883  return
3884 
3885  end subroutine fill_four_tile_bound
3886 
3887 
3888  !################################################################################
3889  subroutine fill_torus_bound(data_all, is, ie, js, je, ioff, joff, tile, &
3890  sbound, wbound)
3891  real, dimension(:,:,:), intent(in) :: data_all
3892  integer, intent(in) :: is, ie, js, je
3893  integer, intent(in) :: tile, ioff, joff
3894  real, dimension(:,:), optional, intent(inout) :: sbound, wbound
3895  integer :: tw, te, ts, tn
3896  integer :: js1, js2, is1, is2
3897 
3898  if(tile .NE. 1) call mpp_error(fatal, "fill_torus_bound: tile must be 1")
3899 
3900  js2 = js
3901  js1 = 1
3902  if( js == 1 .AND. joff==1 ) then
3903  js1 = 2
3904  js2 = js+1
3905  endif
3906  is2 = is
3907  is1 = 1
3908  if( is == 1 .AND. ioff==1 ) then
3909  is1 = 2
3910  is2 = is+1
3911  endif
3912 
3913  if(present(wbound)) then
3914  if(ioff .NE. 1) call mpp_error(fatal, "fill_torus_bound: ioff must be 1 when wbound present")
3915  if( is == 1 ) then
3916  wbound(js1:,:) = data_all(nx+ioff, js2:je+joff, :)
3917  else
3918  wbound(js1:,:) = data_all(is, js2:je+joff, :)
3919  end if
3920  if(js1 == 2) then
3921  if( is == 1 ) then
3922  wbound(1,:) = data_all(nx+1, ny+1, :)
3923  else
3924  wbound(1,:) = data_all(is, ny+1, :)
3925  endif
3926  endif
3927  end if
3928 
3929  if(present(sbound)) then
3930  if(joff .NE. 1) call mpp_error(fatal, "fill_torus_bound: joff must be 1 when sbound present")
3931  if( js == 1 ) then
3932  sbound(is1:,:) = data_all(is2:ie+ioff, ny+joff, :)
3933  else
3934  sbound(is1:,:) = data_all(is2:ie+ioff, js, :)
3935  end if
3936  if(is1 == 2) then
3937  if( js == 1 ) then
3938  sbound(1,:) = data_all(nx+1, ny+1, :)
3939  else
3940  sbound(1,:) = data_all(nx+1, js, :)
3941  endif
3942  endif
3943  end if
3944 
3945  return
3946 
3947  end subroutine fill_torus_bound
3948 
3949  !################################################################################
3950  subroutine fill_folded_north_bound(data_all, is, ie, js, je, ioff, joff, tile, &
3951  sbound, wbound)
3952  real, dimension(:,:,:), intent(in) :: data_all
3953  integer, intent(in) :: is, ie, js, je
3954  integer, intent(in) :: tile, ioff, joff
3955  real, dimension(:,:), optional, intent(inout) :: sbound, wbound
3956  integer :: tw, te, ts, tn
3957  integer :: js1, js2
3958 
3959  if(tile .NE. 1) call mpp_error(fatal, "fill_folded_north_bound: tile must be 1")
3960 
3961  js2 = js
3962  js1 = 1
3963  if( js == 1 .AND. joff==1 ) then
3964  js1 = 2
3965  js2 = js+1
3966  endif
3967 
3968  if(present(wbound)) then
3969  if( is == 1 ) then
3970  wbound(js1:,:) = data_all(nx+ioff, js2:je+joff, :)
3971  else
3972  wbound(js1:,:) = data_all(is, js2:je+joff, :)
3973  end if
3974  end if
3975 
3976  if(present(sbound)) then
3977  if( js == 1 ) then
3978  sbound(:,:) = 0
3979  else
3980  if( is == 1 .AND. ioff == 1 ) then
3981  sbound(1,:) = data_all(nx+1, js, :)
3982  sbound(2:,:) = data_all(is+1:ie+ioff, js, :)
3983  else
3984  sbound(:,:) = data_all(is:ie+ioff, js, :)
3985  endif
3986  end if
3987  end if
3988 
3989  return
3990 
3991  end subroutine fill_folded_north_bound
3992 
3993  !################################################################################
3994  subroutine fill_cubic_grid_bound(data1_all, data2_all, is, ie, js, je, ioff, joff, tile, sign1, sign2, &
3995  ebound, sbound, wbound, nbound )
3996  real, dimension(:,:,:,:), intent(in) :: data1_all, data2_all
3997  integer, intent(in) :: is, ie, js, je
3998  integer, intent(in) :: tile, ioff, joff, sign1, sign2
3999  real, dimension(:,:), optional, intent(inout) :: ebound, sbound, wbound, nbound
4000  integer :: tw, te, ts, tn
4001 
4002  if(mod(tile,2) == 0) then ! tile 2, 4, 6
4003  tw = tile - 1; te = tile + 2; ts = tile - 2; tn = tile + 1
4004  if(te > 6 ) te = te - 6
4005  if(ts < 1 ) ts = ts + 6
4006  if(tn > 6 ) tn = tn - 6
4007  !--- East bound
4008  if(present(ebound)) then
4009  if(ie == nx) then
4010  ebound(:,:) = sign1*data2_all(nx+joff-js+1:nx-je+1:-1,1,:,te)
4011  else
4012  ebound(:,:) = data1_all(ie+ioff, js:je+joff, :,tile)
4013  end if
4014  end if
4015  !--- South bound
4016  if(present(sbound)) then
4017  if(js == 1) then
4018  sbound(:,:) = sign2*data2_all(nx+joff, ny+ioff-is+1:ny-ie+1:-1,:,ts)
4019  else
4020  sbound(:,:) = data1_all(is:ie+ioff, js, :,tile)
4021  end if
4022  end if
4023 
4024  !--- West bound
4025  if(present(wbound)) then
4026  if(is == 1) then
4027  wbound(:,:) = data1_all(nx+ioff, js:je+joff,:,tw)
4028  else
4029  wbound(:,:) = data1_all(is, js:je+joff,:,tile)
4030  end if
4031  end if
4032 
4033  !--- north bound
4034  if(present(nbound)) then
4035  if(je == ny) then
4036  nbound(:,:) = data1_all(is:ie+ioff, 1,:,tn)
4037  else
4038  nbound(:,:) = data1_all(is:ie+ioff, je+joff, :,tile)
4039  end if
4040  end if
4041  else ! tile 1, 3, 5
4042  tw = tile - 2; te = tile + 1; ts = tile - 1; tn = tile + 2
4043  if(tw < 1 ) tw = tw + 6
4044  if(ts < 1 ) ts = ts + 6
4045  if(tn > 6 ) tn = tn - 6
4046  !--- East bound
4047  if(present(ebound)) then
4048  if(ie == nx) then
4049  ebound(:,:) = data1_all(1, js:je+joff, :,te)
4050  else
4051  ebound(:,:) = data1_all(ie+ioff, js:je+joff, :,tile)
4052  end if
4053  end if
4054  !--- South bound
4055  if(present(sbound)) then
4056  if(js == 1) then
4057  sbound(:,:) = data1_all(is:ie+ioff,ny+joff,:,ts)
4058  else
4059  sbound(:,:) = data1_all(is:ie+ioff, js, :,tile)
4060  end if
4061  end if
4062 
4063  !--- West bound
4064  if(present(wbound)) then
4065  if(is == 1) then
4066  wbound(:,:) = sign1*data2_all(nx+joff-js+1:nx-je+1:-1,ny+ioff,:,tw)
4067  else
4068  wbound(:,:) = data1_all(is, js:je+joff,:,tile)
4069  end if
4070  end if
4071 
4072  !--- north bound
4073  if(present(nbound)) then
4074  if(je == ny) then
4075  nbound(:,:) = sign2*data2_all(1, ny+ioff-is+1:ny-ie+1:-1,:,tn)
4076  else
4077  nbound(:,:) = data1_all(is:ie+ioff, je+joff, :,tile)
4078  end if
4079  end if
4080 
4081  end if
4082 
4083  end subroutine fill_cubic_grid_bound
4084 
4085  !##############################################################################
4086  ! this routine fill the halo points for the cubic grid. ioff and joff is used to distinguish
4087  ! T, C, E, or N-cell
4088  subroutine fill_cubic_grid_halo(data, data1_all, data2_all, tile, ioff, joff, sign1, sign2)
4089  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
4090  real, dimension(:,:,:,:), intent(in) :: data1_all, data2_all
4091  integer, intent(in) :: tile, ioff, joff, sign1, sign2
4092  integer :: lw, le, ls, ln
4093 
4094  if(mod(tile,2) == 0) then ! tile 2, 4, 6
4095  lw = tile - 1; le = tile + 2; ls = tile - 2; ln = tile + 1
4096  if(le > 6 ) le = le - 6
4097  if(ls < 1 ) ls = ls + 6
4098  if(ln > 6 ) ln = ln - 6
4099  data(1-whalo:0, 1:ny+joff, :) = data1_all(nx-whalo+1:nx, 1:ny+joff, :, lw) ! west
4100  do i = 1, ehalo
4101  data(nx+i+ioff, 1:ny+joff, :) = sign1*data2_all(nx+joff:1:-1, i+ioff, :, le) ! east
4102  end do
4103  do i = 1, shalo
4104  data(1:nx+ioff, 1-i, :) = sign2*data2_all(nx-i+1, ny+ioff:1:-1, :, ls) ! south
4105  end do
4106  data(1:nx+ioff, ny+1+joff:ny+nhalo+joff, :) = data1_all(1:nx+ioff, 1+joff:nhalo+joff, :, ln) ! north
4107  else ! tile 1, 3, 5
4108  lw = tile - 2; le = tile + 1; ls = tile - 1; ln = tile + 2
4109  if(lw < 1 ) lw = lw + 6
4110  if(ls < 1 ) ls = ls + 6
4111  if(ln > 6 ) ln = ln - 6
4112  do i = 1, whalo
4113  data(1-i, 1:ny+joff, :) = sign1*data2_all(nx+joff:1:-1, ny-i+1, :, lw) ! west
4114  end do
4115  data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff, :) = data1_all(1+ioff:ehalo+ioff, 1:ny+joff, :, le) ! east
4116  data(1:nx+ioff, 1-shalo:0, :) = data1_all(1:nx+ioff, ny-shalo+1:ny, :, ls) ! south
4117  do i = 1, nhalo
4118  data(1:nx+ioff, ny+i+joff, :) = sign2*data2_all(i+joff, ny+ioff:1:-1, :, ln) ! north
4119  end do
4120  end if
4121 
4122  end subroutine fill_cubic_grid_halo
4123 
4124  !#####################################################################
4125  subroutine test_nonuniform_mosaic( type )
4126  character(len=*), intent(in) :: type
4127 
4128  type(domain2D) :: domain
4129  integer :: num_contact, ntiles, ntile_per_pe
4130  integer :: i, j, k, n, nxm, nym, ni, nj, shift
4131  integer :: ism, iem, jsm, jem, isc, iec, jsc, jec
4132  integer :: isd, ied, jsd, jed
4133  integer :: indices(4), msize(2)
4134  character(len=128) :: type2
4135 
4136  integer, allocatable, dimension(:) :: tile
4137  integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
4138  integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
4139  integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
4140  integer, allocatable, dimension(:,:) :: layout2D, global_indices
4141  real, allocatable, dimension(:,:,:,:) :: global1_all, global2_all
4142  real, allocatable, dimension(:,:,:,:) :: global1, global2, x, y
4143 
4144  shift = 0
4145  select case(type)
4146  case('Five-Tile') ! one tile will run on pe 0 and other four tiles will run on pe 1
4147  shift = 1 ! one extra point for symmetry domain
4148  ntiles = 5 ! tile 1 with resolution 2*nx and 2*ny and the tiles are nx and ny.
4149  num_contact = 11
4150  if(npes .NE. 2) then
4151  call mpp_error(note,'TEST_MPP_DOMAINS: Five-Tile mosaic will not be tested because npes is not 2')
4152  return
4153  end if
4154  nxm = 2*nx; nym = 2*ny
4155  layout = 1
4156  if( pe == 0) then
4157  ntile_per_pe = 1
4158  allocate(tile(ntile_per_pe))
4159  tile = 1
4160  indices = (/1,2*nx,1,2*ny/)
4161  ni = 2*nx; nj = 2*ny
4162  else
4163  ntile_per_pe = 4
4164  allocate(tile(ntile_per_pe))
4165  do n = 1, ntile_per_pe
4166  tile(n) = n + 1
4167  end do
4168  indices = (/1,nx,1,ny/)
4169  ni = nx; nj = ny
4170  end if
4171  allocate(pe_start(ntiles), pe_end(ntiles) )
4172  pe_start(1) = 0; pe_start(2:) = 1
4173  pe_end = pe_start
4174  case default
4175  call mpp_error(fatal, 'TEST_MPP_DOMAINS: no such test: '//type)
4176  end select
4177 
4178  allocate(layout2d(2,ntiles), global_indices(4,ntiles) )
4179 
4180  do n = 1, ntiles
4181  if(n==1) then
4182  global_indices(:,n) = (/1,2*nx,1,2*ny/)
4183  else
4184  global_indices(:,n) = (/1,nx,1,ny/)
4185  endif
4186 ! global_indices(:,n) = indices
4187  layout2d(:,n) = layout
4188  end do
4189 
4190  allocate(tile1(num_contact), tile2(num_contact) )
4191  allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
4192  allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
4193 
4194  !--- define domain
4195  select case(type)
4196  case( 'Five-Tile' )
4197  !--- Contact line 1, between tile 1 (EAST) and tile 2 (WEST)
4198  tile1(1) = 1; tile2(1) = 2
4199  istart1(1) = 2*nx; iend1(1) = 2*nx; jstart1(1) = 1; jend1(1) = ny
4200  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
4201  !--- Contact line 2, between tile 1 (EAST) and tile 4 (WEST)
4202  tile1(2) = 1; tile2(2) = 4
4203  istart1(2) = 2*nx; iend1(2) = 2*nx; jstart1(2) = ny+1; jend1(2) = 2*ny
4204  istart2(2) = 1; iend2(2) = 1; jstart2(2) = 1; jend2(2) = ny
4205  !--- Contact line 3, between tile 1 (SOUTH) and tile 1 (NORTH)
4206  tile1(3) = 1; tile2(3) = 1
4207  istart1(3) = 1; iend1(3) = 2*nx; jstart1(3) = 1; jend1(3) = 1
4208  istart2(3) = 1; iend2(3) = 2*nx; jstart2(3) = 2*ny; jend2(3) = 2*ny
4209  !--- Contact line 4, between tile 1 (WEST) and tile 3 (EAST)
4210  tile1(4) = 1; tile2(4) = 3
4211  istart1(4) = 1; iend1(4) = 1; jstart1(4) = 1; jend1(4) = ny
4212  istart2(4) = nx; iend2(4) = nx; jstart2(4) = 1; jend2(4) = ny
4213  !--- Contact line 5, between tile 1 (WEST) and tile 5 (EAST)
4214  tile1(5) = 1; tile2(5) = 5
4215  istart1(5) = 1; iend1(5) = 1; jstart1(5) = ny+1; jend1(5) = 2*ny
4216  istart2(5) = nx; iend2(5) = nx; jstart2(5) = 1; jend2(5) = ny
4217  !--- Contact line 6, between tile 2 (EAST) and tile 3 (WEST)
4218  tile1(6) = 2; tile2(6) = 3
4219  istart1(6) = nx; iend1(6) = nx; jstart1(6) = 1; jend1(6) = ny
4220  istart2(6) = 1; iend2(6) = 1; jstart2(6) = 1; jend2(6) = ny
4221  !--- Contact line 7, between tile 2 (SOUTH) and tile 4 (NORTH) --- cyclic
4222  tile1(7) = 2; tile2(7) = 4
4223  istart1(7) = 1; iend1(7) = nx; jstart1(7) = 1; jend1(7) = 1
4224  istart2(7) = 1; iend2(7) = nx; jstart2(7) = ny; jend2(7) = ny
4225  !--- Contact line 8, between tile 2 (NORTH) and tile 4 (SOUTH)
4226  tile1(8) = 2; tile2(8) = 4
4227  istart1(8) = 1; iend1(8) = nx; jstart1(8) = ny; jend1(8) = ny
4228  istart2(8) = 1; iend2(8) = nx; jstart2(8) = 1; jend2(8) = 1
4229  !--- Contact line 9, between tile 3 (SOUTH) and tile 5 (NORTH) --- cyclic
4230  tile1(9) = 3; tile2(9) = 5
4231  istart1(9) = 1; iend1(9) = nx; jstart1(9) = 1; jend1(9) = 1
4232  istart2(9) = 1; iend2(9) = nx; jstart2(9) = ny; jend2(9) = ny
4233  !--- Contact line 10, between tile 3 (NORTH) and tile 5 (SOUTH)
4234  tile1(10) = 3; tile2(10) = 5
4235  istart1(10) = 1; iend1(10) = nx; jstart1(10) = ny; jend1(10) = ny
4236  istart2(10) = 1; iend2(10) = nx; jstart2(10) = 1; jend2(10) = 1
4237  !--- Contact line 11, between tile 4 (EAST) and tile 5 (WEST)
4238  tile1(11) = 4; tile2(11) = 5
4239  istart1(11) = nx; iend1(11) = nx; jstart1(11) = 1; jend1(11) = ny
4240  istart2(11) = 1; iend2(11) = 1; jstart2(11) = 1; jend2(11) = ny
4241  msize(1) = 2*nx + whalo + ehalo
4242  msize(2) = 2*ny + shalo + nhalo
4243  call mpp_define_mosaic(global_indices, layout2d, domain, ntiles, num_contact, tile1, tile2, &
4244  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
4245  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
4246  name = type, memory_size = msize, symmetry = .true. )
4247  end select
4248 
4249  !--- setup data
4250  allocate(global1_all(1:nxm,1:nym,nz, ntiles) )
4251  allocate(global1(1-whalo:ni+ehalo,1-shalo:nj+nhalo,nz, ntile_per_pe) )
4252  do n = 1, ntiles
4253  do k = 1, nz
4254  do j = 1, nym
4255  do i = 1, nxm
4256  global1_all(i,j,k,n) = n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4257  end do
4258  end do
4259  end do
4260  end do
4261 
4262  do n = 1, ntile_per_pe
4263  global1(1:ni,1:nj,:,n) = global1_all(1:ni,1:nj,:,tile(n))
4264  end do
4265 
4266  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
4267  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
4268  call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
4269 
4270  allocate( x(ism:iem,jsm:jem,nz, ntile_per_pe) )
4271  x = 0.
4272  x(isc:iec,jsc:jec,:,:) = global1(isc:iec,jsc:jec,:,:)
4273 
4274  !--- fill up the value at halo points
4275  do n = 1, ntile_per_pe
4276  call fill_five_tile_halo(global1(:,:,:,n), global1_all, tile(n), 0, 0 )
4277  end do
4278 
4279  ! full update
4280  id = mpp_clock_id( type, flags=mpp_clock_sync+mpp_clock_detailed )
4281  call mpp_clock_begin(id)
4282  do n = 1, ntile_per_pe
4283  call mpp_update_domains( x(:,:,:,n), domain, tile_count = n )
4284  end do
4285  call mpp_clock_end(id)
4286 
4287  do n = 1, ntile_per_pe
4288  write(type2, *)type, " at tile_count = ",n
4289  call compare_checksums( x(isd:ied,jsd:jed,:,n), global1(isd:ied,jsd:jed,:,n), trim(type2) )
4290  end do
4291 
4292  deallocate(global1_all, global1, x)
4293 
4294  !------------------------------------------------------------------
4295  ! vector update : BGRID_NE, one extra point in each direction for Five-Tile
4296  !------------------------------------------------------------------
4297  !--- setup data
4298  allocate(global1_all(nxm+shift,nym+shift,nz, ntiles), global2_all(nxm+shift,nym+shift,nz, ntiles) )
4299  allocate(global1(1-whalo:ni+ehalo+shift,1-shalo:nj+nhalo+shift,nz, ntile_per_pe) )
4300  allocate(global2(1-whalo:ni+ehalo+shift,1-shalo:nj+nhalo+shift,nz, ntile_per_pe) )
4301  do n = 1, ntiles
4302  do k = 1, nz
4303  do j = 1, nym+shift
4304  do i = 1, nxm+shift
4305  global1_all(i,j,k,n) = 1.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4306  global2_all(i,j,k,n) = 2.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4307  end do
4308  end do
4309  end do
4310  end do
4311 
4312  !------------------------------------------------------------------------
4313  ! --- make sure consisency on the boundary for Five-Tile mosaic
4314  ! --- east boundary will take the value of neighbor tile west,
4315  ! --- north boundary will take the value of neighbor tile south.
4316  !------------------------------------------------------------------------
4317  if(type == 'Five-Tile') then
4318  global1_all(nxm+1, 1:ny,:,1) = global1_all(1, 1:ny,:,2) ! east
4319  global1_all(nxm+1,ny+1:nym,:,1) = global1_all(1, 1:ny,:,4) ! east
4320  global1_all(1:nxm+1, nym+1,:,1) = global1_all(1:nxm+1, 1,:,1) ! north
4321  global1_all(nx+1, 1:ny,:,2) = global1_all(1, 1:ny,:,3) ! east
4322  global1_all(1:nx+1, ny+1,:,2) = global1_all(1:nx+1, 1,:,4) ! north
4323  global1_all(nx+1, 1:ny,:,3) = global1_all(1, 1:ny,:,1) ! east
4324  global1_all(1:nx+1, ny+1,:,3) = global1_all(1:nx+1, 1,:,5) ! north
4325  global1_all(nx+1, 1:ny,:,4) = global1_all(1, 1:ny,:,5) ! east
4326  global1_all(1:nx+1, ny+1,:,4) = global1_all(1:nx+1, 1,:,2) ! north
4327  global1_all(nx+1, 1:ny,:,5) = global1_all(1,ny+1:nym,:,1) ! east
4328  global1_all(1:nx+1, ny+1,:,5) = global1_all(1:nx+1, 1,:,3) ! north
4329  global1_all(nx+1, ny+1,:,2) = global1_all(1, 1,:,5) ! northeast
4330  global1_all(nx+1, ny+1,:,3) = global1_all(1, ny+1,:,1) ! northeast
4331  global2_all(nxm+1, 1:ny,:,1) = global2_all(1, 1:ny,:,2) ! east
4332  global2_all(nxm+1,ny+1:nym,:,1) = global2_all(1, 1:ny,:,4) ! east
4333  global2_all(1:nxm+1, nym+1,:,1) = global2_all(1:nxm+1, 1,:,1) ! north
4334  global2_all(nx+1, 1:ny,:,2) = global2_all(1, 1:ny,:,3) ! east
4335  global2_all(1:nx+1, ny+1,:,2) = global2_all(1:nx+1, 1,:,4) ! north
4336  global2_all(nx+1, 1:ny,:,3) = global2_all(1, 1:ny,:,1) ! east
4337  global2_all(1:nx+1, ny+1,:,3) = global2_all(1:nx+1, 1,:,5) ! north
4338  global2_all(nx+1, 1:ny,:,4) = global2_all(1, 1:ny,:,5) ! east
4339  global2_all(1:nx+1, ny+1,:,4) = global2_all(1:nx+1, 1,:,2) ! north
4340  global2_all(nx+1, 1:ny,:,5) = global2_all(1,ny+1:nym,:,1) ! east
4341  global2_all(1:nx+1, ny+1,:,5) = global2_all(1:nx+1, 1,:,3) ! north
4342  global2_all(nx+1, ny+1,:,2) = global2_all(1, 1,:,5) ! northeast
4343  global2_all(nx+1, ny+1,:,3) = global2_all(1, ny+1,:,1) ! northeast
4344  end if
4345 
4346  do n = 1, ntile_per_pe
4347  global1(1:ni+shift,1:nj+shift,:,n) = global1_all(1:ni+shift,1:nj+shift,:,tile(n))
4348  global2(1:ni+shift,1:nj+shift,:,n) = global2_all(1:ni+shift,1:nj+shift,:,tile(n))
4349  end do
4350 
4351  allocate( x(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
4352  allocate( y(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
4353 
4354  x = 0.; y = 0
4355  x(isc:iec+shift,jsc:jec+shift,:,:) = global1(isc:iec+shift,jsc:jec+shift,:,:)
4356  y(isc:iec+shift,jsc:jec+shift,:,:) = global2(isc:iec+shift,jsc:jec+shift,:,:)
4357 
4358  !-----------------------------------------------------------------------
4359  ! fill up the value at halo points.
4360  !-----------------------------------------------------------------------
4361  do n = 1, ntile_per_pe
4362  call fill_five_tile_halo(global1(:,:,:,n), global1_all, tile(n), shift, shift)
4363  call fill_five_tile_halo(global2(:,:,:,n), global2_all, tile(n), shift, shift)
4364  end do
4365 
4366  id = mpp_clock_id( type//' BGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
4367  call mpp_clock_begin(id)
4368  do n = 1, ntile_per_pe
4369  call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=bgrid_ne, tile_count = n )
4370  end do
4371  call mpp_clock_end(id)
4372 
4373  do n = 1, ntile_per_pe
4374  write(type2, *)type, " at tile_count = ",n
4375  call compare_checksums( x(isd:ied+shift,jsd:jed+shift,:,n), global1(isd:ied+shift,jsd:jed+shift,:,n), &
4376  trim(type2)//' BGRID_NE X')
4377  call compare_checksums( y(isd:ied+shift,jsd:jed+shift,:,n), global2(isd:ied+shift,jsd:jed+shift,:,n), &
4378  trim(type2)//' BGRID_NE Y')
4379  end do
4380 
4381  deallocate(global1_all, global2_all, global1, global2, x, y)
4382 
4383  !------------------------------------------------------------------
4384  ! vector update : CGRID_NE
4385  !------------------------------------------------------------------
4386  !--- setup data
4387  allocate(global1_all(nxm+shift,nym,nz, ntiles), global2_all(nxm,nym+shift,nz, ntiles) )
4388  allocate(global1(1-whalo:ni+ehalo+shift, 1-shalo:nj+nhalo, nz, ntile_per_pe) )
4389  allocate(global2(1-whalo:ni+ehalo, 1-shalo:nj+nhalo+shift, nz, ntile_per_pe) )
4390  do n = 1, ntiles
4391  do k = 1, nz
4392  do j = 1, nym
4393  do i = 1, nxm+shift
4394  global1_all(i,j,k,n) = 1.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4395  end do
4396  end do
4397  do j = 1, nym+shift
4398  do i = 1, nxm
4399  global2_all(i,j,k,n) = 2.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4400  end do
4401  end do
4402  end do
4403  end do
4404 
4405  !------------------------------------------------------------------------
4406  ! --- make sure consisency on the boundary for Five-Tile mosaic
4407  ! --- east boundary will take the value of neighbor tile west,
4408  ! --- north boundary will take the value of neighbor tile south.
4409  !------------------------------------------------------------------------
4410  if(type == 'Five-Tile') then
4411  global1_all(nxm+1, 1:ny,:,1) = global1_all(1, 1:ny,:,2) ! east
4412  global1_all(nxm+1,ny+1:nym,:,1) = global1_all(1, 1:ny,:,4) ! east
4413  global1_all(nx+1, 1:ny,:,2) = global1_all(1, 1:ny,:,3) ! east
4414  global1_all(nx+1, 1:ny,:,3) = global1_all(1, 1:ny,:,1) ! east
4415  global1_all(nx+1, 1:ny,:,4) = global1_all(1, 1:ny,:,5) ! east
4416  global1_all(nx+1, 1:ny,:,5) = global1_all(1,ny+1:nym,:,1) ! east
4417  global2_all(1:nxm, nym+1,:,1) = global2_all(1:nxm, 1,:,1) ! north
4418  global2_all(1:nx, ny+1,:,2) = global2_all(1:nx, 1,:,4) ! north
4419  global2_all(1:nx, ny+1,:,3) = global2_all(1:nx, 1,:,5) ! north
4420  global2_all(1:nx, ny+1,:,4) = global2_all(1:nx, 1,:,2) ! north
4421  global2_all(1:nx, ny+1,:,5) = global2_all(1:nx, 1,:,3) ! north
4422  end if
4423 
4424  do n = 1, ntile_per_pe
4425  global1(1:ni+shift, 1:nj,:,n) = global1_all(1:ni+shift, 1:nj,:,tile(n))
4426  global2(1:ni, 1:nj+shift,:,n) = global2_all(1:ni, 1:nj+shift,:,tile(n))
4427  end do
4428 
4429  allocate( x(ism:iem+shift, jsm:jem,nz,ntile_per_pe) )
4430  allocate( y(ism:iem, jsm:jem+shift,nz,ntile_per_pe) )
4431 
4432  x = 0.; y = 0
4433  x(isc:iec+shift, jsc:jec,:,:) = global1(isc:iec+shift, jsc:jec,:,:)
4434  y(isc:iec, jsc:jec+shift,:,:) = global2(isc:iec, jsc:jec+shift,:,:)
4435 
4436  !-----------------------------------------------------------------------
4437  ! fill up the value at halo points.
4438  !-----------------------------------------------------------------------
4439  do n = 1, ntile_per_pe
4440  call fill_five_tile_halo(global1(:,:,:,n), global1_all, tile(n), shift, 0)
4441  call fill_five_tile_halo(global2(:,:,:,n), global2_all, tile(n), 0, shift)
4442  end do
4443 
4444  id = mpp_clock_id( type//' CGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
4445  call mpp_clock_begin(id)
4446  do n = 1, ntile_per_pe
4447  call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=cgrid_ne, tile_count = n )
4448  end do
4449  call mpp_clock_end(id)
4450 
4451  do n = 1, ntile_per_pe
4452  write(type2, *)type, " at tile_count = ",n
4453  call compare_checksums( x(isd:ied+shift,jsd:jed,:,n), global1(isd:ied+shift,jsd:jed,:,n), &
4454  trim(type2)//' CGRID_NE X')
4455  call compare_checksums( y(isd:ied,jsd:jed+shift,:,n), global2(isd:ied,jsd:jed+shift,:,n), &
4456  trim(type2)//' CGRID_NE Y')
4457  end do
4458 
4459  deallocate(global1_all, global2_all, global1, global2, x, y)
4460 
4461  end subroutine test_nonuniform_mosaic
4462 
4463  subroutine fill_five_tile_halo(data, data_all, tile, ioff, joff)
4464  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
4465  real, dimension(:,:,:,:), intent(in) :: data_all
4466  integer, intent(in) :: tile, ioff, joff
4467  integer :: nxm, nym
4468 
4469  nxm = 2*nx; nym = 2*ny
4470 
4471  select case(tile)
4472  case(1)
4473  data(nxm+1+ioff:nxm+ehalo+ioff, 1:ny,:) = data_all(1+ioff:ehalo+ioff, 1:ny,:,2) ! east
4474  data(nxm+1+ioff:nxm+ehalo+ioff, ny+1:nym+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,4) ! east
4475  data(1-whalo:0, 1:ny,:) = data_all(nx-whalo+1:nx, 1:ny,:,3) ! west
4476  data(1-whalo:0, ny+1:nym+joff,:) = data_all(nx-whalo+1:nx, 1:ny+joff,:,5) ! west
4477  data(1:nxm+ioff, 1-shalo:0,:) = data_all(1:nxm+ioff, nym-shalo+1:nym,:,1) ! south
4478  data(1:nxm+ioff, nym+1+joff:nym+nhalo+joff,:) = data_all(1:nxm+ioff, 1+joff:nhalo+joff,:,1) ! north
4479  data(nxm+1+ioff:nxm+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,4) ! southeast
4480  data(1-whalo:0, 1-shalo:0,:) = data_all(nx-whalo+1:nx, ny-shalo+1:ny,:,5) ! southwest
4481  data(nxm+1+ioff:nxm+ehalo+ioff,nym+1+joff:nym+nhalo+joff,:) = data_all(1+ioff:ehalo+ioff, 1+joff:nhalo+joff,:,2) ! northeast
4482  data(1-whalo:0, nym+1+joff:nym+nhalo+joff,:) = data_all(nx-whalo+1:nx, 1+joff:nhalo+joff,:,3) ! northwest
4483  case(2)
4484  data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,3) ! east
4485  data(1-whalo:0, 1:ny+joff,:) = data_all(nxm-whalo+1:nxm, 1:ny+joff,:,1) ! west
4486  data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,4) ! south
4487  data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,4) ! north
4488  data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,5) ! southeast
4489  data(1-whalo:0, 1-shalo:0,:) = data_all(nxm-whalo+1:nxm, nym-shalo+1:nym,:,1) ! southwest
4490  data(nx+1+ioff:nx+ehalo+ioff,ny+1+joff:ny+nhalo+joff,:) = data_all(1+ioff:ehalo+ioff, 1+joff:nhalo+joff,:,5) ! northeast
4491  data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nxm-whalo+1:nxm, ny+1+joff:ny+nhalo+joff,:,1) ! northwest
4492  case(3)
4493  data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,1) ! east
4494  data(1-whalo:0, 1:ny+joff,:) = data_all(nx-whalo+1:nx, 1:ny+joff,:,2) ! west
4495  data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,5) ! south
4496  data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,5) ! north
4497  data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, nym-shalo+1:nym,:,1) ! southeast
4498  data(1-whalo:0, 1-shalo:0,:) = data_all(nx-whalo+1:nx, ny-shalo+1:ny,:,4) ! southwest
4499  data(nx+1+ioff:nx+ehalo+ioff,ny+1+joff:ny+nhalo+joff,:) = data_all(1+ioff:ehalo+ioff,ny+1+joff:ny+nhalo+joff,:,1) ! northeast
4500  data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nx-whalo+1:nx, 1+joff:nhalo+joff,:,4) ! northwest
4501  case(4)
4502  data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,5) ! east
4503  data(1-whalo:0, 1:ny+joff,:) = data_all(nxm-whalo+1:nxm, ny+1:2*ny+joff,:,1) ! west
4504  data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,2) ! south
4505  data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,2) ! north
4506  data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,3) ! southeast
4507  data(1-whalo:0, 1-shalo:0,:) = data_all(nxm-whalo+1:nxm, ny-shalo+1:ny,:,1) ! southwest
4508  data(nx+1+ioff:nx+ehalo+ioff,ny+1+joff:ny+nhalo+joff,:) = data_all(1+ioff:ehalo+ioff,1+joff:nhalo+joff,:,3) ! northeast
4509  data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nxm-whalo+1:nxm, 1+joff:nhalo+joff,:,1) ! northwest
4510  case(5)
4511  data(nx+1+ioff:nx+ehalo+ioff, 1: ny+joff,:) = data_all(1+ioff:ehalo+ioff, ny+1:2*ny+joff,:,1) ! east
4512  data(1-whalo:0, 1:ny+joff,:) = data_all(nx-whalo+1:nx, 1:ny+joff,:,4) ! west
4513  data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,3) ! south
4514  data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,3) ! north
4515  data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,1) ! southeast
4516  data(1-whalo:0, 1-shalo:0,:) = data_all(nx-whalo+1:nx, ny-shalo+1:ny,:,2) ! southwest
4517  data(nx+1+ioff:nx+ehalo+ioff,ny+1+joff:ny+nhalo+joff,:) = data_all(1+ioff:ehalo+ioff,1+joff:nhalo+joff,:,1) ! northeast
4518  data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nx-whalo+1:nx, 1+joff:nhalo+joff,:,2) ! northwest
4519  end select
4520 
4521  end subroutine fill_five_tile_halo
4522 
4523  !#######################################################################################
4524  subroutine test_get_boundary(type)
4525  character(len=*), intent(in) :: type
4526 
4527  type(domain2D) :: domain, domain_nonsym
4528  integer :: ntiles, num_contact, npes_per_tile, ntile_per_pe, layout(2)
4529  integer :: n, l, isc, iec, jsc, jec, ism, iem, jsm, jem
4530  integer, allocatable, dimension(:) :: tile, ni, nj, pe_start, pe_end
4531  integer, allocatable, dimension(:,:) :: layout2D, global_indices
4532  real, allocatable, dimension(:,:,:) :: ebuffer, sbuffer, wbuffer, nbuffer
4533  real, allocatable, dimension(:,:,:) :: ebuffer1, sbuffer1, wbuffer1, nbuffer1
4534  real, allocatable, dimension(:,:,:) :: ebuffer2, sbuffer2, wbuffer2, nbuffer2
4535  real, allocatable, dimension(:,:,:) :: ebound, sbound, wbound, nbound
4536  real, allocatable, dimension(:,:,:) :: ebufferx, sbufferx, wbufferx, nbufferx
4537  real, allocatable, dimension(:,:,:) :: ebufferx1, sbufferx1, wbufferx1, nbufferx1
4538  real, allocatable, dimension(:,:,:) :: ebufferx2, sbufferx2, wbufferx2, nbufferx2
4539  real, allocatable, dimension(:,:,:) :: eboundx, sboundx, wboundx, nboundx
4540  real, allocatable, dimension(:,:,:) :: ebuffery, sbuffery, wbuffery, nbuffery
4541  real, allocatable, dimension(:,:,:) :: ebuffery1, sbuffery1, wbuffery1, nbuffery1
4542  real, allocatable, dimension(:,:,:) :: ebuffery2, sbuffery2, wbuffery2, nbuffery2
4543  real, allocatable, dimension(:,:,:) :: eboundy, sboundy, wboundy, nboundy
4544  real, allocatable, dimension(:,:,:,:) :: global_all, global1_all, global2_all
4545  real, allocatable, dimension(:,:,:,:) :: global, global1, global2
4546  real, allocatable, dimension(:,:,:,:) :: x, x1, x2, y, y1, y2
4547  real, allocatable, dimension(:,:) :: u_nonsym, v_nonsym
4548  logical :: folded_north = .false.
4549  logical :: is_torus = .false.
4550  integer :: nx_save, ny_save
4551 
4552  nx_save = nx
4553  ny_save = ny
4554 
4555  !--- check the type
4556  select case(type)
4557  case ( 'Four-Tile' ) !--- cyclic along both x- and y-direction.
4558  ntiles = 4
4559  num_contact = 8
4560  case ( 'Cubic-Grid' )
4561  ntiles = 6
4562  num_contact = 12
4563  nx = nx_cubic
4564  ny = nx
4565  case ( 'Folded-north' )
4566  folded_north = .true.
4567  ntiles = 1
4568  case ( 'torus' )
4569  is_torus = .true.
4570  ntiles = 1
4571  case default
4572  call mpp_error(fatal, 'TEST_MPP_DOMAINS: no such test: '//type)
4573  end select
4574 
4575  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
4576  allocate(ni(ntiles), nj(ntiles))
4577  ni(:) = nx; nj(:) = ny
4578  if( mod(npes, ntiles) == 0 ) then
4579  npes_per_tile = npes/ntiles
4580  write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
4581  '", each tile will be distributed over ', npes_per_tile, ' processors.'
4582  ntile_per_pe = 1
4583  allocate(tile(ntile_per_pe))
4584  tile = pe/npes_per_tile+1
4585  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
4586  do n = 1, ntiles
4587  pe_start(n) = (n-1)*npes_per_tile
4588  pe_end(n) = n*npes_per_tile-1
4589  end do
4590  else if ( mod(ntiles, npes) == 0 ) then
4591  ntile_per_pe = ntiles/npes
4592  write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
4593  '", there will be ', ntile_per_pe, ' tiles on each processor.'
4594  allocate(tile(ntile_per_pe))
4595  do n = 1, ntile_per_pe
4596  tile(n) = pe*ntile_per_pe + n
4597  end do
4598  do n = 1, ntiles
4599  pe_start(n) = (n-1)/ntile_per_pe
4600  pe_end(n) = pe_start(n)
4601  end do
4602  layout = 1
4603  else
4604  call mpp_error(note,'TEST_MPP_DOMAINS: npes should be multiple of ntiles or ' // &
4605  'ntiles should be multiple of npes. No test is done for '//trim(type) )
4606  return
4607  end if
4608 
4609  do n = 1, ntiles
4610  global_indices(:,n) = (/1,nx,1,ny/)
4611  layout2d(:,n) = layout
4612  end do
4613 
4614  select case(type)
4615  case("Four-Tile")
4616  call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
4617  layout2D, pe_start, pe_end, .true. )
4618  case("Cubic-Grid")
4619  call define_cubic_mosaic(type, domain, ni, nj, global_indices, layout2D, pe_start, pe_end )
4620  case("Folded-north")
4621  call mpp_define_domains((/1,nx,1,ny/), layout, domain, &
4622  xflags=cyclic_global_domain, yflags=fold_north_edge, &
4623  whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
4624  symmetry=.true., name='tripolar' )
4625  call mpp_define_domains((/1,nx,1,ny/), layout, domain_nonsym, &
4626  xflags=cyclic_global_domain, yflags=fold_north_edge, &
4627  whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
4628  symmetry=.false., name='tripolar' )
4629  case("torus")
4630  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
4631  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, &
4632  yflags=cyclic_global_domain, symmetry=.true., name=type)
4633  end select
4634 
4635  !--- Test the get_boundary of the data at C-cell center.
4636  allocate(global_all(1:nx+1,1:ny+1,nz, ntiles) )
4637  allocate(global(1:nx+1,1:ny+1,nz, ntile_per_pe) )
4638  global = 0
4639  do l = 1, ntiles
4640  do k = 1, nz
4641  do j = 1, ny+1
4642  do i = 1, nx+1
4643  global_all(i,j,k,l) = l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4644  end do
4645  end do
4646  end do
4647  end do
4648 
4649  do n = 1, ntile_per_pe
4650  global(:,:,:,n) = global_all(:,:,:,tile(n))
4651  end do
4652 
4653  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
4654  call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
4655  allocate( x(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4656  allocate( x1(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4657  allocate( x2(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4658  x = 0.
4659  x(isc:iec+1,jsc:jec+1,:,:) = global(isc:iec+1,jsc:jec+1,:,:)
4660  x1 = x; x2 = x*10
4661 
4662  !--- buffer allocation
4663  allocate(ebuffer(jsc:jec+1, nz, ntile_per_pe), wbuffer(jsc:jec+1, nz, ntile_per_pe))
4664  allocate(sbuffer(isc:iec+1, nz, ntile_per_pe), nbuffer(isc:iec+1, nz, ntile_per_pe))
4665  allocate(ebuffer1(jsc:jec+1, nz, ntile_per_pe), wbuffer1(jsc:jec+1, nz, ntile_per_pe))
4666  allocate(sbuffer1(isc:iec+1, nz, ntile_per_pe), nbuffer1(isc:iec+1, nz, ntile_per_pe))
4667  allocate(ebuffer2(jsc:jec+1, nz, ntile_per_pe), wbuffer2(jsc:jec+1, nz, ntile_per_pe))
4668  allocate(sbuffer2(isc:iec+1, nz, ntile_per_pe), nbuffer2(isc:iec+1, nz, ntile_per_pe))
4669  allocate(ebound(jsc:jec+1, nz, ntile_per_pe), wbound(jsc:jec+1, nz, ntile_per_pe))
4670  allocate(sbound(isc:iec+1, nz, ntile_per_pe), nbound(isc:iec+1, nz, ntile_per_pe))
4671  ebound = 0; ebuffer = 0; ebuffer1 = 0; ebuffer2 = 0
4672  sbound = 0; sbuffer = 0; sbuffer1 = 0; sbuffer2 = 0
4673  wbound = 0; wbuffer = 0; wbuffer1 = 0; wbuffer2 = 0
4674  nbound = 0; nbuffer = 0; nbuffer1 = 0; nbuffer2 = 0
4675 
4676  do n = 1, ntile_per_pe
4677  if(folded_north .or. is_torus ) then
4678  call mpp_get_boundary(x(:,:,:,n), domain, sbuffer=sbuffer(:,:,n), wbuffer=wbuffer(:,:,n), &
4679  position=corner, tile_count=n )
4680  else
4681  call mpp_get_boundary(x(:,:,:,n), domain, ebuffer=ebuffer(:,:,n), sbuffer=sbuffer(:,:,n), wbuffer=wbuffer(:,:,n), &
4682  nbuffer=nbuffer(:,:,n), position=corner, tile_count=n )
4683  endif
4684  end do
4685 
4686  !--- multiple variable
4687  do n = 1, ntile_per_pe
4688  if(folded_north .or. is_torus) then
4689  call mpp_get_boundary(x1(:,:,:,n), domain, sbuffer=sbuffer1(:,:,n), wbuffer=wbuffer1(:,:,n), &
4690  position=corner, tile_count=n, complete = .false. )
4691  call mpp_get_boundary(x2(:,:,:,n), domain, sbuffer=sbuffer2(:,:,n), wbuffer=wbuffer2(:,:,n), &
4692  position=corner, tile_count=n, complete = .true. )
4693  else
4694  call mpp_get_boundary(x1(:,:,:,n), domain, ebuffer=ebuffer1(:,:,n), sbuffer=sbuffer1(:,:,n), wbuffer=wbuffer1(:,:,n), &
4695  nbuffer=nbuffer1(:,:,n), position=corner, tile_count=n, complete = .false. )
4696  call mpp_get_boundary(x2(:,:,:,n), domain, ebuffer=ebuffer2(:,:,n), sbuffer=sbuffer2(:,:,n), wbuffer=wbuffer2(:,:,n), &
4697  nbuffer=nbuffer2(:,:,n), position=corner, tile_count=n, complete = .true. )
4698  endif
4699  end do
4700 
4701  !--- compare the buffer.
4702  select case(type)
4703  case("Four-Tile")
4704  do n = 1, ntile_per_pe
4705  call fill_four_tile_bound(global_all, isc, iec, jsc, jec, 1, 1, &
4706  tile(n), ebound(:,:,n), sbound(:,:,n), wbound(:,:,n), nbound(:,:,n) )
4707  end do
4708  case("Cubic-Grid")
4709  do n = 1, ntile_per_pe
4710  call fill_cubic_grid_bound(global_all, global_all, isc, iec, jsc, jec, 1, 1, &
4711  tile(n), 1, 1, ebound(:,:,n), sbound(:,:,n), wbound(:,:,n), nbound(:,:,n) )
4712  end do
4713  case("Folded-north")
4714  !---- folded line update
4715  global_all(nx/2+2:nx, ny+1,:,1) = global_all(nx/2:2:-1, ny+1,:,1)
4716  do n = 1, ntile_per_pe
4717  call fill_folded_north_bound(global_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
4718  tile(n), sbound(:,:,n), wbound(:,:,n) )
4719  end do
4720  case("torus")
4721  do n = 1, ntile_per_pe
4722  call fill_torus_bound(global_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
4723  tile(n), sbound(:,:,n), wbound(:,:,n) )
4724  end do
4725  end select
4726 
4727  if(.not. folded_north .AND. .not. is_torus) then
4728  call compare_checksums( ebound, ebuffer(:,:,:), "east bound of "//trim(type) )
4729  call compare_checksums( nbound, nbuffer(:,:,:), "north bound of "//trim(type) )
4730  call compare_checksums( ebound, ebuffer1(:,:,:), "east bound of "//trim(type)//" X1" )
4731  call compare_checksums( nbound, nbuffer1(:,:,:), "north bound of "//trim(type)//" X1" )
4732  call compare_checksums( ebound*10, ebuffer2(:,:,:), "east bound of "//trim(type)//" X2" )
4733  call compare_checksums( nbound*10, nbuffer2(:,:,:), "north bound of "//trim(type)//" X2" )
4734  endif
4735  call compare_checksums( sbound, sbuffer(:,:,:), "south bound of "//trim(type) )
4736  call compare_checksums( wbound, wbuffer(:,:,:), "west bound of "//trim(type) )
4737  call compare_checksums( sbound, sbuffer1(:,:,:), "south bound of "//trim(type)//" X1" )
4738  call compare_checksums( wbound, wbuffer1(:,:,:), "west bound of "//trim(type)//" X1" )
4739  call compare_checksums( sbound*10, sbuffer2(:,:,:), "south bound of "//trim(type)//" X2" )
4740  call compare_checksums( wbound*10, wbuffer2(:,:,:), "west bound of "//trim(type)//" X2" )
4741 
4742  !--- release memory
4743  deallocate(global, global_all, x, x1, x2)
4744  deallocate(ebuffer, sbuffer, wbuffer, nbuffer)
4745  deallocate(ebuffer1, sbuffer1, wbuffer1, nbuffer1)
4746  deallocate(ebuffer2, sbuffer2, wbuffer2, nbuffer2)
4747  deallocate(ebound, sbound, wbound, nbound )
4748 
4749  !-------------------------------------------------------------------------------------------
4750  !
4751  ! Test SCALAR_PAIR BGRID
4752  !
4753  !-------------------------------------------------------------------------------------------
4754  allocate(global1_all(1:nx+1,1:ny+1,nz, ntiles) )
4755  allocate(global2_all(1:nx+1,1:ny+1,nz, ntiles) )
4756  allocate(global1(1:nx+1,1:ny+1,nz, ntile_per_pe) )
4757  allocate(global2(1:nx+1,1:ny+1,nz, ntile_per_pe) )
4758  do l = 1, ntiles
4759  do k = 1, nz
4760  do j = 1, ny+1
4761  do i = 1, nx+1
4762  global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4763  global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4764  end do
4765  end do
4766  end do
4767  end do
4768 
4769  do n = 1, ntile_per_pe
4770  global1(:,:,:,n) = global1_all(:,:,:,tile(n))
4771  global2(:,:,:,n) = global2_all(:,:,:,tile(n))
4772  end do
4773  allocate( x(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4774  allocate( x1(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4775  allocate( x2(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4776  allocate( y(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4777  allocate( y1(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4778  allocate( y2(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
4779  x = 0.; y = 0
4780  if( trim(type) == "Folded-north" ) then
4781  x(isc+1:iec+1,jsc+1:jec+1,:,:) = global1(isc+1:iec+1,jsc+1:jec+1,:,:)
4782  y(isc+1:iec+1,jsc+1:jec+1,:,:) = global2(isc+1:iec+1,jsc+1:jec+1,:,:)
4783  else
4784  x(isc:iec+1,jsc:jec+1,:,:) = global1(isc:iec+1,jsc:jec+1,:,:)
4785  y(isc:iec+1,jsc:jec+1,:,:) = global2(isc:iec+1,jsc:jec+1,:,:)
4786  endif
4787  x1 = x; x2 = x*10
4788  y1 = y; y2 = y*10
4789 
4790  !--- buffer allocation
4791  allocate(ebufferx(jsc:jec+1, nz, ntile_per_pe), wbufferx(jsc:jec+1, nz, ntile_per_pe))
4792  allocate(sbufferx(isc:iec+1, nz, ntile_per_pe), nbufferx(isc:iec+1, nz, ntile_per_pe))
4793  allocate(ebufferx1(jsc:jec+1, nz, ntile_per_pe), wbufferx1(jsc:jec+1, nz, ntile_per_pe))
4794  allocate(sbufferx1(isc:iec+1, nz, ntile_per_pe), nbufferx1(isc:iec+1, nz, ntile_per_pe))
4795  allocate(ebufferx2(jsc:jec+1, nz, ntile_per_pe), wbufferx2(jsc:jec+1, nz, ntile_per_pe))
4796  allocate(sbufferx2(isc:iec+1, nz, ntile_per_pe), nbufferx2(isc:iec+1, nz, ntile_per_pe))
4797  allocate(eboundx(jsc:jec+1, nz, ntile_per_pe), wboundx(jsc:jec+1, nz, ntile_per_pe))
4798  allocate(sboundx(isc:iec+1, nz, ntile_per_pe), nboundx(isc:iec+1, nz, ntile_per_pe))
4799  allocate(ebuffery(jsc:jec+1, nz, ntile_per_pe), wbuffery(jsc:jec+1, nz, ntile_per_pe))
4800  allocate(sbuffery(isc:iec+1, nz, ntile_per_pe), nbuffery(isc:iec+1, nz, ntile_per_pe))
4801  allocate(ebuffery1(jsc:jec+1, nz, ntile_per_pe), wbuffery1(jsc:jec+1, nz, ntile_per_pe))
4802  allocate(sbuffery1(isc:iec+1, nz, ntile_per_pe), nbuffery1(isc:iec+1, nz, ntile_per_pe))
4803  allocate(ebuffery2(jsc:jec+1, nz, ntile_per_pe), wbuffery2(jsc:jec+1, nz, ntile_per_pe))
4804  allocate(sbuffery2(isc:iec+1, nz, ntile_per_pe), nbuffery2(isc:iec+1, nz, ntile_per_pe))
4805  allocate(eboundy(jsc:jec+1, nz, ntile_per_pe), wboundy(jsc:jec+1, nz, ntile_per_pe))
4806  allocate(sboundy(isc:iec+1, nz, ntile_per_pe), nboundy(isc:iec+1, nz, ntile_per_pe))
4807  eboundx = 0; ebufferx = 0; ebufferx1 = 0; ebufferx2 = 0
4808  sboundx = 0; sbufferx = 0; sbufferx1 = 0; sbufferx2 = 0
4809  wboundx = 0; wbufferx = 0; wbufferx1 = 0; wbufferx2 = 0
4810  nboundx = 0; nbufferx = 0; nbufferx1 = 0; nbufferx2 = 0
4811  eboundy = 0; ebuffery = 0; ebuffery1 = 0; ebuffery2 = 0
4812  sboundy = 0; sbuffery = 0; sbuffery1 = 0; sbuffery2 = 0
4813  wboundy = 0; wbuffery = 0; wbuffery1 = 0; wbuffery2 = 0
4814  nboundy = 0; nbuffery = 0; nbuffery1 = 0; nbuffery2 = 0
4815 
4816 
4817  do n = 1, ntile_per_pe
4818  if(folded_north .or. is_torus) then
4819  call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, sbufferx=sbufferx(:,:,n), wbufferx=wbufferx(:,:,n), &
4820  sbuffery=sbuffery(:,:,n), wbuffery=wbuffery(:,:,n), gridtype=bgrid_ne, tile_count=n, flags = scalar_pair )
4821  else
4822  call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, ebufferx=ebufferx(:,:,n), sbufferx=sbufferx(:,:,n), &
4823  wbufferx=wbufferx(:,:,n), nbufferx=nbufferx(:,:,n), ebuffery=ebuffery(:,:,n), &
4824  sbuffery=sbuffery(:,:,n), wbuffery=wbuffery(:,:,n), nbuffery=nbuffery(:,:,n), &
4825  gridtype=bgrid_ne, tile_count=n, flags = scalar_pair )
4826  endif
4827  end do
4828 
4829  do n = 1, ntile_per_pe
4830  if(folded_north .or. is_torus) then
4831  call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, sbufferx=sbufferx1(:,:,n), wbufferx=wbufferx1(:,:,n), &
4832  sbuffery=sbuffery1(:,:,n), wbuffery=wbuffery1(:,:,n), &
4833  gridtype=bgrid_ne, tile_count=n, flags = scalar_pair, complete = .false. )
4834  call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, sbufferx=sbufferx2(:,:,n), wbufferx=wbufferx2(:,:,n), &
4835  sbuffery=sbuffery2(:,:,n), wbuffery=wbuffery2(:,:,n), &
4836  gridtype=bgrid_ne, tile_count=n, flags = scalar_pair, complete = .true. )
4837  else
4838  call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, ebufferx=ebufferx1(:,:,n), sbufferx=sbufferx1(:,:,n), &
4839  wbufferx=wbufferx1(:,:,n), nbufferx=nbufferx1(:,:,n), ebuffery=ebuffery1(:,:,n), &
4840  sbuffery=sbuffery1(:,:,n), wbuffery=wbuffery1(:,:,n), nbuffery=nbuffery1(:,:,n), &
4841  gridtype=bgrid_ne, tile_count=n, flags = scalar_pair, complete = .false. )
4842  call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, ebufferx=ebufferx2(:,:,n), sbufferx=sbufferx2(:,:,n), &
4843  wbufferx=wbufferx2(:,:,n), nbufferx=nbufferx2(:,:,n), ebuffery=ebuffery2(:,:,n), &
4844  sbuffery=sbuffery2(:,:,n), wbuffery=wbuffery2(:,:,n), nbuffery=nbuffery2(:,:,n), &
4845  gridtype=bgrid_ne, tile_count=n, flags = scalar_pair, complete = .true. )
4846  endif
4847  end do
4848 
4849  !--- compare the buffer.
4850  select case(type)
4851  case("Four-Tile")
4852  do n = 1, ntile_per_pe
4853  call fill_four_tile_bound(global1_all, isc, iec, jsc, jec, 1, 1, &
4854  tile(n), eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
4855  call fill_four_tile_bound(global2_all, isc, iec, jsc, jec, 1, 1, &
4856  tile(n), eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
4857  end do
4858  case("Cubic-Grid")
4859  do n = 1, ntile_per_pe
4860  call fill_cubic_grid_bound(global1_all, global2_all, isc, iec, jsc, jec, 1, 1, &
4861  tile(n), 1, 1, eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
4862  call fill_cubic_grid_bound(global2_all, global1_all, isc, iec, jsc, jec, 1, 1, &
4863  tile(n), 1, 1, eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
4864  end do
4865  case("Folded-north")
4866  global1_all(nx/2+2:nx, ny+1,:,1) = global1_all(nx/2:2:-1, ny+1,:,1)
4867  global2_all(nx/2+2:nx, ny+1,:,1) = global2_all(nx/2:2:-1, ny+1,:,1)
4868  do n = 1, ntile_per_pe
4869  call fill_folded_north_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
4870  tile(n), sboundx(:,:,n), wboundx(:,:,n) )
4871  call fill_folded_north_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
4872  tile(n), sboundy(:,:,n), wboundy(:,:,n) )
4873  end do
4874  case("torus")
4875  do n = 1, ntile_per_pe
4876  call fill_torus_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
4877  tile(n), sboundx(:,:,n), wboundx(:,:,n) )
4878  call fill_torus_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
4879  tile(n), sboundy(:,:,n), wboundy(:,:,n) )
4880  end do
4881  end select
4882 
4883  if(.not. folded_north .AND. .not. is_torus ) then
4884  call compare_checksums( eboundx, ebufferx(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" X" )
4885  call compare_checksums( nboundx, nbufferx(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" X" )
4886  call compare_checksums( eboundy, ebuffery(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" Y" )
4887  call compare_checksums( nboundy, nbuffery(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" Y" )
4888  call compare_checksums( eboundx, ebufferx1(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" X1" )
4889  call compare_checksums( nboundx, nbufferx1(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" X1" )
4890  call compare_checksums( eboundy, ebuffery1(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" Y1" )
4891  call compare_checksums( nboundy, nbuffery1(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" Y1" )
4892  endif
4893 
4894  call compare_checksums( sboundx, sbufferx(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" X" )
4895  call compare_checksums( wboundx, wbufferx(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" X" )
4896  call compare_checksums( sboundy, sbuffery(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" Y" )
4897  call compare_checksums( wboundy, wbuffery(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" Y" )
4898  call compare_checksums( sboundx, sbufferx1(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" X1" )
4899  call compare_checksums( wboundx, wbufferx1(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" X1" )
4900  call compare_checksums( sboundy, sbuffery1(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" Y1" )
4901  call compare_checksums( wboundy, wbuffery1(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" Y1" )
4902 
4903  select case(type)
4904  case("Four-Tile")
4905  do n = 1, ntile_per_pe
4906  call fill_four_tile_bound(global1_all*10, isc, iec, jsc, jec, 1, 1, &
4907  tile(n), eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
4908  call fill_four_tile_bound(global2_all*10, isc, iec, jsc, jec, 1, 1, &
4909  tile(n), eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
4910  end do
4911  case("Cubic-Grid")
4912  do n = 1, ntile_per_pe
4913  call fill_cubic_grid_bound(global1_all*10, global2_all*10, isc, iec, jsc, jec, 1, 1, &
4914  tile(n), 1, 1, eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
4915  call fill_cubic_grid_bound(global2_all*10, global1_all*10, isc, iec, jsc, jec, 1, 1, &
4916  tile(n), 1, 1, eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
4917  end do
4918  case("Folded-north")
4919  do n = 1, ntile_per_pe
4920  call fill_folded_north_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
4921  tile(n), sboundx(:,:,n), wboundx(:,:,n) )
4922  call fill_folded_north_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
4923  tile(n), sboundy(:,:,n), wboundy(:,:,n) )
4924  end do
4925  case("torus")
4926  do n = 1, ntile_per_pe
4927  call fill_torus_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
4928  tile(n), sboundx(:,:,n), wboundx(:,:,n) )
4929  call fill_torus_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
4930  tile(n), sboundy(:,:,n), wboundy(:,:,n) )
4931  end do
4932  end select
4933 
4934  if(.not. folded_north .AND. .not. is_torus ) then
4935  call compare_checksums( eboundx, ebufferx2(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" X2" )
4936  call compare_checksums( nboundx, nbufferx2(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" X2" )
4937  call compare_checksums( eboundy, ebuffery2(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" Y2" )
4938  call compare_checksums( nboundy, nbuffery2(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" Y2" )
4939  endif
4940  call compare_checksums( sboundx, sbufferx2(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" X2" )
4941  call compare_checksums( wboundx, wbufferx2(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" X2" )
4942  call compare_checksums( sboundy, sbuffery2(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" Y2" )
4943  call compare_checksums( wboundy, wbuffery2(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" Y2" )
4944 
4945  !-------------------------------------------------------------------------------------------
4946  !
4947  ! Test 2-D Vector BGRID
4948  !
4949  !-------------------------------------------------------------------------------------------
4950  do l = 1, ntiles
4951  do k = 1, nz
4952  do j = 1, ny+1
4953  do i = 1, nx+1
4954  global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4955  global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
4956  end do
4957  end do
4958  end do
4959  end do
4960 
4961  x = 0.; y = 0
4962  eboundx = 0; ebufferx = 0; ebufferx1 = 0; ebufferx2 = 0
4963  sboundx = 0; sbufferx = 0; sbufferx1 = 0; sbufferx2 = 0
4964  wboundx = 0; wbufferx = 0; wbufferx1 = 0; wbufferx2 = 0
4965  nboundx = 0; nbufferx = 0; nbufferx1 = 0; nbufferx2 = 0
4966  eboundy = 0; ebuffery = 0; ebuffery1 = 0; ebuffery2 = 0
4967  sboundy = 0; sbuffery = 0; sbuffery1 = 0; sbuffery2 = 0
4968  wboundy = 0; wbuffery = 0; wbuffery1 = 0; wbuffery2 = 0
4969  nboundy = 0; nbuffery = 0; nbuffery1 = 0; nbuffery2 = 0
4970 
4971  x(isc:iec+1,jsc:jec+1,1,:) = global1(isc:iec+1,jsc:jec+1,1,:)
4972  y(isc:iec+1,jsc:jec+1,1,:) = global2(isc:iec+1,jsc:jec+1,1,:)
4973 
4974  do n = 1, ntile_per_pe
4975  if(folded_north .or. is_torus ) then
4976  call mpp_get_boundary(x(:,:,1,n), y(:,:,1,n), domain, sbufferx=sbufferx(:,1,n), wbufferx=wbufferx(:,1,n), &
4977  sbuffery=sbuffery(:,1,n), wbuffery=wbuffery(:,1,n), gridtype=bgrid_ne, tile_count=n)
4978 
4979  else
4980  call mpp_get_boundary(x(:,:,1,n), y(:,:,1,n), domain, ebufferx=ebufferx(:,1,n), sbufferx=sbufferx(:,1,n), &
4981  wbufferx=wbufferx(:,1,n), nbufferx=nbufferx(:,1,n), ebuffery=ebuffery(:,1,n), &
4982  sbuffery=sbuffery(:,1,n), wbuffery=wbuffery(:,1,n), nbuffery=nbuffery(:,1,n), &
4983  gridtype=bgrid_ne, tile_count=n)
4984  endif
4985  end do
4986 
4987  if(folded_north) then
4988  allocate(u_nonsym(ism:iem,jsm:jem), v_nonsym(ism:iem,jsm:jem))
4989  u_nonsym = 0.0; v_nonsym = 0.0
4990  u_nonsym(isc:iec,jsc:jec) = global1(isc+1:iec+1,jsc+1:jec+1,1,1)
4991  v_nonsym(isc:iec,jsc:jec) = global2(isc+1:iec+1,jsc+1:jec+1,1,1)
4992  call mpp_update_domains(u_nonsym, v_nonsym, domain_nonsym, gridtype=bgrid_ne)
4993  !--- comparing boundary data
4994  do i = isc,iec+1
4995  if(i==1) cycle
4996  if(sbufferx(i,1,1) .NE. u_nonsym(i-1,jsc-1)) then
4997  print*,"pe ", mpp_pe(), i, jsc-1, sbufferx(i,1,1), u_nonsym(i-1,jsc-1)
4998  call mpp_error(fatal, "test_get_boundary: mismatch of sbufferx")
4999  endif
5000  enddo
5001  call mpp_error(note,"test_get_boundary: reproduce non-symmetric halo update for sbufferx")
5002 
5003  do i = isc,iec+1
5004  if(i==1) cycle
5005  if(sbuffery(i,1,1) .NE. v_nonsym(i-1,jsc-1)) then
5006  print*,"pe ", mpp_pe(), i, jsc-1, sbufferx(i,1,1), v_nonsym(i-1,jsc-1)
5007  call mpp_error(fatal, "test_get_boundary: mismatch of sbuffery")
5008  endif
5009  enddo
5010  call mpp_error(note,"test_get_boundary: reproduce non-symmetric halo update for sbuffery")
5011 
5012  do j = jsc,jec+1
5013  if(j == 1) cycle
5014  if(wbufferx(j,1,1) .NE. u_nonsym(isc-1,j-1)) then
5015  print*,"pe ", mpp_pe(), isc-1, j, wbufferx(j,1,1), u_nonsym(isc-1,j-1)
5016  call mpp_error(fatal, "test_get_boundary: mismatch of wbufferx")
5017  endif
5018  enddo
5019  call mpp_error(note,"test_get_boundary: reproduce non-symmetric halo update for wbufferx")
5020 
5021  do j = jsc,jec+1
5022  if(j==1) cycle
5023  if(wbuffery(j,1,1) .NE. v_nonsym(isc-1,j-1)) then
5024  print*,"pe ", mpp_pe(), isc-1, j, wbuffery(j,1,1), v_nonsym(isc-1,j-1)
5025  call mpp_error(fatal, "test_get_boundary: mismatch of wbuffery")
5026  endif
5027  enddo
5028  call mpp_error(note,"test_get_boundary: reproduce non-symmetric halo update for wbuffery")
5029 
5030  deallocate(u_nonsym, v_nonsym)
5031 
5032  endif
5033 
5034  !--- compare the buffer.
5035  select case(type)
5036  case("Four-Tile")
5037  do n = 1, ntile_per_pe
5038  call fill_four_tile_bound(global1_all, isc, iec, jsc, jec, 1, 1, &
5039  tile(n), eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
5040  call fill_four_tile_bound(global2_all, isc, iec, jsc, jec, 1, 1, &
5041  tile(n), eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
5042  end do
5043  case("Cubic-Grid")
5044  do n = 1, ntile_per_pe
5045  call fill_cubic_grid_bound(global1_all, global2_all, isc, iec, jsc, jec, 1, 1, &
5046  tile(n), 1, -1, eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
5047  call fill_cubic_grid_bound(global2_all, global1_all, isc, iec, jsc, jec, 1, 1, &
5048  tile(n), -1, 1, eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
5049  end do
5050  case("Folded-north")
5051  global1_all(nx/2+2:nx, ny+1,:,1) = -global1_all(nx/2:2:-1, ny+1,:,1)
5052  global2_all(nx/2+2:nx, ny+1,:,1) = -global2_all(nx/2:2:-1, ny+1,:,1)
5053  global1_all(1, ny+1,:,1) = 0
5054  global2_all(1, ny+1,:,1) = 0
5055  global1_all(nx/2+1, ny+1,:,1) = 0
5056  global2_all(nx/2+1, ny+1,:,1) = 0
5057  global1_all(nx+1, ny+1,:,1) = 0
5058  global2_all(nx+1, ny+1,:,1) = 0
5059 
5060 
5061  do n = 1, ntile_per_pe
5062  call fill_folded_north_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
5063  tile(n), sboundx(:,:,n), wboundx(:,:,n) )
5064  call fill_folded_north_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
5065  tile(n), sboundy(:,:,n), wboundy(:,:,n) )
5066  ! set wboundx and wbouny to zero at pole (i=1, nx/2+1, nx+1)
5067 ! if( jec == ny ) then
5068 ! if( isc == 1 .OR. isc == nx/2+1 .OR. isc == nx+1 ) then
5069 ! wboundx(jec+1,:,n) = 0
5070 ! wboundy(jec+1,:,n) = 0
5071 ! endif
5072 ! endif
5073  end do
5074  case("torus")
5075  do n = 1, ntile_per_pe
5076  call fill_torus_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
5077  tile(n), sboundx(:,:,n), wboundx(:,:,n) )
5078  call fill_torus_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
5079  tile(n), sboundy(:,:,n), wboundy(:,:,n) )
5080  enddo
5081  end select
5082 
5083  if(.not. folded_north .AND. .not. is_torus ) then
5084  call compare_checksums( eboundx(:,1:1,:), ebufferx(:,1:1,:), "east bound of 2-D BGRID " //trim(type)//" X" )
5085  call compare_checksums( nboundx(:,1:1,:), nbufferx(:,1:1,:), "north bound of 2-D BGRID "//trim(type)//" X" )
5086  call compare_checksums( eboundy(:,1:1,:), ebuffery(:,1:1,:), "east bound of 2-D BGRID " //trim(type)//" Y" )
5087  call compare_checksums( nboundy(:,1:1,:), nbuffery(:,1:1,:), "north bound of 2-D BGRID "//trim(type)//" Y" )
5088  endif
5089 
5090  call compare_checksums( sboundx(:,1:1,:), sbufferx(:,1:1,:), "south bound of 2-D BGRID "//trim(type)//" X" )
5091  call compare_checksums( wboundx(:,1:1,:), wbufferx(:,1:1,:), "west bound of 2-D BGRID " //trim(type)//" X" )
5092  call compare_checksums( sboundy(:,1:1,:), sbuffery(:,1:1,:), "south bound of 2-D BGRID "//trim(type)//" Y" )
5093  call compare_checksums( wboundy(:,1:1,:), wbuffery(:,1:1,:), "west bound of 2-D BGRID " //trim(type)//" Y" )
5094 
5095 
5096  !--- release memory
5097  deallocate(global1, global1_all, global2, global2_all)
5098  deallocate(x, y, x1, y1, x2, y2)
5099  deallocate(ebufferx, sbufferx, wbufferx, nbufferx)
5100  deallocate(ebufferx1, sbufferx1, wbufferx1, nbufferx1)
5101  deallocate(ebufferx2, sbufferx2, wbufferx2, nbufferx2)
5102  deallocate(ebuffery, sbuffery, wbuffery, nbuffery)
5103  deallocate(ebuffery1, sbuffery1, wbuffery1, nbuffery1)
5104  deallocate(ebuffery2, sbuffery2, wbuffery2, nbuffery2)
5105  deallocate(eboundx, sboundx, wboundx, nboundx )
5106  deallocate(eboundy, sboundy, wboundy, nboundy )
5107 
5108  !-------------------------------------------------------------------------------------------
5109  !
5110  ! Test VECTOR CGRID
5111  !
5112  !-------------------------------------------------------------------------------------------
5113  allocate(global1_all(1:nx+1,1:ny, nz, ntiles) )
5114  allocate(global2_all(1:nx, 1:ny+1,nz, ntiles) )
5115  allocate(global1(1:nx+1,1:ny, nz, ntile_per_pe) )
5116  allocate(global2(1:nx, 1:ny+1,nz, ntile_per_pe) )
5117  do l = 1, ntiles
5118  do k = 1, nz
5119  do j = 1, ny
5120  do i = 1, nx+1
5121  global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
5122  end do
5123  end do
5124  do j = 1, ny+1
5125  do i = 1, nx
5126  global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
5127  end do
5128  end do
5129  end do
5130  end do
5131 
5132  do n = 1, ntile_per_pe
5133  global1(:,:,:,n) = global1_all(:,:,:,tile(n))
5134  global2(:,:,:,n) = global2_all(:,:,:,tile(n))
5135  end do
5136  allocate( x(ism:iem+1,jsm:jem, nz, ntile_per_pe) )
5137  allocate( x1(ism:iem+1,jsm:jem, nz, ntile_per_pe) )
5138  allocate( x2(ism:iem+1,jsm:jem, nz, ntile_per_pe) )
5139  allocate( y(ism:iem, jsm:jem+1,nz, ntile_per_pe) )
5140  allocate( y1(ism:iem, jsm:jem+1,nz, ntile_per_pe) )
5141  allocate( y2(ism:iem, jsm:jem+1,nz, ntile_per_pe) )
5142  x = 0.; y = 0
5143  x(isc:iec+1,jsc:jec, :,:) = global1(isc:iec+1,jsc:jec, :,:)
5144  y(isc:iec, jsc:jec+1,:,:) = global2(isc:iec, jsc:jec+1,:,:)
5145  x1 = x; x2 = x*10
5146  y1 = y; y2 = y*10
5147 
5148  !--- buffer allocation
5149  allocate(ebufferx(jec-jsc+1, nz, ntile_per_pe), wbufferx(jec-jsc+1, nz, ntile_per_pe))
5150  allocate(sbufferx(iec-isc+2, nz, ntile_per_pe), nbufferx(iec-isc+2, nz, ntile_per_pe))
5151  allocate(ebufferx1(jec-jsc+1, nz, ntile_per_pe), wbufferx1(jec-jsc+1, nz, ntile_per_pe))
5152  allocate(sbufferx1(iec-isc+2, nz, ntile_per_pe), nbufferx1(iec-isc+2, nz, ntile_per_pe))
5153  allocate(ebufferx2(jec-jsc+1, nz, ntile_per_pe), wbufferx2(jec-jsc+1, nz, ntile_per_pe))
5154  allocate(sbufferx2(iec-isc+2, nz, ntile_per_pe), nbufferx2(iec-isc+2, nz, ntile_per_pe))
5155  allocate(ebuffery(jec-jsc+2, nz, ntile_per_pe), wbuffery(jec-jsc+2, nz, ntile_per_pe))
5156  allocate(sbuffery(iec-isc+1, nz, ntile_per_pe), nbuffery(iec-isc+1, nz, ntile_per_pe))
5157  allocate(ebuffery1(jec-jsc+2, nz, ntile_per_pe), wbuffery1(jec-jsc+2, nz, ntile_per_pe))
5158  allocate(sbuffery1(iec-isc+1, nz, ntile_per_pe), nbuffery1(iec-isc+1, nz, ntile_per_pe))
5159  allocate(ebuffery2(jec-jsc+2, nz, ntile_per_pe), wbuffery2(jec-jsc+2, nz, ntile_per_pe))
5160  allocate(sbuffery2(iec-isc+1, nz, ntile_per_pe), nbuffery2(iec-isc+1, nz, ntile_per_pe))
5161  allocate(eboundx(jec-jsc+1, nz, ntile_per_pe), wboundx(jec-jsc+1, nz, ntile_per_pe))
5162  allocate(sboundy(iec-isc+1, nz, ntile_per_pe), nboundy(iec-isc+1, nz, ntile_per_pe))
5163  eboundx = 0; ebufferx = 0; ebufferx1 = 0; ebufferx2 = 0
5164  wboundx = 0; wbufferx = 0; wbufferx1 = 0; wbufferx2 = 0
5165  sboundy = 0; sbuffery = 0; sbuffery1 = 0; sbuffery2 = 0
5166  nboundy = 0; nbuffery = 0; nbuffery1 = 0; nbuffery2 = 0
5167 
5168 
5169  do n = 1, ntile_per_pe
5170  if(folded_north .or. is_torus) then
5171  call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, wbufferx=wbufferx(:,:,n), &
5172  sbuffery=sbuffery(:,:,n), gridtype=cgrid_ne, tile_count=n )
5173  else
5174  call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, ebufferx=ebufferx(:,:,n), wbufferx=wbufferx(:,:,n), &
5175  sbuffery=sbuffery(:,:,n), nbuffery=nbuffery(:,:,n), gridtype=cgrid_ne, tile_count=n )
5176  endif
5177  end do
5178 
5179  do n = 1, ntile_per_pe
5180  if( folded_north .or. is_torus ) then
5181  call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, wbufferx=wbufferx1(:,:,n), &
5182  sbuffery=sbuffery1(:,:,n), gridtype=cgrid_ne, tile_count=n, &
5183  complete = .false. )
5184  call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, wbufferx=wbufferx2(:,:,n), &
5185  sbuffery=sbuffery2(:,:,n), gridtype=cgrid_ne, tile_count=n, &
5186  complete = .true. )
5187  else
5188  call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, ebufferx=ebufferx1(:,:,n), wbufferx=wbufferx1(:,:,n), &
5189  sbuffery=sbuffery1(:,:,n), nbuffery=nbuffery1(:,:,n), gridtype=cgrid_ne, tile_count=n, &
5190  complete = .false. )
5191  call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, ebufferx=ebufferx2(:,:,n), wbufferx=wbufferx2(:,:,n), &
5192  sbuffery=sbuffery2(:,:,n), nbuffery=nbuffery2(:,:,n), gridtype=cgrid_ne, tile_count=n, &
5193  complete = .true. )
5194  endif
5195  end do
5196 
5197  !--- compare the buffer.
5198  select case(type)
5199  case("Four-Tile")
5200  do n = 1, ntile_per_pe
5201  call fill_four_tile_bound(global1_all, isc, iec, jsc, jec, 1, 0, &
5202  tile(n), ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
5203  call fill_four_tile_bound(global2_all, isc, iec, jsc, jec, 0, 1, &
5204  tile(n), sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
5205  end do
5206  case("Cubic-Grid")
5207  do n = 1, ntile_per_pe
5208  call fill_cubic_grid_bound(global1_all, global2_all, isc, iec, jsc, jec, 1, 0, &
5209  tile(n), 1, -1, ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
5210  call fill_cubic_grid_bound(global2_all, global1_all, isc, iec, jsc, jec, 0, 1, &
5211  tile(n), -1, 1, sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
5212  end do
5213  case("Folded-north")
5214  do n = 1, ntile_per_pe
5215  call fill_folded_north_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 0, &
5216  tile(n), wbound=wboundx(:,:,n) )
5217  call fill_folded_north_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 0, 1, &
5218  tile(n), sbound=sboundy(:,:,n) )
5219  end do
5220  case("torus")
5221  do n = 1, ntile_per_pe
5222  call fill_torus_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 0, &
5223  tile(n), wbound=wboundx(:,:,n) )
5224  call fill_torus_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 0, 1, &
5225  tile(n), sbound=sboundy(:,:,n) )
5226  end do
5227  end select
5228 
5229  if(.not. folded_north .and. .not. is_torus ) then
5230  call compare_checksums( eboundx, ebufferx(:,:,:), "east bound of CGRID " //trim(type)//" X" )
5231  call compare_checksums( nboundy, nbuffery(:,:,:), "north bound of CGRID "//trim(type)//" Y" )
5232  call compare_checksums( eboundx, ebufferx1(:,:,:), "east bound of CGRID " //trim(type)//" X1" )
5233  call compare_checksums( nboundy, nbuffery1(:,:,:), "north bound of CGRID "//trim(type)//" Y1" )
5234  endif
5235  call compare_checksums( wboundx, wbufferx(:,:,:), "west bound of CGRID " //trim(type)//" X" )
5236  call compare_checksums( sboundy, sbuffery(:,:,:), "south bound of CGRID "//trim(type)//" Y" )
5237  call compare_checksums( wboundx, wbufferx1(:,:,:), "west bound of CGRID " //trim(type)//" X1" )
5238  call compare_checksums( sboundy, sbuffery1(:,:,:), "south bound of CGRID "//trim(type)//" Y1" )
5239 
5240  select case(type)
5241  case("Four-Tile")
5242  do n = 1, ntile_per_pe
5243  call fill_four_tile_bound(global1_all*10, isc, iec, jsc, jec, 1, 0, &
5244  tile(n), ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
5245  call fill_four_tile_bound(global2_all*10, isc, iec, jsc, jec, 0, 1, &
5246  tile(n), sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
5247  end do
5248  case("Cubic-Grid")
5249  do n = 1, ntile_per_pe
5250  call fill_cubic_grid_bound(global1_all*10, global2_all*10, isc, iec, jsc, jec, 1, 0, &
5251  tile(n), 1, -1, ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
5252  call fill_cubic_grid_bound(global2_all*10, global1_all*10, isc, iec, jsc, jec, 0, 1, &
5253  tile(n), -1, 1, sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
5254  end do
5255  case("Folded-north")
5256  do n = 1, ntile_per_pe
5257  call fill_folded_north_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 0, &
5258  tile(n), wbound=wboundx(:,:,n) )
5259  call fill_folded_north_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 0, 1, &
5260  tile(n), sbound=sboundy(:,:,n) )
5261  end do
5262  case("torus")
5263  do n = 1, ntile_per_pe
5264  call fill_torus_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 0, &
5265  tile(n), wbound=wboundx(:,:,n) )
5266  call fill_torus_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 0, 1, &
5267  tile(n), sbound=sboundy(:,:,n) )
5268  end do
5269  end select
5270 
5271  if(.not. folded_north .and. .not. is_torus ) then
5272  call compare_checksums( eboundx, ebufferx2(:,:,:), "east bound of CGRID " //trim(type)//" X2" )
5273  call compare_checksums( nboundy, nbuffery2(:,:,:), "north bound of CGRID "//trim(type)//" Y2" )
5274  endif
5275  call compare_checksums( wboundx, wbufferx2(:,:,:), "west bound of CGRID " //trim(type)//" X2" )
5276  call compare_checksums( sboundy, sbuffery2(:,:,:), "south bound of CGRID "//trim(type)//" Y2" )
5277 
5278  !--- release memory
5279  deallocate(global1, global1_all, global2, global2_all)
5280  deallocate(x, y, x1, y1, x2, y2)
5281  deallocate(ebufferx, sbufferx, wbufferx, nbufferx)
5282  deallocate(ebufferx1, sbufferx1, wbufferx1, nbufferx1)
5283  deallocate(ebufferx2, sbufferx2, wbufferx2, nbufferx2)
5284  deallocate(ebuffery, sbuffery, wbuffery, nbuffery)
5285  deallocate(ebuffery1, sbuffery1, wbuffery1, nbuffery1)
5286  deallocate(ebuffery2, sbuffery2, wbuffery2, nbuffery2)
5287  deallocate(eboundx, sboundy, wboundx, nboundy )
5288 
5289  nx = nx_save
5290  ny = ny_save
5291 
5292  end subroutine test_get_boundary
5293 
5294  !######################################################################################
5295  subroutine define_fourtile_mosaic(type, domain, ni, nj, global_indices, layout, pe_start, pe_end, symmetry )
5296  character(len=*), intent(in) :: type
5297  type(domain2d), intent(inout) :: domain
5298  integer, intent(in) :: global_indices(:,:), layout(:,:)
5299  integer, intent(in) :: ni(:), nj(:)
5300  integer, intent(in) :: pe_start(:), pe_end(:)
5301  logical, intent(in) :: symmetry
5302  integer, dimension(8) :: istart1, iend1, jstart1, jend1, tile1
5303  integer, dimension(8) :: istart2, iend2, jstart2, jend2, tile2
5304  integer :: ntiles, num_contact, msize(2)
5305 
5306  ntiles = 4
5307  num_contact = 8
5308  if(size(pe_start(:)) .NE. 4 .OR. size(pe_end(:)) .NE. 4 ) call mpp_error(fatal, &
5309  "define_fourtile_mosaic: size of pe_start and pe_end should be 4")
5310  if(size(global_indices,1) .NE. 4) call mpp_error(fatal, &
5311  "define_fourtile_mosaic: size of first dimension of global_indices should be 4")
5312  if(size(global_indices,2) .NE. 4) call mpp_error(fatal, &
5313  "define_fourtile_mosaic: size of second dimension of global_indices should be 4")
5314  if(size(layout,1) .NE. 2) call mpp_error(fatal, &
5315  "define_fourtile_mosaic: size of first dimension of layout should be 2")
5316  if(size(layout,2) .NE. 4) call mpp_error(fatal, &
5317  "define_fourtile_mosaic: size of second dimension of layout should be 4")
5318  if(size(ni(:)) .NE. 4 .OR. size(nj(:)) .NE. 4) call mpp_error(fatal, &
5319  "define_fourtile_mosaic: size of ni and nj should be 4")
5320 
5321  !--- Contact line 1, between tile 1 (EAST) and tile 2 (WEST)
5322  tile1(1) = 1; tile2(1) = 2
5323  istart1(1) = ni(1); iend1(1) = ni(1); jstart1(1) = 1; jend1(1) = nj(1)
5324  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = nj(2)
5325  !--- Contact line 2, between tile 1 (SOUTH) and tile 3 (NORTH) --- cyclic
5326  tile1(2) = 1; tile2(2) = 3
5327  istart1(2) = 1; iend1(2) = ni(1); jstart1(2) = 1; jend1(2) = 1
5328  istart2(2) = 1; iend2(2) = ni(3); jstart2(2) = nj(3); jend2(2) = nj(3)
5329  !--- Contact line 3, between tile 1 (WEST) and tile 2 (EAST) --- cyclic
5330  tile1(3) = 1; tile2(3) = 2
5331  istart1(3) = 1; iend1(3) = 1; jstart1(3) = 1; jend1(3) = nj(1)
5332  istart2(3) = ni(2); iend2(3) = ni(2); jstart2(3) = 1; jend2(3) = nj(2)
5333  !--- Contact line 4, between tile 1 (NORTH) and tile 3 (SOUTH)
5334  tile1(4) = 1; tile2(4) = 3
5335  istart1(4) = 1; iend1(4) = ni(1); jstart1(4) = nj(1); jend1(4) = nj(1)
5336  istart2(4) = 1; iend2(4) = ni(3); jstart2(4) = 1; jend2(4) = 1
5337  !--- Contact line 5, between tile 2 (SOUTH) and tile 4 (NORTH) --- cyclic
5338  tile1(5) = 2; tile2(5) = 4
5339  istart1(5) = 1; iend1(5) = ni(2); jstart1(5) = 1; jend1(5) = 1
5340  istart2(5) = 1; iend2(5) = ni(4); jstart2(5) = nj(4); jend2(5) = nj(4)
5341  !--- Contact line 6, between tile 2 (NORTH) and tile 4 (SOUTH)
5342  tile1(6) = 2; tile2(6) = 4
5343  istart1(6) = 1; iend1(6) = ni(2); jstart1(6) = nj(2); jend1(6) = nj(2)
5344  istart2(6) = 1; iend2(6) = ni(4); jstart2(6) = 1; jend2(6) = 1
5345  !--- Contact line 7, between tile 3 (EAST) and tile 4 (WEST)
5346  tile1(7) = 3; tile2(7) = 4
5347  istart1(7) = ni(3); iend1(7) = ni(3); jstart1(7) = 1; jend1(7) = nj(3)
5348  istart2(7) = 1; iend2(7) = 1; jstart2(7) = 1; jend2(7) = nj(4)
5349  !--- Contact line 8, between tile 3 (WEST) and tile 4 (EAST) --- cyclic
5350  tile1(8) = 3; tile2(8) = 4
5351  istart1(8) = 1; iend1(8) = 1; jstart1(8) = 1; jend1(8) = nj(3)
5352  istart2(8) = ni(4); iend2(8) = ni(4); jstart2(8) = 1; jend2(8) = nj(4)
5353  msize(1) = maxval(ni(:)/layout(1,:)) + whalo + ehalo + 1 ! make sure memory domain size is no smaller than
5354  msize(2) = maxval(nj(:)/layout(2,:)) + shalo + nhalo + 1 ! data domain size
5355  call mpp_define_mosaic(global_indices, layout, domain, ntiles, num_contact, tile1, tile2, &
5356  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
5357  pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
5358  name = type, memory_size = msize, symmetry = symmetry )
5359 
5360  return
5361 
5362  end subroutine define_fourtile_mosaic
5363 
5364  !#######################################################################################
5365  !--- define mosaic domain for cubic grid
5366  subroutine define_cubic_mosaic(type, domain, ni, nj, global_indices, layout, pe_start, pe_end, use_memsize)
5367  character(len=*), intent(in) :: type
5368  type(domain2d), intent(inout) :: domain
5369  integer, intent(in) :: global_indices(:,:), layout(:,:)
5370  integer, intent(in) :: ni(:), nj(:)
5371  integer, intent(in) :: pe_start(:), pe_end(:)
5372  logical, optional, intent(in) :: use_memsize
5373  integer, dimension(12) :: istart1, iend1, jstart1, jend1, tile1
5374  integer, dimension(12) :: istart2, iend2, jstart2, jend2, tile2
5375  integer :: ntiles, num_contact, msize(2)
5376  logical :: use_memsize_local
5377 
5378  use_memsize_local = .true.
5379  if(present(use_memsize)) use_memsize_local = use_memsize
5380 
5381  ntiles = 6
5382  num_contact = 12
5383  if(size(pe_start(:)) .NE. 6 .OR. size(pe_end(:)) .NE. 6 ) call mpp_error(fatal, &
5384  "define_cubic_mosaic: size of pe_start and pe_end should be 6")
5385  if(size(global_indices,1) .NE. 4) call mpp_error(fatal, &
5386  "define_cubic_mosaic: size of first dimension of global_indices should be 4")
5387  if(size(global_indices,2) .NE. 6) call mpp_error(fatal, &
5388  "define_cubic_mosaic: size of second dimension of global_indices should be 6")
5389  if(size(layout,1) .NE. 2) call mpp_error(fatal, &
5390  "define_cubic_mosaic: size of first dimension of layout should be 2")
5391  if(size(layout,2) .NE. 6) call mpp_error(fatal, &
5392  "define_cubic_mosaic: size of second dimension of layout should be 6")
5393  if(size(ni(:)) .NE. 6 .OR. size(nj(:)) .NE. 6) call mpp_error(fatal, &
5394  "define_cubic_mosaic: size of ni and nj should be 6")
5395 
5396  !--- Contact line 1, between tile 1 (EAST) and tile 2 (WEST)
5397  tile1(1) = 1; tile2(1) = 2
5398  istart1(1) = ni(1); iend1(1) = ni(1); jstart1(1) = 1; jend1(1) = nj(1)
5399  istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = nj(2)
5400  !--- Contact line 2, between tile 1 (NORTH) and tile 3 (WEST)
5401  tile1(2) = 1; tile2(2) = 3
5402  istart1(2) = 1; iend1(2) = ni(1); jstart1(2) = nj(1); jend1(2) = nj(1)
5403  istart2(2) = 1; iend2(2) = 1; jstart2(2) = nj(3); jend2(2) = 1
5404  !--- Contact line 3, between tile 1 (WEST) and tile 5 (NORTH)
5405  tile1(3) = 1; tile2(3) = 5
5406  istart1(3) = 1; iend1(3) = 1; jstart1(3) = 1; jend1(3) = nj(1)
5407  istart2(3) = ni(5); iend2(3) = 1; jstart2(3) = nj(5); jend2(3) = nj(5)
5408  !--- Contact line 4, between tile 1 (SOUTH) and tile 6 (NORTH)
5409  tile1(4) = 1; tile2(4) = 6
5410  istart1(4) = 1; iend1(4) = ni(1); jstart1(4) = 1; jend1(4) = 1
5411  istart2(4) = 1; iend2(4) = ni(6); jstart2(4) = nj(6); jend2(4) = nj(6)
5412  !--- Contact line 5, between tile 2 (NORTH) and tile 3 (SOUTH)
5413  tile1(5) = 2; tile2(5) = 3
5414  istart1(5) = 1; iend1(5) = ni(2); jstart1(5) = nj(2); jend1(5) = nj(2)
5415  istart2(5) = 1; iend2(5) = ni(3); jstart2(5) = 1; jend2(5) = 1
5416  !--- Contact line 6, between tile 2 (EAST) and tile 4 (SOUTH)
5417  tile1(6) = 2; tile2(6) = 4
5418  istart1(6) = ni(2); iend1(6) = ni(2); jstart1(6) = 1; jend1(6) = nj(2)
5419  istart2(6) = ni(4); iend2(6) = 1; jstart2(6) = 1; jend2(6) = 1
5420  !--- Contact line 7, between tile 2 (SOUTH) and tile 6 (EAST)
5421  tile1(7) = 2; tile2(7) = 6
5422  istart1(7) = 1; iend1(7) = ni(2); jstart1(7) = 1; jend1(7) = 1
5423  istart2(7) = ni(6); iend2(7) = ni(6); jstart2(7) = nj(6); jend2(7) = 1
5424  !--- Contact line 8, between tile 3 (EAST) and tile 4 (WEST)
5425  tile1(8) = 3; tile2(8) = 4
5426  istart1(8) = ni(3); iend1(8) = ni(3); jstart1(8) = 1; jend1(8) = nj(3)
5427  istart2(8) = 1; iend2(8) = 1; jstart2(8) = 1; jend2(8) = nj(4)
5428  !--- Contact line 9, between tile 3 (NORTH) and tile 5 (WEST)
5429  tile1(9) = 3; tile2(9) = 5
5430  istart1(9) = 1; iend1(9) = ni(3); jstart1(9) = nj(3); jend1(9) = nj(3)
5431  istart2(9) = 1; iend2(9) = 1; jstart2(9) = nj(5); jend2(9) = 1
5432  !--- Contact line 10, between tile 4 (NORTH) and tile 5 (SOUTH)
5433  tile1(10) = 4; tile2(10) = 5
5434  istart1(10) = 1; iend1(10) = ni(4); jstart1(10) = nj(4); jend1(10) = nj(4)
5435  istart2(10) = 1; iend2(10) = ni(5); jstart2(10) = 1; jend2(10) = 1
5436  !--- Contact line 11, between tile 4 (EAST) and tile 6 (SOUTH)
5437  tile1(11) = 4; tile2(11) = 6
5438  istart1(11) = ni(4); iend1(11) = ni(4); jstart1(11) = 1; jend1(11) = nj(4)
5439  istart2(11) = ni(6); iend2(11) = 1; jstart2(11) = 1; jend2(11) = 1
5440  !--- Contact line 12, between tile 5 (EAST) and tile 6 (WEST)
5441  tile1(12) = 5; tile2(12) = 6
5442  istart1(12) = ni(5); iend1(12) = ni(5); jstart1(12) = 1; jend1(12) = nj(5)
5443  istart2(12) = 1; iend2(12) = 1; jstart2(12) = 1; jend2(12) = nj(6)
5444  msize(1) = maxval(ni(:)/layout(1,:)) + whalo + ehalo + 1 ! make sure memory domain size is no smaller than
5445  msize(2) = maxval(nj(:)/layout(2,:)) + shalo + nhalo + 1 ! data domain size
5446 
5447  if(use_memsize_local) then
5448  call mpp_define_mosaic(global_indices, layout, domain, ntiles, num_contact, tile1, tile2, &
5449  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
5450  pe_start, pe_end, symmetry = .true., whalo=whalo, ehalo=ehalo, &
5451  shalo=shalo, nhalo=nhalo, name = trim(type), memory_size = msize )
5452  else
5453  call mpp_define_mosaic(global_indices, layout, domain, ntiles, num_contact, tile1, tile2, &
5454  istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
5455  pe_start, pe_end, symmetry = .true., whalo=whalo, ehalo=ehalo, &
5456  shalo=shalo, nhalo=nhalo, name = trim(type) )
5457  endif
5458 
5459  return
5460 
5461  end subroutine define_cubic_mosaic
5462 
5463  !#######################################################################################
5464  subroutine fill_regular_refinement_halo( data, data_all, ni, nj, tm, te, tse, ts, tsw, tw, tnw, tn, tne, ioff, joff )
5465  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
5466  real, dimension(:,:,:,:), intent(in) :: data_all
5467  integer, dimension(:), intent(in) :: ni, nj
5468  integer, intent(in) :: tm, te, tse, ts, tsw, tw, tnw, tn, tne
5469  integer, intent(in) :: ioff, joff
5470 
5471 
5472  if(te>0) data (ni(tm)+1+ioff:ni(tm)+ehalo+ioff, 1:nj(tm)+joff, :) = &
5473  data_all(1+ioff:ehalo+ioff, 1:nj(te)+joff, :,te) ! east
5474  if(ts>0) data (1:ni(tm)+ioff, 1-shalo:0, :) = &
5475  data_all(1:ni(ts)+ioff, nj(ts)-shalo+1:nj(ts), :,ts) ! south
5476  if(tw>0) data (1-whalo:0, 1:nj(tm)+joff, :) = &
5477  data_all(ni(tw)-whalo+1:ni(tw), 1:nj(tw)+joff, :,tw) ! west
5478  if(tn>0) data (1:ni(tm)+ioff, nj(tm)+1+joff:nj(tm)+nhalo+joff, :) = &
5479  data_all(1:ni(tn)+ioff, 1+joff:nhalo+joff, :,tn) ! north
5480  if(tse>0)data (ni(tm)+1+ioff:ni(tm)+ehalo+ioff, 1-shalo:0, :) = &
5481  data_all(1+ioff:ehalo+ioff, nj(tse)-shalo+1:nj(tse), :,tse) ! southeast
5482  if(tsw>0)data (1-whalo:0, 1-shalo:0, :) = &
5483  data_all(ni(tsw)-whalo+1:ni(tsw), nj(tsw)-shalo+1:nj(tsw), :,tsw) ! southwest
5484  if(tne>0)data (ni(tm)+1+ioff:ni(tm)+ehalo+ioff, nj(tm)+1+joff:nj(tm)+nhalo+joff, :) = &
5485  data_all(1+ioff:ehalo+ioff, 1+joff:nhalo+joff, :,tnw) ! northeast
5486  if(tnw>0)data (1-whalo:0, nj(tm)+1+joff:nj(tm)+nhalo+joff, :) = &
5487  data_all(ni(tnw)-whalo+1:ni(tnw), 1+joff:nhalo+joff, :,tne) ! northwest
5488 
5489  end subroutine fill_regular_refinement_halo
5490 
5491  !##############################################################################
5492  ! this routine fill the halo points for the refined cubic grid. ioff and joff is used to distinguish
5493  ! T, C, E, or N-cell
5494  subroutine fill_cubicgrid_refined_halo(data, data1_all, data2_all, ni, nj, tile, ioff, joff, sign1, sign2)
5495  real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
5496  real, dimension(:,:,:,:), intent(in) :: data1_all, data2_all
5497  integer, dimension(:), intent(in) :: ni, nj
5498  integer, intent(in) :: tile, ioff, joff, sign1, sign2
5499  integer :: lw, le, ls, ln
5500 
5501  if(mod(tile,2) == 0) then ! tile 2, 4, 6
5502  lw = tile - 1; le = tile + 2; ls = tile - 2; ln = tile + 1
5503  if(le > 6 ) le = le - 6
5504  if(ls < 1 ) ls = ls + 6
5505  if(ln > 6 ) ln = ln - 6
5506  if( nj(tile) == nj(lw) ) then
5507  data(1-whalo:0, 1:nj(tile)+joff, :) = data1_all(ni(lw)-whalo+1:ni(lw), 1:nj(lw)+joff, :, lw) ! west
5508  end if
5509  if( nj(tile) == ni(le) ) then
5510  do i = 1, ehalo
5511  data(ni(tile)+i+ioff, 1:nj(tile)+joff, :) = sign1*data2_all(ni(le)+joff:1:-1, i+ioff, :, le) ! east
5512  end do
5513  end if
5514  if(ni(tile) == nj(ls) ) then
5515  do i = 1, shalo
5516  data(1:ni(tile)+ioff, 1-i, :) = sign2*data2_all(ni(ls)-i+1, nj(ls)+ioff:1:-1, :, ls) ! south
5517  end do
5518  end if
5519  if(ni(tile) == ni(ln) ) then
5520  data(1:ni(tile)+ioff, nj(tile)+1+joff:nj(tile)+nhalo+joff, :) = data1_all(1:ni(ln)+ioff, 1+joff:nhalo+joff, :, ln) ! north
5521  end if
5522  else ! tile 1, 3, 5
5523  lw = tile - 2; le = tile + 1; ls = tile - 1; ln = tile + 2
5524  if(lw < 1 ) lw = lw + 6
5525  if(ls < 1 ) ls = ls + 6
5526  if(ln > 6 ) ln = ln - 6
5527  if(nj(tile) == ni(lw) ) then
5528  do i = 1, whalo
5529  data(1-i, 1:nj(tile)+joff, :) = sign1*data2_all(ni(lw)+joff:1:-1, nj(lw)-i+1, :, lw) ! west
5530  end do
5531  end if
5532  if(nj(tile) == nj(le) ) then
5533  data(ni(tile)+1+ioff:ni(tile)+ehalo+ioff, 1:nj(tile)+joff, :) = data1_all(1+ioff:ehalo+ioff, 1:nj(le)+joff, :, le) ! east
5534  end if
5535  if(ni(tile) == ni(ls) ) then
5536  data(1:ni(tile)+ioff, 1-shalo:0, :) = data1_all(1:ni(ls)+ioff, nj(ls)-shalo+1:nj(ls), :, ls) ! south
5537  end if
5538  if(ni(tile) == nj(ln) ) then
5539  do i = 1, nhalo
5540  data(1:ni(tile)+ioff, nj(tile)+i+joff, :) = sign2*data2_all(i+joff, nj(ln)+ioff:1:-1, :, ln) ! north
5541  end do
5542  end if
5543  end if
5544 
5545  end subroutine fill_cubicgrid_refined_halo
5546 
5547  !##################################################################################
5548  subroutine test_subset_update( )
5549  real, allocatable, dimension(:,:,:) :: x
5550  type(domain2D) :: domain
5551  real, allocatable :: global(:,:,:)
5552  integer :: i, xhalo, yhalo
5553  integer :: is, ie, js, je, isd, ied, jsd, jed
5554 ! integer :: pes9(9)=(/1,2,3,4,5,6,7,8,9/)
5555  integer :: pes9(9)=(/0,2,4,10,12,14,20,22,24/)
5556  integer :: ni, nj
5557 
5558  if(mpp_npes() < 25) then
5559  call mpp_error(note,"test_mpp_domains: test_subset_update will&
5560  & not be done when npes < 25")
5561  return
5562  endif
5563 
5564  call mpp_declare_pelist(pes9)
5565  if(any(mpp_pe()==pes9)) then
5566  call mpp_set_current_pelist(pes9)
5567  layout = (/3,3/)
5568  ni = 3; nj =3
5569  call mpp_define_domains((/1,ni,1,nj/), layout, domain, xhalo=1&
5570  &, yhalo=1, xflags=cyclic_global_domain, yflags&
5571  &=cyclic_global_domain, name='subset domain')
5572  call mpp_get_compute_domain(domain, is, ie, js, je)
5573  print*, "pe=", mpp_pe(), is, ie, js, je
5574 
5575  allocate(global(0:ni+1,0:nj+1,nz) )
5576 
5577  global = 0
5578  do k = 1,nz
5579  do j = 1,nj
5580  do i = 1,ni
5581  global(i,j,k) = k + i*1e-3 + j*1e-6
5582  end do
5583  end do
5584  end do
5585 
5586  global(0, 1:nj,:) = global(ni, 1:nj,:)
5587  global(ni+1, 1:nj,:) = global(1, 1:nj,:)
5588  global(0:ni+1, 0, :) = global(0:ni+1, nj, :)
5589  global(0:ni+1, nj+1,:) = global(0:ni+1, 1, :)
5590 
5591  !set up x array
5592  call mpp_get_compute_domain( domain, is, ie, js, je )
5593  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
5594  allocate( x(isd:ied,jsd:jed,nz) )
5595 
5596  x = 0.
5597  x(is:ie,js:je,:) = global(is:ie,js:je,:)
5598 
5599 !full update
5600  call mpp_update_domains( x, domain )
5601  call compare_checksums( x, global(isd:ied,jsd:jed,:), '9pe subset' )
5602 
5603  deallocate(x, global)
5604  call mpp_deallocate_domain(domain)
5605  endif
5606 
5607  call mpp_set_current_pelist()
5608 
5609  end subroutine test_subset_update
5610 
5611  !##################################################################################
5612  subroutine test_halo_update( type )
5613  character(len=*), intent(in) :: type
5614  real, allocatable, dimension(:,:,:) :: x, x1, x2, x3, x4
5615  real, allocatable, dimension(:,:,:) :: y, y1, y2, y3, y4
5616  type(domain2D) :: domain
5617  real, allocatable :: global1(:,:,:), global2(:,:,:), global(:,:,:)
5618  logical, allocatable :: maskmap(:,:)
5619  integer :: shift, i, xhalo, yhalo
5620  logical :: is_symmetry, folded_south, folded_west, folded_east
5621  integer :: is, ie, js, je, isd, ied, jsd, jed
5622 
5623  ! when testing maskmap option, nx*ny should be able to be divided by both npes and npes+1
5624  if(type == 'Masked' .or. type == 'Masked symmetry') then
5625  if(mod(nx*ny, npes) .NE. 0 .OR. mod(nx*ny, npes+1) .NE. 0 ) then
5626  call mpp_error(note,'TEST_MPP_DOMAINS: nx*ny can not be divided by both npes and npes+1, '//&
5627  'Masked test_halo_update will not be tested')
5628  return
5629  end if
5630  end if
5631 
5632  if(type == 'Folded xy_halo' ) then
5633  xhalo = max(whalo, ehalo); yhalo = max(shalo, nhalo)
5634  allocate(global(1-xhalo:nx+xhalo,1-yhalo:ny+yhalo,nz) )
5635  else
5636  allocate(global(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz) )
5637  end if
5638 
5639  global = 0
5640  do k = 1,nz
5641  do j = 1,ny
5642  do i = 1,nx
5643  global(i,j,k) = k + i*1e-3 + j*1e-6
5644  end do
5645  end do
5646  end do
5647 
5648  if(index(type, 'symmetry') == 0) then
5649  is_symmetry = .false.
5650  else
5651  is_symmetry = .true.
5652  end if
5653  select case(type)
5654  case( 'Simple', 'Simple symmetry' )
5655  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
5656  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
5657  shalo=shalo, nhalo=nhalo, name=type, symmetry = is_symmetry )
5658  case( 'Cyclic', 'Cyclic symmetry' )
5659  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
5660  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
5661  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=cyclic_global_domain, &
5662  name=type, symmetry = is_symmetry )
5663  global(1-whalo:0, 1:ny,:) = global(nx-whalo+1:nx, 1:ny,:)
5664  global(nx+1:nx+ehalo, 1:ny,:) = global(1:ehalo, 1:ny,:)
5665  global(1-whalo:nx+ehalo, 1-shalo:0,:) = global(1-whalo:nx+ehalo, ny-shalo+1:ny,:)
5666  global(1-whalo:nx+ehalo, ny+1:ny+nhalo,:) = global(1-whalo:nx+ehalo, 1:nhalo,:)
5667  case( 'Folded-north', 'Folded-north symmetry' )
5668  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
5669  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
5670  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=fold_north_edge, &
5671  name=type, symmetry = is_symmetry )
5672  call fill_folded_north_halo(global, 0, 0, 0, 0, 1)
5673  case( 'Folded-south symmetry' )
5674  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
5675  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
5676  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=fold_south_edge, &
5677  name=type, symmetry = is_symmetry )
5678  call fill_folded_south_halo(global, 0, 0, 0, 0, 1)
5679  case( 'Folded-west symmetry' )
5680  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
5681  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
5682  shalo=shalo, nhalo=nhalo, xflags=fold_west_edge, yflags=cyclic_global_domain, &
5683  name=type, symmetry = is_symmetry )
5684  call fill_folded_west_halo(global, 0, 0, 0, 0, 1)
5685  case( 'Folded-east symmetry' )
5686  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
5687  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
5688  shalo=shalo, nhalo=nhalo, xflags=fold_east_edge, yflags=cyclic_global_domain, &
5689  name=type, symmetry = is_symmetry )
5690  call fill_folded_east_halo(global, 0, 0, 0, 0, 1)
5691  case( 'Folded xy_halo' )
5692  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
5693  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, xhalo=xhalo, yhalo=yhalo, &
5694  xflags=cyclic_global_domain, yflags=fold_north_edge, name=type, symmetry = is_symmetry )
5695  global(1-xhalo:0, 1:ny,:) = global(nx-xhalo+1:nx, 1:ny,:)
5696  global(nx+1:nx+xhalo, 1:ny,:) = global(1:xhalo, 1:ny,:)
5697  global(1-xhalo:nx+xhalo,ny+1:ny+yhalo,:) = global(nx+xhalo:1-xhalo:-1, ny:ny-yhalo+1:-1,:)
5698  case( 'Masked', 'Masked symmetry' )
5699 !with fold and cyclic, assign to npes+1 and mask out the top-rightdomain
5700  call mpp_define_layout( (/1,nx,1,ny/), npes+1, layout )
5701  allocate( maskmap(layout(1),layout(2)) )
5702  maskmap(:,:) = .true.; maskmap(layout(1),layout(2)) = .false.
5703  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
5704  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=fold_north_edge, &
5705  maskmap=maskmap, name=type, symmetry = is_symmetry )
5706  deallocate(maskmap)
5707  !we need to zero out the global data on the missing domain.
5708  !this logic assumes top-right, in an even division
5709  if( mod(nx,layout(1)).NE.0 .OR. mod(ny,layout(2)).NE.0 )call mpp_error( fatal, &
5710  'TEST_MPP_DOMAINS: test for masked domains needs (nx,ny) to divide evenly on npes+1 PEs.' )
5711  global(nx-nx/layout(1)+1:nx,ny-ny/layout(2)+1:ny,:) = 0
5712  call fill_folded_north_halo(global, 0, 0, 0, 0, 1)
5713  case default
5714  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
5715  end select
5716 
5717 !set up x array
5718  call mpp_get_compute_domain( domain, is, ie, js, je )
5719  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
5720  allocate( x(isd:ied,jsd:jed,nz) )
5721  allocate( x1(isd:ied,jsd:jed,nz) )
5722  allocate( x2(isd:ied,jsd:jed,nz) )
5723  allocate( x3(isd:ied,jsd:jed,nz) )
5724  allocate( x4(isd:ied,jsd:jed,nz) )
5725  x = 0.
5726  x(is:ie,js:je,:) = global(is:ie,js:je,:)
5727  x1 = x; x2 = x; x3 = x; x4 = x
5728 
5729 !full update
5730  id = mpp_clock_id( type, flags=mpp_clock_sync+mpp_clock_detailed )
5731  call mpp_clock_begin(id)
5732  call mpp_update_domains( x, domain )
5733  call mpp_clock_end (id)
5734  call compare_checksums( x, global(isd:ied,jsd:jed,:), type )
5735 
5736 !partial update
5737  id = mpp_clock_id( type//' partial', flags=mpp_clock_sync+mpp_clock_detailed )
5738  call mpp_clock_begin(id)
5739  call mpp_update_domains( x1, domain, nupdate+eupdate, complete=.false. )
5740  call mpp_update_domains( x2, domain, nupdate+eupdate, complete=.false. )
5741  call mpp_update_domains( x3, domain, nupdate+eupdate, complete=.false. )
5742  call mpp_update_domains( x4, domain, nupdate+eupdate, complete=.true. )
5743  call mpp_clock_end (id)
5744  call compare_checksums( x1(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x1' )
5745  call compare_checksums( x2(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x2' )
5746  call compare_checksums( x3(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x3' )
5747  call compare_checksums( x4(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x4' )
5748 
5749  !--- test vector update for FOLDED and MASKED case.
5750  if(type == 'Simple' .or. type == 'Simple symmetry' .or. type == 'Cyclic' .or. type == 'Cyclic symmetry') then
5751  deallocate(x,x1,x2,x3,x4)
5752  return
5753  end if
5754 
5755  !------------------------------------------------------------------
5756  ! vector update : BGRID_NE
5757  !------------------------------------------------------------------
5758  shift = 0
5759  if(is_symmetry) then
5760  shift = 1
5761  deallocate(global)
5762  allocate(global(1-whalo:nx+ehalo+shift,1-shalo:ny+nhalo+shift,nz) )
5763  global = 0.0
5764  do k = 1,nz
5765  do j = 1,ny+1
5766  do i = 1,nx+1
5767  global(i,j,k) = k + i*1e-3 + j*1e-6
5768  end do
5769  end do
5770  end do
5771  if(type == 'Masked symmetry') then
5772  global(nx-nx/layout(1)+1:nx+1,ny-ny/layout(2)+1:ny+1,:) = 0
5773  endif
5774  deallocate(x, x1, x2, x3, x4)
5775  allocate( x(isd:ied+1,jsd:jed+1,nz) )
5776  allocate( x1(isd:ied+1,jsd:jed+1,nz) )
5777  allocate( x2(isd:ied+1,jsd:jed+1,nz) )
5778  allocate( x3(isd:ied+1,jsd:jed+1,nz) )
5779  allocate( x4(isd:ied+1,jsd:jed+1,nz) )
5780  endif
5781 
5782  folded_south = .false.
5783  folded_west = .false.
5784  folded_east = .false.
5785  select case (type)
5786  case ('Folded-north', 'Masked')
5787  !fill in folded north edge, cyclic east and west edge
5788  call fill_folded_north_halo(global, 1, 1, 0, 0, -1)
5789  case ('Folded xy_halo')
5790  !fill in folded north edge, cyclic east and west edge
5791  global(1-xhalo:0, 1:ny,:) = global(nx-xhalo+1:nx, 1:ny,:)
5792  global(nx+1:nx+xhalo, 1:ny,:) = global(1:xhalo, 1:ny,:)
5793  global(1-xhalo:nx+xhalo-1,ny+1:ny+yhalo,:) = -global(nx+xhalo-1:1-xhalo:-1,ny-1:ny-yhalo:-1,:)
5794  global(nx+xhalo, ny+1:ny+yhalo,:) = -global(nx-xhalo, ny-1:ny-yhalo:-1,:)
5795  case ('Folded-north symmetry', 'Masked symmetry' )
5796  call fill_folded_north_halo(global, 1, 1, 1, 1, -1)
5797  case ('Folded-south symmetry' )
5798  folded_south = .true.
5799  call fill_folded_south_halo(global, 1, 1, 1, 1, -1)
5800  case ('Folded-west symmetry' )
5801  folded_west = .true.
5802  call fill_folded_west_halo(global, 1, 1, 1, 1, -1)
5803  case ('Folded-east symmetry' )
5804  folded_east = .true.
5805  call fill_folded_east_halo(global, 1, 1, 1, 1, -1)
5806  case default
5807  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
5808  end select
5809 
5810  x = 0.
5811  x(is:ie+shift,js:je+shift,:) = global(is:ie+shift,js:je+shift,:)
5812  !set up y array
5813  allocate( y(isd:ied+shift,jsd:jed+shift,nz) )
5814  allocate( y1(isd:ied+shift,jsd:jed+shift,nz) )
5815  allocate( y2(isd:ied+shift,jsd:jed+shift,nz) )
5816  allocate( y3(isd:ied+shift,jsd:jed+shift,nz) )
5817  allocate( y4(isd:ied+shift,jsd:jed+shift,nz) )
5818  y = x; x1 = x; x2 = x; x3 = x; x4 = x
5819  y = x; y1 = x; y2 = x; y3 = x; y4 = x
5820 
5821  id = mpp_clock_id( type//' vector BGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
5822  call mpp_clock_begin(id)
5823  call mpp_update_domains( x, y, domain, gridtype=bgrid_ne)
5824  call mpp_update_domains( x1, y1, domain, gridtype=bgrid_ne, complete=.false. )
5825  call mpp_update_domains( x2, y2, domain, gridtype=bgrid_ne, complete=.false. )
5826  call mpp_update_domains( x3, y3, domain, gridtype=bgrid_ne, complete=.false. )
5827  call mpp_update_domains( x4, y4, domain, gridtype=bgrid_ne, complete=.true. )
5828  call mpp_clock_end (id)
5829 
5830  !redundant points must be equal and opposite
5831 
5832  if(folded_south) then
5833  global(nx/2+shift, 1,:) = 0. !pole points must have 0 velocity
5834  global(nx+shift , 1,:) = 0. !pole points must have 0 velocity
5835  global(nx/2+1+shift:nx-1+shift, 1,:) = -global(nx/2-1+shift:1+shift:-1, 1,:)
5836  global(1-whalo:shift, 1,:) = -global(nx-whalo+1:nx+shift, 1,:)
5837  global(nx+1+shift:nx+ehalo+shift, 1,:) = -global(1+shift:ehalo+shift, 1,:)
5838  !--- the following will fix the +0/-0 problem on altix
5839  if(shalo >0) global(shift,1,:) = 0. !pole points must have 0 velocity
5840  else if(folded_west) then
5841  global(1, ny/2+shift, :) = 0. !pole points must have 0 velocity
5842  global(1, ny+shift, :) = 0. !pole points must have 0 velocity
5843  global(1, ny/2+1+shift:ny-1+shift, :) = -global(1, ny/2-1+shift:1+shift:-1, :)
5844  global(1, 1-shalo:shift, :) = -global(1, ny-shalo+1:ny+shift, :)
5845  global(1, ny+1+shift:ny+nhalo+shift, :) = -global(1, 1+shift:nhalo+shift, :)
5846  !--- the following will fix the +0/-0 problem on altix
5847  if(whalo>0) global(1, shift, :) = 0. !pole points must have 0 velocity
5848  else if(folded_east) then
5849  global(nx+shift, ny/2+shift, :) = 0. !pole points must have 0 velocity
5850  global(nx+shift, ny+shift, :) = 0. !pole points must have 0 velocity
5851  global(nx+shift, ny/2+1+shift:ny-1+shift, :) = -global(nx+shift, ny/2-1+shift:1+shift:-1, :)
5852  global(nx+shift, 1-shalo:shift, :) = -global(nx+shift, ny-shalo+1:ny+shift, :)
5853  global(nx+shift, ny+1+shift:ny+nhalo+shift, :) = -global(nx+shift, 1+shift:nhalo+shift, :)
5854  if(ehalo >0) global(nx+shift, shift, :) = 0. !pole points must have 0 velocity
5855  else
5856  global(nx/2+shift, ny+shift,:) = 0. !pole points must have 0 velocity
5857  global(nx+shift , ny+shift,:) = 0. !pole points must have 0 velocity
5858  global(nx/2+1+shift:nx-1+shift, ny+shift,:) = -global(nx/2-1+shift:1+shift:-1, ny+shift,:)
5859  if(type == 'Folded xy_halo') then
5860  global(1-xhalo:shift, ny+shift,:) = -global(nx-xhalo+1:nx+shift, ny+shift,:)
5861  global(nx+1+shift:nx+xhalo+shift, ny+shift,:) = -global(1+shift:xhalo+shift, ny+shift,:)
5862  else
5863  global(1-whalo:shift, ny+shift,:) = -global(nx-whalo+1:nx+shift, ny+shift,:)
5864  global(nx+1+shift:nx+ehalo+shift, ny+shift,:) = -global(1+shift:ehalo+shift, ny+shift,:)
5865  end if
5866  !--- the following will fix the +0/-0 problem on altix
5867  if(nhalo >0) global(shift,ny+shift,:) = 0. !pole points must have 0 velocity
5868  endif
5869 
5870  call compare_checksums( x, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X' )
5871  call compare_checksums( y, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y' )
5872  call compare_checksums( x1, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X1' )
5873  call compare_checksums( x2, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X2' )
5874  call compare_checksums( x3, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X3' )
5875  call compare_checksums( x4, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X4' )
5876  call compare_checksums( y1, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y1' )
5877  call compare_checksums( y2, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y2' )
5878  call compare_checksums( y3, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y3' )
5879  call compare_checksums( y4, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y4' )
5880 
5881  deallocate(global, x, x1, x2, x3, x4, y, y1, y2, y3, y4)
5882 
5883  !------------------------------------------------------------------
5884  ! vector update : CGRID_NE
5885  !------------------------------------------------------------------
5886  !--- global1 is x-component and global2 is y-component
5887  if(type == 'Folded xy_halo') then
5888  allocate(global1(1-xhalo:nx+xhalo, 1-yhalo:ny+yhalo, nz))
5889  allocate(global2(1-xhalo:nx+xhalo, 1-yhalo:ny+yhalo, nz))
5890  else
5891  allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz))
5892  allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz))
5893  end if
5894  allocate(x(isd:ied+shift,jsd:jed,nz), y(isd:ied,jsd:jed+shift,nz) )
5895  allocate(x1(isd:ied+shift,jsd:jed,nz), y1(isd:ied,jsd:jed+shift,nz) )
5896  allocate(x2(isd:ied+shift,jsd:jed,nz), y2(isd:ied,jsd:jed+shift,nz) )
5897  allocate(x3(isd:ied+shift,jsd:jed,nz), y3(isd:ied,jsd:jed+shift,nz) )
5898  allocate(x4(isd:ied+shift,jsd:jed,nz), y4(isd:ied,jsd:jed+shift,nz) )
5899 
5900  global1 = 0.0
5901  global2 = 0.0
5902  do k = 1,nz
5903  do j = 1,ny
5904  do i = 1,nx+shift
5905  global1(i,j,k) = k + i*1e-3 + j*1e-6
5906  end do
5907  end do
5908  do j = 1,ny+shift
5909  do i = 1,nx
5910  global2(i,j,k) = k + i*1e-3 + j*1e-6
5911  end do
5912  end do
5913  end do
5914 
5915  if(type == 'Masked' .or. type == 'Masked symmetry') then
5916  global1(nx-nx/layout(1)+1:nx+shift,ny-ny/layout(2)+1:ny,:) = 0
5917  global2(nx-nx/layout(1)+1:nx,ny-ny/layout(2)+1:ny+shift,:) = 0
5918  end if
5919 
5920  select case (type)
5921  case ('Folded-north', 'Masked')
5922  !fill in folded north edge, cyclic east and west edge
5923  call fill_folded_north_halo(global1, 1, 0, 0, 0, -1)
5924  call fill_folded_north_halo(global2, 0, 1, 0, 0, -1)
5925  case ('Folded xy_halo')
5926  global1(1-xhalo:0, 1:ny,:) = global1(nx-xhalo+1:nx, 1:ny,:)
5927  global1(nx+1:nx+xhalo, 1:ny,:) = global1(1:xhalo, 1:ny,:)
5928  global2(1-xhalo:0, 1:ny,:) = global2(nx-xhalo+1:nx, 1:ny,:)
5929  global2(nx+1:nx+xhalo, 1:ny,:) = global2(1:xhalo, 1:ny,:)
5930  global1(1-xhalo:nx+xhalo-1, ny+1:ny+yhalo,:) = -global1(nx+xhalo-1:1-xhalo:-1, ny:ny-yhalo+1:-1,:)
5931  global1(nx+xhalo, ny+1:ny+yhalo,:) = -global1(nx-xhalo, ny:ny-yhalo+1:-1,:)
5932  global2(1-xhalo:nx+xhalo, ny+1:ny+yhalo,:) = -global2(nx+xhalo:1-xhalo:-1, ny-1:ny-yhalo:-1,:)
5933  case ('Folded-north symmetry')
5934  call fill_folded_north_halo(global1, 1, 0, 1, 0, -1)
5935  call fill_folded_north_halo(global2, 0, 1, 0, 1, -1)
5936  case ('Folded-south symmetry')
5937  call fill_folded_south_halo(global1, 1, 0, 1, 0, -1)
5938  call fill_folded_south_halo(global2, 0, 1, 0, 1, -1)
5939  case ('Folded-west symmetry')
5940  call fill_folded_west_halo(global1, 1, 0, 1, 0, -1)
5941  call fill_folded_west_halo(global2, 0, 1, 0, 1, -1)
5942  case ('Folded-east symmetry')
5943  call fill_folded_east_halo(global1, 1, 0, 1, 0, -1)
5944  call fill_folded_east_halo(global2, 0, 1, 0, 1, -1)
5945  case default
5946  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
5947  end select
5948 
5949  x = 0.; y = 0.
5950  x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
5951  y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
5952  x1 = x; x2 = x; x3 = x; x4 = x
5953  y1 = y; y2 = y; y3 = y; y4 = y
5954 
5955  id = mpp_clock_id( type//' vector CGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
5956  call mpp_clock_begin(id)
5957  call mpp_update_domains( x, y, domain, gridtype=cgrid_ne)
5958  call mpp_update_domains( x1, y1, domain, gridtype=cgrid_ne, complete=.false. )
5959  call mpp_update_domains( x2, y2, domain, gridtype=cgrid_ne, complete=.false. )
5960  call mpp_update_domains( x3, y3, domain, gridtype=cgrid_ne, complete=.false. )
5961  call mpp_update_domains( x4, y4, domain, gridtype=cgrid_ne, complete=.true. )
5962  call mpp_clock_end (id)
5963 
5964  !redundant points must be equal and opposite
5965  if(folded_south) then
5966  global2(nx/2+1:nx, 1,:) = -global2(nx/2:1:-1, 1,:)
5967  global2(1-whalo:0, 1,:) = -global2(nx-whalo+1:nx, 1, :)
5968  global2(nx+1:nx+ehalo, 1,:) = -global2(1:ehalo, 1, :)
5969  else if(folded_west) then
5970  global1(1, ny/2+1:ny, :) = -global1(1, ny/2:1:-1, :)
5971  global1(1, 1-shalo:0, :) = -global1(1, ny-shalo+1:ny, :)
5972  global1(1, ny+1:ny+nhalo, :) = -global1(1, 1:nhalo, :)
5973  else if(folded_east) then
5974  global1(nx+shift, ny/2+1:ny, :) = -global1(nx+shift, ny/2:1:-1, :)
5975  global1(nx+shift, 1-shalo:0, :) = -global1(nx+shift, ny-shalo+1:ny, :)
5976  global1(nx+shift, ny+1:ny+nhalo, :) = -global1(nx+shift, 1:nhalo, :)
5977  else
5978  global2(nx/2+1:nx, ny+shift,:) = -global2(nx/2:1:-1, ny+shift,:)
5979  if(type == 'Folded xy_halo') then
5980  global2(1-xhalo:0, ny+shift,:) = -global2(nx-xhalo+1:nx, ny+shift,:)
5981  global2(nx+1:nx+xhalo, ny+shift,:) = -global2(1:xhalo, ny+shift,:)
5982  else
5983  global2(1-whalo:0, ny+shift,:) = -global2(nx-whalo+1:nx, ny+shift,:)
5984  global2(nx+1:nx+ehalo, ny+shift,:) = -global2(1:ehalo, ny+shift,:)
5985  end if
5986  endif
5987 
5988  call compare_checksums( x, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X' )
5989  call compare_checksums( y, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y' )
5990  call compare_checksums( x1, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X1' )
5991  call compare_checksums( x2, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X2' )
5992  call compare_checksums( x3, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X3' )
5993  call compare_checksums( x4, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X4' )
5994  call compare_checksums( y1, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y1' )
5995  call compare_checksums( y2, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y2' )
5996  call compare_checksums( y3, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y3' )
5997  call compare_checksums( y4, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y4' )
5998 
5999  deallocate(global1, global2, x, x1, x2, x3, x4, y, y1, y2, y3, y4)
6000 
6001 
6002  end subroutine test_halo_update
6003 
6004  subroutine set_corner_zero( data, isd, ied, jsd, jed, isc, iec, jsc, jec )
6005  integer, intent(in) :: isd, ied, jsd, jed
6006  integer, intent(in) :: isc, iec, jsc, jec
6007  real, dimension(isd:,jsd:,:), intent(inout) :: data
6008 
6009  data (isd :isc-1, jsd :jsc-1,:) = 0
6010  data (isd :isc-1, jec+1:jed, :) = 0
6011  data (iec+1:ied , jsd :jsc-1,:) = 0
6012  data (iec+1:ied , jec+1:jed, :) = 0
6013 
6014 
6015  end subroutine set_corner_zero
6016 
6017  !##################################################################################
6018  subroutine test_update_edge( type )
6019  character(len=*), intent(in) :: type
6020  real, allocatable, dimension(:,:,:) :: x, x2, a
6021  real, allocatable, dimension(:,:,:) :: y, y2, b
6022  type(domain2D) :: domain
6023  real, allocatable :: global1(:,:,:), global2(:,:,:), global(:,:,:)
6024  logical, allocatable :: maskmap(:,:)
6025  integer :: shift, i, xhalo, yhalo
6026  logical :: is_symmetry, folded_south, folded_west, folded_east
6027  integer :: is, ie, js, je, isd, ied, jsd, jed
6028  integer :: id_update
6029 
6030  allocate(global(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz) )
6031 
6032  global = 0
6033  do k = 1,nz
6034  do j = 1,ny
6035  do i = 1,nx
6036  global(i,j,k) = k + i*1e-3 + j*1e-6
6037  end do
6038  end do
6039  end do
6040 
6041  if(index(type, 'symmetry') == 0) then
6042  is_symmetry = .false.
6043  else
6044  is_symmetry = .true.
6045  end if
6046  select case(type)
6047  case( 'Cyclic' )
6048  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
6049  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6050  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=cyclic_global_domain, &
6051  name=type, symmetry = is_symmetry )
6052  global(1-whalo:0, 1:ny,:) = global(nx-whalo+1:nx, 1:ny,:)
6053  global(nx+1:nx+ehalo, 1:ny,:) = global(1:ehalo, 1:ny,:)
6054  global(1:nx, 1-shalo:0,:) = global(1:nx, ny-shalo+1:ny,:)
6055  global(1:nx, ny+1:ny+nhalo,:) = global(1:nx, 1:nhalo, :)
6056  case( 'Folded-north', 'Folded-north symmetry' )
6057  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
6058  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6059  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=fold_north_edge, &
6060  name=type, symmetry = is_symmetry )
6061  call fill_folded_north_halo(global, 0, 0, 0, 0, 1)
6062  !--- set the corner to 0
6063  call set_corner_zero(global, 1-whalo, nx+ehalo, 1-shalo, ny+ehalo, 1, nx, 1, ny)
6064  case default
6065  call mpp_error( fatal, 'test_update_edge: no such test: '//type )
6066  end select
6067 
6068 !set up x array
6069  call mpp_get_compute_domain( domain, is, ie, js, je )
6070  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
6071  allocate( x(isd:ied,jsd:jed,nz) )
6072  allocate( a(isd:ied,jsd:jed,nz) )
6073  allocate( x2(isd:ied,jsd:jed,nz) )
6074  x2(isd:ied,jsd:jed,:) = global(isd:ied,jsd:jed,:)
6075  call set_corner_zero(x2, isd, ied, jsd, jed, is, ie, js, je)
6076 
6077  x = 0.
6078  x(is:ie,js:je,:) = global(is:ie,js:je,:)
6079 
6080 !full update
6081  id = mpp_clock_id( type, flags=mpp_clock_sync+mpp_clock_detailed )
6082  call mpp_clock_begin(id)
6083  call mpp_update_domains( x, domain, flags=edgeupdate)
6084  call mpp_clock_end (id)
6085  call compare_checksums( x, x2, type )
6086  deallocate(x2)
6087 
6088  a = 0
6089  a(is:ie,js:je,:) = global(is:ie,js:je,:)
6090  id_update = mpp_start_update_domains( a, domain, flags=edgeupdate)
6091  call mpp_complete_update_domains(id_update, a, domain, flags=edgeupdate)
6092  call compare_checksums( x, a, type//" nonblock")
6093 
6094  !--- test vector update for FOLDED and MASKED case.
6095  if( type == 'Cyclic' ) then
6096  deallocate(global, x, a)
6097  return
6098  end if
6099 
6100  !------------------------------------------------------------------
6101  ! vector update : BGRID_NE
6102  !------------------------------------------------------------------
6103  shift = 0
6104  if(is_symmetry) then
6105  shift = 1
6106  deallocate(global)
6107  allocate(global(1-whalo:nx+ehalo+shift,1-shalo:ny+nhalo+shift,nz) )
6108  global = 0.0
6109  do k = 1,nz
6110  do j = 1,ny+1
6111  do i = 1,nx+1
6112  global(i,j,k) = k + i*1e-3 + j*1e-6
6113  end do
6114  end do
6115  end do
6116  deallocate(x,a)
6117  allocate( x(isd:ied+1,jsd:jed+1,nz) )
6118  allocate( a(isd:ied+1,jsd:jed+1,nz) )
6119  endif
6120 
6121  select case (type)
6122  case ('Folded-north')
6123  !fill in folded north edge, cyclic east and west edge
6124  call fill_folded_north_halo(global, 1, 1, 0, 0, -1)
6125  case ('Folded-north symmetry')
6126  call fill_folded_north_halo(global, 1, 1, 1, 1, -1)
6127  case default
6128  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
6129  end select
6130 
6131  x = 0.
6132  a = 0.
6133  x(is:ie+shift,js:je+shift,:) = global(is:ie+shift,js:je+shift,:)
6134  a(is:ie+shift,js:je+shift,:) = global(is:ie+shift,js:je+shift,:)
6135  !set up y array
6136  allocate( y(isd:ied+shift,jsd:jed+shift,nz) )
6137  allocate( b(isd:ied+shift,jsd:jed+shift,nz) )
6138  b = x
6139  y = x
6140  id = mpp_clock_id( type//' vector BGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
6141  call mpp_clock_begin(id)
6142  call mpp_update_domains( x, y, domain, flags=edgeupdate, gridtype=bgrid_ne)
6143  call mpp_clock_end (id)
6144 
6145  !--nonblocking update
6146  id_update = mpp_start_update_domains(a,b, domain, flags=edgeupdate, gridtype=bgrid_ne)
6147  call mpp_complete_update_domains(id_update, a,b, domain, flags=edgeupdate, gridtype=bgrid_ne)
6148 
6149  !redundant points must be equal and opposite
6150 
6151 
6152  global(nx/2+shift, ny+shift,:) = 0. !pole points must have 0 velocity
6153  global(nx+shift , ny+shift,:) = 0. !pole points must have 0 velocity
6154  global(nx/2+1+shift:nx-1+shift, ny+shift,:) = -global(nx/2-1+shift:1+shift:-1, ny+shift,:)
6155 
6156  global(1-whalo:shift, ny+shift,:) = -global(nx-whalo+1:nx+shift, ny+shift,:)
6157  global(nx+1+shift:nx+ehalo+shift, ny+shift,:) = -global(1+shift:ehalo+shift, ny+shift,:)
6158  !--- the following will fix the +0/-0 problem on altix
6159  if(nhalo >0) global(shift,ny+shift,:) = 0. !pole points must have 0 velocity
6160 
6161  allocate( x2(isd:ied+shift,jsd:jed+shift,nz) )
6162  x2(isd:ied+shift,jsd:jed+shift,:) = global(isd:ied+shift,jsd:jed+shift,:)
6163  call set_corner_zero(x2, isd, ied+shift, jsd, jed+shift, is, ie+shift, js, je+shift)
6164 
6165  call compare_checksums( x, x2, type//' BGRID_NE X' )
6166  call compare_checksums( y, x2, type//' BGRID_NE Y' )
6167  call compare_checksums( a, x2, type//' BGRID_NE X nonblock' )
6168  call compare_checksums( b, x2, type//' BGRID_NE Y nonblock' )
6169 
6170  deallocate(global, x, y, x2, a, b)
6171 
6172  !------------------------------------------------------------------
6173  ! vector update : CGRID_NE
6174  !------------------------------------------------------------------
6175  !--- global1 is x-component and global2 is y-component
6176  allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz))
6177  allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz))
6178  allocate(x(isd:ied+shift,jsd:jed,nz), y(isd:ied,jsd:jed+shift,nz) )
6179  allocate(x2(isd:ied+shift,jsd:jed,nz), y2(isd:ied,jsd:jed+shift,nz) )
6180  allocate(a(isd:ied+shift,jsd:jed,nz), b(isd:ied,jsd:jed+shift,nz) )
6181 
6182  global1 = 0.0
6183  global2 = 0.0
6184  do k = 1,nz
6185  do j = 1,ny
6186  do i = 1,nx+shift
6187  global1(i,j,k) = k + i*1e-3 + j*1e-6
6188  end do
6189  end do
6190  do j = 1,ny+shift
6191  do i = 1,nx
6192  global2(i,j,k) = k + i*1e-3 + j*1e-6
6193  end do
6194  end do
6195  end do
6196 
6197  select case (type)
6198  case ('Folded-north')
6199  !fill in folded north edge, cyclic east and west edge
6200  call fill_folded_north_halo(global1, 1, 0, 0, 0, -1)
6201  call fill_folded_north_halo(global2, 0, 1, 0, 0, -1)
6202  !--- set the corner to 0
6203  global1(1-whalo:0, 1-shalo:0, :) = 0
6204  global1(1-whalo:0, ny+1:ny+nhalo, :) = 0
6205  global1(nx+1:nx+ehalo, 1-shalo:0, :) = 0
6206  global1(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
6207  global2(1-whalo:0, 1-shalo:0, :) = 0
6208  global2(1-whalo:0, ny+1:ny+nhalo, :) = 0
6209  global2(nx+1:nx+ehalo, 1-shalo:0, :) = 0
6210  global2(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
6211  case ('Folded-north symmetry')
6212  call fill_folded_north_halo(global1, 1, 0, 1, 0, -1)
6213  call fill_folded_north_halo(global2, 0, 1, 0, 1, -1)
6214  case default
6215  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
6216  end select
6217 
6218  x = 0.; y = 0.
6219  x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
6220  y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
6221  a = 0.; b = 0.
6222  a(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
6223  b(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
6224 
6225  id = mpp_clock_id( type//' vector CGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
6226  call mpp_clock_begin(id)
6227  call mpp_update_domains( x, y, domain, flags=edgeupdate, gridtype=cgrid_ne)
6228  call mpp_clock_end (id)
6229 
6230  !--nonblocking
6231  id_update = mpp_start_update_domains( a, b, domain, flags=edgeupdate, gridtype=cgrid_ne)
6232  call mpp_complete_update_domains(id_update, a, b, domain, flags=edgeupdate, gridtype=cgrid_ne)
6233 
6234  !redundant points must be equal and opposite
6235  global2(nx/2+1:nx, ny+shift,:) = -global2(nx/2:1:-1, ny+shift,:)
6236  global2(1-whalo:0, ny+shift,:) = -global2(nx-whalo+1:nx, ny+shift,:)
6237  global2(nx+1:nx+ehalo, ny+shift,:) = -global2(1:ehalo, ny+shift,:)
6238 
6239  x2(isd:ied+shift,jsd:jed,:) = global1(isd:ied+shift,jsd:jed,:)
6240  y2(isd:ied,jsd:jed+shift,:) = global2(isd:ied,jsd:jed+shift,:)
6241  call set_corner_zero(x2, isd, ied+shift, jsd, jed, is, ie+shift, js, je)
6242  call set_corner_zero(y2, isd, ied, jsd, jed+shift, is, ie, js, je+shift)
6243 
6244  call compare_checksums( x, x2, type//' CGRID_NE X' )
6245  call compare_checksums( y, y2, type//' CGRID_NE Y' )
6246  call compare_checksums( a, x2, type//' CGRID_NE X nonblock' )
6247  call compare_checksums( b, y2, type//' CGRID_NE Y nonblock' )
6248 
6249  deallocate(global1, global2, x, y, x2, y2, a, b)
6250 
6251 
6252  end subroutine test_update_edge
6253 
6254 
6255  !##################################################################################
6256  subroutine test_update_nonsym_edge( type )
6257  character(len=*), intent(in) :: type
6258  real, allocatable, dimension(:,:,:) :: x, x2
6259  real, allocatable, dimension(:,:,:) :: y, y2
6260  type(domain2D) :: domain
6261  real, allocatable :: global1(:,:,:), global2(:,:,:)
6262  integer :: shift, i, xhalo, yhalo
6263  logical :: is_symmetry
6264  integer :: is, ie, js, je, isd, ied, jsd, jed
6265  type(mpp_group_update_type) :: group_update
6266 
6267  if(index(type, 'symmetry') == 0) then
6268  shift = 0
6269  is_symmetry = .false.
6270  else
6271  shift = 1
6272  is_symmetry = .true.
6273  end if
6274  select case(type)
6275  case( 'Folded-north', 'Folded-north symmetry' )
6276  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
6277  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6278  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=fold_north_edge, &
6279  name=type, symmetry = is_symmetry )
6280  case default
6281  call mpp_error( fatal, 'test_update_edge: no such test: '//type )
6282  end select
6283 
6284  call mpp_get_compute_domain( domain, is, ie, js, je )
6285  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
6286 
6287  !------------------------------------------------------------------
6288  ! vector update : CGRID_NE
6289  !------------------------------------------------------------------
6290  !--- global1 is x-component and global2 is y-component
6291  allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz))
6292  allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz))
6293  allocate(x(isd:ied+shift,jsd:jed,nz), y(isd:ied,jsd:jed+shift,nz) )
6294  allocate(x2(isd:ied+shift,jsd:jed,nz), y2(isd:ied,jsd:jed+shift,nz) )
6295 
6296  global1 = 0.0
6297  global2 = 0.0
6298  do k = 1,nz
6299  do j = 1,ny
6300  do i = 1,nx+shift
6301  global1(i,j,k) = k + i*1e-3 + j*1e-6
6302  end do
6303  end do
6304  do j = 1,ny+shift
6305  do i = 1,nx
6306  global2(i,j,k) = k + i*1e-3 + j*1e-6
6307  end do
6308  end do
6309  end do
6310 
6311  select case (type)
6312  case ('Folded-north')
6313  !fill in folded north edge, cyclic east and west edge
6314  call fill_folded_north_halo(global1, 1, 0, 0, 0, -1)
6315  call fill_folded_north_halo(global2, 0, 1, 0, 0, -1)
6316  !--- set the corner to 0
6317  global1(1-whalo:0, 1-shalo:0, :) = 0
6318  global1(1-whalo:0, ny+1:ny+nhalo, :) = 0
6319  global1(nx+1:nx+ehalo, 1-shalo:0, :) = 0
6320  global1(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
6321  global2(1-whalo:0, 1-shalo:0, :) = 0
6322  global2(1-whalo:0, ny+1:ny+nhalo, :) = 0
6323  global2(nx+1:nx+ehalo, 1-shalo:0, :) = 0
6324  global2(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
6325  case ('Folded-north symmetry')
6326  call fill_folded_north_halo(global1, 1, 0, 1, 0, -1)
6327  call fill_folded_north_halo(global2, 0, 1, 0, 1, -1)
6328  case default
6329  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
6330  end select
6331 
6332  !redundant points must be equal and opposite
6333  global2(nx/2+1:nx, ny+shift,:) = -global2(nx/2:1:-1, ny+shift,:)
6334  global2(1-whalo:0, ny+shift,:) = -global2(nx-whalo+1:nx, ny+shift,:)
6335 ! global2(nx+1:nx+ehalo, ny+shift,:) = -global2(1:ehalo, ny+shift,:)
6336 
6337  x2 = 0.0; y2 = 0.0
6338  if(is_symmetry) then
6339  x2(isd:ie+shift,jsd:je,:) = global1(isd:ie+shift,jsd:je,:)
6340  y2(isd:ie,jsd:je+shift,:) = global2(isd:ie,jsd:je+shift,:)
6341  else
6342  x2(isd:ie+shift,js:je,:) = global1(isd:ie+shift,js:je,:)
6343  y2(is:ie,jsd:je+shift,:) = global2(is:ie,jsd:je+shift,:)
6344  endif
6345 
6346  x = 0.; y = 0.
6347  x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
6348  y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
6349 
6350  call mpp_create_group_update(group_update, x, y, domain, gridtype=cgrid_ne, &
6351  flags=wupdate+supdate+nonsymedgeupdate, whalo=1, ehalo=1, shalo=1, nhalo=1)
6352  call mpp_do_group_update(group_update, domain, x(is,js,1))
6353 
6354  call compare_checksums( x, x2, type//' CGRID_NE X' )
6355  call compare_checksums( y, y2, type//' CGRID_NE Y' )
6356 
6357  call mpp_sync()
6358 
6359  x = 0.; y = 0.
6360  x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
6361  y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
6362  call mpp_start_group_update(group_update, domain, x(is,js,1))
6363  call mpp_complete_group_update(group_update, domain, x(is,js,1))
6364 
6365  call compare_checksums( x, x2, type//' CGRID_NE X nonblock' )
6366  call compare_checksums( y, y2, type//' CGRID_NE Y nonblock' )
6367 
6368  deallocate(global1, global2, x, y, x2, y2)
6369  call mpp_clear_group_update(group_update)
6370 
6371  end subroutine test_update_nonsym_edge
6372 
6373 
6374  !##################################################################################
6375  subroutine test_cyclic_offset( type )
6376  character(len=*), intent(in) :: type
6377  real, allocatable, dimension(:,:,:) :: x, x1, x2, x3, x4
6378  real, allocatable, dimension(:,:,:) :: y, y1, y2, y3, y4
6379  type(domain2D) :: domain
6380  real, allocatable :: global1(:,:,:), global2(:,:,:), global(:,:,:)
6381  integer :: i, j, k, jj, ii
6382  integer :: is, ie, js, je, isd, ied, jsd, jed
6383  character(len=128) :: type2
6384 
6385  allocate(global(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz))
6386 
6387  global = 0
6388  do k = 1,nz
6389  do j = 1,ny
6390  do i = 1,nx
6391  global(i,j,k) = k + i*1e-3 + j*1e-6
6392  end do
6393  end do
6394  end do
6395 
6396  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
6397  select case(type)
6398  case( 'x_cyclic_offset' )
6399  write(type2, *)type, ' x_cyclic=', x_cyclic_offset
6400  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6401  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, &
6402  name=type, x_cyclic_offset = x_cyclic_offset)
6403  do j = 1, ny
6404  jj = mod(j + x_cyclic_offset + ny, ny)
6405  if(jj==0) jj = ny
6406  global(1-whalo:0,j,:) = global(nx-whalo+1:nx, jj,:) ! West
6407  jj = mod(j - x_cyclic_offset + ny, ny)
6408  if(jj==0) jj = ny
6409  global(nx+1:nx+ehalo,j,:) = global(1:ehalo,jj,:) ! East
6410  end do
6411  case( 'y_cyclic_offset' )
6412  write(type2, *)type, ' y_cyclic = ', y_cyclic_offset
6413  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6414  shalo=shalo, nhalo=nhalo, yflags=cyclic_global_domain, &
6415  name=type, y_cyclic_offset = y_cyclic_offset)
6416  do i = 1, nx
6417  ii = mod(i + y_cyclic_offset + nx, nx)
6418  if(ii==0) ii = nx
6419  global(i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! South
6420  ii = mod(i - y_cyclic_offset + nx, nx)
6421  if(ii==0) ii = nx
6422  global(i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! NORTH
6423  end do
6424  case( 'torus_x_offset' )
6425  write(type2, *)type, ' x_cyclic = ', x_cyclic_offset
6426  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6427  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, &
6428  yflags=cyclic_global_domain, name=type, &
6429  x_cyclic_offset = x_cyclic_offset)
6430  do j = 1, ny
6431  jj = mod(j + x_cyclic_offset + ny, ny)
6432  if(jj==0) jj = ny
6433  global(1-whalo:0,j,:) = global(nx-whalo+1:nx, jj,:) ! West
6434  jj = mod(j - x_cyclic_offset + ny, ny)
6435  if(jj==0) jj = ny
6436  global(nx+1:nx+ehalo,j,:) = global(1:ehalo,jj,:) ! East
6437  end do
6438  global(1:nx,1-shalo:0,:) = global(1:nx, ny-shalo+1:ny,:) ! South
6439  global(1:nx,ny+1:ny+nhalo,:) = global(1:nx, 1:nhalo, :) ! NORTH
6440 
6441  do j = 1, shalo
6442  jj = mod(ny-j+1 + x_cyclic_offset + ny, ny)
6443  if(jj==0) jj = ny
6444  global(1-whalo:0, 1-j,:) = global(nx-whalo+1:nx, jj, :) ! Southwest
6445  jj = mod(ny-j+1-x_cyclic_offset+ny,ny)
6446  if(jj==0) jj = ny
6447  global(nx+1:nx+ehalo, 1-j,:) = global(1:ehalo, jj, :) ! Southeast
6448  end do
6449  do j = 1, nhalo
6450  jj = mod(j + x_cyclic_offset + ny, ny)
6451  if(jj==0) jj = ny
6452  global(1-whalo:0, ny+j,:) = global(nx-whalo+1:nx, jj, :) ! northwest
6453  jj = mod(j - x_cyclic_offset+ny,ny)
6454  if(jj==0) jj = ny
6455  global(nx+1:nx+ehalo, ny+j,:) = global(1:ehalo, jj, :) ! northeast
6456  end do
6457 
6458  case( 'torus_y_offset' )
6459  write(type2, *)type, ' y_cyclic = ', y_cyclic_offset
6460  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6461  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, &
6462  yflags=cyclic_global_domain, name=type, &
6463  y_cyclic_offset = y_cyclic_offset)
6464  do i = 1, nx
6465  ii = mod(i + y_cyclic_offset + nx, nx)
6466  if(ii==0) ii = nx
6467  global(i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! South
6468  ii = mod(i - y_cyclic_offset + nx, nx)
6469  if(ii==0) ii = nx
6470  global(i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! NORTH
6471  end do
6472  global(1-whalo:0,1:ny,:) = global(nx-whalo+1:nx, 1:ny,:) ! West
6473  global(nx+1:nx+ehalo,1:ny,:) = global(1:ehalo, 1:ny, :) ! East
6474  do i = 1, whalo
6475  ii = mod(nx-i+1 + y_cyclic_offset + nx, nx)
6476  if(ii==0) ii = nx
6477  global(1-i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! southwest
6478  ii = mod(nx-i+1 - y_cyclic_offset + nx, nx)
6479  if(ii==0) ii = nx
6480  global(1-i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! northwest
6481  end do
6482  do i = 1, ehalo
6483  ii = mod(i + y_cyclic_offset + nx, nx)
6484  if(ii==0) ii = nx
6485  global(nx+i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! southeast
6486  ii = mod(i - y_cyclic_offset + nx, nx)
6487  if(ii==0) ii = nx
6488  global(nx+i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! northeast
6489  end do
6490  case default
6491  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
6492  end select
6493 
6494 !set up x array
6495  call mpp_get_compute_domain( domain, is, ie, js, je )
6496  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
6497  allocate( x(isd:ied,jsd:jed,nz) )
6498  allocate( x1(isd:ied,jsd:jed,nz) )
6499  allocate( x2(isd:ied,jsd:jed,nz) )
6500  allocate( x3(isd:ied,jsd:jed,nz) )
6501  allocate( x4(isd:ied,jsd:jed,nz) )
6502  x = 0.
6503  x(is:ie,js:je,:) = global(is:ie,js:je,:)
6504  x1 = x; x2 = x; x3 = x; x4 = x
6505 
6506 !full update
6507  id = mpp_clock_id( type, flags=mpp_clock_sync+mpp_clock_detailed )
6508  call mpp_clock_begin(id)
6509  call mpp_update_domains( x, domain )
6510  call mpp_clock_end (id)
6511  call compare_checksums( x, global(isd:ied,jsd:jed,:), trim(type2) )
6512 
6513 !partial update
6514  id = mpp_clock_id( type//' partial', flags=mpp_clock_sync+mpp_clock_detailed )
6515  call mpp_clock_begin(id)
6516  call mpp_update_domains( x1, domain, nupdate+eupdate, complete=.false. )
6517  call mpp_update_domains( x2, domain, nupdate+eupdate, complete=.false. )
6518  call mpp_update_domains( x3, domain, nupdate+eupdate, complete=.false. )
6519  call mpp_update_domains( x4, domain, nupdate+eupdate, complete=.true. )
6520  call mpp_clock_end (id)
6521  call compare_checksums( x1(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x1' )
6522  call compare_checksums( x2(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x2' )
6523  call compare_checksums( x3(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x3' )
6524  call compare_checksums( x4(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x4' )
6525 
6526  !--- test vector update for FOLDED and MASKED case.
6527  deallocate(x,x1,x2,x3,x4)
6528 
6529 
6530  !------------------------------------------------------------------
6531  ! vector update : BGRID_NE
6532  !------------------------------------------------------------------
6533  !--- global1 is x-component and global2 is y-component
6534  allocate(global1(1-whalo:nx+ehalo, 1-shalo:ny+nhalo, nz))
6535  allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo, nz))
6536  allocate(x(isd:ied,jsd:jed,nz), y(isd:ied,jsd:jed,nz) )
6537  allocate(x1(isd:ied,jsd:jed,nz), y1(isd:ied,jsd:jed,nz) )
6538  allocate(x2(isd:ied,jsd:jed,nz), y2(isd:ied,jsd:jed,nz) )
6539  allocate(x3(isd:ied,jsd:jed,nz), y3(isd:ied,jsd:jed,nz) )
6540  allocate(x4(isd:ied,jsd:jed,nz), y4(isd:ied,jsd:jed,nz) )
6541  where (global >0)
6542  global1 = 1000 + global
6543  global2 = 2000 + global
6544  elsewhere
6545  global1 = 0
6546  global2 = 0
6547  end where
6548  x = 0.; y = 0
6549  x(is:ie,js:je,:) = global1(is:ie,js:je,:)
6550  y(is:ie,js:je,:) = global2(is:ie,js:je,:)
6551  x1 = x; x2 = x; x3 = x; x4 = x
6552  y1 = y; y2 = y; y3 = y; y4 = y
6553 
6554  id = mpp_clock_id( type//' vector BGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
6555  call mpp_clock_begin(id)
6556  call mpp_update_domains( x, y, domain, gridtype=bgrid_ne)
6557  call mpp_update_domains( x1, y1, domain, gridtype=bgrid_ne, complete=.false. )
6558  call mpp_update_domains( x2, y2, domain, gridtype=bgrid_ne, complete=.false. )
6559  call mpp_update_domains( x3, y3, domain, gridtype=bgrid_ne, complete=.false. )
6560  call mpp_update_domains( x4, y4, domain, gridtype=bgrid_ne, complete=.true. )
6561  call mpp_clock_end (id)
6562 
6563  !redundant points must be equal and opposite
6564 
6565  call compare_checksums( x, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X' )
6566  call compare_checksums( y, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y' )
6567  call compare_checksums( x1, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X1' )
6568  call compare_checksums( x2, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X2' )
6569  call compare_checksums( x3, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X3' )
6570  call compare_checksums( x4, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X4' )
6571  call compare_checksums( y1, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y1' )
6572  call compare_checksums( y2, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y2' )
6573  call compare_checksums( y3, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y3' )
6574  call compare_checksums( y4, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y4' )
6575 
6576  !------------------------------------------------------------------
6577  ! vector update : CGRID_NE
6578  !------------------------------------------------------------------
6579 
6580  x = 0.; y = 0.
6581  x(is:ie,js:je,:) = global1(is:ie,js:je,:)
6582  y(is:ie,js:je,:) = global2(is:ie,js:je,:)
6583  x1 = x; x2 = x; x3 = x; x4 = x
6584  y1 = y; y2 = y; y3 = y; y4 = y
6585 
6586  id = mpp_clock_id( type//' vector CGRID_NE', flags=mpp_clock_sync+mpp_clock_detailed )
6587  call mpp_clock_begin(id)
6588  call mpp_update_domains( x, y, domain, gridtype=cgrid_ne)
6589  call mpp_update_domains( x1, y1, domain, gridtype=cgrid_ne, complete=.false. )
6590  call mpp_update_domains( x2, y2, domain, gridtype=cgrid_ne, complete=.false. )
6591  call mpp_update_domains( x3, y3, domain, gridtype=cgrid_ne, complete=.false. )
6592  call mpp_update_domains( x4, y4, domain, gridtype=cgrid_ne, complete=.true. )
6593  call mpp_clock_end (id)
6594 
6595  call compare_checksums( x, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X' )
6596  call compare_checksums( y, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y' )
6597  call compare_checksums( x1, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X1' )
6598  call compare_checksums( x2, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X2' )
6599  call compare_checksums( x3, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X3' )
6600  call compare_checksums( x4, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X4' )
6601  call compare_checksums( y1, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y1' )
6602  call compare_checksums( y2, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y2' )
6603  call compare_checksums( y3, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y3' )
6604  call compare_checksums( y4, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y4' )
6605 
6606  deallocate(global1, global2, x, x1, x2, x3, x4, y, y1, y2, y3, y4)
6607 
6608 
6609  end subroutine test_cyclic_offset
6610 
6611 
6612  subroutine test_global_field( type )
6613  character(len=*), intent(in) :: type
6614  real, allocatable, dimension(:,:,:) :: x, gcheck
6615  type(domain2D) :: domain
6616  real, allocatable :: global1(:,:,:)
6617  integer :: ishift, jshift, ni, nj, i, j, position
6618  integer, allocatable :: pelist(:)
6619  integer :: is, ie, js, je, isd, ied, jsd, jed
6620 
6621  !--- set up domain
6622  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
6623  select case(type)
6624  case( 'Non-symmetry' )
6625  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6626  shalo=shalo, nhalo=nhalo, name=type )
6627  case( 'Symmetry center', 'Symmetry corner', 'Symmetry east', 'Symmetry north' )
6628  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6629  shalo=shalo, nhalo=nhalo, name=type, symmetry = .true. )
6630  case default
6631  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type//' in test_global_field' )
6632  end select
6633  call mpp_get_compute_domain( domain, is, ie, js, je )
6634  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
6635 
6636  !--- determine if an extra point is needed
6637  ishift = 0; jshift = 0
6638  position = center
6639  select case(type)
6640  case ('Symmetry corner')
6641  ishift = 1; jshift = 1; position=corner
6642  case ('Symmetry east')
6643  ishift = 1; jshift = 0; position=east
6644  case ('Symmetry north')
6645  ishift = 0; jshift = 1; position=north
6646  end select
6647 
6648  ie = ie+ishift; je = je+jshift
6649  ied = ied+ishift; jed = jed+jshift
6650  ni = nx+ishift; nj = ny+jshift
6651  allocate(global1(1-whalo:ni+ehalo, 1-shalo:nj+nhalo, nz))
6652  global1 = 0.0
6653  do k = 1,nz
6654  do j = 1,nj
6655  do i = 1,ni
6656  global1(i,j,k) = k + i*1e-3 + j*1e-6
6657  end do
6658  end do
6659  enddo
6660 
6661  allocate( gcheck(ni, nj, nz) )
6662  allocate( x(isd:ied,jsd:jed,nz) )
6663 
6664  x(:,:,:) = global1(isd:ied,jsd:jed,:)
6665 
6666  !--- test the data on data domain
6667  gcheck = 0.
6668  id = mpp_clock_id( type//' global field on data domain', flags=mpp_clock_sync+mpp_clock_detailed )
6669  call mpp_clock_begin(id)
6670  call mpp_global_field( domain, x, gcheck, position=position )
6671  call mpp_clock_end (id)
6672  !compare checksums between global and x arrays
6673  call compare_checksums( global1(1:ni,1:nj,:), gcheck, type//' mpp_global_field on data domain' )
6674 
6675  !--- Since in the disjoint redistribute mpp test, pelist1 = (npes/2+1 .. npes-1)
6676  !--- will be declared. But for the x-direction global field, mpp_sync_self will
6677  !--- be called. For some pe count, pelist1 will be set ( only on pe of pelist1 )
6678  !--- in the mpp_sync_self call, later when calling mpp_declare_pelist(pelist1),
6679  !--- deadlock will happen. For example npes = 6 and layout = (2,3), pelist = (4,5)
6680  !--- will be set in mpp_sync_self. To solve the problem, some explicit mpp_declare_pelist
6681  !--- on all pe is needed for those partial pelist. But for y-update, it is ok.
6682  !--- because the pelist in y-update is not continous.
6683  allocate(pelist(0:layout(1)-1))
6684  do j = 0, layout(2)-1
6685  do i = 0, layout(1)-1
6686  pelist(i) = j*layout(1) + i
6687  end do
6688  call mpp_declare_pelist(pelist)
6689  end do
6690  deallocate(pelist)
6691 
6692  !xupdate
6693  gcheck = 0.
6694  call mpp_clock_begin(id)
6695  call mpp_global_field( domain, x, gcheck, flags = xupdate, position=position )
6696  call mpp_clock_end (id)
6697  !compare checksums between global and x arrays
6698  call compare_checksums( global1(1:ni,js:je,:), gcheck(1:ni,js:je,:), &
6699  type//' mpp_global_field xupdate only on data domain' )
6700 
6701  !yupdate
6702  gcheck = 0.
6703  call mpp_clock_begin(id)
6704  call mpp_global_field( domain, x, gcheck, flags = yupdate, position=position )
6705  call mpp_clock_end (id)
6706  !compare checksums between global and x arrays
6707  call compare_checksums( global1(is:ie,1:nj,:), gcheck(is:ie,1:nj,:), &
6708  type//' mpp_global_field yupdate only on data domain' )
6709 
6710  call mpp_clock_begin(id)
6711  call mpp_global_field( domain, x, gcheck, position=position )
6712 
6713  call mpp_clock_end (id)
6714  !compare checksums between global and x arrays
6715  call compare_checksums( global1(1:ni,1:nj,:), gcheck, &
6716  type//' mpp_global_field on data domain' )
6717 
6718  !--- test the data on compute domain
6719  gcheck = 0.
6720  id = mpp_clock_id( type//' global field on compute domain', flags=mpp_clock_sync+mpp_clock_detailed )
6721  call mpp_clock_begin(id)
6722  call mpp_global_field( domain, x(is:ie, js:je, :), gcheck, position=position )
6723  call mpp_clock_end (id)
6724  !compare checksums between global and x arrays
6725  call compare_checksums( global1(1:ni,1:nj,:), gcheck, type//' mpp_global_field on compute domain' )
6726 
6727  !xupdate
6728  gcheck = 0.
6729  call mpp_clock_begin(id)
6730  call mpp_global_field( domain, x(is:ie, js:je,:), gcheck, flags = xupdate, position=position )
6731  call mpp_clock_end (id)
6732  !compare checksums between global and x arrays
6733  call compare_checksums( global1(1:ni,js:je,:), gcheck(1:ni,js:je,:), &
6734  type//' mpp_global_field xupdate only on compute domain' )
6735 
6736  !yupdate
6737  gcheck = 0.
6738  call mpp_clock_begin(id)
6739  call mpp_global_field( domain, x(is:ie, js:je,:), gcheck, flags = yupdate, position=position )
6740  call mpp_clock_end (id)
6741  !compare checksums between global and x arrays
6742  call compare_checksums( global1(is:ie,1:nj,:), gcheck(is:ie,1:nj,:), &
6743  type//' mpp_global_field yupdate only on compute domain' )
6744 
6745 
6746  deallocate(global1, gcheck, x)
6747 
6748  end subroutine test_global_field
6749 
6750  !--- test mpp_global_sum, mpp_global_min and mpp_global_max
6751  subroutine test_global_reduce (type)
6752  character(len=*), intent(in) :: type
6753  real :: lsum, gsum, lmax, gmax, lmin, gmin
6754  integer :: ni, nj, ishift, jshift, position
6755  integer :: is, ie, js, je, isd, ied, jsd, jed
6756 
6757  type(domain2D) :: domain
6758  real, allocatable, dimension(:,:,:) :: global1, x
6759  real, allocatable, dimension(:,:) :: global2D
6760  !--- set up domain
6761  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
6762  select case(type)
6763  case( 'Simple' )
6764  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6765  shalo=shalo, nhalo=nhalo, name=type )
6766  case( 'Simple symmetry center', 'Simple symmetry corner', 'Simple symmetry east', 'Simple symmetry north' )
6767  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
6768  shalo=shalo, nhalo=nhalo, name=type, symmetry = .true. )
6769  case( 'Cyclic symmetry center', 'Cyclic symmetry corner', 'Cyclic symmetry east', 'Cyclic symmetry north' )
6770  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
6771  name=type, symmetry = .true., xflags=cyclic_global_domain, yflags=cyclic_global_domain )
6772  case default
6773  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type//' in test_global_field' )
6774  end select
6775  call mpp_get_compute_domain( domain, is, ie, js, je )
6776  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
6777 
6778  !--- determine if an extra point is needed
6779  ishift = 0; jshift = 0; position = center
6780  select case(type)
6781  case ('Simple symmetry corner', 'Cyclic symmetry corner')
6782  ishift = 1; jshift = 1; position = corner
6783  case ('Simple symmetry east', 'Cyclic symmetry east' )
6784  ishift = 1; jshift = 0; position = east
6785  case ('Simple symmetry north', 'Cyclic symmetry north')
6786  ishift = 0; jshift = 1; position = north
6787  end select
6788 
6789  ie = ie+ishift; je = je+jshift
6790  ied = ied+ishift; jed = jed+jshift
6791  ni = nx+ishift; nj = ny+jshift
6792  allocate(global1(1-whalo:ni+ehalo, 1-shalo:nj+nhalo, nz))
6793  global1 = 0.0
6794  do k = 1,nz
6795  do j = 1,nj
6796  do i = 1,ni
6797  global1(i,j,k) = k + i*1e-3 + j*1e-6
6798  end do
6799  end do
6800  enddo
6801 
6802  !--- NOTE: even though the domain is cyclic, no need to apply cyclic condition on the global data
6803 
6804  allocate( x(isd:ied,jsd:jed,nz) )
6805  allocate( global2d(ni,nj))
6806 
6807  x(:,:,:) = global1(isd:ied,jsd:jed,:)
6808  do j = 1, nj
6809  do i = 1, ni
6810  global2d(i,j) = sum(global1(i,j,:))
6811  enddo
6812  enddo
6813  !test mpp_global_sum
6814 
6815  if(type(1:6) == 'Simple') then
6816  gsum = sum( global2d(1:ni,1:nj) )
6817  else
6818  gsum = sum( global2d(1:nx, 1:ny) )
6819  endif
6820  id = mpp_clock_id( type//' sum', flags=mpp_clock_sync+mpp_clock_detailed )
6821  call mpp_clock_begin(id)
6822  lsum = mpp_global_sum( domain, x, position = position )
6823  call mpp_clock_end (id)
6824  if( pe.EQ.mpp_root_pe() )print '(a,2es15.8,a,es12.4)', type//' Fast sum=', lsum, gsum
6825 
6826  !test exact mpp_global_sum
6827  id = mpp_clock_id( type//' exact sum', flags=mpp_clock_sync+mpp_clock_detailed )
6828  call mpp_clock_begin(id)
6829  lsum = mpp_global_sum( domain, x, bitwise_exact_sum, position = position )
6830  call mpp_clock_end (id)
6831  !--- The following check will fail on altix in normal mode, but it is ok
6832  !--- in debugging mode. It is ok on irix.
6833  call compare_data_scalar(lsum, gsum, fatal, type//' mpp_global_exact_sum')
6834 
6835  !test mpp_global_min
6836  gmin = minval(global1(1:ni, 1:nj, :))
6837  id = mpp_clock_id( type//' min', flags=mpp_clock_sync+mpp_clock_detailed )
6838  call mpp_clock_begin(id)
6839  lmin = mpp_global_min( domain, x, position = position )
6840  call mpp_clock_end (id)
6841  call compare_data_scalar(lmin, gmin, fatal, type//' mpp_global_min')
6842 
6843  !test mpp_global_max
6844  gmax = maxval(global1(1:ni, 1:nj, :))
6845  id = mpp_clock_id( type//' max', flags=mpp_clock_sync+mpp_clock_detailed )
6846  call mpp_clock_begin(id)
6847  lmax = mpp_global_max( domain, x, position = position )
6848  call mpp_clock_end (id)
6849  call compare_data_scalar(lmax, gmax, fatal, type//' mpp_global_max' )
6850 
6851  deallocate(global1, x)
6852 
6853  end subroutine test_global_reduce
6854 
6855 
6856  subroutine test_parallel ( )
6857 
6858  integer :: npes, layout(2), i, j, k,is, ie, js, je, isd, ied, jsd, jed
6859  real, dimension(:,:), allocatable :: field, lfield
6860  real, dimension(:,:,:), allocatable :: field3d, lfield3d
6861  type(domain2d) :: domain
6862  integer, dimension(:), allocatable :: pelist1 , pelist2
6863  logical :: group1, group2
6864  character(len=128) :: mesg
6865 
6866  npes = mpp_npes()
6867  allocate(pelist1(npes-mpes), pelist2(mpes))
6868  pelist1 = (/(i, i = 0, npes-mpes -1)/)
6869  pelist2 = (/(i, i = npes-mpes, npes - 1)/)
6870  call mpp_declare_pelist(pelist1)
6871  call mpp_declare_pelist(pelist2)
6872  group1 = .false. ; group2 = .false.
6873  if(any(pelist1==pe)) group1 = .true.
6874  if(any(pelist2==pe)) group2 = .true.
6875  mesg = 'parallel checking'
6876 
6877  if(group1) then
6878  call mpp_set_current_pelist(pelist1)
6879  call mpp_define_layout( (/1,nx,1,ny/), npes-mpes, layout )
6880  else if(group2) then
6881  call mpp_set_current_pelist(pelist2)
6882  call mpp_define_layout( (/1,nx,1,ny/), mpes, layout )
6883  endif
6884  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo)
6885 
6886  call mpp_set_current_pelist()
6887 
6888  call mpp_get_compute_domain(domain, is, ie, js, je)
6889  call mpp_get_data_domain(domain, isd, ied, jsd, jed)
6890  allocate(lfield(is:ie,js:je),field(isd:ied,jsd:jed))
6891  allocate(lfield3d(is:ie,js:je,nz),field3d(isd:ied,jsd:jed,nz))
6892 
6893  do i = is, ie
6894  do j = js, je
6895  lfield(i,j) = real(i)+real(j)*0.001
6896  enddo
6897  enddo
6898  do i = is, ie
6899  do j = js, je
6900  do k = 1, nz
6901  lfield3d(i,j,k) = real(i)+real(j)*0.001+real(k)*0.00001
6902  enddo
6903  enddo
6904  enddo
6905  field = 0.0
6906  field3d = 0.0
6907  field(is:ie,js:je)= lfield(is:ie,js:je)
6908  field3d(is:ie,js:je,:) = lfield3d(is:ie,js:je,:)
6909  call mpp_update_domains(field,domain)
6910  call mpp_update_domains(field3d,domain)
6911 
6912  call mpp_check_field(field, pelist1, pelist2,domain, '2D '//mesg, w_halo = whalo, &
6913  s_halo = shalo, e_halo = ehalo, n_halo = nhalo)
6914  call mpp_check_field(field3d, pelist1, pelist2,domain, '3D '//mesg, w_halo = whalo, &
6915  s_halo = shalo, e_halo = ehalo, n_halo = nhalo)
6916 
6917  end subroutine test_parallel
6918 
6919  subroutine test_modify_domain( )
6920 
6921  type(domain2D) :: domain2d_no_halo, domain2d_with_halo
6922  integer :: is1, ie1, js1, je1, isd1, ied1, jsd1, jed1
6923  integer :: is2, ie2, js2, je2, isd2, ied2, jsd2, jed2
6924 
6925  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
6926  call mpp_define_domains( (/1,nx,1,ny/), layout, domain2d_no_halo, &
6927  yflags=cyclic_global_domain, xhalo=0, yhalo=0)
6928 
6929  call mpp_get_compute_domain(domain2d_no_halo, is1, ie1, js1, je1)
6930  call mpp_get_data_domain(domain2d_no_halo, isd1, ied1, jsd1, jed1)
6931  call mpp_modify_domain(domain2d_no_halo, domain2d_with_halo, whalo=whalo,ehalo=ehalo,shalo=shalo,nhalo=nhalo)
6932  call mpp_get_compute_domain(domain2d_with_halo, is2, ie2, js2, je2)
6933  call mpp_get_data_domain(domain2d_with_halo, isd2, ied2, jsd2, jed2)
6934  if( is1 .NE. is2 .OR. ie1 .NE. ie2 .OR. js1 .NE. js2 .OR. je1 .NE. je2 ) then
6935  print*, "at pe ", pe, " compute domain without halo: ", is1, ie1, js1, je1, &
6936  " is not equal to the domain with halo ", is2, ie2, js2, je2
6937  call mpp_error(fatal, "compute domain mismatch between domain without halo and domain with halo")
6938  end if
6939 
6940  if( isd1-whalo .NE. isd2 .OR. ied1+ehalo .NE. ied2 .OR. jsd1-shalo .NE. jsd2 .OR. jed1+nhalo .NE. jed2 ) then
6941  print*, "at pe ", pe, "halo is w=",whalo,",e=",ehalo,",s=",shalo,"n=",nhalo, &
6942  ",data domain without halo is ",isd1, ied1, jsd1, jed1, &
6943  ", data domain with halo is ", isd2, ied2, jsd2, jed2
6944  else
6945  if( pe.EQ.mpp_root_pe() )call mpp_error( note, 'test_modify_domain: OK.' )
6946  end if
6947 
6948  return
6949 
6950 end subroutine test_modify_domain
6951 
6952  subroutine compare_checksums( a, b, string )
6953  real, intent(in), dimension(:,:,:) :: a, b
6954  character(len=*), intent(in) :: string
6955  integer(LONG_KIND) :: sum1, sum2
6956  integer :: i, j, k
6957 
6958  ! z1l can not call mpp_sync here since there might be different number of tiles on each pe.
6959  ! mpp_sync()
6960  call mpp_sync_self()
6961 
6962  if(size(a,1) .ne. size(b,1) .or. size(a,2) .ne. size(b,2) .or. size(a,3) .ne. size(b,3) ) &
6963  call mpp_error(fatal,'compare_chksum: size of a and b does not match')
6964 
6965  do k = 1, size(a,3)
6966  do j = 1, size(a,2)
6967  do i = 1, size(a,1)
6968  if(a(i,j,k) .ne. b(i,j,k)) then
6969  write(stdunit,'(a,i3,a,i3,a,i3,a,i3,a,f20.9,a,f20.9)')" at pe ", mpp_pe(), &
6970  ", at point (",i,", ", j, ", ", k, "), a = ", a(i,j,k), ", b = ", b(i,j,k)
6971  call mpp_error(fatal, trim(string)//': point by point comparison are not OK.')
6972  endif
6973  enddo
6974  enddo
6975  enddo
6976 
6977  sum1 = mpp_chksum( a, (/pe/) )
6978  sum2 = mpp_chksum( b, (/pe/) )
6979 
6980  if( sum1.EQ.sum2 )then
6981  if( pe.EQ.mpp_root_pe() )call mpp_error( note, trim(string)//': OK.' )
6982  !--- in some case, even though checksum agree, the two arrays
6983  ! actually are different, like comparing (1.1,-1.2) with (-1.1,1.2)
6984  !--- hence we need to check the value point by point.
6985  else
6986  call mpp_error( fatal, trim(string)//': chksums are not OK.' )
6987  end if
6988  end subroutine compare_checksums
6989 
6990  !###########################################################################
6991  subroutine compare_checksums_2d( a, b, string )
6992  real, intent(in), dimension(:,:) :: a, b
6993  character(len=*), intent(in) :: string
6994  integer(LONG_KIND) :: sum1, sum2
6995  integer :: i, j
6996 
6997  ! z1l can not call mpp_sync here since there might be different number of tiles on each pe.
6998  ! mpp_sync()
6999  call mpp_sync_self()
7000 
7001  if(size(a,1) .ne. size(b,1) .or. size(a,2) .ne. size(b,2) ) &
7002  call mpp_error(fatal,'compare_chksum_2D: size of a and b does not match')
7003 
7004  do j = 1, size(a,2)
7005  do i = 1, size(a,1)
7006  if(a(i,j) .ne. b(i,j)) then
7007  print*, "a =", a(i,j)
7008  print*, "b =", b(i,j)
7009  write(stdunit,'(a,i3,a,i3,a,i3,a,f20.9,a,f20.9)')"at pe ", mpp_pe(), &
7010  ", at point (",i,", ", j, "),a=", a(i,j), ",b=", b(i,j)
7011  call mpp_error(fatal, trim(string)//': point by point comparison are not OK.')
7012  endif
7013  enddo
7014  enddo
7015 
7016  sum1 = mpp_chksum( a, (/pe/) )
7017  sum2 = mpp_chksum( b, (/pe/) )
7018 
7019  if( sum1.EQ.sum2 )then
7020  if( pe.EQ.mpp_root_pe() )call mpp_error( note, trim(string)//': OK.' )
7021  !--- in some case, even though checksum agree, the two arrays
7022  ! actually are different, like comparing (1.1,-1.2) with (-1.1,1.2)
7023  !--- hence we need to check the value point by point.
7024  else
7025  call mpp_error( fatal, trim(string)//': chksums are not OK.' )
7026  end if
7027  end subroutine compare_checksums_2d
7028 
7029 
7030  !###########################################################################
7031 
7032  subroutine compare_data_scalar( a, b, action, string )
7033  real, intent(in) :: a, b
7034  integer, intent(in) :: action
7035  character(len=*), intent(in) :: string
7036  if( a .EQ. b)then
7037  if( pe.EQ.mpp_root_pe() )call mpp_error( note, trim(string)//': data comparison are OK.' )
7038  else
7039  write(stdunit,'(a,i3,a,es12.4,a,es12.4,a,es12.4)')' on pe ', mpp_pe(),' a = ', a, ', b = ', b, ', a - b =', a-b
7040  call mpp_error( action, trim(string)//': data comparison are not OK.' )
7041  end if
7042 
7043  end subroutine compare_data_scalar
7044 
7045  subroutine test_get_neighbor_1d
7046  type(domain1d) :: dmn1d
7047  integer npes, peN, peS
7048  npes = mpp_npes()
7049  call mpp_define_domains((/1,npes/), npes, dmn1d)
7050  call mpp_get_neighbor_pe(dmn1d, direction=+1, pe=pen)
7051  call mpp_get_neighbor_pe(dmn1d, direction=-1, pe=pes)
7052  print '(a,i2,a,2i3)', 'PE: ', mpp_pe(), ' R/L pes: ', pen, pes
7053  end subroutine test_get_neighbor_1d
7054 
7055  subroutine test_get_neighbor_non_cyclic
7056  type(domain2d) :: domain
7057  integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
7058  nx = 10
7059  ny = 20
7060  halo = 2
7061  npes = mpp_npes()
7062  if( npes .NE. 8 ) then
7063  call mpp_error(note, 'test_mpp_domains: test_get_neighbor_non_cyclic '// &
7064  ' will be performed only when npes = 8')
7065  return
7066  end if
7067  call mpp_define_layout( (/1,nx, 1,ny/), npes, layout )
7068  call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo)
7069  call mpp_get_neighbor_pe(domain, direction=north, pe=pen)
7070  call mpp_get_neighbor_pe(domain, direction=south, pe=pes)
7071  call mpp_get_neighbor_pe(domain, direction=east, pe=pee)
7072  call mpp_get_neighbor_pe(domain, direction=west, pe=pew)
7073  call mpp_get_neighbor_pe(domain, direction=north_east, pe=pene)
7074  call mpp_get_neighbor_pe(domain, direction=north_west, pe=penw)
7075  call mpp_get_neighbor_pe(domain, direction=south_east, pe=pese)
7076  call mpp_get_neighbor_pe(domain, direction=south_west, pe=pesw)
7077  print '(a,i2,a,2i2,a,8i3)','PE: ', mpp_pe(), ' layout (non-cyclic): ', layout, &
7078  & ' N/S/E/W/NE/SE/SW/NW pes: ', pen, pes, pee, pew, pene, pese, pesw, penw
7079  end subroutine test_get_neighbor_non_cyclic
7080 
7081  subroutine test_get_neighbor_cyclic
7082  type(domain2d) :: domain
7083  integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
7084  nx = 10
7085  ny = 20
7086  halo = 2
7087  npes = mpp_npes()
7088  if( npes .NE. 8 ) then
7089  call mpp_error(note, 'test_mpp_domains: test_get_neighbor_cyclic '// &
7090  ' will be performed only when npes = 8')
7091  return
7092  end if
7093  call mpp_define_layout( (/1,nx, 1,ny/), npes, layout )
7094  call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo, &
7095  xflags=cyclic_global_domain, yflags=cyclic_global_domain)
7096  call mpp_get_neighbor_pe(domain, direction=north, pe=pen)
7097  call mpp_get_neighbor_pe(domain, direction=south, pe=pes)
7098  call mpp_get_neighbor_pe(domain, direction=east, pe=pee)
7099  call mpp_get_neighbor_pe(domain, direction=west, pe=pew)
7100  call mpp_get_neighbor_pe(domain, direction=north_east, pe=pene)
7101  call mpp_get_neighbor_pe(domain, direction=north_west, pe=penw)
7102  call mpp_get_neighbor_pe(domain, direction=south_east, pe=pese)
7103  call mpp_get_neighbor_pe(domain, direction=south_west, pe=pesw)
7104  print '(a,i2,a,2i2,a,8i3)','PE: ', mpp_pe(), ' layout (cyclic) : ', layout, &
7105  & ' N/S/E/W/NE/SE/SW/NW pes: ', pen, pes, pee, pew, pene, pese, pesw, penw
7106  end subroutine test_get_neighbor_cyclic
7107 
7108  subroutine test_get_neighbor_folded_north
7109  type(domain2d) :: domain
7110  integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
7111  nx = 10
7112  ny = 20
7113  halo = 2
7114  npes = mpp_npes()
7115  if( npes .NE. 8 ) then
7116  call mpp_error(note, 'test_mpp_domains: test_get_neighbor_folded_north '// &
7117  ' will be performed only when npes = 8')
7118  return
7119  end if
7120  call mpp_define_layout( (/1,nx, 1,ny/), npes, layout )
7121  call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo, &
7122  xflags=cyclic_global_domain, yflags=fold_north_edge)
7123  call mpp_get_neighbor_pe(domain, direction=north, pe=pen)
7124  call mpp_get_neighbor_pe(domain, direction=south, pe=pes)
7125  call mpp_get_neighbor_pe(domain, direction=east, pe=pee)
7126  call mpp_get_neighbor_pe(domain, direction=west, pe=pew)
7127  call mpp_get_neighbor_pe(domain, direction=north_east, pe=pene)
7128  call mpp_get_neighbor_pe(domain, direction=north_west, pe=penw)
7129  call mpp_get_neighbor_pe(domain, direction=south_east, pe=pese)
7130  call mpp_get_neighbor_pe(domain, direction=south_west, pe=pesw)
7131  print '(a,i2,a,2i2,a,8i3)','PE: ', mpp_pe(), ' layout (folded N) : ', layout, &
7132  & ' N/S/E/W/NE/SE/SW/NW pes: ', pen, pes, pee, pew, pene, pese, pesw, penw
7133  end subroutine test_get_neighbor_folded_north
7134 
7135  subroutine test_get_neighbor_mask
7136  logical, allocatable :: mask(:,:)
7137  integer :: im, jm, n_remove
7138  type(domain2d) :: domain
7139  integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
7140  nx = 10
7141  ny = 20
7142  halo = 2
7143  npes = mpp_npes()
7144 
7145  n_remove = 2
7146  if( npes .NE. 8 ) then
7147  call mpp_error(note, 'test_mpp_domains: test_get_neighbor_mask '// &
7148  ' will be performed only when npes = 8')
7149  return
7150  end if
7151  call mpp_define_layout( (/1,nx, 1,ny/), npes+n_remove, layout )
7152  allocate(mask(layout(1), layout(2)))
7153  mask = .true. ! activate domains
7154  im = min(layout(1), ceiling(layout(1)/2.0))
7155  jm = min(layout(2), ceiling(layout(2)/2.0))
7156  mask(im ,jm ) = .false. ! deactivate domain
7157  mask(im ,jm-1) = .false. ! deactivate domain
7158  print '(a,2i3,a,2i3)', 'Masked out domains ', im, jm, ' and ', im,jm-1
7159  call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo, &
7160  maskmap=mask)
7161  call mpp_get_neighbor_pe(domain, direction=north, pe=pen)
7162  call mpp_get_neighbor_pe(domain, direction=south, pe=pes)
7163  call mpp_get_neighbor_pe(domain, direction=east, pe=pee)
7164  call mpp_get_neighbor_pe(domain, direction=west, pe=pew)
7165  call mpp_get_neighbor_pe(domain, direction=north_east, pe=pene)
7166  call mpp_get_neighbor_pe(domain, direction=north_west, pe=penw)
7167  call mpp_get_neighbor_pe(domain, direction=south_east, pe=pese)
7168  call mpp_get_neighbor_pe(domain, direction=south_west, pe=pesw)
7169  print '(a,i3,a,2i3,a,8i3)','PE: ', mpp_pe(), ' layout (mask ) : ', layout, &
7170  & ' N/S/E/W/NE/SE/SW/NW pes: ', pen, pes, pee, pew, pene, pese, pesw, penw
7171  end subroutine test_get_neighbor_mask
7172 
7173  subroutine test_define_mosaic_pelist(type, ntile)
7174  character(len=*), intent(in) :: type
7175  integer, intent(in) :: ntile
7176  integer :: npes, root_pe, start_pe, n, ntile_per_pe
7177  integer, dimension(:), allocatable :: pe1_start, pe1_end, pe2_start, pe2_end
7178  integer, dimension(:), allocatable :: sizes, costpertile
7179 
7180  root_pe = mpp_root_pe()
7181  npes = mpp_npes()
7182 
7183  allocate(sizes(ntile), pe1_start(ntile), pe1_end(ntile), pe2_start(ntile), pe2_end(ntile),costpertile(ntile) )
7184  costpertile = 1
7185  sizes = nx*ny
7186  if(npes ==1) then
7187  pe1_start = root_pe; pe1_end = root_pe
7188  end if
7189  select case(type)
7190  case('One tile')
7191  pe1_start = root_pe; pe1_end = npes+root_pe-1
7192  case('Two uniform tile')
7193  if(mod(npes,2) .NE. 0 .AND. npes .NE. 1) then
7194  call mpp_error(note, 'test_define_mosaic_pelist: npes can not be divided by 2, no test for '//type )
7195  return
7196  end if
7197  if(npes .NE. 1) then
7198  pe1_start(1) = root_pe; pe1_end(1) = npes/2+root_pe-1
7199  pe1_start(2) = npes/2+root_pe; pe1_end(2) = npes+root_pe-1
7200  end if
7201  case('Two nonuniform tile')
7202  if(mod(npes,3) .NE. 0 .AND. npes .NE. 1) then
7203  call mpp_error(note, 'test_define_mosaic_pelist: npes can not be divided by 3, no test for '//type )
7204  return
7205  end if
7206  sizes(1) = 2*nx*ny
7207  if(npes .NE. 1) then
7208  pe1_start(1) = root_pe; pe1_end(1) = npes/3*2+root_pe-1
7209  pe1_start(2) = npes/3*2+root_pe; pe1_end(2) = npes+root_pe-1
7210  end if
7211  case('Ten tile')
7212  if(mod(npes,10) .NE. 0 .AND. npes .NE. 1 .AND. mod(10,npes) .NE. 0) then
7213  call mpp_error(note, 'test_define_mosaic_pelist: npes can not be divided by 10(or reverse), no test for '//type )
7214  return
7215  end if
7216  if(mod(10, npes)==0) then
7217  ntile_per_pe = ntile/npes
7218  do n = 1, ntile
7219  pe1_start(n) = root_pe+(n-1)/ntile_per_pe; pe1_end(n) = pe1_start(n)
7220  end do
7221  else if(mod(npes,10) == 0) then
7222  do n = 1, ntile
7223  pe1_start(n) = npes/10*(n-1)+root_pe; pe1_end(n) = npes/10*n+root_pe-1
7224  end do
7225  end if
7226  case('Ten tile with nonuniform cost')
7227  if(mod(npes,15) .NE. 0 .AND. npes .NE. 1) then
7228  call mpp_error(note, 'test_define_mosaic_pelist: npes can not be divided by 15, no test for '//type )
7229  return
7230  end if
7231  costpertile(1:5) = 2; costpertile(6:ntile) = 1
7232  if(npes .NE. 1) then
7233  start_pe = root_pe
7234  do n = 1, ntile
7235  pe1_start(n) = start_pe
7236  pe1_end(n) = start_pe + npes/15*costpertile(n)-1
7237  start_pe = pe1_end(n) + 1
7238  end do
7239  end if
7240  case default
7241  call mpp_error(fatal,"test_define_mosaic_pelist: "//type//" is an invalid type")
7242  end select
7243 
7244  call mpp_define_mosaic_pelist( sizes, pe2_start, pe2_end, costpertile=costpertile)
7245  if( any(pe1_start .NE. pe2_start) .OR. any(pe1_end .NE. pe2_end) ) then
7246  call mpp_error(fatal,"test_define_mosaic_pelist: test failed for "//trim(type) )
7247  else
7248  call mpp_error(note,"test_define_mosaic_pelist: test successful for "//trim(type) )
7249  end if
7250 
7251  end subroutine test_define_mosaic_pelist
7252 
7253 !###############################################################################
7254  subroutine test_update_nest_domain( type )
7255  character(len=*), intent(in) :: type
7256  logical :: cubic_grid, concurrent
7257  logical :: is_fine_pe, is_coarse_pe
7258  integer :: n, i, j, k, l
7259  integer :: ntiles, num_contact, npes_per_tile
7260  integer :: isc_coarse, iec_coarse, jsc_coarse, jec_coarse
7261  integer :: isd_coarse, ied_coarse, jsd_coarse, jed_coarse
7262  integer :: isd_fine, ied_fine, jsd_fine, jed_fine
7263  integer :: isc_fine, iec_fine, jsc_fine, jec_fine
7264  integer :: x_refine, y_refine, nx_coarse, ny_coarse
7265  integer :: nxc_fine, nyc_fine, nxc_coarse, nyc_coarse
7266  integer :: isw_f, iew_f, jsw_f, jew_f, isw_c, iew_c, jsw_c, jew_c
7267  integer :: ise_f, iee_f, jse_f, jee_f, ise_c, iee_c, jse_c, jee_c
7268  integer :: iss_f, ies_f, jss_f, jes_f, iss_c, ies_c, jss_c, jes_c
7269  integer :: isn_f, ien_f, jsn_f, jen_f, isn_c, ien_c, jsn_c, jen_c
7270  integer :: isw_f2, iew_f2, jsw_f2, jew_f2, isw_c2, iew_c2, jsw_c2, jew_c2, tile_w2
7271  integer :: ise_f2, iee_f2, jse_f2, jee_f2, ise_c2, iee_c2, jse_c2, jee_c2, tile_e2
7272  integer :: iss_f2, ies_f2, jss_f2, jes_f2, iss_c2, ies_c2, jss_c2, jes_c2, tile_s2
7273  integer :: isn_f2, ien_f2, jsn_f2, jen_f2, isn_c2, ien_c2, jsn_c2, jen_c2, tile_n2
7274  integer :: is_c, ie_c, js_c, je_c, is_f, ie_f, js_f, je_f
7275  integer :: is_c2, ie_c2, js_c2, je_c2, is_f2, ie_f2, js_f2, je_f2
7276  integer :: nx_fine, ny_fine, tile, position, ishift, jshift
7277  integer :: layout_fine(2)
7278  integer, allocatable :: pelist(:)
7279  integer, allocatable :: pelist_coarse(:)
7280  integer, allocatable :: pelist_fine(:)
7281  integer, allocatable :: pe_start(:), pe_end(:)
7282  integer, allocatable :: layout2D(:,:), global_indices(:,:)
7283  real, allocatable :: x(:,:,:)
7284  real, allocatable :: wbuffer(:,:,:), wbuffer2(:,:,:)
7285  real, allocatable :: ebuffer(:,:,:), ebuffer2(:,:,:)
7286  real, allocatable :: sbuffer(:,:,:), sbuffer2(:,:,:)
7287  real, allocatable :: nbuffer(:,:,:), nbuffer2(:,:,:)
7288  real, allocatable :: buffer(:,:,:), buffer2(:,:,:)
7289  character(len=32) :: position_name
7290  type(domain2d) :: domain_coarse, domain_fine
7291  type(nest_domain_type) :: nest_domain
7292 
7293  select case(type)
7294  case ( 'Cubic-Grid' )
7295  if( nx_cubic == 0 ) then
7296  call mpp_error(note,'test_update_nest_domain: for Cubic_grid mosaic, nx_cubic is zero, '//&
7297  'No test is done for Cubic-Grid mosaic. ' )
7298  return
7299  endif
7300  if( nx_cubic .NE. ny_cubic ) then
7301  call mpp_error(note,'test_update_nest_domain: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
7302  'No test is done for Cubic-Grid mosaic. ' )
7303  return
7304  endif
7305  nx = nx_cubic
7306  ny = ny_cubic
7307  ntiles = 6
7308  num_contact = 12
7309  cubic_grid = .true.
7310  case default
7311  call mpp_error(fatal, 'test_update_nest_domain: no such test: '//type)
7312  end select
7313 
7314  npes = mpp_npes()
7315  if(mod(npes_coarse,ntiles) .NE. 0) call mpp_error(fatal, "test_mpp_domains: npes_coarse should be divided by ntiles")
7316 
7317  !--- npes_coarse + npes_fine (concurrent) == npes or npes_coarse = npes_fine = npes (series)
7318  npes = mpp_npes()
7319  allocate(pelist(npes))
7320  call mpp_get_current_pelist(pelist)
7321  allocate(pelist_coarse(npes_coarse))
7322  allocate(pelist_fine(npes_fine))
7323  if( npes_coarse + npes_fine == mpp_npes() ) then
7324  concurrent = .true.
7325  pelist_coarse(1:npes_coarse) = pelist(1:npes_coarse)
7326  pelist_fine(1:npes_fine) = pelist(npes_coarse+1:npes_coarse+npes_fine)
7327  else if(npes_coarse == npes_fine .AND. npes_coarse == npes) then
7328  concurrent = .false.
7329  pelist_fine = pelist
7330  pelist_coarse = pelist
7331  else
7332  call mpp_error(fatal, 'test_update_nest_domain: either npes_fine+npes_coarse=npes or npes_fine=npes_coarse=npes')
7333  endif
7334 
7335  call mpp_declare_pelist(pelist_fine, "fine grid")
7336  call mpp_declare_pelist(pelist_coarse, "coarse grid")
7337 
7338  is_fine_pe = any(pelist_fine(:) == mpp_pe())
7339  is_coarse_pe = any(pelist_coarse(:) == mpp_pe())
7340 
7341  !--- first define the coarse grid mosaic domain.
7342  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
7343  if(is_coarse_pe) then
7344  npes_per_tile = npes_coarse/ntiles
7345 
7346  call mpp_set_current_pelist(pelist_coarse)
7347  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
7348  do n = 1, ntiles
7349  global_indices(:,n) = (/1,nx,1,ny/)
7350  layout2d(:,n) = layout
7351  end do
7352  do n = 1, ntiles
7353  pe_start(n) = (n-1)*npes_per_tile
7354  pe_end(n) = n*npes_per_tile-1
7355  end do
7356 
7357  if( cubic_grid ) then
7358  call define_cubic_mosaic(type, domain_coarse, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
7359  global_indices, layout2D, pe_start, pe_end )
7360  endif
7361  call mpp_get_compute_domain(domain_coarse, isc_coarse, iec_coarse, jsc_coarse, jec_coarse)
7362  call mpp_get_data_domain(domain_coarse, isd_coarse, ied_coarse, jsd_coarse, jed_coarse)
7363  endif
7364 
7365  !--- define the fine grid mosaic doamin
7366  nx_fine = iend_fine - istart_fine + 1
7367  ny_fine = jend_fine - jstart_fine + 1
7368  if(is_fine_pe) then
7369  call mpp_set_current_pelist(pelist_fine)
7370  call mpp_define_layout( (/1,nx_fine,1,ny_fine/), npes_fine, layout_fine )
7371  call mpp_define_domains((/1,nx_fine,1,ny_fine/), layout_fine, domain_fine, &
7372  whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
7373  symmetry=.true., name="fine grid domain")
7374  call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine)
7375  call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine)
7376  endif
7377 
7378  !--- define the nest domain
7379  call mpp_set_current_pelist()
7380 
7381  !--- for concurrent run, need to broadcast domain
7382  if( concurrent ) then
7383  call mpp_broadcast_domain(domain_fine)
7384  call mpp_broadcast_domain(domain_coarse)
7385  endif
7386 
7387  !--- make sure the integer refinement
7388  nx_coarse = iend_coarse - istart_coarse + 1
7389  ny_coarse = jend_coarse - jstart_coarse + 1
7390  if( mod(nx_fine,nx_coarse) .NE. 0 ) call mpp_error(fatal, &
7391  "test_mpp_domains: The refinement in x-direction is not integer for type="//trim(type) )
7392  x_refine = nx_fine/nx_coarse
7393  if( mod(ny_fine,ny_coarse) .NE. 0 ) call mpp_error(fatal, &
7394  "test_mpp_domains: The refinement in y-direction is not integer for type="//trim(type) )
7395  y_refine = ny_fine/ny_coarse
7396 
7397 
7398  call mpp_define_nest_domains(nest_domain, domain_fine, domain_coarse, tile_fine, tile_coarse, &
7399  istart_fine, iend_fine, jstart_fine, jend_fine, &
7400  istart_coarse, iend_coarse, jstart_coarse, jend_coarse, &
7401  pelist, extra_halo, name="nest_domain")
7402 
7403  !---------------------------------------------------------------------------
7404  !
7405  ! Coarse to Fine
7406  !
7407  !---------------------------------------------------------------------------
7408  do l = 1, 4 ! T, E, C, N
7409  select case(l)
7410  case(1)
7411  position = center
7412  position_name = "CENTER"
7413  case(2)
7414  position = east
7415  position_name = "EAST"
7416  case(3)
7417  position = corner
7418  position_name = "CORNER"
7419  case(4)
7420  position = north
7421  position_name = "NORTH"
7422  end select
7423 
7424  call mpp_get_domain_shift(domain_coarse, ishift, jshift, position)
7425  !--- first check the index is correct or not
7426  if(is_fine_pe) then
7427  !--- The index from nest domain
7428  call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine, position=position)
7429  call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine, position=position)
7430  call mpp_get_c2f_index(nest_domain, isw_f, iew_f, jsw_f, jew_f, isw_c, iew_c, jsw_c, jew_c, west, position=position)
7431  call mpp_get_c2f_index(nest_domain, ise_f, iee_f, jse_f, jee_f, ise_c, iee_c, jse_c, jee_c, east, position=position)
7432  call mpp_get_c2f_index(nest_domain, iss_f, ies_f, jss_f, jes_f, iss_c, ies_c, jss_c, jes_c, south, position=position)
7433  call mpp_get_c2f_index(nest_domain, isn_f, ien_f, jsn_f, jen_f, isn_c, ien_c, jsn_c, jen_c, north, position=position)
7434 
7435  !-- The assumed index
7436  isw_f2 = 0; iew_f2 = -1; jsw_f2 = 0; jew_f2 = -1
7437  isw_c2 = 0; iew_c2 = -1; jsw_c2 = 0; jew_c2 = -1
7438  ise_f2 = 0; iee_f2 = -1; jse_f2 = 0; jee_f2 = -1
7439  ise_c2 = 0; iee_c2 = -1; jse_c2 = 0; jee_c2 = -1
7440  iss_f2 = 0; ies_f2 = -1; jss_f2 = 0; jes_f2 = -1
7441  iss_c2 = 0; ies_c2 = -1; jss_c2 = 0; jes_c2 = -1
7442  isn_f2 = 0; ien_f2 = -1; jsn_f2 = 0; jen_f2 = -1
7443  isn_c2 = 0; ien_c2 = -1; jsn_c2 = 0; jen_c2 = -1
7444 
7445  !--- west
7446  if( isc_fine == 1 ) then
7447  isw_f2 = isd_fine; iew_f2 = isc_fine - 1
7448  jsw_f2 = jsd_fine; jew_f2 = jed_fine
7449  isw_c2 = istart_coarse-whalo
7450  iew_c2 = istart_coarse
7451  jsw_c2 = jstart_coarse + (jsc_fine - jstart_fine)/y_refine - shalo
7452  jew_c2 = jstart_coarse + (jec_fine - jstart_fine)/y_refine + nhalo
7453  endif
7454  !--- east
7455  if( iec_fine == nx_fine+ishift ) then
7456  ise_f2 = iec_fine+1; iee_f2 = ied_fine
7457  jse_f2 = jsd_fine; jee_f2 = jed_fine
7458  ise_c2 = iend_coarse+ishift
7459  iee_c2 = iend_coarse+ehalo+ishift
7460  jse_c2 = jstart_coarse + (jsc_fine - jstart_fine)/y_refine - shalo
7461  jee_c2 = jstart_coarse + (jec_fine - jstart_fine)/y_refine + nhalo
7462  endif
7463  !--- south
7464  if( jsc_fine == 1 ) then
7465  iss_f2 = isd_fine; ies_f2 = ied_fine
7466  jss_f2 = jsd_fine; jes_f2 = jsc_fine - 1
7467  iss_c2 = istart_coarse + (isc_fine - istart_fine)/x_refine - whalo
7468  ies_c2 = istart_coarse + (iec_fine - istart_fine)/x_refine + ehalo
7469  jss_c2 = jstart_coarse-shalo
7470  jes_c2 = jstart_coarse
7471  endif
7472  !--- north
7473  if( jec_fine == ny_fine+jshift ) then
7474  isn_f2 = isd_fine; ien_f2 = ied_fine
7475  jsn_f2 = jec_fine+1; jen_f2 = jed_fine
7476  isn_c2 = istart_coarse + (isc_fine - istart_fine)/x_refine - whalo
7477  ien_c2 = istart_coarse + (iec_fine - istart_fine)/x_refine + ehalo
7478  jsn_c2 = jend_coarse+jshift
7479  jen_c2 = jend_coarse+nhalo+jshift
7480  endif
7481 
7482  if( isw_f .NE. isw_f2 .OR. iew_f .NE. iew_f2 .OR. jsw_f .NE. jsw_f2 .OR. jew_f .NE. jew_f2 .OR. &
7483  isw_c .NE. isw_c2 .OR. iew_c .NE. iew_c2 .OR. jsw_c .NE. jsw_c2 .OR. jew_c .NE. jew_c2 ) then
7484  call mpp_error(fatal, "test_mpp_domains: west buffer index mismatch for "//trim(position_name))
7485  endif
7486  if( ise_f .NE. ise_f2 .OR. iee_f .NE. iee_f2 .OR. jse_f .NE. jse_f2 .OR. jee_f .NE. jee_f2 .OR. &
7487  ise_c .NE. ise_c2 .OR. iee_c .NE. iee_c2 .OR. jse_c .NE. jse_c2 .OR. jee_c .NE. jee_c2 ) then
7488  call mpp_error(fatal, "test_mpp_domains: east buffer index mismatch for "//trim(position_name))
7489  endif
7490  if( iss_f .NE. iss_f2 .OR. ies_f .NE. ies_f2 .OR. jss_f .NE. jss_f2 .OR. jes_f .NE. jes_f2 .OR. &
7491  iss_c .NE. iss_c2 .OR. ies_c .NE. ies_c2 .OR. jss_c .NE. jss_c2 .OR. jes_c .NE. jes_c2 ) then
7492  call mpp_error(fatal, "test_mpp_domains: south buffer index mismatch for "//trim(position_name))
7493  endif
7494  if( isn_f .NE. isn_f2 .OR. ien_f .NE. ien_f2 .OR. jsn_f .NE. jsn_f2 .OR. jen_f .NE. jen_f2 .OR. &
7495  isn_c .NE. isn_c2 .OR. ien_c .NE. ien_c2 .OR. jsn_c .NE. jsn_c2 .OR. jen_c .NE. jen_c2 ) then
7496  call mpp_error(fatal, "test_mpp_domains: north buffer index mismatch for "//trim(position_name))
7497  endif
7498  endif
7499 
7500  if(is_coarse_pe) then
7501  call mpp_get_compute_domain(domain_coarse, isc_coarse, iec_coarse, jsc_coarse, jec_coarse, position=position)
7502  call mpp_get_data_domain(domain_coarse, isd_coarse, ied_coarse, jsd_coarse, jed_coarse, position=position)
7503  allocate(x(isd_coarse:ied_coarse, jsd_coarse:jed_coarse, nz))
7504  x = 0
7505  npes_per_tile = npes_coarse/ntiles
7506  tile = mpp_pe()/npes_per_tile + 1
7507  do k = 1, nz
7508  do j = jsc_coarse, jec_coarse
7509  do i = isc_coarse, iec_coarse
7510  x(i,j,k) = tile + i*1.e-3 + j*1.e-6 + k*1.e-9
7511  enddo
7512  enddo
7513  enddo
7514  else
7515  allocate(x(isd_fine:ied_fine, jsd_fine:jed_fine, nz))
7516  x = 0
7517  do k = 1, nz
7518  do j = jsc_fine, jec_fine
7519  do i = isc_fine, iec_fine
7520  x(i,j,k) = i*1.e+6 + j*1.e+3 + k
7521  enddo
7522  enddo
7523  enddo
7524  endif
7525 
7526  if(is_fine_pe) then
7527  if( iew_c .GE. isw_c .AND. jew_c .GE. jsw_c ) then
7528  allocate(wbuffer(isw_c:iew_c, jsw_c:jew_c,nz))
7529  allocate(wbuffer2(isw_c:iew_c, jsw_c:jew_c,nz))
7530  else
7531  allocate(wbuffer(1,1,1))
7532  allocate(wbuffer2(1,1,1))
7533  endif
7534  wbuffer = 0; wbuffer2 = 0
7535 
7536  if( iee_c .GE. ise_c .AND. jee_c .GE. jse_c ) then
7537  allocate(ebuffer(ise_c:iee_c, jse_c:jee_c,nz))
7538  allocate(ebuffer2(ise_c:iee_c, jse_c:jee_c,nz))
7539  else
7540  allocate(ebuffer(1,1,1))
7541  allocate(ebuffer2(1,1,1))
7542  endif
7543  ebuffer = 0; ebuffer2 = 0
7544 
7545  if( ies_c .GE. iss_c .AND. jes_c .GE. jss_c ) then
7546  allocate(sbuffer(iss_c:ies_c, jss_c:jes_c,nz))
7547  allocate(sbuffer2(iss_c:ies_c, jss_c:jes_c,nz))
7548  else
7549  allocate(sbuffer(1,1,1))
7550  allocate(sbuffer2(1,1,1))
7551  endif
7552  sbuffer = 0; sbuffer2 = 0
7553 
7554  if( ien_c .GE. isn_c .AND. jen_c .GE. jsn_c ) then
7555  allocate(nbuffer(isn_c:ien_c, jsn_c:jen_c,nz))
7556  allocate(nbuffer2(isn_c:ien_c, jsn_c:jen_c,nz))
7557  else
7558  allocate(nbuffer(1,1,1))
7559  allocate(nbuffer2(1,1,1))
7560  endif
7561  nbuffer = 0; nbuffer2 = 0
7562 
7563  endif
7564 
7565  call mpp_update_nest_fine(x, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, position=position)
7566 
7567  !--- compare with the assumed value.
7568  if( is_fine_pe ) then
7569  if( iew_c .GE. isw_c .AND. jew_c .GE. jsw_c ) then
7570  do k = 1, nz
7571  do j = jsw_c, jew_c
7572  do i = isw_c, iew_c
7573  wbuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
7574  enddo
7575  enddo
7576  enddo
7577  endif
7578  call compare_checksums(wbuffer, wbuffer2, trim(type)//' west buffer '//trim(position_name))
7579 
7580  if( ies_c .GE. iss_c .AND. jes_c .GE. jss_c ) then
7581  do k = 1, nz
7582  do j = jss_c, jes_c
7583  do i = iss_c, ies_c
7584  sbuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
7585  enddo
7586  enddo
7587  enddo
7588  endif
7589  call compare_checksums(sbuffer, sbuffer2, trim(type)//' south buffer '//trim(position_name))
7590 
7591  if( iee_c .GE. ise_c .AND. jee_c .GE. jse_c ) then
7592  do k = 1, nz
7593  do j = jse_c, jee_c
7594  do i = ise_c, iee_c
7595  ebuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
7596  enddo
7597  enddo
7598  enddo
7599  endif
7600  call compare_checksums(ebuffer, ebuffer2, trim(type)//' east buffer '//trim(position_name))
7601 
7602  if( ien_c .GE. isn_c .AND. jen_c .GE. jsn_c ) then
7603  do k = 1, nz
7604  do j = jsn_c, jen_c
7605  do i = isn_c, ien_c
7606  nbuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
7607  enddo
7608  enddo
7609  enddo
7610  endif
7611  call compare_checksums(nbuffer, nbuffer2, trim(type)//' north buffer '//trim(position_name))
7612 
7613  endif
7614  if(is_fine_pe) then
7615  deallocate(wbuffer, ebuffer, sbuffer, nbuffer)
7616  deallocate(wbuffer2, ebuffer2, sbuffer2, nbuffer2)
7617  endif
7618  deallocate(x)
7619  enddo
7620  !---------------------------------------------------------------------------
7621  ! check fine to coarse
7622  !---------------------------------------------------------------------------
7623  if(is_fine_pe) then
7624  call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine)
7625  call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine)
7626  endif
7627 
7628  if(is_coarse_pe) then
7629  call mpp_get_compute_domain(domain_coarse, isc_coarse, iec_coarse, jsc_coarse, jec_coarse)
7630  call mpp_get_data_domain(domain_coarse, isd_coarse, ied_coarse, jsd_coarse, jed_coarse)
7631  endif
7632 
7633  do l = 1, 4 ! T, E, C, N
7634  select case(l)
7635  case(1)
7636  position = center
7637  position_name = "CENTER"
7638  case(2)
7639  position = east
7640  position_name = "EAST"
7641  case(3)
7642  position = corner
7643  position_name = "CORNER"
7644  case(4)
7645  position = north
7646  position_name = "NORTH"
7647  end select
7648 
7649  call mpp_get_domain_shift(domain_coarse, ishift, jshift, position)
7650 
7651  if(is_fine_pe) then
7652  call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine,position=position)
7653  call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine,position=position)
7654  allocate(x(isd_fine:ied_fine, jsd_fine:jed_fine, nz))
7655  x = 0
7656  do k = 1, nz
7657  do j = jsc_fine, jec_fine+jshift
7658  do i = isc_fine, iec_fine+ishift
7659  x(i,j,k) = i*1.e+6 + j*1.e+3 + k
7660  enddo
7661  enddo
7662  enddo
7663  else
7664  allocate(x(isd_coarse:ied_coarse+ishift, jsd_coarse:jed_coarse+jshift, nz))
7665  x = 0
7666  npes_per_tile = npes_coarse/ntiles
7667  tile = mpp_pe()/npes_per_tile + 1
7668  do k = 1, nz
7669  do j = jsc_coarse, jec_coarse+jshift
7670  do i = isc_coarse, iec_coarse+ishift
7671  x(i,j,k) = tile + i*1.e-3 + j*1.e-6 + k*1.e-9
7672  enddo
7673  enddo
7674  enddo
7675  endif
7676 
7677 
7678  if(is_coarse_pe) then
7679  !--- The index from nest domain
7680  call mpp_get_f2c_index(nest_domain, is_c, ie_c, js_c, je_c, is_f, ie_f, js_f, je_f,position=position)
7681  npes_per_tile = npes_coarse/ntiles
7682  tile = mpp_pe()/npes_per_tile + 1
7683  !-- The assumed index
7684  is_c2 = max(istart_coarse, isc_coarse)
7685  ie_c2 = min(iend_coarse, iec_coarse)
7686  js_c2 = max(jstart_coarse, jsc_coarse)
7687  je_c2 = min(jend_coarse, jec_coarse)
7688  if( tile == tile_coarse .AND. ie_c .GE. is_c .AND. je_c .GE. js_c ) then
7689  is_f2 = istart_fine + (is_c2 - istart_coarse)*x_refine
7690  ie_f2 = istart_fine + (ie_c2 - istart_coarse + 1)*x_refine - 1
7691  js_f2 = jstart_fine + (js_c2 - jstart_coarse)*y_refine
7692  je_f2 = jstart_fine + (je_c2 - jstart_coarse + 1)*y_refine - 1
7693  ie_f2 = ie_f2 + ishift; je_f2 = je_f2 + jshift
7694  ie_c2 = ie_c2 + ishift; je_c2 = je_c2 + jshift
7695  else
7696  is_f2 = 0; ie_f2 = -1; js_f2 = 0; je_f2 = -1
7697  is_c2 = 0; ie_c2 = -1; js_c2 = 0; je_c2 = -1
7698  endif
7699 
7700  if( is_f .NE. is_f2 .OR. ie_f .NE. ie_f2 .OR. js_f .NE. js_f2 .OR. je_f .NE. je_f2 .OR. &
7701  is_c .NE. is_c2 .OR. ie_c .NE. ie_c2 .OR. js_c .NE. js_c2 .OR. je_c .NE. je_c2 ) then
7702  call mpp_error(fatal, "test_mpp_domains: fine to coarse buffer index mismatch")
7703  endif
7704  endif
7705 
7706  if(is_coarse_pe) then
7707  if( ie_f .GE. is_f .AND. je_f .GE. js_f ) then
7708  allocate(buffer(is_f:ie_f, js_f:je_f,nz))
7709  allocate(buffer2(is_f:ie_f, js_f:je_f,nz))
7710  do k = 1, nz
7711  do j = js_f, je_f
7712  do i = is_f, ie_f
7713  buffer2(i,j,k) = i*1.e+6 + j*1.e+3 + k
7714  enddo
7715  enddo
7716  enddo
7717  else
7718  allocate(buffer(1,1,1))
7719  allocate(buffer2(1,1,1))
7720  buffer2 = 0
7721  endif
7722  buffer = 0
7723  endif
7724 
7725  call mpp_update_nest_coarse(x, nest_domain, buffer, position=position)
7726 
7727  !--- compare with assumed value
7728  if( is_coarse_pe) then
7729  call compare_checksums(buffer, buffer2, trim(type)//' fine to coarse buffer '//trim(position_name))
7730  endif
7731  if(allocated(buffer)) deallocate(buffer)
7732  if(allocated(buffer2)) deallocate(buffer2)
7733  if(allocated(x)) deallocate(x)
7734  enddo
7735 
7736  deallocate(pelist, pelist_fine, pelist_coarse)
7737  deallocate(layout2d, global_indices, pe_start, pe_end )
7738 
7739  end subroutine test_update_nest_domain
7740  subroutine test_get_boundary_ad(type)
7741  use mpp_mod, only : mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
7742  use mpp_domains_mod, only : cgrid_ne
7743  use mpp_domains_mod, only : mpp_get_boundary
7745 
7746  character(len=*), intent(in) :: type
7747 
7748  type(domain2D) :: domain
7749  integer :: ntiles, num_contact, npes_per_tile, ntile_per_pe, layout(2)
7750  integer :: n, l, isc, iec, jsc, jec, ism, iem, jsm, jem
7751  integer, allocatable, dimension(:) :: tile, ni, nj, pe_start, pe_end
7752  integer, allocatable, dimension(:,:) :: layout2D, global_indices
7753 
7754  real*8, allocatable, dimension(:,:,:) :: x_ad, y_ad, x_fd, y_fd, x_save, y_save
7755  real*8, allocatable, dimension(:,:) :: ebufferx2_ad, wbufferx2_ad
7756  real*8, allocatable, dimension(:,:) :: sbuffery2_ad, nbuffery2_ad
7757  real*8 :: ad_sum, fd_sum
7758  integer :: shift,i,j,k,pe
7759 
7760  !--- check the type
7761  ntiles = 4
7762  num_contact = 8
7763 
7764  allocate(layout2d(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
7765  allocate(ni(ntiles), nj(ntiles))
7766  ni(:) = nx; nj(:) = ny
7767  if( mod(npes, ntiles) == 0 ) then
7768  npes_per_tile = npes/ntiles
7769  write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
7770  '", each tile will be distributed over ', npes_per_tile, ' processors.'
7771  ntile_per_pe = 1
7772  allocate(tile(ntile_per_pe))
7773  tile = pe/npes_per_tile+1
7774  call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
7775  do n = 1, ntiles
7776  pe_start(n) = (n-1)*npes_per_tile
7777  pe_end(n) = n*npes_per_tile-1
7778  end do
7779  else
7780  call mpp_error(note,'TEST_MPP_DOMAINS: npes should be multiple of ntiles or ' // &
7781  'ntiles should be multiple of npes. No test is done for '//trim(type) )
7782  return
7783  end if
7784 
7785  do n = 1, ntiles
7786  global_indices(:,n) = (/1,nx,1,ny/)
7787  layout2d(:,n) = layout
7788  end do
7789 
7790  call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
7791  layout2D, pe_start, pe_end, .true. )
7792 
7793  call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
7794  call mpp_get_memory_domain( domain, ism, iem, jsm, jem )
7795 
7796  deallocate(layout2d, global_indices, pe_start, pe_end )
7797  deallocate(ni, nj)
7798 
7799  shift = 1
7800  allocate( x_ad(ism:iem+shift,jsm:jem ,nz) )
7801  allocate( x_fd(ism:iem+shift,jsm:jem ,nz) )
7802  allocate( x_save(ism:iem+shift,jsm:jem ,nz) )
7803  allocate( y_ad(ism:iem ,jsm:jem+shift,nz) )
7804  allocate( y_fd(ism:iem ,jsm:jem+shift,nz) )
7805  allocate( y_save(ism:iem ,jsm:jem+shift,nz) )
7806  allocate(ebufferx2_ad(jec-jsc+1, nz), wbufferx2_ad(jec-jsc+1, nz))
7807  allocate(sbuffery2_ad(iec-isc+1, nz), nbuffery2_ad(iec-isc+1, nz))
7808 
7809  pe = mpp_pe()
7810 
7811  x_fd=0; y_fd=0
7812  do k = 1,nz
7813  do j = jsc,jec
7814  do i = isc,iec
7815  x_fd(i,j,k)= i*j
7816  y_fd(i,j,k)= i*j
7817  end do
7818  end do
7819  end do
7820 
7821  x_save=x_fd
7822  y_save=y_fd
7823 
7824  ebufferx2_ad = 0
7825  wbufferx2_ad = 0
7826  sbuffery2_ad = 0
7827  nbuffery2_ad = 0
7828 
7829  call mpp_get_boundary(x_fd, y_fd, domain, ebufferx=ebufferx2_ad(:,:), wbufferx=wbufferx2_ad(:,:), &
7830  sbuffery=sbuffery2_ad(:,:), nbuffery=nbuffery2_ad(:,:), gridtype=cgrid_ne, &
7831  complete = .true. )
7832  fd_sum = 0.
7833  do k = 1,nz
7834  do j = jsc,jec
7835  do i = isc,iec
7836  fd_sum = fd_sum + x_fd(i,j,k)*x_fd(i,j,k)
7837  end do
7838  end do
7839  end do
7840  do k = 1,nz
7841  do j = jsc,jec
7842  do i = isc,iec
7843  fd_sum = fd_sum + y_fd(i,j,k)*y_fd(i,j,k)
7844  end do
7845  end do
7846  end do
7847  do k = 1,nz
7848  do i = 1,jec-jsc+1
7849  fd_sum = fd_sum + ebufferx2_ad(i,k)*ebufferx2_ad(i,k)
7850  end do
7851  end do
7852  do k = 1,nz
7853  do i = 1,jec-jsc+1
7854  fd_sum = fd_sum + wbufferx2_ad(i,k)*wbufferx2_ad(i,k)
7855  end do
7856  end do
7857  do k = 1,nz
7858  do i = 1,iec-isc+1
7859  fd_sum = fd_sum + sbuffery2_ad(i,k)*sbuffery2_ad(i,k)
7860  end do
7861  end do
7862  do k = 1,nz
7863  do i = 1,iec-isc+1
7864  fd_sum = fd_sum + nbuffery2_ad(i,k)*nbuffery2_ad(i,k)
7865  end do
7866  end do
7867  call mpp_sum( fd_sum )
7868 
7869  x_ad = x_fd
7870  y_ad = y_fd
7871 
7872  call mpp_get_boundary_ad(x_ad, y_ad, domain, ebufferx=ebufferx2_ad(:,:), wbufferx=wbufferx2_ad(:,:), &
7873  sbuffery=sbuffery2_ad(:,:), nbuffery=nbuffery2_ad(:,:), gridtype=cgrid_ne, &
7874  complete = .true. )
7875 
7876  ad_sum = 0.
7877  do k = 1,nz
7878  do j = jsc,jec
7879  do i = isc,iec
7880  ad_sum = ad_sum + x_ad(i,j,k)*x_save(i,j,k)
7881  end do
7882  end do
7883  end do
7884  do k = 1,nz
7885  do j = jsc,jec
7886  do i = isc,iec
7887  ad_sum = ad_sum + y_ad(i,j,k)*y_save(i,j,k)
7888  end do
7889  end do
7890  end do
7891  call mpp_sum( ad_sum )
7892 
7893  if( pe.EQ.mpp_root_pe() ) then
7894  if (abs(ad_sum-fd_sum)/fd_sum.lt.1e-7) then
7895  print*, "Passed Adjoint Dot Test: mpp_get_boundary_ad"
7896  endif
7897  endif
7898 
7899  deallocate (x_ad, y_ad, x_fd, y_fd, x_save, y_save)
7900  deallocate (ebufferx2_ad, wbufferx2_ad)
7901  deallocate (sbuffery2_ad, nbuffery2_ad)
7902 
7903  end subroutine test_get_boundary_ad
7904 
7905  subroutine test_halo_update_ad( type )
7906  use mpp_mod, only : mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
7907  use mpp_domains_mod, only : cgrid_ne
7909 
7910  character(len=*), intent(in) :: type
7911  type(domain2D) :: domain
7912 
7913  integer :: shift, i, j, k
7914  logical :: is_symmetry
7915  integer :: is, ie, js, je, isd, ied, jsd, jed, pe
7916 
7917  real*8, allocatable, dimension(:,:,:) :: x_ad, y_ad, x_fd, y_fd, x_save, y_save
7918  real*8 :: ad_sum, fd_sum
7919 
7920  if(index(type, 'symmetry') == 0) then
7921  is_symmetry = .false.
7922  else
7923  is_symmetry = .true.
7924  end if
7925  select case(type)
7926  case( 'Simple', 'Simple symmetry' )
7927  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
7928  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
7929  shalo=shalo, nhalo=nhalo, name=type, symmetry = is_symmetry )
7930  case( 'Cyclic', 'Cyclic symmetry' )
7931  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
7932  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
7933  shalo=shalo, nhalo=nhalo, xflags=cyclic_global_domain, yflags=cyclic_global_domain, &
7934  name=type, symmetry = is_symmetry )
7935  case default
7936  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type )
7937  end select
7938 
7939 !set up x array
7940  call mpp_get_compute_domain( domain, is, ie, js, je )
7941  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
7942 
7943  shift=1
7944 !---test 3d single fields----------------------------------------------------------
7945  allocate( x_fd(isd:ied,jsd:jed,nz) )
7946  allocate( x_ad(isd:ied,jsd:jed,nz) )
7947  allocate( x_save(isd:ied,jsd:jed,nz) )
7948  x_fd = 0.; x_ad = 0.; x_save = 0.
7949 
7950  do k = 1,nz
7951  do j = js,je
7952  do i = is,ie
7953  x_fd(i,j,k) = i*j
7954  end do
7955  end do
7956  end do
7957  x_save = x_fd
7958 
7959 !full update
7960  call mpp_update_domains( x_fd, domain )
7961 
7962  fd_sum = 0.
7963  do k = 1,nz
7964  do j = jsd,jed
7965  do i = isd,ied
7966  fd_sum = fd_sum + x_fd(i,j,k)*x_fd(i,j,k)
7967  end do
7968  end do
7969  end do
7970  call mpp_sum( fd_sum )
7971 
7972  x_ad = x_fd
7973  call mpp_update_domains_ad( x_ad, domain )
7974 
7975  ad_sum = 0.
7976  do k = 1,nz
7977  do j = jsd,jed
7978  do i = isd,ied
7979  ad_sum = ad_sum + x_ad(i,j,k)*x_save(i,j,k)
7980  end do
7981  end do
7982  end do
7983  call mpp_sum( ad_sum )
7984 
7985  pe = mpp_pe()
7986  if( pe.EQ.mpp_root_pe() ) then
7987  if (abs(ad_sum-fd_sum)/fd_sum.lt.1e-7) then
7988  print*, "Passed Adjoint Dot Test: mpp_update_domains_ad(single 3D field)"
7989  endif
7990  endif
7991 
7992  deallocate (x_ad, x_fd, x_save)
7993 
7994 !---test 3d vector fields----------------------------------------------------------
7995  allocate( x_ad(isd:ied+shift,jsd:jed ,nz) )
7996  allocate( x_fd(isd:ied+shift,jsd:jed ,nz) )
7997  allocate( x_save(isd:ied+shift,jsd:jed ,nz) )
7998  allocate( y_ad(isd:ied ,jsd:jed+shift,nz) )
7999  allocate( y_fd(isd:ied ,jsd:jed+shift,nz) )
8000  allocate( y_save(isd:ied ,jsd:jed+shift,nz) )
8001 
8002  x_fd=0; y_fd=0
8003  do k = 1,nz
8004  do j = js,je
8005  do i = is,ie
8006  x_fd(i,j,k)=i*j
8007  y_fd(i,j,k)=i*j
8008  end do
8009  end do
8010  end do
8011 
8012  call mpp_update_domains( x_fd, y_fd, domain, gridtype=cgrid_ne)
8013  x_save=x_fd
8014  y_save=y_fd
8015 
8016  fd_sum = 0.
8017  do k = 1,nz
8018  do j = jsd,jed
8019  do i = isd,ied+shift
8020  fd_sum = fd_sum + x_fd(i,j,k)*x_fd(i,j,k)
8021  end do
8022  end do
8023  end do
8024  do k = 1,nz
8025  do j = jsd,jed+shift
8026  do i = isd,ied
8027  fd_sum = fd_sum + y_fd(i,j,k)*y_fd(i,j,k)
8028  end do
8029  end do
8030  end do
8031  call mpp_sum( fd_sum )
8032 
8033  x_ad = x_fd
8034  y_ad = y_fd
8035  call mpp_update_domains_ad( x_ad, y_ad, domain, gridtype=cgrid_ne)
8036 
8037  ad_sum = 0.
8038  do k = 1,nz
8039  do j = jsd,jed
8040  do i = isd,ied+shift
8041  ad_sum = ad_sum + x_ad(i,j,k)*x_save(i,j,k)
8042  end do
8043  end do
8044  end do
8045  do k = 1,nz
8046  do j = jsd,jed+shift
8047  do i = isd,ied
8048  ad_sum = ad_sum + y_ad(i,j,k)*y_save(i,j,k)
8049  end do
8050  end do
8051  end do
8052  call mpp_sum( ad_sum )
8053 
8054  if( pe.EQ.mpp_root_pe() ) then
8055  if (abs(ad_sum-fd_sum)/fd_sum.lt.1e-7) then
8056  print*, "Passed Adjoint Dot Test: mpp_update_domains_ad(vector 3D fields)"
8057  endif
8058  endif
8059  deallocate (x_ad, y_ad, x_fd, y_fd, x_save, y_save)
8060 
8061  end subroutine test_halo_update_ad
8062 
8063  subroutine test_global_reduce_ad (type)
8064  use mpp_mod, only : mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
8066  character(len=*), intent(in) :: type
8067  real :: gsum_tl, gsum_ad
8068  real*8 :: gsum_tl_save, gsum_ad_save
8069  real :: gsum_tl_bit, gsum_ad_bit
8070  real*8 :: gsum_tl_save_bit, gsum_ad_save_bit
8071  integer :: i,j,k, ishift, jshift, position
8072  integer :: isd, ied, jsd, jed
8073 
8074  type(domain2D) :: domain
8075  real, allocatable, dimension(:,:,:) :: x, x_ad, x_ad_bit
8076 
8077  !--- set up domain
8078  call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
8079  select case(type)
8080  case( 'Simple' )
8081  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
8082  shalo=shalo, nhalo=nhalo, name=type )
8083  case( 'Simple symmetry center', 'Simple symmetry corner', 'Simple symmetry east', 'Simple symmetry north' )
8084  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
8085  shalo=shalo, nhalo=nhalo, name=type, symmetry = .true. )
8086  case( 'Cyclic symmetry center', 'Cyclic symmetry corner', 'Cyclic symmetry east', 'Cyclic symmetry north' )
8087  call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
8088  name=type, symmetry = .true., xflags=cyclic_global_domain, yflags=cyclic_global_domain )
8089  case default
8090  call mpp_error( fatal, 'TEST_MPP_DOMAINS: no such test: '//type//' in test_global_field' )
8091  end select
8092 
8093  call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
8094 
8095  !--- determine if an extra point is needed
8096  ishift = 0; jshift = 0; position = center
8097  select case(type)
8098  case ('Simple symmetry corner', 'Cyclic symmetry corner')
8099  ishift = 1; jshift = 1; position = corner
8100  case ('Simple symmetry east', 'Cyclic symmetry east' )
8101  ishift = 1; jshift = 0; position = east
8102  case ('Simple symmetry north', 'Cyclic symmetry north')
8103  ishift = 0; jshift = 1; position = north
8104  end select
8105 
8106  ied = ied+ishift; jed = jed+jshift
8107 
8108  allocate( x(isd:ied,jsd:jed,nz), x_ad(isd:ied,jsd:jed,nz), x_ad_bit(isd:ied,jsd:jed,nz) )
8109 
8110  x=0.
8111  do k = 1,nz
8112  do j = jsd, jed
8113  do i = isd, ied
8114  x(i,j,k) = i+j+k
8115  enddo
8116  enddo
8117  enddo
8118 
8119  gsum_tl = mpp_global_sum( domain, x, position = position )
8120  gsum_tl_bit = mpp_global_sum( domain, x, flags=bitwise_exact_sum )
8121  gsum_tl_save = gsum_tl*gsum_tl
8122  gsum_tl_save_bit = gsum_tl_bit*gsum_tl_bit
8123 
8124  gsum_ad = gsum_tl
8125  gsum_ad_bit = gsum_tl_bit
8126 
8127  x_ad = 0.
8128  x_ad_bit = 0.
8129  call mpp_global_sum_ad( domain, x_ad, gsum_ad, position = position )
8130  call mpp_global_sum_ad( domain, x_ad_bit, gsum_ad_bit, flags = bitwise_exact_sum )
8131 
8132  gsum_ad_save = 0.
8133  gsum_ad_save_bit = 0.
8134 
8135  do k = 1,nz
8136  do j = jsd, jed
8137  do i = isd, ied
8138  gsum_ad_save = gsum_ad_save + x_ad(i,j,k)*x(i,j,k)
8139  gsum_ad_save_bit = gsum_ad_save_bit + x_ad_bit(i,j,k)*x(i,j,k)
8140  enddo
8141  enddo
8142  enddo
8143 
8144  call mpp_sum( gsum_ad_save )
8145  call mpp_sum( gsum_ad_save_bit )
8146 
8147  pe = mpp_pe()
8148  if( pe.EQ.mpp_root_pe() ) then
8149  if (abs(gsum_ad_save-gsum_tl_save)/gsum_tl_save.lt.1e-7) then
8150  print*, "Passed Adjoint Dot Test: mpp_global_sum_ad"
8151  endif
8152  if (abs(gsum_ad_save_bit-gsum_tl_save_bit)/gsum_tl_save_bit.lt.1e-7) then
8153  print*, "Passed Adjoint Dot Test: mpp_global_sum_ad, flags=BITWISE_EXACT_SUM"
8154  endif
8155  endif
8156 
8157  deallocate(x, x_ad, x_ad_bit)
8158 
8159  end subroutine test_global_reduce_ad
8160 
8161 end program test
8162 #else
8164 end module
8165 #endif
real(fp), parameter, public zero
subroutine define_cubic_mosaic(type, domain, ni, nj, global_indices, layout, pe_start, pe_end)
subroutine, public mpp_memuse_begin
subroutine compare_checksums(a, b, string)
Definition: mpp.F90:39
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
subroutine, public mpp_memuse_end(text, unit)
#define max(a, b)
Definition: mosaic_util.h:33
subroutine compare_checksums_2d(a, b, string)
#define min(a, b)
Definition: mosaic_util.h:32