!***********************************************************************
!* GNU Lesser General Public License
!*
!* This file is part of the GFDL Flexible Modeling System (FMS).
!*
!* FMS is free software: you can redistribute it and/or modify it under
!* the terms of the GNU Lesser General Public License as published by
!* the Free Software Foundation, either version 3 of the License, or (at
!* your option) any later version.
!*
!* FMS is distributed in the hope that it will be useful, but WITHOUT
!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
!* for more details.
!*
!* You should have received a copy of the GNU Lesser General Public
!* License along with FMS. If not, see .
!***********************************************************************
program test_mpp_domains
use mpp_mod, only : FATAL, WARNING, MPP_DEBUG, NOTE, MPP_CLOCK_SYNC,MPP_CLOCK_DETAILED
use mpp_mod, only : mpp_pe, mpp_npes, mpp_node, mpp_root_pe, mpp_error, mpp_set_warn_level
use mpp_mod, only : mpp_declare_pelist, mpp_set_current_pelist, mpp_sync, mpp_sync_self
use mpp_mod, only : mpp_clock_begin, mpp_clock_end, mpp_clock_id
use mpp_mod, only : mpp_init, mpp_exit, mpp_chksum, stdout, stderr
use mpp_mod, only : input_nml_file
use mpp_mod, only : mpp_get_current_pelist, mpp_broadcast
use mpp_domains_mod, only : GLOBAL_DATA_DOMAIN, BITWISE_EXACT_SUM, BGRID_NE, CGRID_NE, DGRID_NE, AGRID
use mpp_domains_mod, only : FOLD_SOUTH_EDGE, FOLD_NORTH_EDGE, FOLD_WEST_EDGE, FOLD_EAST_EDGE
use mpp_domains_mod, only : MPP_DOMAIN_TIME, CYCLIC_GLOBAL_DOMAIN, NUPDATE,EUPDATE, XUPDATE, YUPDATE, SCALAR_PAIR
use mpp_domains_mod, only : domain1D, domain2D, DomainCommunicator2D, BITWISE_EFP_SUM
use mpp_domains_mod, only : mpp_get_compute_domain, mpp_get_data_domain, mpp_domains_set_stack_size
use mpp_domains_mod, only : mpp_global_field, mpp_global_sum, mpp_global_max, mpp_global_min
use mpp_domains_mod, only : mpp_domains_init, mpp_domains_exit, mpp_broadcast_domain
use mpp_domains_mod, only : mpp_update_domains, mpp_check_field, mpp_redistribute, mpp_get_memory_domain
use mpp_domains_mod, only : mpp_define_layout, mpp_define_domains, mpp_modify_domain
use mpp_domains_mod, only : mpp_get_neighbor_pe, mpp_define_mosaic, mpp_nullify_domain_list
use mpp_domains_mod, only : NORTH, NORTH_EAST, EAST, SOUTH_EAST, CORNER, CENTER
use mpp_domains_mod, only : SOUTH, SOUTH_WEST, WEST, NORTH_WEST, mpp_define_mosaic_pelist
use mpp_domains_mod, only : mpp_get_global_domain, ZERO, NINETY, MINUS_NINETY
use mpp_domains_mod, only : mpp_get_boundary, mpp_start_update_domains, mpp_complete_update_domains
use mpp_domains_mod, only : mpp_define_nest_domains, nest_domain_type
use mpp_domains_mod, only : mpp_get_C2F_index, mpp_update_nest_fine
use mpp_domains_mod, only : mpp_get_F2C_index, mpp_update_nest_coarse
use mpp_domains_mod, only : mpp_get_domain_shift, EDGEUPDATE, mpp_deallocate_domain
use mpp_domains_mod, only : mpp_group_update_type, mpp_create_group_update
use mpp_domains_mod, only : mpp_do_group_update, mpp_clear_group_update
use mpp_domains_mod, only : mpp_start_group_update, mpp_complete_group_update
use mpp_domains_mod, only : WUPDATE, SUPDATE, mpp_get_compute_domains, NONSYMEDGEUPDATE
use mpp_domains_mod, only : domainUG, mpp_define_unstruct_domain, mpp_get_UG_domain_tile_id
use mpp_domains_mod, only : mpp_get_UG_compute_domain, mpp_pass_SG_to_UG, mpp_pass_UG_to_SG
use mpp_domains_mod, only : mpp_get_ug_global_domain, mpp_global_field_ug
use mpp_memutils_mod, only : mpp_memuse_begin, mpp_memuse_end
implicit none
#include
integer :: pe, npes
integer :: nx=128, ny=128, nz=40, stackmax=4000000
integer :: unit=7
integer :: stdunit = 6
logical :: debug=.FALSE., opened
integer :: mpes = 0
integer :: whalo = 2, ehalo = 2, shalo = 2, nhalo = 2
integer :: x_cyclic_offset = 3 ! to be used in test_cyclic_offset
integer :: y_cyclic_offset = -4 ! to be used in test_cyclic_offset
character(len=32) :: warn_level = "fatal"
integer :: wide_halo_x = 0, wide_halo_y = 0
integer :: nx_cubic = 0, ny_cubic = 0
logical :: test_performance = .false.
logical :: test_interface = .true.
logical :: test_nest_domain = .false.
logical :: test_edge_update = .false.
logical :: test_nonsym_edge = .false.
logical :: test_group = .false.
logical :: test_cubic_grid_redistribute = .false.
logical :: check_parallel = .FALSE. ! when check_parallel set to false,
logical :: test_get_nbr = .FALSE.
logical :: test_boundary = .false.
logical :: test_global_sum = .false.
logical :: test_halosize_performance = .false.
integer :: ensemble_size = 1
integer :: layout_cubic(2) = (/0,0/)
integer :: layout_tripolar(2) = (/0,0/)
integer :: layout_ensemble(2) = (/0,0/)
logical :: do_sleep = .false.
integer :: num_iter = 1
integer :: num_fields = 4
!--- namelist variable for nest domain
integer :: tile_fine = 1
integer :: tile_coarse = 1
integer :: istart_fine = 0, iend_fine = -1, jstart_fine = 0, jend_fine = -1
integer :: istart_coarse = 0, iend_coarse = -1, jstart_coarse = 0, jend_coarse = -1
integer :: npes_coarse = 0
integer :: npes_fine = 0
integer :: extra_halo = 0
logical :: mix_2D_3D = .false.
logical :: test_subset = .false.
logical :: test_unstruct = .false.
integer :: nthreads = 1
logical :: test_adjoint = .false.
logical :: wide_halo = .false.
namelist / test_mpp_domains_nml / nx, ny, nz, stackmax, debug, mpes, check_parallel, &
whalo, ehalo, shalo, nhalo, x_cyclic_offset, y_cyclic_offset, &
warn_level, wide_halo_x, wide_halo_y, nx_cubic, ny_cubic, &
test_performance, test_interface, num_fields, do_sleep, num_iter, &
test_nest_domain, tile_fine, tile_coarse, istart_fine, iend_fine, &
jstart_fine, jend_fine, istart_coarse, iend_coarse, jstart_coarse, &
jend_coarse, extra_halo, npes_fine, npes_coarse, mix_2D_3D, test_get_nbr, &
test_edge_update, test_cubic_grid_redistribute, ensemble_size, &
layout_cubic, layout_ensemble, nthreads, test_boundary, &
layout_tripolar, test_group, test_global_sum, test_subset, test_unstruct, &
test_nonsym_edge, test_halosize_performance, test_adjoint, wide_halo
integer :: i, j, k
integer :: layout(2)
integer :: id
integer :: outunit, errunit, io_status
integer :: get_cpu_affinity, base_cpu, omp_get_num_threads, omp_get_thread_num
call mpp_memuse_begin()
call mpp_init()
outunit = stdout()
errunit = stderr()
#ifdef INTERNAL_FILE_NML
read (input_nml_file, test_mpp_domains_nml, iostat=io_status)
#else
do
inquire( unit=unit, opened=opened )
if( .NOT.opened )exit
unit = unit + 1
if( unit.EQ.100 )call mpp_error( FATAL, 'Unable to locate unit number.' )
end do
open( unit=unit, file='input.nml', iostat=io_status )
read( unit,test_mpp_domains_nml, iostat=io_status )
close(unit)
#endif
if (io_status > 0) then
call mpp_error(FATAL,'=>test_mpp_domains: Error reading input.nml')
endif
select case(trim(warn_level))
case("fatal")
call mpp_set_warn_level(FATAL)
case("warning")
call mpp_set_warn_level(WARNING)
case default
call mpp_error(FATAL, "test_mpp_domains: warn_level should be fatal or warning")
end select
pe = mpp_pe()
npes = mpp_npes()
if( debug )then
call mpp_domains_init(MPP_DEBUG)
else
call mpp_domains_init(MPP_DOMAIN_TIME)
end if
call mpp_domains_set_stack_size(stackmax)
!$ call omp_set_num_threads(nthreads)
!$ base_cpu = get_cpu_affinity()
!$OMP PARALLEL
!$ call set_cpu_affinity( base_cpu + omp_get_thread_num() )
!$OMP END PARALLEL
if( pe.EQ.mpp_root_pe() )print '(a,9i6)', 'npes, mpes, nx, ny, nz, whalo, ehalo, shalo, nhalo =', &
npes, mpes, nx, ny, nz, whalo, ehalo, shalo, nhalo
call mpp_memuse_end("in the begining", outunit)
!--- wide_halo_x and wide_halo_y must be either both 0 or both positive.
if( wide_halo_x < 0 .OR. wide_halo_y < 0) call mpp_error(FATAL, &
"test_mpp_domain: both wide_halo_x and wide_halo_y should be non-negative")
if( wide_halo_x == 0 .NEQV. wide_halo_y == 0) call mpp_error(FATAL, &
"test_mpp_domain: wide_halo_x and wide_halo_y should be both zero or both positive")
!--- nx_cubic and ny_cubic must be either both 0 or both positive.
if( nx_cubic < 0 .OR. ny_cubic < 0) call mpp_error(FATAL, &
"test_mpp_domain: both nx_cubic and ny_cubic should be non-negative")
if( nx_cubic == 0 .NEQV. ny_cubic == 0) call mpp_error(FATAL, &
"test_mpp_domain: nx_cubic and ny_cubic should be both zero or both positive")
if( test_nest_domain ) then
if( istart_fine > iend_fine .OR. jstart_fine > jend_fine ) call mpp_error(FATAL, &
"test_mpp_domain: check the setting of namelist variable istart_fine, iend_fine, jstart_fine, jend_fine")
if( istart_coarse > iend_coarse .OR. jstart_coarse > jend_coarse ) call mpp_error(FATAL, &
"test_mpp_domain: check the setting of namelist variable istart_coarse, iend_coarse, jstart_coarse, jend_coarse")
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_update_nest_domain <-------------------'
call test_update_nest_domain('Cubic-Grid')
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_update_nest_domain <-------------------'
endif
if(test_subset) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_subset_update <-------------------'
call test_subset_update()
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_subset_update <-------------------'
endif
if( test_halosize_performance ) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_halosize_performance <-------------------'
call test_halosize_update( 'Folded-north' )
call test_halosize_update( 'Folded-north symmetry' )
call test_halosize_update( 'Cubic-Grid' )
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_halosize_performance <-------------------'
endif
if( test_edge_update ) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_edge_update <-------------------'
call test_update_edge( 'Cyclic' )
call test_update_edge( 'Folded-north' ) !includes vector field test
call test_update_edge( 'Folded-north symmetry' )
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_edge_update <-------------------'
endif
if( test_nonsym_edge ) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_nonsym_edge <-------------------'
call test_update_nonsym_edge( 'Folded-north' ) !includes vector field test
call test_update_nonsym_edge( 'Folded-north symmetry' )
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_nonsym_edge <-------------------'
endif
if( test_performance) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_performance <-------------------'
call update_domains_performance('Folded-north')
call update_domains_performance('Cubic-Grid')
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_performance <-------------------'
endif
if( test_global_sum ) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_mpp_global_sum <-------------------'
call test_mpp_global_sum('Folded-north')
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_mpp_global_sum <-------------------'
endif
if( test_cubic_grid_redistribute ) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling cubic_grid_redistribute <-------------------'
call cubic_grid_redistribute()
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished cubic_grid_redistribute <-------------------'
endif
if(test_boundary) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_boundary <-------------------'
call test_get_boundary('torus')
call test_get_boundary('Four-Tile')
call test_get_boundary('Cubic-Grid')
call test_get_boundary('Folded-north')
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_boundary <-------------------'
endif
! Adjoint Dot Test ------------------------------------------
if (test_adjoint) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_adjoint <-------------------'
call test_get_boundary_ad('Four-Tile')
call test_halo_update_ad( 'Simple' )
call test_global_reduce_ad( 'Simple')
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finished test_adjoint <-------------------'
endif
if( test_unstruct) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_unstruct <-------------------'
call test_unstruct_update( 'Cubic-Grid' )
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_unstruct <-------------------'
endif
if( test_group) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_group <-------------------'
call test_group_update( 'Folded-north' )
call test_group_update( 'Cubic-Grid' )
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_group <-------------------'
endif
if( test_interface ) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_interface <-------------------'
call test_modify_domain()
!!$ call test_cyclic_offset('x_cyclic_offset')
!!$ call test_cyclic_offset('y_cyclic_offset')
!!$ call test_cyclic_offset('torus_x_offset')
!!$ call test_cyclic_offset('torus_y_offset')
if(.not. wide_halo) call test_uniform_mosaic('Single-Tile')
call test_uniform_mosaic('Folded-north mosaic') ! one-tile tripolar grid
call test_uniform_mosaic('Folded-north symmetry mosaic') ! one-tile tripolar grid
if(.not. wide_halo) then
call test_uniform_mosaic('Folded-south symmetry mosaic') ! one-tile tripolar grid
call test_uniform_mosaic('Folded-west symmetry mosaic') ! one-tile tripolar grid
call test_uniform_mosaic('Folded-east symmetry mosaic') ! one-tile tripolar grid
call test_uniform_mosaic('Four-Tile')
endif
call test_uniform_mosaic('Cubic-Grid') ! 6 tiles.
call test_nonuniform_mosaic('Five-Tile')
call test_halo_update( 'Simple' ) !includes global field, global sum tests
call test_halo_update( 'Cyclic' )
call test_halo_update( 'Folded-north' ) !includes vector field test
! call test_halo_update( 'Masked' ) !includes vector field test
call test_halo_update( 'Folded xy_halo' ) !
if(.not. wide_halo) then
call test_halo_update( 'Simple symmetry' ) !includes global field, global sum tests
call test_halo_update( 'Cyclic symmetry' )
endif
call test_halo_update( 'Folded-north symmetry' ) !includes vector field test
if(.not. wide_halo) then
call test_halo_update( 'Folded-south symmetry' ) !includes vector field test
call test_halo_update( 'Folded-west symmetry' ) !includes vector field test
call test_halo_update( 'Folded-east symmetry' ) !includes vector field test
endif
!--- z1l: The following will not work due to symmetry and domain%x is cyclic.
!--- Will solve this problem in the future if needed.
! call test_halo_update( 'Masked symmetry' ) !includes vector field test
call test_global_field( 'Non-symmetry' )
call test_global_field( 'Symmetry center' )
call test_global_field( 'Symmetry corner' )
call test_global_field( 'Symmetry east' )
call test_global_field( 'Symmetry north' )
if(.not. wide_halo) then
call test_global_reduce( 'Simple')
call test_global_reduce( 'Simple symmetry center')
call test_global_reduce( 'Simple symmetry corner')
call test_global_reduce( 'Simple symmetry east')
call test_global_reduce( 'Simple symmetry north')
call test_global_reduce( 'Cyclic symmetry center')
call test_global_reduce( 'Cyclic symmetry corner')
call test_global_reduce( 'Cyclic symmetry east')
call test_global_reduce( 'Cyclic symmetry north')
endif
call test_redistribute( 'Complete pelist' )
! call test_redistribute( 'Overlap pelist' )
! call test_redistribute( 'Disjoint pelist' )
if(.not. wide_halo) then
call test_define_mosaic_pelist('One tile', 1)
call test_define_mosaic_pelist('Two uniform tile', 2)
call test_define_mosaic_pelist('Two nonuniform tile', 2)
call test_define_mosaic_pelist('Ten tile', 10)
call test_define_mosaic_pelist('Ten tile with nonuniform cost', 10)
endif
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finish test_interface <-------------------'
endif
if( check_parallel) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_check_parallel <-------------------'
call test_parallel( )
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finish test_check_parallel <-------------------'
endif
!!$!Balaji adding openMP tests
!!$ call test_openmp()
!!$! Alewxander.Pletzer get_neighbor tests
if( test_get_nbr ) then
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Calling test_get_nbr <-------------------'
call test_get_neighbor_1d
call test_get_neighbor_non_cyclic
call test_get_neighbor_cyclic
call test_get_neighbor_folded_north
call test_get_neighbor_mask
call mpp_sync()
if (mpp_pe() == mpp_root_pe()) print *, '--------------------> Finish test_get_nbr <-------------------'
endif
call mpp_domains_exit()
call mpp_exit()
contains
subroutine test_openmp()
#ifdef _OPENMP_TEST
integer :: omp_get_num_thread, omp_get_max_threads, omp_get_thread_num
real, allocatable :: a(:,:,:)
type(domain2D) :: domain
integer :: layout(2)
integer :: i,j,k, jthr
integer :: thrnum, maxthr
integer(LONG_KIND) :: sum1, sum2
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain )
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
allocate( a(isd:ied,jsd:jed,nz) )
maxthr = omp_get_max_threads()
write( outunit,'(a,4i6)' )'pe,js,je,maxthr=', pe, js, je, maxthr
if( mod(je-js+1,maxthr).NE.0 ) &
call mpp_error( FATAL, 'maxthr must divide domain (TEMPORARY).' )
jthr = (je-js+1)/maxthr
!$OMP PARALLEL PRIVATE(i,j,k,thrnum)
thrnum = omp_get_thread_num()
write( outunit,'(a,4i6)' )'pe,thrnum,js,je=', &
pe, thrnum, js+thrnum*jthr,js+(thrnum+1)*jthr-1
write( outunit,'(a,3i6)' )'pe,thrnum,node=', pe, thrnum, mpp_node()
!!$OMP DO
do k = 1,nz
!when omp DO is commented out, user must compute j loop limits
!with omp DO, let OMP figure it out
do j = js+thrnum*jthr,js+(thrnum+1)*jthr-1
! do j = js,je
do i = is,ie
a(i,j,k) = global(i,j,k)
end do
end do
end do
!!$OMP END DO
!$OMP END PARALLEL
sum1 = mpp_chksum( a(is:ie,js:je,:) )
sum2 = mpp_chksum( global(is:ie,js:je,:) )
if( sum1.EQ.sum2 )then
call mpp_error( NOTE, 'OMP parallel test OK.' )
else
if( mpp_pe().EQ.mpp_root_pe() )write( errunit,'(a,2z18)' )'OMP checksums: ', sum1, sum2
call mpp_error( FATAL, 'OMP parallel test failed.' )
end if
#endif
return
end subroutine test_openmp
subroutine test_redistribute( type )
!test redistribute between two domains
character(len=*), intent(in) :: type
type(domain2D) :: domainx, domainy
type(DomainCommunicator2D), pointer, save :: dch =>NULL()
real, allocatable, dimension(:,:,:) :: gcheck, global
real, allocatable, dimension(:,:,:), save :: x, y
real, allocatable, dimension(:,:,:), save :: x2, y2
real, allocatable, dimension(:,:,:), save :: x3, y3
real, allocatable, dimension(:,:,:), save :: x4, y4
real, allocatable, dimension(:,:,:), save :: x5, y5
real, allocatable, dimension(:,:,:), save :: x6, y6
integer, allocatable :: pelist(:)
integer :: pemax
integer :: is, ie, js, je, isd, ied, jsd, jed
pemax = npes/2 !the partial pelist will run from 0...pemax
!--- nullify domain list otherwise it retains memory between calls.
call mpp_nullify_domain_list(domainx)
call mpp_nullify_domain_list(domainy)
allocate( gcheck(nx,ny,nz), global(nx,ny,nz) )
!fill in global array: with k.iiijjj
do k = 1,nz
do j = 1,ny
do i = 1,nx
global(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
!select pelists
select case(type)
case( 'Complete pelist' )
!both pelists run from 0...npes-1
if(nx < npes) then
call mpp_error(NOTE, &
"test_mpp_domains(test_redistribute): nx is less than npes, no test will be done for complete pelist")
return
endif
allocate( pelist(0:npes-1) )
pelist = (/ (i,i=0,npes-1) /)
call mpp_declare_pelist( pelist )
case( 'Overlap pelist' )
!one pelist from 0...pemax, other from 0...npes-1
allocate( pelist(0:pemax) )
pelist = (/ (i,i=0,pemax) /)
call mpp_declare_pelist( pelist )
case( 'Disjoint pelist' )
!one pelist from 0...pemax, other from pemax+1...npes-1
if( pemax+1.GE.npes )return
allocate( pelist(0:pemax) )
pelist = (/ (i,i=0,pemax) /)
call mpp_declare_pelist( pelist )
! z1l: the follwing will cause deadlock will happen
! for npes = 6, x- mpp_global_field will call mpp_sync
call mpp_declare_pelist( (/ (i,i=pemax+1,npes-1) /))
case default
call mpp_error( FATAL, 'TEST_REDISTRIBUTE: no such test: '//type )
end select
!set up x and y arrays
select case(type)
case( 'Complete pelist' )
!set up x array
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domainx, name=type )
call mpp_get_compute_domain( domainx, is, ie, js, je )
call mpp_get_data_domain ( domainx, isd, ied, jsd, jed )
allocate( x(isd:ied,jsd:jed,nz) )
allocate( x2(isd:ied,jsd:jed,nz) )
allocate( x3(isd:ied,jsd:jed,nz) )
allocate( x4(isd:ied,jsd:jed,nz) )
allocate( x5(isd:ied,jsd:jed,nz) )
allocate( x6(isd:ied,jsd:jed,nz) )
x = 0.
x(is:ie,js:je,:) = global(is:ie,js:je,:)
x2 = x; x3 = x; x4 = x; x5 = x; x6 = x
!set up y array
call mpp_define_domains( (/1,nx,1,ny/), (/npes,1/), domainy, name=type )
call mpp_get_compute_domain( domainy, is, ie, js, je )
call mpp_get_data_domain ( domainy, isd, ied, jsd, jed )
allocate( y(isd:ied,jsd:jed,nz) )
allocate( y2(isd:ied,jsd:jed,nz) )
allocate( y3(isd:ied,jsd:jed,nz) )
allocate( y4(isd:ied,jsd:jed,nz) )
allocate( y5(isd:ied,jsd:jed,nz) )
allocate( y6(isd:ied,jsd:jed,nz) )
y = 0.
y2 = 0.;y3 = 0.;y4 = 0.;y5 = 0.;y6 = 0.
case( 'Overlap pelist' )
!one pelist from 0...pemax, other from 0...npes-1
!set up x array
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domainx, name=type )
call mpp_get_compute_domain( domainx, is, ie, js, je )
call mpp_get_data_domain ( domainx, isd, ied, jsd, jed )
allocate( x(isd:ied,jsd:jed,nz) )
allocate( x2(isd:ied,jsd:jed,nz) )
allocate( x3(isd:ied,jsd:jed,nz) )
allocate( x4(isd:ied,jsd:jed,nz) )
allocate( x5(isd:ied,jsd:jed,nz) )
allocate( x6(isd:ied,jsd:jed,nz) )
x = 0.
x(is:ie,js:je,:) = global(is:ie,js:je,:)
x2 = x; x3 = x; x4 = x; x5 = x; x6 = x
!set up y array
if( ANY(pelist.EQ.pe) )then
call mpp_set_current_pelist(pelist)
call mpp_define_layout( (/1,nx,1,ny/), mpp_npes(), layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domainy, name=type )
call mpp_get_compute_domain( domainy, is, ie, js, je )
call mpp_get_data_domain ( domainy, isd, ied, jsd, jed )
allocate( y(isd:ied,jsd:jed,nz) )
allocate( y2(isd:ied,jsd:jed,nz) )
allocate( y3(isd:ied,jsd:jed,nz) )
allocate( y4(isd:ied,jsd:jed,nz) )
allocate( y5(isd:ied,jsd:jed,nz) )
allocate( y6(isd:ied,jsd:jed,nz) )
y = 0.
y2 = 0.;y3 = 0.;y4 = 0.;y5 = 0.;y6 = 0.
end if
case( 'Disjoint pelist' )
!one pelist from 0...pemax, other from pemax+1...npes-1
!set up y array
if( ANY(pelist.EQ.pe) )then
call mpp_set_current_pelist(pelist)
call mpp_define_layout( (/1,nx,1,ny/), mpp_npes(), layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domainy, name=type )
call mpp_get_compute_domain( domainy, is, ie, js, je )
call mpp_get_data_domain ( domainy, isd, ied, jsd, jed )
allocate( y(isd:ied,jsd:jed,nz) )
allocate( y2(isd:ied,jsd:jed,nz) )
allocate( y3(isd:ied,jsd:jed,nz) )
allocate( y4(isd:ied,jsd:jed,nz) )
allocate( y5(isd:ied,jsd:jed,nz) )
allocate( y6(isd:ied,jsd:jed,nz) )
y = 0.
y2 = 0.;y3 = 0.;y4 = 0.;y5 = 0.;y6 = 0.
else
!set up x array
call mpp_set_current_pelist( (/ (i,i=pemax+1,npes-1) /) )
call mpp_define_layout( (/1,nx,1,ny/), mpp_npes(), layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domainx, name=type )
call mpp_get_compute_domain( domainx, is, ie, js, je )
call mpp_get_data_domain ( domainx, isd, ied, jsd, jed )
allocate( x(isd:ied,jsd:jed,nz) )
allocate( x2(isd:ied,jsd:jed,nz) )
allocate( x3(isd:ied,jsd:jed,nz) )
allocate( x4(isd:ied,jsd:jed,nz) )
allocate( x5(isd:ied,jsd:jed,nz) )
allocate( x6(isd:ied,jsd:jed,nz) )
x = 0.
x(is:ie,js:je,:) = global(is:ie,js:je,:)
x2 = x; x3 = x; x4 = x; x5 = x; x6 = x
end if
end select
!go global and redistribute
call mpp_set_current_pelist()
call mpp_broadcast_domain(domainx)
call mpp_broadcast_domain(domainy)
id = mpp_clock_id( type, flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_redistribute( domainx, x, domainy, y )
call mpp_clock_end (id)
!check answers on pelist
if( ANY(pelist.EQ.pe) )then
call mpp_set_current_pelist(pelist)
call mpp_global_field( domainy, y, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
end if
call mpp_set_current_pelist()
call mpp_clock_begin(id)
if(ALLOCATED(y))y=0.
call mpp_redistribute( domainx, x, domainy, y, complete=.false. )
call mpp_redistribute( domainx, x2, domainy, y2, complete=.false. )
call mpp_redistribute( domainx, x3, domainy, y3, complete=.false. )
call mpp_redistribute( domainx, x4, domainy, y4, complete=.false. )
call mpp_redistribute( domainx, x5, domainy, y5, complete=.false. )
call mpp_redistribute( domainx, x6, domainy, y6, complete=.true., dc_handle=dch )
call mpp_clock_end (id)
!check answers on pelist
if( ANY(pelist.EQ.pe) )then
call mpp_set_current_pelist(pelist)
call mpp_global_field( domainy, y, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y2, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y3, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y4, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y5, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y6, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
end if
call mpp_set_current_pelist()
if(type == 'Complete pelist')then
write(outunit,*) 'Use domain communicator handle'
call mpp_clock_begin(id)
if(ALLOCATED(y))then
y=0.; y2=0.; y3=0.; y4=0.; y5=0.; y6=0.
endif
call mpp_redistribute( domainx, x, domainy, y, complete=.false. )
call mpp_redistribute( domainx, x2, domainy, y2, complete=.false. )
call mpp_redistribute( domainx, x3, domainy, y3, complete=.false. )
call mpp_redistribute( domainx, x4, domainy, y4, complete=.false. )
call mpp_redistribute( domainx, x5, domainy, y5, complete=.false. )
call mpp_redistribute( domainx, x6, domainy, y6, complete=.true., dc_handle=dch )
call mpp_clock_end (id)
!check answers on pelist
if( ANY(pelist.EQ.pe) )then
call mpp_set_current_pelist(pelist)
call mpp_global_field( domainy, y, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y2, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y3, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y4, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y5, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
call mpp_global_field( domainy, y6, gcheck )
call compare_checksums( global(1:nx,1:ny,:), gcheck, type )
end if
endif
dch =>NULL()
call mpp_set_current_pelist()
deallocate(gcheck, global)
if(ALLOCATED(pelist)) deallocate(pelist)
if(ALLOCATED(x))then
call mpp_redistribute( domainx, x, domainy, y, free=.true.,list_size=6 )
deallocate(x,x2,x3,x4,x5,x6)
endif
if(ALLOCATED(y))deallocate(y,y2,y3,y4,y5,y6)
end subroutine test_redistribute
subroutine cubic_grid_redistribute
integer :: npes, npes_per_ensemble, npes_per_tile
integer :: ensemble_id, tile_id, ensemble_tile_id
integer :: i, j, p, n, ntiles, my_root_pe
integer :: isc_ens, iec_ens, jsc_ens, jec_ens
integer :: isd_ens, ied_ens, jsd_ens, jed_ens
integer :: isc, iec, jsc, jec
integer :: isd, ied, jsd, jed
integer, allocatable :: my_ensemble_pelist(:), pe_start(:), pe_end(:)
integer, allocatable :: global_indices(:,:), layout2D(:,:)
real, allocatable :: x(:,:,:,:), x_ens(:,:,:), y(:,:,:)
integer :: layout(2)
type(domain2D) :: domain
type(domain2D), allocatable :: domain_ensemble(:)
character(len=128) :: mesg
! --- set up pelist
npes = mpp_npes()
if(mod(npes, ensemble_size) .NE. 0) call mpp_error(FATAL, &
"test_mpp_domains: npes is not divisible by ensemble_size")
npes_per_ensemble = npes/ensemble_size
allocate(my_ensemble_pelist(0:npes_per_ensemble-1))
ensemble_id = mpp_pe()/npes_per_ensemble + 1
do p = 0, npes_per_ensemble-1
my_ensemble_pelist(p) = (ensemble_id-1)*npes_per_ensemble + p
enddo
call mpp_declare_pelist(my_ensemble_pelist)
!--- define a mosaic use all the pelist
ntiles = 6
if( mod(npes, ntiles) .NE. 0 ) call mpp_error(FATAL, &
"test_mpp_domains: npes is not divisible by ntiles")
npes_per_tile = npes/ntiles
tile_id = mpp_pe()/npes_per_tile + 1
if( npes_per_tile == layout_cubic(1) * layout_cubic(2) ) then
layout = layout_cubic
else
call mpp_define_layout( (/1,nx_cubic,1,ny_cubic/), npes_per_tile, layout )
endif
allocate(global_indices(4, ntiles))
allocate(layout2D(2, ntiles))
allocate(pe_start(ntiles), pe_end(ntiles))
do n = 1, ntiles
global_indices(:,n) = (/1,nx_cubic,1,ny_cubic/)
layout2D(:,n) = layout
end do
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
call define_cubic_mosaic("cubic_grid", domain, (/nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic/), &
(/ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic/), &
global_indices, layout2D, pe_start, pe_end )
allocate(domain_ensemble(ensemble_size))
!-- define domain for each ensemble
call mpp_set_current_pelist( my_ensemble_pelist )
if( mod(npes_per_ensemble, ntiles) .NE. 0 ) call mpp_error(FATAL, &
"test_mpp_domains: npes_per_ensemble is not divisible by ntiles")
npes_per_tile = npes_per_ensemble/ntiles
my_root_pe = my_ensemble_pelist(0)
ensemble_tile_id = (mpp_pe() - my_root_pe)/npes_per_tile + 1
if( npes_per_tile == layout_ensemble(1) * layout_ensemble(2) ) then
layout = layout_ensemble
else
call mpp_define_layout( (/1,nx_cubic,1,ny_cubic/), npes_per_tile, layout )
endif
do n = 1, ntiles
global_indices(:,n) = (/1,nx_cubic,1,ny_cubic/)
layout2D(:,n) = layout
end do
do n = 1, ntiles
pe_start(n) = my_root_pe + (n-1)*npes_per_tile
pe_end(n) = my_root_pe + n*npes_per_tile-1
end do
call define_cubic_mosaic("cubic_grid", domain_ensemble(ensemble_id), (/nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic,nx_cubic/), &
(/ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic,ny_cubic/), &
global_indices, layout2D, pe_start, pe_end )
call mpp_set_current_pelist()
do n = 1, ensemble_size
call mpp_broadcast_domain(domain_ensemble(n))
enddo
call mpp_get_data_domain( domain_ensemble(ensemble_id), isd_ens, ied_ens, jsd_ens, jed_ens)
call mpp_get_compute_domain( domain_ensemble(ensemble_id), isc_ens, iec_ens, jsc_ens, jec_ens)
call mpp_get_data_domain( domain, isd, ied, jsd, jed)
call mpp_get_compute_domain( domain, isc, iec, jsc, jec)
allocate(x_ens(isd_ens:ied_ens, jsd_ens:jed_ens, nz))
allocate(x(isd:ied, jsd:jed, nz, ensemble_size))
allocate(y(isd:ied, jsd:jed, nz))
x = 0
do k = 1, nz
do j = jsc_ens, jec_ens
do i = isc_ens, iec_ens
x_ens(i,j,k) = ensemble_id *1e6 + ensemble_tile_id*1e3 + i + j * 1.e-3 + k * 1.e-6
enddo
enddo
enddo
do n = 1, ensemble_size
x = 0
call mpp_redistribute( domain_ensemble(n), x_ens, domain, x(:,:,:,n) )
y = 0
do k = 1, nz
do j = jsc, jec
do i = isc, iec
y(i,j,k) = n *1e6 + tile_id*1e3 + i + j * 1.e-3 + k * 1.e-6
enddo
enddo
enddo
write(mesg,'(a,i4)') "cubic_grid redistribute from ensemble", n
call compare_checksums( x(isc:iec,jsc:jec,:,n), y(isc:iec,jsc:jec,:), trim(mesg) )
enddo
! redistribute data to each ensemble.
deallocate(x,y,x_ens)
allocate(x(isd:ied, jsd:jed, nz, ensemble_size))
allocate(x_ens(isd_ens:ied_ens, jsd_ens:jed_ens, nz))
allocate(y(isd_ens:ied_ens, jsd_ens:jed_ens, nz))
y = 0
do k = 1, nz
do j = jsc, jec
do i = isc, iec
x(i,j,k,:) = i + j * 1.e-3 + k * 1.e-6
enddo
enddo
enddo
do n = 1, ensemble_size
x_ens = 0
call mpp_redistribute(domain, x(:,:,:,n), domain_ensemble(n), x_ens)
y = 0
if( ensemble_id == n ) then
do k = 1, nz
do j = jsc_ens, jec_ens
do i = isc_ens, iec_ens
y(i,j,k) = i + j * 1.e-3 + k * 1.e-6
enddo
enddo
enddo
endif
write(mesg,'(a,i4)') "cubic_grid redistribute to ensemble", n
call compare_checksums( x_ens(isc_ens:iec_ens,jsc_ens:jec_ens,:), y(isc_ens:iec_ens,jsc_ens:jec_ens,:), trim(mesg) )
enddo
deallocate(x, y, x_ens)
call mpp_deallocate_domain(domain)
do n = 1, ensemble_size
call mpp_deallocate_domain(domain_ensemble(n))
enddo
deallocate(domain_ensemble)
end subroutine cubic_grid_redistribute
subroutine test_uniform_mosaic( type )
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: num_contact, ntiles, npes_per_tile, ntile_per_pe, update_flags
integer :: i, j, k, l, n, shift, tw, te, ts, tn, tsw, tnw, tse, tne
integer :: ism, iem, jsm, jem, wh, eh, sh, nh
integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
real :: gsum, lsum
integer, allocatable, dimension(:) :: tile
integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:) :: global2D
real, allocatable, dimension(:,:,:) :: local1, local2
real, allocatable, dimension(:,:,:,:) :: x, y, x1, x2, x3, x4, y1, y2, y3, y4
real, allocatable, dimension(:,:,:,:) :: global1, global2, gcheck
real, allocatable, dimension(:,:,:,:) :: global1_all, global2_all, global_all
character(len=256) :: type2, type3
logical :: folded_north, folded_north_sym, folded_north_nonsym
logical :: folded_south_sym, folded_west_sym, folded_east_sym
logical :: cubic_grid, single_tile, four_tile
integer :: whalo_save, ehalo_save, nhalo_save, shalo_save
integer :: nx_save, ny_save
logical :: same_layout = .false.
nx_save = nx
ny_save = ny
if(type == 'Cubic-Grid' .and. nx_cubic >0) then
nx = nx_cubic
ny = ny_cubic
endif
if(wide_halo_x > 0) then
whalo_save = whalo
ehalo_save = ehalo
shalo_save = shalo
nhalo_save = nhalo
if(type == 'Single-Tile' .OR. type == 'Folded-north mosaic' .OR. type == 'Cubic-Grid') then
whalo = wide_halo_x
ehalo = wide_halo_x
shalo = wide_halo_y
nhalo = wide_halo_y
endif
endif
folded_north_nonsym = .false.
folded_north_sym = .false.
folded_north = .false.
folded_south_sym = .false.
folded_west_sym = .false.
folded_east_sym = .false.
cubic_grid = .false.
single_tile = .false.
four_tile = .false.
!--- check the type
select case(type)
case ( 'Single-Tile' ) !--- single with cyclic along x- and y-direction
single_tile = .true.
ntiles = 1
num_contact = 2
case ( 'Folded-north mosaic' )
ntiles = 1
num_contact = 2
folded_north_nonsym = .true.
case ( 'Folded-north symmetry mosaic' )
ntiles = 1
num_contact = 2
folded_north_sym = .true.
case ( 'Folded-south symmetry mosaic' )
ntiles = 1
num_contact = 2
folded_south_sym = .true.
case ( 'Folded-west symmetry mosaic' )
ntiles = 1
num_contact = 2
folded_west_sym = .true.
case ( 'Folded-east symmetry mosaic' )
ntiles = 1
num_contact = 2
folded_east_sym = .true.
case ( 'Four-Tile' ) !--- cyclic along both x- and y-direction.
ntiles = 4
num_contact = 8
four_tile = .true.
case ( 'Cubic-Grid' )
ntiles = 6
num_contact = 12
cubic_grid = .true.
if( nx .NE. ny) then
call mpp_error(NOTE,'TEST_MPP_DOMAINS: for Cubic_grid mosaic, nx should equal ny, '//&
'No test is done for Cubic-Grid mosaic. ' )
if(wide_halo_x > 0) then
whalo = whalo_save
ehalo = ehalo_save
shalo = shalo_save
nhalo = nhalo_save
nx = nx_save
ny = ny_save
endif
return
end if
case default
call mpp_error(FATAL, 'TEST_MPP_DOMAINS: no such test: '//type)
end select
folded_north = folded_north_nonsym .OR. folded_north_sym
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
if( mod(npes, ntiles) == 0 ) then
npes_per_tile = npes/ntiles
write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
'", each tile will be distributed over ', npes_per_tile, ' processors.'
ntile_per_pe = 1
allocate(tile(ntile_per_pe))
tile = pe/npes_per_tile+1
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
else if ( mod(ntiles, npes) == 0 ) then
ntile_per_pe = ntiles/npes
write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
'", there will be ', ntile_per_pe, ' tiles on each processor.'
allocate(tile(ntile_per_pe))
do n = 1, ntile_per_pe
tile(n) = pe*ntile_per_pe + n
end do
do n = 1, ntiles
pe_start(n) = (n-1)/ntile_per_pe
pe_end(n) = pe_start(n)
end do
layout = 1
else
call mpp_error(NOTE,'TEST_MPP_DOMAINS: npes should be multiple of ntiles or ' // &
'ntiles should be multiple of npes. No test is done for '//trim(type) )
nx = nx_save
ny = ny_save
if(wide_halo_x > 0) then
whalo = whalo_save
ehalo = ehalo_save
shalo = shalo_save
nhalo = nhalo_save
endif
return
end if
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
same_layout = .false.
if(layout(1) == layout(2)) same_layout = .true.
allocate(tile1(num_contact), tile2(num_contact) )
allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
call mpp_memuse_begin()
!--- define domain
if(single_tile) then
!--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST)
tile1(1) = 1; tile2(1) = 1
istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (SOUTH) and tile 1 (NORTH) --- cyclic
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = nx; jstart1(2) = 1; jend1(2) = 1
istart2(2) = 1; iend2(2) = nx; jstart2(2) = ny; jend2(2) = ny
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .false. )
else if(folded_north) then
!--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
tile1(1) = 1; tile2(1) = 1
istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
if(folded_north_nonsym) then
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .false. )
else
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .true. )
endif
else if(folded_south_sym) then
!--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
tile1(1) = 1; tile2(1) = 1
istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (SOUTH) and tile 1 (SOUTH) --- folded-south-edge
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = 1; jend1(2) = 1
istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = 1; jend2(2) = 1
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .true. )
else if(folded_west_sym) then
!--- Contact line 1, between tile 1 (NORTH) and tile 1 (SOUTH) --- cyclic
tile1(1) = 1; tile2(1) = 1
istart1(1) = 1; iend1(1) = nx; jstart1(1) = ny; jend1(1) = ny
istart2(1) = 1; iend2(1) = nx; jstart2(1) = 1; jend2(1) = 1
!--- Contact line 2, between tile 1 (WEST) and tile 1 (WEST) --- folded-west-edge
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = 1; jstart1(2) = 1; jend1(2) = ny/2
istart2(2) = 1; iend2(2) = 1; jstart2(2) = ny; jend2(2) = ny/2+1
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .true. )
else if(folded_east_sym) then
!--- Contact line 1, between tile 1 (NORTH) and tile 1 (SOUTH) --- cyclic
tile1(1) = 1; tile2(1) = 1
istart1(1) = 1; iend1(1) = nx; jstart1(1) = ny; jend1(1) = ny
istart2(1) = 1; iend2(1) = nx; jstart2(1) = 1; jend2(1) = 1
!--- Contact line 2, between tile 1 (EAST) and tile 1 (EAST) --- folded-west-edge
tile1(2) = 1; tile2(2) = 1
istart1(2) = nx; iend1(2) = nx; jstart1(2) = 1; jend1(2) = ny/2
istart2(2) = nx; iend2(2) = nx; jstart2(2) = ny; jend2(2) = ny/2+1
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .true. )
else if( four_tile ) then
call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
layout2D, pe_start, pe_end, symmetry = .false. )
else if( cubic_grid ) then
call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
global_indices, layout2D, pe_start, pe_end )
endif
call mpp_memuse_end(trim(type)//" mpp_define_mosaic", outunit )
!--- setup data
allocate(global2(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz, ntile_per_pe) )
allocate(global_all(1:nx,1:ny,nz, ntiles) )
global2 = 0
do l = 1, ntiles
do k = 1, nz
do j = 1, ny
do i = 1, nx
global_all(i,j,k,l) = l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
do n = 1, ntile_per_pe
global2(1:nx,1:ny,:,n) = global_all(:,:,:,tile(n))
end do
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
allocate( gcheck(nx, ny, nz, ntile_per_pe) )
allocate( x (ism:iem,jsm:jem,nz, ntile_per_pe) )
allocate( x1(ism:iem,jsm:jem,nz, ntile_per_pe) )
allocate( x2(ism:iem,jsm:jem,nz, ntile_per_pe) )
allocate( x3(ism:iem,jsm:jem,nz, ntile_per_pe) )
allocate( x4(ism:iem,jsm:jem,nz, ntile_per_pe) )
x = 0.
x(isc:iec,jsc:jec,:,:) = global2(isc:iec,jsc:jec,:,:)
x1 = x; x2 = x; x3 = x; x4 = x;
!--- test mpp_global_sum
gsum = 0
allocate(global2D(nx,ny))
do n = 1, ntiles
do j = 1, ny
do i = 1, nx
global2D(i,j) = sum(global_all(i,j,:,n))
end do
end do
gsum = gsum + sum(global2D)
end do
do n = 1, ntile_per_pe
lsum = mpp_global_sum( domain, x(:,:,:,n), tile_count=n )
end do
if( pe.EQ.mpp_root_pe() )print '(a,2es15.8,a,es12.4)', type//' Fast sum=', lsum, gsum
!test exact mpp_global_sum
do n = 1, ntile_per_pe
lsum = mpp_global_sum( domain, x(:,:,:,n), BITWISE_EXACT_SUM, tile_count=n)
end do
call compare_data_scalar(lsum, gsum, FATAL, type//' mpp_global_exact_sum')
!--- test mpp_global_field
gcheck = 0.
id = mpp_clock_id( type//' global field ', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
do n = 1, ntile_per_pe
call mpp_global_field( domain, x(:,:,:,n), gcheck(:,:,:,n), tile_count=n)
end do
call mpp_clock_end (id)
!compare checksums between global and x arrays
do n = 1, ntile_per_pe
call compare_checksums( global2(1:nx,1:ny,:,n), gcheck(:,:,:,n), type//' mpp_global_field ' )
end do
id = mpp_clock_id( type, flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
do n = 1, ntile_per_pe
!--- fill up the value at halo points.
if(single_tile) then
call fill_regular_mosaic_halo(global2(:,:,:,n), global_all, 1, 1, 1, 1, 1, 1, 1, 1)
else if(folded_north) then
call fill_folded_north_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
else if(folded_south_sym) then
call fill_folded_south_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
else if(folded_west_sym) then
call fill_folded_west_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
else if(folded_east_sym) then
call fill_folded_east_halo(global2(:,:,:,n), 0, 0, 0, 0, 1)
else if(four_tile) then
select case ( tile(n) )
case (1)
tw = 2; ts = 3; tsw = 4
case (2)
tw = 1; ts = 4; tsw = 3
case (3)
tw = 4; ts = 1; tsw = 2
case (4)
tw = 3; ts = 2; tsw = 1
end select
te = tw; tn = ts; tse = tsw; tnw = tsw; tne = tsw
call fill_regular_mosaic_halo(global2(:,:,:,n), global_all, te, tse, ts, tsw, tw, tnw, tn, tne )
else if(cubic_grid) then
call fill_cubic_grid_halo(global2(:,:,:,n), global_all, global_all, tile(n), 0, 0, 1, 1 )
endif
!full update
call mpp_clock_begin(id)
if(ntile_per_pe == 1) then
call mpp_update_domains( x(:,:,:,n), domain )
else
call mpp_update_domains( x(:,:,:,n), domain, tile_count = n )
end if
call mpp_clock_end (id)
end do
type2 = type
do n = 1, ntile_per_pe
if(ntile_per_pe>1) write(type2, *)type, " at tile_count = ",n
call compare_checksums( x(ism:ism+ied-isd,jsm:jsm+jed-jsd,:,n), global2(isd:ied,jsd:jed,:,n), trim(type2) )
end do
!partial update only be done when there is at most one tile on each pe
if(ntile_per_pe == 1 ) then
id = mpp_clock_id( type//' partial', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x1, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x2, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x3, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x4, domain, NUPDATE+EUPDATE, complete=.true. )
call mpp_clock_end (id)
call compare_checksums( x1(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x1' )
call compare_checksums( x2(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x2' )
call compare_checksums( x3(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x3' )
call compare_checksums( x4(isc:ied,jsc:jed,:,1), global2(isc:ied,jsc:jed,:,1), type//' partial x4' )
!arbitrary halo update. not for tripolar grid
if(wide_halo_x == 0) then
if(single_tile .or. four_tile .or. (cubic_grid .and. same_layout) .or. folded_north ) then
allocate(local2(isd:ied,jsd:jed,nz) )
do wh = 1, whalo
do eh = 1, ehalo
if(wh .NE. eh) cycle
do sh = 1, shalo
do nh = 1, nhalo
if(sh .NE. nh) cycle
local2(isd:ied,jsd:jed,:) = global2(isd:ied,jsd:jed,:,1)
x = 0.
x(isc:iec,jsc:jec,:,1) = local2(isc:iec,jsc:jec,:)
call fill_halo_zero(local2, wh, eh, sh, nh, 0, 0, isc, iec, jsc, jec, isd, ied, jsd, jed)
write(type2,'(a,a,i2,a,i2,a,i2,a,i2)') trim(type), ' with whalo = ', wh, &
', ehalo = ',eh, ', shalo = ', sh, ', nhalo = ', nh
call mpp_update_domains( x, domain, whalo=wh, ehalo=eh, shalo=sh, nhalo=nh, name = type2 )
call compare_checksums( x(isd:ied,jsd:jed,:,1), local2, trim(type2) )
end do
end do
end do
end do
deallocate(local2)
end if
endif
end if
deallocate(global2, global_all, x, x1, x2, x3, x4)
!------------------------------------------------------------------
! vector update : BGRID_NE, one extra point in each direction for cubic-grid
!------------------------------------------------------------------
!--- setup data
shift = 0
if(single_tile .or. four_tile .or. folded_north_nonsym) then
shift = 0
else
shift = 1
endif
allocate(global1(1-whalo:nx+shift+ehalo,1-shalo:ny+shift+nhalo,nz,ntile_per_pe) )
allocate(global2(1-whalo:nx+shift+ehalo,1-shalo:ny+shift+nhalo,nz,ntile_per_pe) )
allocate(global1_all(nx+shift,ny+shift,nz, ntiles), global2_all(nx+shift,ny+shift,nz, ntiles))
global1 = 0; global2 = 0
do l = 1, ntiles
do k = 1, nz
do j = 1, ny+shift
do i = 1, nx+shift
global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
!-----------------------------------------------------------------------
!--- make sure consistency on the boundary for cubic grid
!--- east boundary will take the value of neighbor tile ( west/south),
!--- north boundary will take the value of neighbor tile ( south/west).
!--- for the point on the corner, the 12 corner take the following value
!--- corner between 1, 2, 3 takes the value at 3,
!--- corner between 1, 3, 5 takes the value at 3
!-----------------------------------------------------------------------
if( cubic_grid ) then
do l = 1, ntiles
if(mod(l,2) == 0) then ! tile 2, 4, 6
te = l + 2
tn = l + 1
if(te>6) te = te - 6
if(tn > 6) tn = tn - 6
global1_all(nx+shift,1:ny+1,:,l) = global2_all(nx+shift:1:-1,1,:,te) ! east
global2_all(nx+shift,1:ny+1,:,l) = global1_all(nx+shift:1:-1,1,:,te) ! east
global1_all(1:nx,ny+shift,:,l) = global1_all(1:nx,1,:,tn) ! north
global2_all(1:nx,ny+shift,:,l) = global2_all(1:nx,1,:,tn) ! north
else ! tile 1, 3, 5
te = l + 1
tn = l + 2
if(tn > 6) tn = tn - 6
global1_all(nx+shift,:,:,l) = global1_all(1,:,:,te) ! east
global2_all(nx+shift,:,:,l) = global2_all(1,:,:,te) ! east
global1_all(1:nx+1,ny+shift,:,l) = global2_all(1,ny+shift:1:-1,:,tn) ! north
global2_all(1:nx+1,ny+shift,:,l) = global1_all(1,ny+shift:1:-1,:,tn) ! north
end if
end do
! set the corner value to 0
global1_all(1,ny+1,:,:) = 0; global1_all(nx+1,1,:,:) = 0; global1_all(1,1,:,:) = 0; global1_all(nx+1,ny+1,:,:) = 0
global2_all(1,ny+1,:,:) = 0; global2_all(nx+1,1,:,:) = 0; global2_all(1,1,:,:) = 0; global2_all(nx+1,ny+1,:,:) = 0
end if
do n = 1, ntile_per_pe
global1(1:nx+shift,1:ny+shift,:,n) = global1_all(:,:,:,tile(n))
global2(1:nx+shift,1:ny+shift,:,n) = global2_all(:,:,:,tile(n))
end do
if(folded_north) then
call fill_folded_north_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
call fill_folded_north_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
else if(folded_south_sym) then
call fill_folded_south_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
call fill_folded_south_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
else if(folded_west_sym) then
call fill_folded_west_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
call fill_folded_west_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
else if(folded_east_sym) then
call fill_folded_east_halo(global1(:,:,:,1), 1, 1, shift, shift, -1)
call fill_folded_east_halo(global2(:,:,:,1), 1, 1, shift, shift, -1)
endif
allocate( x (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( x1(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( x2(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( x3(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( x4(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y1(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y2(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y3(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y4(ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
x = 0.; y = 0
x (isc:iec+shift,jsc:jec+shift,:,:) = global1(isc:iec+shift,jsc:jec+shift,:,:)
y (isc:iec+shift,jsc:jec+shift,:,:) = global2(isc:iec+shift,jsc:jec+shift,:,:)
x1 = x; x2 = x; x3 = x; x4 = x
y1 = y; y2 = y; y3 = y; y4 = y
!-----------------------------------------------------------------------
! fill up the value at halo points.
!-----------------------------------------------------------------------
if(cubic_grid) then
type2 = type//' paired-scalar BGRID_NE'
update_flags = SCALAR_PAIR
else
type2 = type//' vector BGRID_NE'
update_flags = XUPDATE + YUPDATE
endif
id = mpp_clock_id( trim(type2), flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
type3 = type2
do n = 1, ntile_per_pe
if(single_tile) then
call fill_regular_mosaic_halo(global1(:,:,:,n), global1_all, 1, 1, 1, 1, 1, 1, 1, 1)
call fill_regular_mosaic_halo(global2(:,:,:,n), global2_all, 1, 1, 1, 1, 1, 1, 1, 1)
else if(folded_north) then
!redundant points must be equal and opposite for tripolar grid
global1(nx/2+shift, ny+shift,:,:) = 0. !pole points must have 0 velocity
global1(nx+shift , ny+shift,:,:) = 0. !pole points must have 0 velocity
global1(nx/2+1+shift:nx-1+shift, ny+shift,:,:) = -global1(nx/2-1+shift:1+shift:-1, ny+shift,:,:)
global1(1-whalo:shift, ny+shift,:,:) = -global1(nx-whalo+1:nx+shift, ny+shift,:,:)
global1(nx+1+shift:nx+ehalo+shift, ny+shift,:,:) = -global1(1+shift:ehalo+shift, ny+shift,:,:)
global2(nx/2+shift, ny+shift,:,:) = 0. !pole points must have 0 velocity
global2(nx+shift , ny+shift,:,:) = 0. !pole points must have 0 velocity
global2(nx/2+1+shift:nx-1+shift, ny+shift,:,:) = -global2(nx/2-1+shift:1+shift:-1, ny+shift,:,:)
global2(1-whalo:shift, ny+shift,:,:) = -global2(nx-whalo+1:nx+shift, ny+shift,:,:)
global2(nx+1+shift:nx+ehalo+shift, ny+shift,:,:) = -global2(1+shift:ehalo+shift, ny+shift,:,:)
!--- the following will fix the +0/-0 problem on altix
if(nhalo >0) then
global1(shift,ny+shift,:,:) = 0. !pole points must have 0 velocity
global2(shift,ny+shift,:,:) = 0. !pole points must have 0 velocity
end if
else if(folded_south_sym) then
global1(nx/2+shift, 1,:,:) = 0. !pole points must have 0 velocity
global1(nx+shift , 1,:,:) = 0. !pole points must have 0 velocity
global1(nx/2+1+shift:nx-1+shift, 1,:,:) = -global1(nx/2-1+shift:1+shift:-1, 1,:,:)
global1(1-whalo:shift, 1,:,:) = -global1(nx-whalo+1:nx+shift, 1,:,:)
global1(nx+1+shift:nx+ehalo+shift, 1,:,:) = -global1(1+shift:ehalo+shift, 1,:,:)
global2(nx/2+shift, 1,:,:) = 0. !pole points must have 0 velocity
global2(nx+shift , 1,:,:) = 0. !pole points must have 0 velocity
global2(nx/2+1+shift:nx-1+shift, 1,:,:) = -global2(nx/2-1+shift:1+shift:-1, 1,:,:)
global2(1-whalo:shift, 1,:,:) = -global2(nx-whalo+1:nx+shift, 1,:,:)
global2(nx+1+shift:nx+ehalo+shift, 1,:,:) = -global2(1+shift:ehalo+shift, 1,:,:)
!--- the following will fix the +0/-0 problem on altix
if(shalo >0) then
global1(shift,1,:,:) = 0. !pole points must have 0 velocity
global2(shift,1,:,:) = 0. !pole points must have 0 velocity
endif
else if(folded_west_sym) then
global1(1, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
global1(1, ny+shift, :,:) = 0. !pole points must have 0 velocity
global1(1, ny/2+1+shift:ny-1+shift, :,:) = -global1(1, ny/2-1+shift:1+shift:-1, :,:)
global1(1, 1-shalo:shift, :,:) = -global1(1, ny-shalo+1:ny+shift, :,:)
global1(1, ny+1+shift:ny+nhalo+shift, :,:) = -global1(1, 1+shift:nhalo+shift, :,:)
global2(1, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
global2(1, ny+shift, :,:) = 0. !pole points must have 0 velocity
global2(1, ny/2+1+shift:ny-1+shift, :,:) = -global2(1, ny/2-1+shift:1+shift:-1, :,:)
global2(1, 1-shalo:shift, :,:) = -global2(1, ny-shalo+1:ny+shift, :,:)
global2(1, ny+1+shift:ny+nhalo+shift, :,:) = -global2(1, 1+shift:nhalo+shift, :,:)
!--- the following will fix the +0/-0 problem on altix
if(whalo>0) then
global1(1, shift, :, :) = 0. !pole points must have 0 velocity
global2(1, shift, :, :) = 0. !pole points must have 0 velocity
endif
else if(folded_east_sym) then
global1(nx+shift, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
global1(nx+shift, ny+shift, :,:) = 0. !pole points must have 0 velocity
global1(nx+shift, ny/2+1+shift:ny-1+shift, :,:) = -global1(nx+shift, ny/2-1+shift:1+shift:-1, :,:)
global1(nx+shift, 1-shalo:shift, :,:) = -global1(nx+shift, ny-shalo+1:ny+shift, :,:)
global1(nx+shift, ny+1+shift:ny+nhalo+shift, :,:) = -global1(nx+shift, 1+shift:nhalo+shift, :,:)
global2(nx+shift, ny/2+shift, :,:) = 0. !pole points must have 0 velocity
global2(nx+shift, ny+shift, :,:) = 0. !pole points must have 0 velocity
global2(nx+shift, ny/2+1+shift:ny-1+shift, :,:) = -global2(nx+shift, ny/2-1+shift:1+shift:-1, :,:)
global2(nx+shift, 1-shalo:shift, :,:) = -global2(nx+shift, ny-shalo+1:ny+shift, :,:)
global2(nx+shift, ny+1+shift:ny+nhalo+shift, :,:) = -global2(nx+shift, 1+shift:nhalo+shift, :,:)
!--- the following will fix the +0/-0 problem on altix
if(ehalo >0) then
global1(nx+shift, shift, :,:) = 0. !pole points must have 0 velocity
global2(nx+shift, shift, :,:) = 0. !pole points must have 0 velocity
end if
else if(four_tile) then
select case ( tile(n) )
case (1)
tw = 2; ts = 3; tsw = 4
case (2)
tw = 1; ts = 4; tsw = 3
case (3)
tw = 4; ts = 1; tsw = 2
case (4)
tw = 3; ts = 2; tsw = 1
end select
te = tw; tn = ts; tse = tsw; tnw = tsw; tne = tsw
call fill_regular_mosaic_halo(global1(:,:,:,n), global1_all, te, tse, ts, tsw, tw, tnw, tn, tne )
call fill_regular_mosaic_halo(global2(:,:,:,n), global2_all, te, tse, ts, tsw, tw, tnw, tn, tne )
else if(cubic_grid) then
call fill_cubic_grid_halo(global1(:,:,:,n), global1_all, global2_all, tile(n), 1, 1, 1, 1 )
call fill_cubic_grid_halo(global2(:,:,:,n), global2_all, global1_all, tile(n), 1, 1, 1, 1 )
endif
if(ntile_per_pe > 1) write(type3, *)trim(type2), " at tile_count = ",n
call mpp_clock_begin(id)
if(ntile_per_pe == 1) then
call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, flags=update_flags, gridtype=BGRID_NE, name=type3)
else
call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, flags=update_flags, gridtype=BGRID_NE, &
name=type3, tile_count = n)
end if
call mpp_clock_end (id)
end do
do n = 1, ntile_per_pe
if(ntile_per_pe > 1) write(type3, *)trim(type2), " at tile_count = ", n
call compare_checksums( x (isd:ied+shift,jsd:jed+shift,:,n), global1(isd:ied+shift,jsd:jed+shift,:,n), trim(type3)//' X' )
call compare_checksums( y (isd:ied+shift,jsd:jed+shift,:,n), global2(isd:ied+shift,jsd:jed+shift,:,n), trim(type3)//' Y' )
end do
if(ntile_per_pe == 1) then
call mpp_clock_begin(id)
call mpp_update_domains( x1, y1, domain, flags=update_flags, gridtype=BGRID_NE, complete=.false., name=type2)
call mpp_update_domains( x2, y2, domain, flags=update_flags, gridtype=BGRID_NE, complete=.false., name=type2)
call mpp_update_domains( x3, y3, domain, flags=update_flags, gridtype=BGRID_NE, complete=.false., name=type2)
call mpp_update_domains( x4, y4, domain, flags=update_flags, gridtype=BGRID_NE, complete=.true., name=type2)
call mpp_clock_end (id)
call compare_checksums( x1(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X1')
call compare_checksums( x2(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X2')
call compare_checksums( x3(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X3')
call compare_checksums( x4(isd:ied+shift,jsd:jed+shift,:,1), global1(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' X4')
call compare_checksums( y1(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y1')
call compare_checksums( y2(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y2')
call compare_checksums( y3(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y3')
call compare_checksums( y4(isd:ied+shift,jsd:jed+shift,:,1), global2(isd:ied+shift,jsd:jed+shift,:,1), trim(type2)//' Y4')
!--- arbitrary halo updates ---------------------------------------
if(wide_halo_x == 0) then
if(single_tile .or. four_tile .or. (cubic_grid .and. same_layout) .or. folded_north) then
allocate(local1(isd:ied+shift,jsd:jed+shift,nz) )
allocate(local2(isd:ied+shift,jsd:jed+shift,nz) )
do wh = 1, whalo
do eh = 1, ehalo
if(wh .NE. eh) cycle
do sh = 1, shalo
do nh = 1, nhalo
if(nh .NE. sh) cycle
local1(isd:ied+shift,jsd:jed+shift,:) = global1(isd:ied+shift,jsd:jed+shift,:,1)
local2(isd:ied+shift,jsd:jed+shift,:) = global2(isd:ied+shift,jsd:jed+shift,:,1)
x = 0.; y = 0.
x(isc:iec+shift,jsc:jec+shift,:,1) = global1(isc:iec+shift,jsc:jec+shift,:,1)
y(isc:iec+shift,jsc:jec+shift,:,1) = global2(isc:iec+shift,jsc:jec+shift,:,1)
call fill_halo_zero(local1, wh, eh, sh, nh, shift, shift, isc, iec, jsc, jec, isd, ied, jsd, jed)
call fill_halo_zero(local2, wh, eh, sh, nh, shift, shift, isc, iec, jsc, jec, isd, ied, jsd, jed)
write(type3,'(a,a,i2,a,i2,a,i2,a,i2)') trim(type2), ' with whalo = ', wh, &
', ehalo = ',eh, ', shalo = ', sh, ', nhalo = ', nh
call mpp_update_domains( x, y, domain, flags=update_flags, gridtype=BGRID_NE, &
whalo=wh, ehalo=eh, shalo=sh, nhalo=nh, name=type3)
call compare_checksums( x(isd:ied+shift,jsd:jed+shift,:,1), local1, trim(type3)//' X' )
call compare_checksums( y(isd:ied+shift,jsd:jed+shift,:,1), local2, trim(type3)//' Y' )
end do
end do
end do
end do
deallocate(local1, local2)
end if
endif
end if
!------------------------------------------------------------------
! vector update : CGRID_NE
!------------------------------------------------------------------
!--- setup data
if(cubic_grid .or. folded_north .or. folded_south_sym .or. folded_west_sym .or. folded_east_sym ) then
deallocate(global1_all, global2_all)
allocate(global1_all(nx+shift,ny,nz, ntiles), global2_all(nx,ny+shift,nz, ntiles))
deallocate(global1, global2, x, y, x1, x2, x3, x4, y1, y2, y3, y4)
allocate(global1(1-whalo:nx+shift+ehalo,1-shalo:ny +nhalo,nz,ntile_per_pe) )
allocate( x (ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( y (ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
allocate( x1(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( x2(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( x3(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( x4(ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( y1(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y2(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y3(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y4(ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
allocate(global2(1-whalo:nx +ehalo,1-shalo:ny+shift+nhalo,nz,ntile_per_pe) )
global1 = 0; global2 = 0
do l = 1, ntiles
do k = 1, nz
do j = 1, ny
do i = 1, nx+shift
global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
do j = 1, ny+shift
do i = 1, nx
global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
endif
if( folded_north .or. folded_south_sym .or. folded_west_sym .or. folded_east_sym ) then
do n = 1, ntile_per_pe
global1(1:nx+shift,1:ny ,:,n) = global1_all(1:nx+shift,1:ny, :,tile(n))
global2(1:nx ,1:ny+shift,:,n) = global2_all(1:nx ,1:ny+shift,:,tile(n))
end do
endif
if( cubic_grid ) then
!-----------------------------------------------------------------------
!--- make sure consistency on the boundary for cubic grid
!--- east boundary will take the value of neighbor tile ( west/south),
!--- north boundary will take the value of neighbor tile ( south/west).
!-----------------------------------------------------------------------
do l = 1, ntiles
if(mod(l,2) == 0) then ! tile 2, 4, 6
te = l + 2
tn = l + 1
if(te>6) te = te - 6
if(tn > 6) tn = tn - 6
global1_all(nx+shift,1:ny,:,l) = global2_all(nx:1:-1,1,:,te) ! east
global2_all(1:nx,ny+shift,:,l) = global2_all(1:nx,1,:,tn) ! north
else ! tile 1, 3, 5
te = l + 1
tn = l + 2
if(tn > 6) tn = tn - 6
global1_all(nx+shift,:,:,l) = global1_all(1,:,:,te) ! east
global2_all(1:nx,ny+shift,:,l) = global1_all(1,ny:1:-1,:,tn) ! north
end if
end do
do n = 1, ntile_per_pe
global1(1:nx+shift,1:ny ,:,n) = global1_all(1:nx+shift,1:ny, :,tile(n))
global2(1:nx ,1:ny+shift,:,n) = global2_all(1:nx ,1:ny+shift,:,tile(n))
end do
else if( folded_north ) then
call fill_folded_north_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
call fill_folded_north_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
else if(folded_south_sym ) then
call fill_folded_south_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
call fill_folded_south_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
else if(folded_west_sym ) then
call fill_folded_west_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
call fill_folded_west_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
else if(folded_east_sym ) then
call fill_folded_east_halo(global1(:,:,:,1), 1, 0, shift, 0, -1)
call fill_folded_east_halo(global2(:,:,:,1), 0, 1, 0, shift, -1)
endif
x = 0.; y = 0.
x (isc:iec+shift,jsc:jec ,:,:) = global1(isc:iec+shift,jsc:jec ,:,:)
y (isc:iec ,jsc:jec+shift,:,:) = global2(isc:iec ,jsc:jec+shift,:,:)
x1 = x; x2 = x; x3 = x; x4 = x
y1 = y; y2 = y; y3 = y; y4 = y
!-----------------------------------------------------------------------
! fill up the value at halo points for cubic-grid.
! On the contact line, the following relation will be used to
! --- fill the value on contact line ( balance send and recv).
! 2W --> 1E, 1S --> 6N, 3W --> 1N, 4S --> 2E
! 4W --> 3E, 3S --> 2N, 1W --> 5N, 2S --> 6E
! 6W --> 5E, 5S --> 4N, 5W --> 3N, 6S --> 4E
!---------------------------------------------------------------------------
id = mpp_clock_id( type//' vector CGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
type2 = type
do n = 1, ntile_per_pe
if( cubic_grid ) then
call fill_cubic_grid_halo(global1(:,:,:,n), global1_all, global2_all, tile(n), 1, 0, 1, -1 )
call fill_cubic_grid_halo(global2(:,:,:,n), global2_all, global1_all, tile(n), 0, 1, -1, 1 )
else if( folded_north ) then
!redundant points must be equal and opposite
global2(nx/2+1:nx, ny+shift,:,:) = -global2(nx/2:1:-1, ny+shift,:,:)
global2(1-whalo:0, ny+shift,:,:) = -global2(nx-whalo+1:nx, ny+shift,:,:)
global2(nx+1:nx+ehalo, ny+shift,:,:) = -global2(1:ehalo, ny+shift,:,:)
else if( folded_south_sym ) then
global2(nx/2+1:nx, 1,:,:) = -global2(nx/2:1:-1, 1,:,:)
global2(1-whalo:0, 1,:,:) = -global2(nx-whalo+1:nx, 1, :,:)
global2(nx+1:nx+ehalo, 1,:,:) = -global2(1:ehalo, 1, :,:)
else if( folded_west_sym ) then
global1(1, ny/2+1:ny, :,:) = -global1(1, ny/2:1:-1, :,:)
global1(1, 1-shalo:0, :,:) = -global1(1, ny-shalo+1:ny, :,:)
global1(1, ny+1:ny+nhalo, :,:) = -global1(1, 1:nhalo, :,:)
else if( folded_east_sym ) then
global1(nx+shift, ny/2+1:ny, :,:) = -global1(nx+shift, ny/2:1:-1, :,:)
global1(nx+shift, 1-shalo:0, :,:) = -global1(nx+shift, ny-shalo+1:ny, :,:)
global1(nx+shift, ny+1:ny+nhalo, :,:) = -global1(nx+shift, 1:nhalo, :,:)
end if
if(ntile_per_pe > 1) write(type2, *)type, " at tile_count = ",n
call mpp_clock_begin(id)
if(ntile_per_pe == 1) then
call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=CGRID_NE, name=type2//' vector CGRID_NE')
else
call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=CGRID_NE, &
name=type2//' vector CGRID_NE', tile_count = n)
end if
call mpp_clock_end (id)
end do
do n = 1, ntile_per_pe
if(ntile_per_pe > 1) write(type2, *)type, " at tile_count = ",n
call compare_checksums( x(isd:ied+shift,jsd:jed,:,n), global1(isd:ied+shift,jsd:jed, :,n), &
trim(type2)//' CGRID_NE X')
call compare_checksums( y(isd:ied,jsd:jed+shift,:,n), global2(isd:ied, jsd:jed+shift,:,n), &
trim(type2)//' CGRID_NE Y')
end do
if(ntile_per_pe == 1) then
call mpp_clock_begin(id)
call mpp_update_domains( x1, y1, domain, gridtype=CGRID_NE, complete=.false., name=type//' vector CGRID_NE' )
call mpp_update_domains( x2, y2, domain, gridtype=CGRID_NE, complete=.false., name=type//' vector CGRID_NE')
call mpp_update_domains( x3, y3, domain, gridtype=CGRID_NE, complete=.false., name=type//' vector CGRID_NE' )
call mpp_update_domains( x4, y4, domain, gridtype=CGRID_NE, complete=.true. , name=type//' vector CGRID_NE')
call mpp_clock_end (id)
call compare_checksums( x1(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X1')
call compare_checksums( x2(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X2')
call compare_checksums( x3(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X3')
call compare_checksums( x4(isd:ied+shift,jsd:jed,:,1), global1(isd:ied+shift,jsd:jed,:,1), type//' CGRID_NE X4')
call compare_checksums( y1(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y1')
call compare_checksums( y2(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y2')
call compare_checksums( y3(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y3')
call compare_checksums( y4(isd:ied,jsd:jed+shift,:,1), global2(isd:ied,jsd:jed+shift,:,1), type//' CGRID_NE Y4')
!--- arbitrary halo updates ---------------------------------------
if(wide_halo_x ==0) then
if(single_tile .or. four_tile .or. (cubic_grid .and. same_layout) .or. folded_north ) then
allocate(local1(isd:ied+shift,jsd:jed, nz) )
allocate(local2(isd:ied, jsd:jed+shift,nz) )
do wh = 1, whalo
do eh = 1, ehalo
if(wh .NE. eh) cycle
do sh = 1, shalo
do nh = 1, nhalo
if(sh .NE. nh) cycle
local1(isd:ied+shift,jsd:jed, :) = global1(isd:ied+shift,jsd:jed, :,1)
local2(isd:ied, jsd:jed+shift,:) = global2(isd:ied, jsd:jed+shift,:,1)
x = 0.; y = 0.
x(isc:iec+shift,jsc:jec, :,1) = global1(isc:iec+shift,jsc:jec, :,1)
y(isc:iec, jsc:jec+shift,:,1) = global2(isc:iec, jsc:jec+shift,:,1)
call fill_halo_zero(local1, wh, eh, sh, nh, shift, 0, isc, iec, jsc, jec, isd, ied, jsd, jed)
call fill_halo_zero(local2, wh, eh, sh, nh, 0, shift, isc, iec, jsc, jec, isd, ied, jsd, jed)
write(type3,'(a,a,i2,a,i2,a,i2,a,i2)') trim(type), ' vector CGRID_NE with whalo = ', &
wh, ', ehalo = ',eh, ', shalo = ', sh, ', nhalo = ', nh
call mpp_update_domains( x, y, domain, gridtype=CGRID_NE, whalo=wh, ehalo=eh, &
shalo=sh, nhalo=nh, name=type3)
call compare_checksums( x(isd:ied+shift,jsd:jed, :,1), local1, trim(type3)//' X' )
call compare_checksums( y(isd:ied,jsd:jed+shift, :,1), local2, trim(type3)//' Y' )
end do
end do
end do
end do
deallocate(local1, local2)
end if
endif
end if
deallocate(global1, global2, x, y, x1, x2, x3, x4, y1, y2, y3, y4, global1_all, global2_all)
deallocate(layout2D, global_indices, pe_start, pe_end, tile1, tile2)
deallocate(istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2 )
if(wide_halo_x > 0) then
whalo = whalo_save
ehalo = ehalo_save
shalo = shalo_save
nhalo = nhalo_save
endif
nx = nx_save
ny = ny_save
end subroutine test_uniform_mosaic
!#################################################################################
subroutine update_domains_performance( type )
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: num_contact, ntiles, npes_per_tile, ntile_per_pe
integer :: i, j, k, l, n, shift
integer :: ism, iem, jsm, jem
integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
integer, allocatable, dimension(:) :: tile
integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:,:,:) :: x, x1, y, y1, x_save, y_save
real, allocatable, dimension(:,:,:,:) :: a, a1, b, b1
real, allocatable, dimension(:,:,: ) :: a1_2D, b1_2D
integer :: id_update
integer :: id1, id2
logical :: folded_north
logical :: cubic_grid, single_tile, four_tile
character(len=3) :: text
integer :: nx_save, ny_save
integer :: id_single, id_update_single
folded_north = .false.
cubic_grid = .false.
single_tile = .false.
four_tile = .false.
nx_save = nx
ny_save = ny
!--- check the type
select case(type)
case ( 'Single-Tile' ) !--- single with cyclic along x- and y-direction
single_tile = .true.
ntiles = 1
num_contact = 2
case ( 'Folded-north' )
ntiles = 1
num_contact = 2
folded_north = .true.
case ( 'Four-Tile' ) !--- cyclic along both x- and y-direction.
ntiles = 4
num_contact = 8
four_tile = .true.
case ( 'Cubic-Grid' )
if( nx_cubic == 0 ) then
call mpp_error(NOTE,'update_domains_performance: for Cubic_grid mosaic, nx_cubic is zero, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
if( nx_cubic .NE. ny_cubic ) then
call mpp_error(NOTE,'update_domains_performance: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
nx = nx_cubic
ny = ny_cubic
ntiles = 6
num_contact = 12
cubic_grid = .true.
case default
call mpp_error(FATAL, 'update_domains_performance: no such test: '//type)
end select
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
if( mod(npes, ntiles) == 0 ) then
npes_per_tile = npes/ntiles
write(outunit,*)'NOTE from update_domains_performance ==> For Mosaic "', trim(type), &
'", each tile will be distributed over ', npes_per_tile, ' processors.'
ntile_per_pe = 1
allocate(tile(ntile_per_pe))
tile = pe/npes_per_tile+1
if(cubic_grid) then
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
else if ( mod(ntiles, npes) == 0 ) then
ntile_per_pe = ntiles/npes
write(outunit,*)'NOTE from update_domains_performance ==> For Mosaic "', trim(type), &
'", there will be ', ntile_per_pe, ' tiles on each processor.'
allocate(tile(ntile_per_pe))
do n = 1, ntile_per_pe
tile(n) = pe*ntile_per_pe + n
end do
do n = 1, ntiles
pe_start(n) = (n-1)/ntile_per_pe
pe_end(n) = pe_start(n)
end do
layout = 1
else
call mpp_error(NOTE,'update_domains_performance: npes should be multiple of ntiles or ' // &
'ntiles should be multiple of npes. No test is done for '//trim(type) )
return
end if
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
allocate(tile1(num_contact), tile2(num_contact) )
allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
!--- define domain
if(single_tile) then
!--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST)
tile1(1) = 1; tile2(1) = 1
istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (SOUTH) and tile 1 (NORTH) --- cyclic
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = nx; jstart1(2) = 1; jend1(2) = 1
istart2(2) = 1; iend2(2) = nx; jstart2(2) = ny; jend2(2) = ny
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .false. )
else if(folded_north) then
!--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
tile1(1) = 1; tile2(1) = 1
istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .false. )
else if( four_tile ) then
call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
layout2D, pe_start, pe_end, symmetry = .false. )
else if( cubic_grid ) then
call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
global_indices, layout2D, pe_start, pe_end )
endif
!--- setup data
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
allocate( x (ism:iem,jsm:jem,nz, ntile_per_pe) )
allocate( x_save (ism:iem,jsm:jem,nz, ntile_per_pe) )
allocate( a (ism:iem,jsm:jem,nz, ntile_per_pe) )
x = 0
do l = 1, ntile_per_pe
do k = 1, nz
do j = jsc, jec
do i = isc, iec
x(i, j, k, l) = tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
enddo
enddo
enddo
enddo
a = x
x_save = x
if(num_fields<1) then
call mpp_error(FATAL, "test_mpp_domains: num_fields must be a positive integer")
endif
id1 = mpp_clock_id( type, flags=MPP_CLOCK_SYNC)
id_single = mpp_clock_id( type//' non-blocking', flags=MPP_CLOCK_SYNC)
call mpp_clock_begin(id1)
call mpp_update_domains( x, domain)
call mpp_clock_end (id1)
call mpp_clock_begin(id_single)
id_update_single = mpp_start_update_domains(a, domain)
call mpp_clock_end (id_single)
!---- sleep some time for non-blocking.
if(do_sleep) call sleep(1)
id1 = mpp_clock_id( type//' group', flags=MPP_CLOCK_SYNC )
id2 = mpp_clock_id( type//' group non-blocking', flags=MPP_CLOCK_SYNC )
if(ntile_per_pe == 1) then
allocate( x1(ism:iem,jsm:jem,nz, num_fields) )
allocate( a1(ism:iem,jsm:jem,nz, num_fields) )
if(mix_2D_3D) allocate( a1_2D(ism:iem,jsm:jem,num_fields) )
do n = 1, num_iter
do l = 1, num_fields
x1(:,:,:,l) = x_save(:,:,:,1)
a1(:,:,:,l) = x_save(:,:,:,1)
if(mix_2D_3D) a1_2D(:,:,l) = x_save(:,:,1,1)
enddo
call mpp_clock_begin(id1)
do l = 1, num_fields
call mpp_update_domains( x1(:,:,:,l), domain, complete=l==num_fields )
enddo
call mpp_clock_end (id1)
! non-blocking update
call mpp_clock_begin(id2)
if( n == 1 ) then
do l = 1, num_fields
if(mix_2D_3D) id_update = mpp_start_update_domains(a1_2D(:,:,l), domain, complete=.false.)
id_update = mpp_start_update_domains(a1(:,:,:,l), domain, complete=l==num_fields)
enddo
else
do l = 1, num_fields
if(mix_2D_3D) id_update = mpp_start_update_domains(a1_2D(:,:,l), domain, update_id=id_update, complete=.false.)
id_update = mpp_start_update_domains(a1(:,:,:,l), domain, update_id=id_update, complete=l==num_fields)
enddo
endif
call mpp_clock_end (id2)
!---- sleep some time for non-blocking.
if(do_sleep) call sleep(1)
call mpp_clock_begin(id2)
do l = 1, num_fields
if(mix_2D_3D) call mpp_complete_update_domains(id_update, a1_2D(:,:,l), domain, complete=.false.)
call mpp_complete_update_domains(id_update, a1(:,:,:,l), domain, complete=l==num_fields)
enddo
call mpp_clock_end (id2)
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' X'//text)
enddo
if(mix_2D_3D)call compare_checksums( x1(:,:,1,:), a1_2D(:,:,:), type//' X 2D')
enddo
deallocate(x1, a1)
if(mix_2D_3D) deallocate(a1_2D)
endif
call mpp_clock_begin(id_single)
call mpp_complete_update_domains(id_update_single, a, domain)
call mpp_clock_end (id_single)
call compare_checksums( x(:,:,:,1), a(:,:,:,1), type)
deallocate(x, a, x_save)
!------------------------------------------------------------------
! vector update : BGRID_NE, one extra point in each direction for cubic-grid
!------------------------------------------------------------------
!--- setup data
shift = 0
if(single_tile .or. four_tile .or. folded_north) then
shift = 0
else
shift = 1
endif
allocate( x (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( x_save (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y_save (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( a (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( b (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
x = 0
y = 0
do l = 1, ntile_per_pe
do k = 1, nz
do j = jsc, jec+shift
do i = isc, iec+shift
x(i,j,k,l) = 1.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
y(i,j,k,l) = 2.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
enddo
a = x; b = y
x_save = x; y_save = y
id1 = mpp_clock_id( trim(type)//' BGRID', flags=MPP_CLOCK_SYNC )
id_single = mpp_clock_id( trim(type)//' BGRID non-blocking', flags=MPP_CLOCK_SYNC )
call mpp_clock_begin(id1)
call mpp_update_domains( x, y, domain, gridtype=BGRID_NE)
call mpp_clock_end (id1)
!--- non-blocking update
call mpp_clock_begin(id_single)
id_update_single = mpp_start_update_domains(a, b, domain, gridtype=BGRID_NE)
call mpp_clock_end (id_single)
!---- sleep some time for non-blocking.
if(do_sleep) call sleep(1)
id1 = mpp_clock_id( trim(type)//' BGRID group', flags=MPP_CLOCK_SYNC)
id2 = mpp_clock_id( trim(type)//' BGRID group non-blocking', flags=MPP_CLOCK_SYNC)
if(ntile_per_pe == 1) then
allocate( x1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
allocate( y1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
allocate( a1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
allocate( b1(ism:iem+shift,jsm:jem+shift,nz,num_fields) )
if(mix_2D_3D) then
allocate( a1_2D(ism:iem+shift,jsm:jem+shift,num_fields) )
allocate( b1_2D(ism:iem+shift,jsm:jem+shift,num_fields) )
endif
do n = 1, num_iter
do l = 1, num_fields
x1(:,:,:,l) = x_save(:,:,:,1)
a1(:,:,:,l) = x_save(:,:,:,1)
y1(:,:,:,l) = y_save(:,:,:,1)
b1(:,:,:,l) = y_save(:,:,:,1)
if(mix_2D_3D) then
a1_2D(:,:,l) = x_save(:,:,1,1)
b1_2D(:,:,l) = y_save(:,:,1,1)
endif
enddo
call mpp_clock_begin(id1)
do l = 1, num_fields
call mpp_update_domains( x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=BGRID_NE, complete=l==num_fields )
enddo
call mpp_clock_end (id1)
!--- non-blocking update
call mpp_clock_begin(id2)
if( n == 1 ) then
do l = 1, num_fields
if(mix_2D_3D) id_update = mpp_start_update_domains(a1_2D(:,:,l), b1_2D(:,:,l), domain, &
gridtype=BGRID_NE, complete=.false.)
id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, &
gridtype=BGRID_NE, complete=l==num_fields)
enddo
else
do l = 1, num_fields
if(mix_2D_3D) id_update = mpp_start_update_domains(a1_2D(:,:,l), b1_2D(:,:,l), domain, gridtype=BGRID_NE, &
update_id=id_update, complete=.false.)
id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, gridtype=BGRID_NE, &
update_id=id_update, complete=l==num_fields)
enddo
endif
call mpp_clock_end (id2)
!---- sleep some time for non-blocking.
if(do_sleep) call sleep(1)
call mpp_clock_begin(id2)
do l = 1, num_fields
if(mix_2D_3D)call mpp_complete_update_domains(id_update, a1_2D(:,:,l), b1_2D(:,:,l), domain, &
gridtype=BGRID_NE, complete=.false.)
call mpp_complete_update_domains(id_update, a1(:,:,:,l), b1(:,:,:,l), domain, &
gridtype=BGRID_NE, complete=l==num_fields)
enddo
call mpp_clock_end (id2)
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' BGRID X'//text)
call compare_checksums( y1(:,:,:,l), b1(:,:,:,l), type//' BGRID Y'//text)
if(mix_2D_3D) then
call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' BGRID X'//text)
call compare_checksums( y1(:,:,:,1), b1(:,:,:,1), type//' BGRID Y'//text)
endif
enddo
if(mix_2D_3D) then
call compare_checksums( x1(:,:,1,:), a1_2D(:,:,:), type//' BGRID X 2D')
call compare_checksums( y1(:,:,1,:), b1_2D(:,:,:), type//' BGRID Y 2D')
endif
enddo
deallocate(x1, y1, a1, b1)
if(mix_2D_3D) deallocate(a1_2D, b1_2D)
endif
call mpp_clock_begin(id_single)
call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=BGRID_NE)
call mpp_clock_end (id_single)
!--- compare checksum
call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' BGRID X')
call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' BGRID Y')
deallocate(x, y, a, b, x_save, y_save)
!------------------------------------------------------------------
! vector update : CGRID_NE, one extra point in each direction for cubic-grid
!------------------------------------------------------------------
allocate( x (ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( y (ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
allocate( a (ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( b (ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
allocate( x_save (ism:iem+shift,jsm:jem ,nz,ntile_per_pe) )
allocate( y_save (ism:iem ,jsm:jem+shift,nz,ntile_per_pe) )
x = 0
y = 0
do l = 1, ntile_per_pe
do k = 1, nz
do j = jsc, jec
do i = isc, iec+shift
x(i,j,k,l) = 1.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
do j = jsc, jec+shift
do i = isc, iec
y(i,j,k,l) = 2.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
enddo
a = x; b = y
x_save = x; y_save = y
id1 = mpp_clock_id( trim(type)//' CGRID', flags=MPP_CLOCK_SYNC )
id_single = mpp_clock_id( trim(type)//' CGRID non-blocking', flags=MPP_CLOCK_SYNC )
call mpp_clock_begin(id1)
call mpp_update_domains( x, y, domain, gridtype=CGRID_NE)
call mpp_clock_end (id1)
!--- non-blocking update
call mpp_clock_begin(id_single)
id_update_single = mpp_start_update_domains(a, b, domain, gridtype=CGRID_NE)
call mpp_clock_end (id_single)
!---- sleep some time for non-blocking.
if(do_sleep) call sleep(1)
id1 = mpp_clock_id( trim(type)//' CGRID group', flags=MPP_CLOCK_SYNC )
id2 = mpp_clock_id( trim(type)//' CGRID group non-blocking', flags=MPP_CLOCK_SYNC )
if(ntile_per_pe == 1) then
allocate( x1(ism:iem+shift,jsm:jem ,nz,num_fields) )
allocate( y1(ism:iem ,jsm:jem+shift,nz,num_fields) )
allocate( a1(ism:iem+shift,jsm:jem ,nz,num_fields) )
allocate( b1(ism:iem ,jsm:jem+shift,nz,num_fields) )
if(mix_2D_3D) then
allocate( a1_2D(ism:iem+shift,jsm:jem ,num_fields) )
allocate( b1_2D(ism:iem ,jsm:jem+shift,num_fields) )
endif
do n = 1, num_iter
do l = 1, num_fields
x1(:,:,:,l) = x_save(:,:,:,1)
a1(:,:,:,l) = x_save(:,:,:,1)
y1(:,:,:,l) = y_save(:,:,:,1)
b1(:,:,:,l) = y_save(:,:,:,1)
if(mix_2D_3D) then
a1_2D(:,:,l) = x_save(:,:,1,1)
b1_2D(:,:,l) = y_save(:,:,1,1)
endif
enddo
call mpp_clock_begin(id1)
do l = 1, num_fields
call mpp_update_domains( x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=CGRID_NE, complete=l==num_fields )
enddo
call mpp_clock_end (id1)
!--- non-blocking update
call mpp_clock_begin(id2)
if( n == 1 ) then
do l = 1, num_fields
if(mix_2D_3D) id_update = mpp_start_update_domains(a1_2D(:,:,l), b1_2D(:,:,l), domain, &
gridtype=CGRID_NE, complete=.false.)
id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, &
gridtype=CGRID_NE, complete=l==num_fields)
enddo
else
do l = 1, num_fields
if(mix_2D_3D)id_update = mpp_start_update_domains(a1_2D(:,:,l), b1_2D(:,:,l), domain, gridtype=CGRID_NE, &
update_id=id_update, complete=.false.)
id_update = mpp_start_update_domains(a1(:,:,:,l), b1(:,:,:,l), domain, gridtype=CGRID_NE, &
update_id=id_update, complete=l==num_fields)
enddo
endif
call mpp_clock_end (id2)
!---- sleep some time for non-blocking.
if(do_sleep) call sleep(1)
call mpp_clock_begin(id2)
do l = 1, num_fields
if(mix_2D_3D)call mpp_complete_update_domains(id_update, a1_2D(:,:,l), b1_2D(:,:,l), domain, &
gridtype=CGRID_NE, complete=.false.)
call mpp_complete_update_domains(id_update, a1(:,:,:,l), b1(:,:,:,l), domain, &
gridtype=CGRID_NE, complete=l==num_fields)
enddo
call mpp_clock_end (id2)
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums( x1(:,:,:,l), a1(:,:,:,l), type//' CGRID X'//text)
call compare_checksums( y1(:,:,:,l), b1(:,:,:,l), type//' CGRID Y'//text)
enddo
if(mix_2D_3D) then
call compare_checksums( x1(:,:,1,:), a1_2D(:,:,:), type//' BGRID X 2D')
call compare_checksums( y1(:,:,1,:), b1_2D(:,:,:), type//' BGRID Y 2D')
endif
enddo
deallocate(x1, y1, a1, b1)
if(mix_2D_3D) deallocate(a1_2D, b1_2D)
endif
call mpp_clock_begin(id_single)
call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=CGRID_NE)
call mpp_clock_end (id_single)
!--- compare checksum
call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' CGRID X')
call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' CGRID Y')
deallocate(x, y, a, b, x_save, y_save)
!------------------------------------------------------------------
! vector update : AGRID vector and scalar pair
!------------------------------------------------------------------
allocate( x (ism:iem,jsm:jem,nz,ntile_per_pe) )
allocate( y (ism:iem,jsm:jem,nz,ntile_per_pe) )
allocate( a (ism:iem,jsm:jem,nz,ntile_per_pe) )
allocate( b (ism:iem,jsm:jem,nz,ntile_per_pe) )
allocate( x_save (ism:iem,jsm:jem,nz,ntile_per_pe) )
allocate( y_save (ism:iem,jsm:jem,nz,ntile_per_pe) )
x = 0
y = 0
do l = 1, ntile_per_pe
do k = 1, nz
do j = jsc, jec
do i = isc, iec+shift
x(i,j,k,l) = 1.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
do j = jsc, jec+shift
do i = isc, iec
y(i,j,k,l) = 2.0e3 + tile(l) + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
enddo
a = x; b = y
x_save = x; y_save = y
call mpp_update_domains( x, y, domain, gridtype=AGRID)
id_update_single = mpp_start_update_domains(a, b, domain, gridtype=AGRID)
call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=AGRID)
!--- compare checksum
call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' AGRID X')
call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' AGRID Y')
x = x_save; y = y_save
a = x_save; b = y_save
call mpp_update_domains( x, y, domain, gridtype=AGRID, flags = SCALAR_PAIR)
id_update_single = mpp_start_update_domains(a, b, domain, gridtype=AGRID, flags = SCALAR_PAIR)
call mpp_complete_update_domains(id_update_single, a, b, domain, gridtype=AGRID, flags = SCALAR_PAIR)
!--- compare checksum
call compare_checksums( x(:,:,:,1), a(:,:,:,1), type//' AGRID SCALAR-PAIR X')
call compare_checksums( y(:,:,:,1), b(:,:,:,1), type//' AGRID SCALAR-PAIR Y')
deallocate(x, y, a, b, x_save, y_save)
nx = nx_save
ny = ny_save
deallocate(layout2D, global_indices, pe_start, pe_end, tile1, tile2)
deallocate(istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2 )
end subroutine update_domains_performance
!###############################################################
subroutine test_mpp_global_sum( type )
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: num_contact, ntiles, npes_per_tile
integer :: i, j, k, l, n, shift
integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
integer :: ism, iem, jsm, jem
integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:,:) :: data_3D
real, allocatable, dimension(:,:) :: data_2D
integer(kind=8) :: mold
logical :: folded_north, cubic_grid
character(len=3) :: text
integer :: nx_save, ny_save
integer :: id1, id2, id3, id4
real :: gsum1, gsum2, gsum3, gsum4
folded_north = .false.
cubic_grid = .false.
nx_save = nx
ny_save = ny
!--- check the type
select case(type)
case ( 'Folded-north' )
ntiles = 1
shift = 0
num_contact = 2
folded_north = .true.
npes_per_tile = npes
if(layout_tripolar(1)*layout_tripolar(2) == npes ) then
layout = layout_tripolar
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
case ( 'Cubic-Grid' )
if( nx_cubic == 0 ) then
call mpp_error(NOTE,'test_group_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
if( nx_cubic .NE. ny_cubic ) then
call mpp_error(NOTE,'test_group_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
shift = 1
nx = nx_cubic
ny = ny_cubic
ntiles = 6
num_contact = 12
cubic_grid = .true.
if( mod(npes, ntiles) == 0 ) then
npes_per_tile = npes/ntiles
write(outunit,*)'NOTE from test_mpp_global_sum ==> For Mosaic "', trim(type), &
'", each tile will be distributed over ', npes_per_tile, ' processors.'
else
call mpp_error(NOTE,'test_group_update: npes should be multiple of ntiles No test is done for '//trim(type))
return
endif
if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
layout = layout_cubic
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
case default
call mpp_error(FATAL, 'test_mpp_global_sum: no such test: '//type)
end select
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
allocate(tile1(num_contact), tile2(num_contact) )
allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
!--- define domain
if(folded_north) then
!--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
tile1(1) = 1; tile2(1) = 1
istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .false. )
else if( cubic_grid ) then
call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
global_indices, layout2D, pe_start, pe_end )
endif
!--- setup data
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
allocate(data_2d(isd:ied,jsd:jed))
allocate(data_3d(isd:ied,jsd:jed,nz))
do k = 1, nz
do j = jsd, jed
do i = isd, ied
data_3d(i,j,k) = k*1e3 + i + j*1e-3
enddo
enddo
enddo
do j = jsd, jed
do i = isd, ied
data_2d(i,j) = i*1e3 + j*1e-3
enddo
enddo
id1 = mpp_clock_id( type//' bitwise sum 3D', flags=MPP_CLOCK_SYNC )
id2 = mpp_clock_id( type//' EFP sum 3D', flags=MPP_CLOCK_SYNC )
id3 = mpp_clock_id( type//' EFP sum 3D check', flags=MPP_CLOCK_SYNC )
id4 = mpp_clock_id( type//' non-bitwise sum 3D', flags=MPP_CLOCK_SYNC )
call mpp_clock_begin(id1)
do n = 1, num_iter
gsum1 = mpp_global_sum(domain, data_3d, flags=BITWISE_EXACT_SUM)
enddo
call mpp_clock_end(id1)
call mpp_clock_begin(id2)
do n = 1, num_iter
gsum2 = mpp_global_sum(domain, data_3d, flags=BITWISE_EFP_SUM)
enddo
call mpp_clock_end(id2)
call mpp_clock_begin(id3)
do n = 1, num_iter
gsum3 = mpp_global_sum(domain, data_3d, flags=BITWISE_EFP_SUM, overflow_check=.true. )
enddo
call mpp_clock_end(id3)
call mpp_clock_begin(id4)
do n = 1, num_iter
gsum4= mpp_global_sum(domain, data_3d)
enddo
call mpp_clock_end(id4)
write(outunit, *) " ********************************************************************************"
write(outunit, *) " global sum for "//type//' bitwise exact sum 3D = ', gsum1
write(outunit, *) " global sum for "//type//' bitwise EFP sum 3D = ', gsum2
write(outunit, *) " global sum for "//type//' bitwise EFP sum 3D with overflow_check = ', gsum3
write(outunit, *) " global sum for "//type//' non-bitwise sum 3D = ', gsum4
write(outunit, *) " "
write(outunit, *) " chksum for "//type//' bitwise exact sum 3D = ', transfer(gsum1, mold)
write(outunit, *) " chksum for "//type//' bitwise EFP sum 3D = ', transfer(gsum2, mold)
write(outunit, *) " chksum for "//type//' bitwise EFP sum 3D with overflow_check = ', transfer(gsum3, mold)
write(outunit, *) " chksum for "//type//' non-bitwise sum 3D = ', transfer(gsum4, mold)
write(outunit, *) " ********************************************************************************"
id1 = mpp_clock_id( type//' bitwise sum 2D', flags=MPP_CLOCK_SYNC )
id2 = mpp_clock_id( type//' EFP sum 2D', flags=MPP_CLOCK_SYNC )
id3 = mpp_clock_id( type//' EFP sum 2D check', flags=MPP_CLOCK_SYNC )
id4 = mpp_clock_id( type//' non-bitwise sum 2D', flags=MPP_CLOCK_SYNC )
call mpp_clock_begin(id1)
do n = 1, num_iter
gsum1 = mpp_global_sum(domain, data_2d, flags=BITWISE_EXACT_SUM)
enddo
call mpp_clock_end(id1)
call mpp_clock_begin(id2)
do n = 1, num_iter
gsum2 = mpp_global_sum(domain, data_2d, flags=BITWISE_EFP_SUM)
enddo
call mpp_clock_end(id2)
call mpp_clock_begin(id3)
do n = 1, num_iter
gsum3 = mpp_global_sum(domain, data_2d, flags=BITWISE_EFP_SUM, overflow_check=.true. )
enddo
call mpp_clock_end(id3)
call mpp_clock_begin(id4)
do n = 1, num_iter
gsum4= mpp_global_sum(domain, data_2d)
enddo
call mpp_clock_end(id4)
write(outunit, *) " ********************************************************************************"
write(outunit, *) " global sum for "//type//' bitwise exact sum 2D = ', gsum1
write(outunit, *) " global sum for "//type//' bitwise EFP sum 2D = ', gsum2
write(outunit, *) " global sum for "//type//' bitwise EFP sum 2D with overflow_check = ', gsum3
write(outunit, *) " global sum for "//type//' non-bitwise sum 2D = ', gsum4
write(outunit, *) " "
write(outunit, *) " chksum for "//type//' bitwise exact sum 2D = ', transfer(gsum1, mold)
write(outunit, *) " chksum for "//type//' bitwise EFP sum 2D = ', transfer(gsum2, mold)
write(outunit, *) " chksum for "//type//' bitwise EFP sum 2D with overflow_check = ', transfer(gsum3, mold)
write(outunit, *) " chksum for "//type//' non-bitwise sum 2D = ', transfer(gsum4, mold)
write(outunit, *) " ********************************************************************************"
nx = nx_save
ny = ny_save
end subroutine test_mpp_global_sum
!###############################################################
subroutine test_group_update( type )
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: num_contact, ntiles, npes_per_tile
integer :: i, j, k, l, n, shift
integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
integer :: ism, iem, jsm, jem
integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:,:,:) :: x1, y1, x2, y2
real, allocatable, dimension(:,:,:,:) :: a1, a2
real, allocatable, dimension(:,:,:) :: base
integer :: id1, id2, id3
logical :: folded_north
logical :: cubic_grid
character(len=3) :: text
integer :: nx_save, ny_save
type(mpp_group_update_type) :: group_update
type(mpp_group_update_type), allocatable :: update_list(:)
folded_north = .false.
cubic_grid = .false.
nx_save = nx
ny_save = ny
!--- check the type
select case(type)
case ( 'Folded-north' )
ntiles = 1
shift = 0
num_contact = 2
folded_north = .true.
npes_per_tile = npes
if(layout_tripolar(1)*layout_tripolar(2) == npes ) then
layout = layout_tripolar
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
case ( 'Cubic-Grid' )
if( nx_cubic == 0 ) then
call mpp_error(NOTE,'test_group_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
if( nx_cubic .NE. ny_cubic ) then
call mpp_error(NOTE,'test_group_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
shift = 1
nx = nx_cubic
ny = ny_cubic
ntiles = 6
num_contact = 12
cubic_grid = .true.
if( mod(npes, ntiles) == 0 ) then
npes_per_tile = npes/ntiles
write(outunit,*)'NOTE from update_domains_performance ==> For Mosaic "', trim(type), &
'", each tile will be distributed over ', npes_per_tile, ' processors.'
else
call mpp_error(NOTE,'test_group_update: npes should be multiple of ntiles No test is done for '//trim(type))
return
endif
if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
layout = layout_cubic
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
case default
call mpp_error(FATAL, 'test_group_update: no such test: '//type)
end select
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
allocate(tile1(num_contact), tile2(num_contact) )
allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
!--- define domain
if(folded_north) then
!--- Contact line 1, between tile 1 (EAST) and tile 1 (WEST) --- cyclic
tile1(1) = 1; tile2(1) = 1
istart1(1) = nx; iend1(1) = nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (NORTH) and tile 1 (NORTH) --- folded-north-edge
tile1(2) = 1; tile2(2) = 1
istart1(2) = 1; iend1(2) = nx/2; jstart1(2) = ny; jend1(2) = ny
istart2(2) = nx; iend2(2) = nx/2+1; jstart2(2) = ny; jend2(2) = ny
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, symmetry = .false. )
else if( cubic_grid ) then
call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
global_indices, layout2D, pe_start, pe_end )
endif
!--- setup data
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
if(num_fields<1) then
call mpp_error(FATAL, "test_mpp_domains: num_fields must be a positive integer")
endif
allocate(update_list(num_fields))
id1 = mpp_clock_id( type//' group 2D', flags=MPP_CLOCK_SYNC )
id2 = mpp_clock_id( type//' non-group 2D', flags=MPP_CLOCK_SYNC )
id3 = mpp_clock_id( type//' non-block group 2D', flags=MPP_CLOCK_SYNC )
allocate( a1(ism:iem, jsm:jem, nz, num_fields) )
allocate( x1(ism:iem+shift,jsm:jem, nz, num_fields) )
allocate( y1(ism:iem, jsm:jem+shift, nz, num_fields) )
allocate( a2(ism:iem, jsm:jem, nz, num_fields) )
allocate( x2(ism:iem+shift,jsm:jem, nz, num_fields) )
allocate( y2(ism:iem, jsm:jem+shift, nz, num_fields) )
allocate( base(isc:iec+shift,jsc:jec+shift,nz) )
a1 = 0; x1 = 0; y1 = 0
base = 0
do k = 1,nz
do j = jsc, jec+shift
do i = isc, iec+shift
base(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
!--- Test for partial direction update
do l =1, num_fields
call mpp_create_group_update(group_update, a1(:,:,:,l), domain, flags=WUPDATE+SUPDATE)
end do
do l = 1, num_fields
a1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3
do k=1,nz
do i=isc-1,iec+1
a1(i,jsc-1,k,l) = 999;
a1(i,jec+1,k,l) = 999;
enddo
do j=jsc,jec
a1(isc-1,j,k,l) = 999
a1(iec+1,j,k,l) = 999
enddo
enddo
enddo
a2 = a1
call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
do l = 1, num_fields
call mpp_update_domains( a2(:,:,:,l), domain, flags=WUPDATE+SUPDATE, complete=l==num_fields )
enddo
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied,jsd:jed,:,l),a2(isd:ied,jsd:jed,:,l),type//' CENTER South West '//text)
enddo
call mpp_clear_group_update(group_update)
!--- Test for DGRID update
if(type == 'Cubic-Grid' ) then
x1 = 0; y1 = 0
do l =1, num_fields
call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=DGRID_NE)
end do
do l = 1, num_fields
y1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
x1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
enddo
x2 = x1; y2 = y1
call mpp_start_group_update(group_update, domain, x1(isc,jsc,1,1))
call mpp_complete_group_update(group_update, domain, x1(isc,jsc,1,1))
do l = 1, num_fields
call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=DGRID_NE, complete=l==num_fields )
enddo
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l),type//' DGRID X'//text)
call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l),type//' DGRID Y'//text)
enddo
call mpp_clear_group_update(group_update)
endif
!--- Test for CGRID
a1 = 0; x1 = 0; y1 = 0
do l =1, num_fields
call mpp_create_group_update(group_update, a1(:,:,:,l), domain)
call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=CGRID_NE)
end do
do n = 1, num_iter
a1 = 0; x1 = 0; y1 = 0
do l = 1, num_fields
a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
x1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
y1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
enddo
a2 = a1; x2 = x1; y2 = y1
call mpp_clock_begin(id1)
call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_clock_end (id1)
call mpp_clock_begin(id2)
do l = 1, num_fields
call mpp_update_domains( a2(:,:,:,l), domain, complete=l==num_fields )
enddo
do l = 1, num_fields
call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=CGRID_NE, complete=l==num_fields )
enddo
call mpp_clock_end(id2)
!--- compare checksum
if( n == num_iter ) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l),type//' CENTER '//text)
call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l),type//' CGRID X'//text)
call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l),type//' CGRID Y'//text)
enddo
endif
a1 = 0; x1 = 0; y1 = 0
do l = 1, num_fields
a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
x1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
y1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
enddo
call mpp_clock_begin(id3)
call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_clock_end (id3)
!--- compare checksum
if( n == num_iter ) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l), &
type//' nonblock CENTER '//text)
call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l), &
type//' nonblock CGRID X'//text)
call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l), &
type//' nonblock CGRID Y'//text)
enddo
endif
enddo
call mpp_clear_group_update(group_update)
!--- The following is to test overlapping start and complete
if( num_fields > 1 ) then
do l =1, num_fields
call mpp_create_group_update(update_list(l), a1(:,:,:,l), domain)
call mpp_create_group_update(update_list(l), x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=CGRID_NE)
end do
do n = 1, num_iter
a1 = 0; x1 = 0; y1 = 0
do l = 1, num_fields
a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
x1(isc:iec+shift,jsc:jec, :,l) = base(isc:iec+shift,jsc:jec, :) + l*1e3 + 1e6
y1(isc:iec, jsc:jec+shift,:,l) = base(isc:iec, jsc:jec+shift,:) + l*1e3 + 2*1e6
enddo
do l = 1, num_fields-1
call mpp_start_group_update(update_list(l), domain, a1(isc,jsc,1,1))
enddo
call mpp_complete_group_update(update_list(1), domain, a1(isc,jsc,1,1))
call mpp_start_group_update(update_list(num_fields), domain, a1(isc,jsc,1,1))
do l = 2, num_fields
call mpp_complete_group_update(update_list(l), domain, a1(isc,jsc,1,1))
enddo
!--- compare checksum
if( n == num_iter ) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l), &
type//' multiple nonblock CENTER '//text)
call compare_checksums(x1(isd:ied+shift,jsd:jed, :,l),x2(isd:ied+shift,jsd:jed, :,l), &
type//' multiple nonblock CGRID X'//text)
call compare_checksums(y1(isd:ied, jsd:jed+shift,:,l),y2(isd:ied, jsd:jed+shift,:,l), &
type//' multiple nonblock CGRID Y'//text)
enddo
endif
enddo
endif
do l =1, num_fields
call mpp_clear_group_update(update_list(l))
enddo
deallocate(update_list)
!--- test scalar 4-D variable
call mpp_create_group_update(group_update, a1(:,:,:,:), domain)
a1 = 0; x1 = 0; y1 = 0
do l = 1, num_fields
a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
enddo
a2 = a1; x2 = x1; y2 = y1
call mpp_clock_begin(id1)
call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_clock_end (id1)
call mpp_clock_begin(id2)
call mpp_update_domains( a2(:,:,:,:), domain )
call mpp_clock_end(id2)
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l),type//' 4D CENTER '//text)
enddo
a1 = 0
do l = 1, num_fields
a1(isc:iec, jsc:jec, :,l) = base(isc:iec, jsc:jec, :) + l*1e3
enddo
call mpp_clock_begin(id3)
call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_clock_end (id3)
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied, jsd:jed, :,l),a2(isd:ied, jsd:jed, :,l), &
type//' nonblock 4D CENTER '//text)
enddo
!--- test for BGRID.
deallocate(a1, x1, y1)
deallocate(a2, x2, y2)
call mpp_clear_group_update(group_update)
allocate( a1(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
allocate( x1(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
allocate( y1(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
allocate( a2(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
allocate( x2(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
allocate( y2(ism:iem+shift,jsm:jem+shift, nz, num_fields) )
do l =1, num_fields
call mpp_create_group_update(group_update, a1(:,:,:,l), domain, position=CORNER)
call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=BGRID_NE)
end do
do n = 1, num_iter
a1 = 0; x1 = 0; y1 = 0
do l = 1, num_fields
a1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3
x1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 1e6
y1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 2*1e6
enddo
a2 = a1; x2 = x1; y2 = y1
call mpp_clock_begin(id1)
call mpp_do_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_clock_end (id1)
call mpp_clock_begin(id2)
do l = 1, num_fields
call mpp_update_domains( a2(:,:,:,l), domain, position=CORNER, complete=l==num_fields )
enddo
do l = 1, num_fields
call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=BGRID_NE, complete=l==num_fields )
enddo
call mpp_clock_end(id2)
!--- compare checksum
if( n == num_iter ) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied+shift,jsd:jed+shift,:,l),a2(isd:ied+shift,jsd:jed+shift,:,l),type//' CORNER '//text)
call compare_checksums(x1(isd:ied+shift,jsd:jed+shift,:,l),x2(isd:ied+shift,jsd:jed+shift,:,l),type//' BGRID X'//text)
call compare_checksums(y1(isd:ied+shift,jsd:jed+shift,:,l),y2(isd:ied+shift,jsd:jed+shift,:,l),type//' BGRID Y'//text)
enddo
endif
a1 = 0; x1 = 0; y1 = 0
do l = 1, num_fields
a1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3
x1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 1e6
y1(isc:iec+shift,jsc:jec+shift,:,l) = base(isc:iec+shift,jsc:jec+shift,:) + l*1e3 + 2*1e6
enddo
call mpp_clock_begin(id3)
call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_clock_end (id3)
!--- compare checksum
if( n == num_iter ) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(isd:ied+shift,jsd:jed+shift,:,l),a2(isd:ied+shift,jsd:jed+shift,:,l), &
type//' nonblockCORNER '//text)
call compare_checksums(x1(isd:ied+shift,jsd:jed+shift,:,l),x2(isd:ied+shift,jsd:jed+shift,:,l), &
type//' nonblock BGRID X'//text)
call compare_checksums(y1(isd:ied+shift,jsd:jed+shift,:,l),y2(isd:ied+shift,jsd:jed+shift,:,l), &
type//' nonblock BGRID Y'//text)
enddo
endif
enddo
call mpp_clear_group_update(group_update)
!-----------------------------------------------------------------------------
! test for AGRID vector and scalar pair
!-----------------------------------------------------------------------------
deallocate(x1, y1)
deallocate(x2, y2)
allocate( x1(ism:iem,jsm:jem, nz, num_fields) )
allocate( y1(ism:iem,jsm:jem, nz, num_fields) )
allocate( x2(ism:iem,jsm:jem, nz, num_fields) )
allocate( y2(ism:iem,jsm:jem, nz, num_fields) )
x1 = 0; y1 = 0
do l = 1, num_fields
x1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 1e6
y1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 2*1e6
enddo
x2 = x1; y2 = y1
do l =1, num_fields
call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=AGRID)
end do
do l = 1, num_fields
call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=AGRID, complete=l==num_fields )
enddo
call mpp_start_group_update(group_update, domain, a1(isc,jsc,1,1))
call mpp_complete_group_update(group_update, domain, a1(isc,jsc,1,1))
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(x1(isd:ied,jsd:jed,:,l),x2(isd:ied,jsd:jed,:,l),type//' AGRID X'//text)
call compare_checksums(y1(isd:ied,jsd:jed,:,l),y2(isd:ied,jsd:jed,:,l),type//' AGRID Y'//text)
enddo
call mpp_clear_group_update(group_update)
x1 = 0; y1 = 0
do l = 1, num_fields
x1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 1e6
y1(isc:iec,jsc:jec,:,l) = base(isc:iec,jsc:jec,:) + l*1e3 + 2*1e6
enddo
x2 = x1; y2 = y1
do l =1, num_fields
call mpp_create_group_update(group_update, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=AGRID, flags=SCALAR_PAIR)
end do
do l = 1, num_fields
call mpp_update_domains( x2(:,:,:,l), y2(:,:,:,l), domain, gridtype=AGRID, flags=SCALAR_PAIR, complete=l==num_fields)
enddo
call mpp_start_group_update(group_update, domain, x1(isc,jsc,1,1))
call mpp_complete_group_update(group_update, domain, x1(isc,jsc,1,1))
!--- compare checksum
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(x1(isd:ied,jsd:jed,:,l),x2(isd:ied,jsd:jed,:,l),type//' AGRID SCALAR_PAIR X'//text)
call compare_checksums(y1(isd:ied,jsd:jed,:,l),y2(isd:ied,jsd:jed,:,l),type//' AGRID SCALAR_PAIR Y'//text)
enddo
call mpp_clear_group_update(group_update)
deallocate(pe_start, pe_end, tile1, tile2)
deallocate(istart1, iend1, jstart1, jend1)
deallocate(istart2, iend2, jstart2, jend2)
deallocate(layout2D, global_indices)
deallocate(a1, x1, y1)
deallocate(a2, x2, y2)
deallocate(base)
call mpp_deallocate_domain(domain)
end subroutine test_group_update
!###############################################################
!--- This will test scalar and CGRID performance between halo=1 and halo=3
subroutine test_halosize_update( type )
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: ntiles, npes_per_tile
integer :: i, j, k, l, n, shift
integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
integer :: ism, iem, jsm, jem
integer, allocatable, dimension(:) :: pe_start, pe_end
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:,:,:) :: x1, y1, x2, y2
real, allocatable, dimension(:,:,:,:) :: a1, a2
real, allocatable, dimension(:,:,:,:) :: base, global_all, global
real, allocatable, dimension(:,:,:,:) :: base1, global1_all, global1
real, allocatable, dimension(:,:,:,:) :: base2, global2_all, global2
integer :: id1, id2, id3
logical :: folded_north
logical :: cubic_grid, is_symmetry
character(len=3) :: text
character(len=1) :: halostr
integer :: nx_save, ny_save
integer :: mytile
type(mpp_group_update_type) :: group_update1, group_update2
type(mpp_group_update_type), allocatable :: update_list(:)
if(whalo .ne. ehalo .or. whalo .ne. shalo .or. whalo .ne. nhalo) then
call mpp_error(FATAL,"test_mpp_domains: whalo, ehalo, shalo, nhalo must be the same when test_halosize_performance=true")
endif
folded_north = .false.
cubic_grid = .false.
nx_save = nx
ny_save = ny
!--- check the type
select case(type)
case ( 'Folded-north', 'Folded-north symmetry' )
ntiles = 1
mytile = 1
folded_north = .true.
npes_per_tile = npes
if(layout_tripolar(1)*layout_tripolar(2) == npes ) then
layout = layout_tripolar
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
if(index(type, 'symmetry') == 0) then
is_symmetry = .false.
else
is_symmetry = .true.
end if
case ( 'Cubic-Grid' )
is_symmetry = .true.
if( nx_cubic == 0 ) then
call mpp_error(NOTE,'test_halosize_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
if( nx_cubic .NE. ny_cubic ) then
call mpp_error(NOTE,'test_halosize_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
nx = nx_cubic
ny = ny_cubic
ntiles = 6
if( mod(npes, ntiles) .ne. 0 ) then
call mpp_error(NOTE,'test_halosize_update: npes is not divisible by ntiles, no test is done for '//trim(type) )
return
endif
npes_per_tile = npes/ntiles
mytile = mpp_pe()/npes_per_tile + 1
cubic_grid = .true.
if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
layout = layout_cubic
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
case default
call mpp_error(FATAL, 'test_group_update: no such test: '//type)
end select
shift = 0
if(is_symmetry) shift = 1
!--- define domain
if(folded_north) then
call mpp_define_domains((/1,nx,1,ny/), layout, domain, &
xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, &
whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
symmetry=is_symmetry, name=type )
else if( cubic_grid ) then
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
call define_cubic_mosaic(type, domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
global_indices, layout2D, pe_start, pe_end, use_memsize=.false.)
deallocate(pe_start, pe_end)
deallocate(layout2D, global_indices)
endif
!--- setup data
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
if(num_fields<1) then
call mpp_error(FATAL, "test_mpp_domains: num_fields must be a positive integer")
endif
!--- scalar update
write(halostr,'(I1)') whalo
id1 = mpp_clock_id( type//' halo='//halostr//' scalar', flags=MPP_CLOCK_SYNC )
id2 = mpp_clock_id( type//' halo=1 scalar', flags=MPP_CLOCK_SYNC )
allocate( a1(isd:ied, jsd:jed, nz, num_fields) )
allocate( a2(isd:ied, jsd:jed, nz, num_fields) )
allocate(base(isc:iec, jsc:jec, nz, num_fields))
allocate(global_all(1:nx,1:ny,nz,ntiles) )
allocate(global(1-whalo:nx+ehalo, 1-shalo:ny+nhalo, nz, num_fields))
do n = 1, ntiles
do k = 1, nz
do j = 1, ny
do i = 1, nx
global_all(i,j,k,n) = n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
global = 0.0
do l = 1, num_fields
global(1:nx,1:ny,:,l) = global_all(:,:,:,mytile)
enddo
base(isc:iec,jsc:jec,:,:) = global(isc:iec,jsc:jec,:,:)
!--- fill up the value at halo points
do l = 1, num_fields
if(folded_north) then
call fill_folded_north_halo(global(:,:,:,l), 0, 0, 0, 0, 1)
else if(cubic_grid) then
call fill_cubic_grid_halo(global(:,:,:,l), global_all, global_all, mytile, 0, 0, 1, 1 )
endif
enddo
a1 = 0.0
a2(isd:ied,jsd:jed,:,:) = global(isd:ied,jsd:jed,:,:)
do l =1, num_fields
call mpp_create_group_update(group_update1, a1(:,:,:,l), domain)
end do
do l =1, num_fields
call mpp_create_group_update(group_update2, a1(:,:,:,l), domain, whalo=1, ehalo=1, shalo=1, nhalo=1)
end do
do n = 1, num_iter
a1 = 0.0
a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
call mpp_clock_begin(id1)
call mpp_do_group_update(group_update1, domain, a1(isc,jsc,1,1))
call mpp_clock_end(id1)
if(n==num_iter) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//' halo='//halostr//' scalar'//text)
enddo
endif
enddo
!--- make sure mpp_start_group_update/mpp_complete_group_update is OK
a1 = 0.0
a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
call mpp_start_group_update(group_update1, domain, a1(isc,jsc,1,1))
call mpp_complete_group_update(group_update1, domain, a1(isc,jsc,1,1))
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//'nonblock halo='//halostr//' scalar'//text)
enddo
a2 = 0
a2(isc-1:iec+1,jsc-1:jec+1,:,:) = global(isc-1:iec+1,jsc-1:jec+1,:,:)
do n = 1, num_iter
a1 = 0.0
a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
call mpp_clock_begin(id2)
call mpp_do_group_update(group_update2, domain, a1(isc,jsc,1,1))
call mpp_clock_end(id2)
if(n==num_iter) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//' halo=1 scalar'//text)
enddo
endif
enddo
a1 = 0.0
a1(isc:iec,jsc:jec,:,:) = base(isc:iec,jsc:jec,:,:)
call mpp_start_group_update(group_update2, domain, a1(isc,jsc,1,1))
call mpp_complete_group_update(group_update2, domain, a1(isc,jsc,1,1))
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(a1(:,:,:,l),a2(:,:,:,l),type//' nonblock halo=1 scalar'//text)
enddo
call mpp_clear_group_update(group_update1)
call mpp_clear_group_update(group_update2)
deallocate(a1,a2,global,global_all,base)
!--- CGRID vector update -------------------------
id1 = mpp_clock_id( type//' halo='//halostr//' CGRID', flags=MPP_CLOCK_SYNC )
id2 = mpp_clock_id( type//' halo=1 CGRID', flags=MPP_CLOCK_SYNC )
allocate( x1(isd:ied+shift,jsd:jed, nz, num_fields) )
allocate( y1(isd:ied, jsd:jed+shift, nz, num_fields) )
allocate( x2(isd:ied+shift,jsd:jed, nz, num_fields) )
allocate( y2(isd:ied, jsd:jed+shift, nz, num_fields) )
allocate(base1(isc:iec+shift, jsc:jec, nz, num_fields))
allocate(base2(isc:iec, jsc:jec+shift, nz, num_fields))
allocate(global1_all(1:nx+shift,1:ny,nz,ntiles) )
allocate(global2_all(1:nx,1:ny+shift,nz,ntiles) )
allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz, num_fields))
allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz, num_fields))
do l = 1, ntiles
do k = 1, nz
do j = 1, ny
do i = 1, nx+shift
global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
do j = 1, ny+shift
do i = 1, nx
global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
global1 = 0.0; global2 = 0.0
do l = 1, num_fields
global1(1:nx+shift,1:ny,:,l) = global1_all(1:nx+shift,1:ny,:,mytile)
global2(1:nx,1:ny+shift,:,l) = global2_all(1:nx,1:ny+shift,:,mytile)
end do
if(folded_north) then
do l = 1, num_fields
call fill_folded_north_halo(global1(:,:,:,l), 1, 0, shift, 0, -1)
call fill_folded_north_halo(global2(:,:,:,l), 0, 1, 0, shift, -1)
enddo
endif
base1(isc:iec+shift,jsc:jec,:,:) = global1(isc:iec+shift,jsc:jec,:,:)
base2(isc:iec,jsc:jec+shift,:,:) = global2(isc:iec,jsc:jec+shift,:,:)
if(folded_north) then
!redundant points must be equal and opposite for tripolar grid
global2(nx/2+1:nx, ny+shift,:,:) = -global2(nx/2:1:-1, ny+shift,:,:)
global2(1-whalo:0, ny+shift,:,:) = -global2(nx-whalo+1:nx, ny+shift,:,:)
global2(nx+1:nx+ehalo, ny+shift,:,:) = -global2(1:ehalo, ny+shift,:,:)
else if(cubic_grid) then
do l = 1, num_fields
call fill_cubic_grid_halo(global1(:,:,:,l), global1_all, global2_all, mytile, 1, 0, 1, -1 )
call fill_cubic_grid_halo(global2(:,:,:,l), global2_all, global1_all, mytile, 0, 1, -1, 1 )
enddo
endif
x1 = 0; y1 = 0
do l =1, num_fields
call mpp_create_group_update(group_update1, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=CGRID_NE)
end do
do l =1, num_fields
call mpp_create_group_update(group_update2, x1(:,:,:,l), y1(:,:,:,l), domain, gridtype=CGRID_NE, &
whalo=1, ehalo=1, shalo=1, nhalo=1 )
end do
x2(:,:,:,:) = global1(isd:ied+shift,jsd:jed,:,:)
y2(:,:,:,:) = global2(isd:ied,jsd:jed+shift,:,:)
do n = 1, num_iter
x1 = 0.0; y1 = 0.0
x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
call mpp_clock_begin(id1)
call mpp_do_group_update(group_update1, domain, x1(isc,jsc,1,1))
call mpp_clock_end(id1)
if(n==num_iter) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' halo='//halostr//' CGRID X'//text)
call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' halo='//halostr//' CGRID Y'//text)
enddo
endif
enddo
!--- make sure non-blocking call is OK
x1 = 0.0; y1 = 0.0
x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
call mpp_start_group_update(group_update1, domain, x1(isc,jsc,1,1))
call mpp_complete_group_update(group_update1, domain, x1(isc,jsc,1,1))
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' nonblock halo='//halostr//' CGRID X'//text)
call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' nonblock halo='//halostr//' CGRID Y'//text)
enddo
x2 = 0; y2 = 0
x2(isc-1:iec+1+shift,jsc-1:jec+1,:,:) = global1(isc-1:iec+1+shift,jsc-1:jec+1,:,:)
y2(isc-1:iec+1,jsc-1:jec+1+shift,:,:) = global2(isc-1:iec+1,jsc-1:jec+1+shift,:,:)
do n = 1, num_iter
x1 = 0.0; y1 = 0.0
x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
call mpp_clock_begin(id2)
call mpp_do_group_update(group_update2, domain, x1(isc,jsc,1,1))
call mpp_clock_end(id2)
if(n==num_iter) then
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' halo=1 CGRID X'//text)
call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' halo=1 CGRID Y'//text)
enddo
endif
enddo
x1 = 0.0; y1 = 0.0
x1(isc:iec+shift,jsc:jec, :,:) = base1(isc:iec+shift,jsc:jec, :,:)
y1(isc:iec, jsc:jec+shift,:,:) = base2(isc:iec, jsc:jec+shift,:,:)
call mpp_start_group_update(group_update2, domain, x1(isc,jsc,1,1))
call mpp_complete_group_update(group_update2, domain, x1(isc,jsc,1,1))
do l = 1, num_fields
write(text, '(i3.3)') l
call compare_checksums(x1(:,:,:,l),x2(:,:,:,l),type//' nonblock halo=1 CGRID X'//text)
call compare_checksums(y1(:,:,:,l),y2(:,:,:,l),type//' nonblock halo=1 CGRID Y'//text)
enddo
call mpp_clear_group_update(group_update1)
call mpp_clear_group_update(group_update2)
deallocate(x1, y1, global1, global2)
deallocate(x2, y2, global1_all, global2_all)
deallocate(base1, base2)
call mpp_deallocate_domain(domain)
end subroutine test_halosize_update
!###############################################################
subroutine test_unstruct_update( type )
character(len=*), intent(in) :: type
type(domain2D) :: SG_domain
type(domainUG) :: UG_domain
integer :: num_contact, ntiles, npes_per_tile
integer :: i, j, k, l, n, shift
integer :: isc, iec, jsc, jec, isd, ied, jsd, jed
integer :: ism, iem, jsm, jem, lsg, leg
integer, allocatable, dimension(:) :: pe_start, pe_end, npts_tile, grid_index, ntiles_grid
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:) :: x1, x2, g1, g2
real, allocatable, dimension(:,:,:) :: a1, a2, gdata
real, allocatable, dimension(:,:) :: rmask
real, allocatable, dimension(:) :: frac_crit
logical, allocatable, dimension(:,:,:) :: lmask
integer, allocatable, dimension(:) :: isl, iel, jsl, jel
logical :: cubic_grid
character(len=3) :: text
integer :: nx_save, ny_save, tile
integer :: ntotal_land, istart, iend, pos
cubic_grid = .false.
nx_save = nx
ny_save = ny
!--- check the type
select case(type)
case ( 'Cubic-Grid' )
if( nx_cubic == 0 ) then
call mpp_error(NOTE,'test_unstruct_update: for Cubic_grid mosaic, nx_cubic is zero, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
if( nx_cubic .NE. ny_cubic ) then
call mpp_error(NOTE,'test_unstruct_update: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
nx = nx_cubic
ny = ny_cubic
ntiles = 6
num_contact = 12
cubic_grid = .true.
if( mod(npes, ntiles) == 0 ) then
npes_per_tile = npes/ntiles
write(outunit,*)'NOTE from test_unstruct_update ==> For Mosaic "', trim(type), &
'", each tile will be distributed over ', npes_per_tile, ' processors.'
else
call mpp_error(NOTE,'test_unstruct_update: npes should be multiple of ntiles No test is done for '//trim(type))
return
endif
if(layout_cubic(1)*layout_cubic(2) == npes_per_tile) then
layout = layout_cubic
else
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
endif
allocate(frac_crit(ntiles))
frac_crit(1) = 0.3; frac_crit(2) = 0.1; frac_crit(3) = 0.6
frac_crit(4) = 0.2; frac_crit(5) = 0.4; frac_crit(6) = 0.5
case default
call mpp_error(FATAL, 'test_group_update: no such test: '//type)
end select
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
!--- define domain
if( cubic_grid ) then
call define_cubic_mosaic(type, SG_domain, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
global_indices, layout2D, pe_start, pe_end )
endif
!--- setup data
call mpp_get_compute_domain( SG_domain, isc, iec, jsc, jec )
call mpp_get_data_domain ( SG_domain, isd, ied, jsd, jed )
allocate(lmask(nx,ny,ntiles))
allocate(npts_tile(ntiles))
lmask = .false.
if(mpp_pe() == mpp_root_pe() ) then
allocate(rmask(nx,ny))
!--- construct gmask.
do n = 1, ntiles
call random_number(rmask)
do j = 1, ny
do i = 1, nx
if(rmask(i,j) > frac_crit(n)) then
lmask(i,j,n) = .true.
endif
enddo
enddo
npts_tile(n) = count(lmask(:,:,n))
enddo
ntotal_land = sum(npts_tile)
allocate(grid_index(ntotal_land))
l = 0
allocate(isl(0:mpp_npes()-1), iel(0:mpp_npes()-1))
allocate(jsl(0:mpp_npes()-1), jel(0:mpp_npes()-1))
call mpp_get_compute_domains(SG_domain,xbegin=isl,xend=iel,ybegin=jsl,yend=jel)
do n = 1, ntiles
do j = 1, ny
do i = 1, nx
if(lmask(i,j,n)) then
l = l + 1
grid_index(l) = (j-1)*nx+i
endif
enddo
enddo
enddo
deallocate(rmask, isl, iel, jsl, jel)
endif
call mpp_broadcast(npts_tile, ntiles, mpp_root_pe())
if(mpp_pe() .NE. mpp_root_pe()) then
ntotal_land = sum(npts_tile)
allocate(grid_index(ntotal_land))
endif
call mpp_broadcast(grid_index, ntotal_land, mpp_root_pe())
allocate(ntiles_grid(ntotal_land))
ntiles_grid = 1
!--- define the unstructured grid domain
call mpp_define_unstruct_domain(UG_domain, SG_domain, npts_tile, ntiles_grid, mpp_npes(), 1, grid_index, name="LAND unstruct")
call mpp_get_UG_compute_domain(UG_domain, istart, iend)
!--- figure out lmask according to grid_index
pos = 0
do n = 1, ntiles
do l = 1, npts_tile(n)
pos = pos + 1
j = (grid_index(pos)-1)/nx + 1
i = mod((grid_index(pos)-1),nx) + 1
lmask(i,j,n) = .true.
enddo
enddo
!--- set up data
allocate(gdata(nx,ny,ntiles))
gdata = -999
do n = 1, ntiles
do j = 1, ny
do i = 1, nx
if(lmask(i,j,n)) then
gdata(i,j,n) = n*1.e+3 + i + j*1.e-3
endif
end do
end do
end do
!--- test the 2-D data is on computing domain
allocate( a1(isc:iec, jsc:jec,1), a2(isc:iec,jsc:jec,1 ) )
tile = mpp_pe()/npes_per_tile + 1
do j = jsc, jec
do i = isc, iec
a1(i,j,1) = gdata(i,j,tile)
enddo
enddo
a2 = -999
write(mpp_pe()+1000,*) "npts_tile = "
write(mpp_pe()+1000,*) npts_tile
write(mpp_pe()+1000,*) "a1 = ", isc, iec, jsc, jec
do j = jsc, jec
write(mpp_pe()+1000,*) a1(:,j,1)
enddo
allocate(x1(istart:iend,1), x2(istart:iend,1))
x1 = -999
x2 = -999
!--- fill the value of x2
tile = mpp_get_UG_domain_tile_id(UG_domain)
pos = 0
do n = 1, tile-1
pos = pos + npts_tile(n)
enddo
do l = istart, iend
i = mod((grid_index(pos+l)-1), nx) + 1
j = (grid_index(pos+l)-1)/nx + 1
x2(l,1) = gdata(i,j,tile)
enddo
call mpp_pass_SG_to_UG(UG_domain, a1(:,:,1), x1(:,1))
call compare_checksums_2D(x1, x2, type//' SG2UG 2-D compute domain')
call mpp_pass_UG_to_SG(UG_domain, x1(:,1), a2(:,:,1))
call compare_checksums(a1(:,:,1:1),a2(:,:,1:1),type//' UG2SG 2-D compute domain')
deallocate(a1,a2,x1,x2)
!--- test the 3-D data is on computing domain
allocate( a1(isc:iec, jsc:jec,nz), a2(isc:iec,jsc:jec,nz ) )
tile = mpp_pe()/npes_per_tile + 1
do k = 1, nz
do j = jsc, jec
do i = isc, iec
a1(i,j,k) = gdata(i,j,tile)
if(a1(i,j,k) .NE. -999) a1(i,j,k) = a1(i,j,k) + k*1.e-6
enddo
enddo
enddo
a2 = -999
allocate(x1(istart:iend,nz), x2(istart:iend,nz))
x1 = -999
x2 = -999
!--- fill the value of x2
tile = mpp_get_UG_domain_tile_id(UG_domain)
pos = 0
do n = 1, tile-1
pos = pos + npts_tile(n)
enddo
do l = istart, iend
i = mod((grid_index(pos+l)-1), nx) + 1
j = (grid_index(pos+l)-1)/nx + 1
do k = 1, nz
x2(l,k) = gdata(i,j,tile) + k*1.e-6
enddo
enddo
call mpp_pass_SG_to_UG(UG_domain, a1, x1)
call compare_checksums_2D(x1, x2, type//' SG2UG 3-D compute domain')
write(mpp_pe()+1000,*) "x1 = ", istart, iend
call mpp_pass_UG_to_SG(UG_domain, x1, a2)
call compare_checksums(a1,a2,type//' UG2SG 3-D compute domain')
deallocate(a1,a2,x1,x2)
!--- test the 2-D data is on data domain
allocate( a1(isd:ied, jsd:jed,1), a2(isd:ied,jsd:jed,1 ) )
a1 = -999; a2 = -999
tile = mpp_pe()/npes_per_tile + 1
do j = jsc, jec
do i = isc, iec
a1(i,j,1) = gdata(i,j,tile)
enddo
enddo
a2 = -999
write(mpp_pe()+1000,*) "npts_tile = "
write(mpp_pe()+1000,*) npts_tile
allocate(x1(istart:iend,1), x2(istart:iend,1))
x1 = -999
x2 = -999
!--- fill the value of x2
tile = mpp_get_UG_domain_tile_id(UG_domain)
pos = 0
do n = 1, tile-1
pos = pos + npts_tile(n)
enddo
do l = istart, iend
i = mod((grid_index(pos+l)-1), nx) + 1
j = (grid_index(pos+l)-1)/nx + 1
x2(l,1) = gdata(i,j,tile)
enddo
call mpp_pass_SG_to_UG(UG_domain, a1(:,:,1), x1(:,1))
call compare_checksums_2D(x1, x2, type//' SG2UG 2-D data domain')
write(mpp_pe()+1000,*) "x1 = ", istart, iend
write(mpp_pe()+1000,*) x1
call mpp_pass_UG_to_SG(UG_domain, x1(:,1), a2(:,:,1))
call compare_checksums(a1(:,:,1:1),a2(:,:,1:1),type//' UG2SG 2-D data domain')
deallocate(a1,a2,x1,x2)
!--- test the 3-D data is on computing domain
allocate( a1(isd:ied, jsd:jed,nz), a2(isd:ied,jsd:jed,nz ) )
a1 = -999; a2 = -999
tile = mpp_pe()/npes_per_tile + 1
do k = 1, nz
do j = jsc, jec
do i = isc, iec
a1(i,j,k) = gdata(i,j,tile)
if(a1(i,j,k) .NE. -999) a1(i,j,k) = a1(i,j,k) + k*1.e-6
enddo
enddo
enddo
a2 = -999
write(mpp_pe()+1000,*) "npts_tile = "
write(mpp_pe()+1000,*) npts_tile
do j = jsc, jec
write(mpp_pe()+1000,*) a1(:,j,1)
enddo
allocate(x1(istart:iend,nz), x2(istart:iend,nz))
x1 = -999
x2 = -999
!--- fill the value of x2
tile = mpp_get_UG_domain_tile_id(UG_domain)
pos = 0
do n = 1, tile-1
pos = pos + npts_tile(n)
enddo
do l = istart, iend
i = mod((grid_index(pos+l)-1), nx) + 1
j = (grid_index(pos+l)-1)/nx + 1
do k = 1, nz
x2(l,k) = gdata(i,j,tile) + k*1.e-6
enddo
enddo
call mpp_pass_SG_to_UG(UG_domain, a1, x1)
call compare_checksums_2D(x1, x2, type//' SG2UG 3-D data domain')
write(mpp_pe()+1000,*) "x1 = ", istart, iend
call mpp_pass_UG_to_SG(UG_domain, x1, a2)
call compare_checksums(a1,a2,type//' UG2SG 3-D data domain')
deallocate(a1,a2,x1,x2)
!----------------------------------------------------------------
! test mpp_global_field_ug
!----------------------------------------------------------------
call mpp_get_UG_global_domain(UG_domain, lsg, leg)
tile = mpp_get_UG_domain_tile_id(UG_domain)
allocate(g1(lsg:leg,nz), g2(lsg:leg,nz), x1(istart:iend,nz))
g1 = 0
g2 = 0
x1 = 0
do k = 1, nz
do l = lsg, leg
g1(l,k) = tile*1e6 + l + k*1.e-3
enddo
do l = istart, iend
x1(l,k) = g1(l,k)
enddo
enddo
call mpp_global_field_ug(UG_domain, x1, g2)
call compare_checksums_2D(g1,g2,type//' global_field_ug 3-D')
g2 = 0.0
call mpp_global_field_ug(UG_domain, x1(:,1), g2(:,1))
call compare_checksums_2D(g1(:,1:1),g2(:,1:1),type//' global_field_ug 2-D')
deallocate(g1,g2,x1)
end subroutine test_unstruct_update
!#################################################################################
subroutine fill_halo_zero(data, whalo, ehalo, shalo, nhalo, xshift, yshift, isc, iec, jsc, jec, isd, ied, jsd, jed)
integer, intent(in) :: isc, iec, jsc, jec, isd, ied, jsd, jed
integer, intent(in) :: whalo, ehalo, shalo, nhalo, xshift, yshift
real, dimension(isd:,jsd:,:), intent(inout) :: data
if(whalo >=0) then
data(iec+ehalo+1+xshift:ied+xshift,jsd:jed+yshift,:) = 0
data(isd:isc-whalo-1,jsd:jed+yshift,:) = 0
else
data(iec+1+xshift:iec-ehalo+xshift,jsc+shalo:jec-nhalo+yshift,:) = 0
data(isc+whalo:isc-1,jsc+shalo:jec-nhalo+yshift,:) = 0
end if
if(shalo>=0) then
data(isd:ied+xshift, jec+nhalo+1+yshift:jed+yshift,:) = 0
data(isd:ied+xshift, jsd:jsc-shalo-1,:) = 0
else
data(isc+whalo:iec-ehalo+xshift,jec+1+yshift:jec-nhalo+yshift,:) = 0
data(isc+whalo:iec-ehalo+xshift,jsc+shalo:jsc-1,:) = 0
end if
end subroutine fill_halo_zero
!##############################################################################
! this routine fill the halo points for the regular mosaic.
subroutine fill_regular_mosaic_halo(data, data_all, te, tse, ts, tsw, tw, tnw, tn, tne)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
real, dimension(:,:,:,:), intent(in) :: data_all
integer, intent(in) :: te, tse, ts, tsw, tw, tnw, tn, tne
data(nx+1:nx+ehalo, 1:ny, :) = data_all(1:ehalo, 1:ny, :, te) ! east
data(1:nx, 1-shalo:0, :) = data_all(1:nx, ny-shalo+1:ny, :, ts) ! south
data(1-whalo:0, 1:ny, :) = data_all(nx-whalo+1:nx, 1:ny, :, tw) ! west
data(1:nx, ny+1:ny+nhalo, :) = data_all(1:nx, 1:nhalo, :, tn) ! north
data(nx+1:nx+ehalo, 1-shalo:0, :) = data_all(1:ehalo, ny-shalo+1:ny, :,tse) ! southeast
data(1-whalo:0, 1-shalo:0, :) = data_all(nx-whalo+1:nx, ny-shalo+1:ny, :,tsw) ! southwest
data(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = data_all(1:ehalo, 1:nhalo, :,tnw) ! northeast
data(1-whalo:0, ny+1:ny+nhalo, :) = data_all(nx-whalo+1:nx, 1:nhalo, :,tne) ! northwest
end subroutine fill_regular_mosaic_halo
!################################################################################
subroutine fill_folded_north_halo(data, ioff, joff, ishift, jshift, sign)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
integer, intent(in ) :: ioff, joff, ishift, jshift, sign
integer :: nxp, nyp, m1, m2
nxp = nx+ishift
nyp = ny+jshift
m1 = ishift - ioff
m2 = 2*ishift - ioff
data(1-whalo:0, 1:nyp,:) = data(nx-whalo+1:nx, 1:ny+jshift,:) ! west
data(nx+1:nx+ehalo+ishift, 1:nyp,:) = data(1:ehalo+ishift, 1:ny+jshift,:) ! east
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,:)
data(m1+1:nx+m2, nyp+1:nyp+nhalo,:) = sign*data(nx+ishift:1:-1, nyp-joff:nyp-nhalo-joff+1:-1,:)
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,:)
end subroutine fill_folded_north_halo
!################################################################################
subroutine fill_folded_south_halo(data, ioff, joff, ishift, jshift, sign)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
integer, intent(in ) :: ioff, joff, ishift, jshift, sign
integer :: nxp, nyp, m1, m2
nxp = nx+ishift
nyp = ny+jshift
m1 = ishift - ioff
m2 = 2*ishift - ioff
data(1-whalo:0, 1:nyp,:) = data(nx-whalo+1:nx, 1:nyp,:) ! west
data(nx+1:nx+ehalo+ishift, 1:nyp,:) = data(1:ehalo+ishift, 1:nyp,:) ! east
if(m1 .GE. 1-whalo)data(1-whalo:m1, 1-shalo:0,:) = sign*data(whalo+m2:1+ishift:-1, shalo+jshift:1+jshift:-1,:)
data(m1+1:nx+m2, 1-shalo:0,:) = sign*data(nxp:1:-1, shalo+jshift:1+jshift:-1,:)
data(nx+m2+1:nxp+ehalo,1-shalo:0,:) = sign*data(nx:nx-ehalo+m1+1:-1, shalo+jshift:1+jshift:-1,:)
end subroutine fill_folded_south_halo
!################################################################################
subroutine fill_folded_west_halo(data, ioff, joff, ishift, jshift, sign)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
integer, intent(in ) :: ioff, joff, ishift, jshift, sign
integer :: nxp, nyp, m1, m2
nxp = nx+ishift
nyp = ny+jshift
m1 = jshift - joff
m2 = 2*jshift - joff
data(1:nxp, 1-shalo:0, :) = data(1:nxp, ny-shalo+1:ny, :) ! south
data(1:nxp, ny+1:nyp+nhalo, :) = data(1:nxp, 1:nhalo+jshift,:) ! north
if(m1 .GE. 1-shalo) data(1-whalo:0, 1-shalo:m1, :) = sign*data(whalo+ishift:1+ishift:-1, shalo+m2:1+jshift:-1,:)
data(1-whalo:0, m1+1:ny+m2, :) = sign*data(whalo+ishift:1+ishift:-1, nyp:1:-1, :)
data(1-whalo:0, ny+m2+1:nyp+nhalo,:) = sign*data(whalo+ishift:1+ishift:-1, ny:ny-nhalo+m1+1:-1,:)
end subroutine fill_folded_west_halo
!################################################################################
subroutine fill_folded_east_halo(data, ioff, joff, ishift, jshift, sign)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
integer, intent(in ) :: ioff, joff, ishift, jshift, sign
integer :: nxp, nyp, m1, m2
nxp = nx+ishift
nyp = ny+jshift
m1 = jshift - joff
m2 = 2*jshift - joff
data(1:nxp, 1-shalo:0, :) = data(1:nxp, ny-shalo+1:ny, :) ! south
data(1:nxp, ny+1:nyp+nhalo, :) = data(1:nxp, 1:nhalo+jshift,:) ! north
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,:)
data(nxp+1:nxp+ehalo, m1+1:ny+m2, :) = sign*data(nxp-ioff:nxp-ehalo-ioff+1:-1, nyp:1:-1, :)
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,:)
end subroutine fill_folded_east_halo
!################################################################################
subroutine fill_four_tile_bound(data_all, is, ie, js, je, ioff, joff, tile, &
ebound, sbound, wbound, nbound )
real, dimension(:,:,:,:), intent(in) :: data_all
integer, intent(in) :: is, ie, js, je
integer, intent(in) :: tile, ioff, joff
real, dimension(:,:), optional, intent(inout) :: ebound, sbound, wbound, nbound
integer :: tw, te, ts, tn
if(tile == 1 .OR. tile == 3) te = tile + 1
if(tile == 2 .OR. tile == 4) te = tile - 1
if(tile == 1 .OR. tile == 2) ts = tile + 2
if(tile == 3 .OR. tile == 4) ts = tile - 2
tw = te; tn = ts
if(present(ebound)) then
if( ie == nx ) then
ebound(:,:) = data_all(1, js:je+joff, :, te)
else
ebound(:,:) = data_all(ie+ioff, js:je+joff, :, tile)
end if
end if
if(present(wbound)) then
if( is == 1 ) then
wbound(:,:) = data_all(nx+ioff, js:je+joff, :, tw)
else
wbound(:,:) = data_all(is, js:je+joff, :, tile)
end if
end if
if(present(sbound)) then
if( js == 1 ) then
sbound(:,:) = data_all(is:ie+ioff, ny+joff, :, ts)
else
sbound(:,:) = data_all(is:ie+ioff, js, :, tile)
end if
end if
if(present(nbound)) then
if( je == ny ) then
nbound(:,:) = data_all(is:ie+ioff, 1, :, tn)
else
nbound(:,:) = data_all(is:ie+ioff, je+joff, :, tile)
end if
end if
return
end subroutine fill_four_tile_bound
!################################################################################
subroutine fill_torus_bound(data_all, is, ie, js, je, ioff, joff, tile, &
sbound, wbound)
real, dimension(:,:,:), intent(in) :: data_all
integer, intent(in) :: is, ie, js, je
integer, intent(in) :: tile, ioff, joff
real, dimension(:,:), optional, intent(inout) :: sbound, wbound
integer :: tw, te, ts, tn
integer :: js1, js2, is1, is2
if(tile .NE. 1) call mpp_error(FATAL, "fill_torus_bound: tile must be 1")
js2 = js
js1 = 1
if( js == 1 .AND. joff==1 ) then
js1 = 2
js2 = js+1
endif
is2 = is
is1 = 1
if( is == 1 .AND. ioff==1 ) then
is1 = 2
is2 = is+1
endif
if(present(wbound)) then
if(ioff .NE. 1) call mpp_error(FATAL, "fill_torus_bound: ioff must be 1 when wbound present")
if( is == 1 ) then
wbound(js1:,:) = data_all(nx+ioff, js2:je+joff, :)
else
wbound(js1:,:) = data_all(is, js2:je+joff, :)
end if
if(js1 == 2) then
if( is == 1 ) then
wbound(1,:) = data_all(nx+1, ny+1, :)
else
wbound(1,:) = data_all(is, ny+1, :)
endif
endif
end if
if(present(sbound)) then
if(joff .NE. 1) call mpp_error(FATAL, "fill_torus_bound: joff must be 1 when sbound present")
if( js == 1 ) then
sbound(is1:,:) = data_all(is2:ie+ioff, ny+joff, :)
else
sbound(is1:,:) = data_all(is2:ie+ioff, js, :)
end if
if(is1 == 2) then
if( js == 1 ) then
sbound(1,:) = data_all(nx+1, ny+1, :)
else
sbound(1,:) = data_all(nx+1, js, :)
endif
endif
end if
return
end subroutine fill_torus_bound
!################################################################################
subroutine fill_folded_north_bound(data_all, is, ie, js, je, ioff, joff, tile, &
sbound, wbound)
real, dimension(:,:,:), intent(in) :: data_all
integer, intent(in) :: is, ie, js, je
integer, intent(in) :: tile, ioff, joff
real, dimension(:,:), optional, intent(inout) :: sbound, wbound
integer :: tw, te, ts, tn
integer :: js1, js2
if(tile .NE. 1) call mpp_error(FATAL, "fill_folded_north_bound: tile must be 1")
js2 = js
js1 = 1
if( js == 1 .AND. joff==1 ) then
js1 = 2
js2 = js+1
endif
if(present(wbound)) then
if( is == 1 ) then
wbound(js1:,:) = data_all(nx+ioff, js2:je+joff, :)
else
wbound(js1:,:) = data_all(is, js2:je+joff, :)
end if
end if
if(present(sbound)) then
if( js == 1 ) then
sbound(:,:) = 0
else
if( is == 1 .AND. ioff == 1 ) then
sbound(1,:) = data_all(nx+1, js, :)
sbound(2:,:) = data_all(is+1:ie+ioff, js, :)
else
sbound(:,:) = data_all(is:ie+ioff, js, :)
endif
end if
end if
return
end subroutine fill_folded_north_bound
!################################################################################
subroutine fill_cubic_grid_bound(data1_all, data2_all, is, ie, js, je, ioff, joff, tile, sign1, sign2, &
ebound, sbound, wbound, nbound )
real, dimension(:,:,:,:), intent(in) :: data1_all, data2_all
integer, intent(in) :: is, ie, js, je
integer, intent(in) :: tile, ioff, joff, sign1, sign2
real, dimension(:,:), optional, intent(inout) :: ebound, sbound, wbound, nbound
integer :: tw, te, ts, tn
if(mod(tile,2) == 0) then ! tile 2, 4, 6
tw = tile - 1; te = tile + 2; ts = tile - 2; tn = tile + 1
if(te > 6 ) te = te - 6
if(ts < 1 ) ts = ts + 6
if(tn > 6 ) tn = tn - 6
!--- East bound
if(present(ebound)) then
if(ie == nx) then
ebound(:,:) = sign1*data2_all(nx+joff-js+1:nx-je+1:-1,1,:,te)
else
ebound(:,:) = data1_all(ie+ioff, js:je+joff, :,tile)
end if
end if
!--- South bound
if(present(sbound)) then
if(js == 1) then
sbound(:,:) = sign2*data2_all(nx+joff, ny+ioff-is+1:ny-ie+1:-1,:,ts)
else
sbound(:,:) = data1_all(is:ie+ioff, js, :,tile)
end if
end if
!--- West bound
if(present(wbound)) then
if(is == 1) then
wbound(:,:) = data1_all(nx+ioff, js:je+joff,:,tw)
else
wbound(:,:) = data1_all(is, js:je+joff,:,tile)
end if
end if
!--- north bound
if(present(nbound)) then
if(je == ny) then
nbound(:,:) = data1_all(is:ie+ioff, 1,:,tn)
else
nbound(:,:) = data1_all(is:ie+ioff, je+joff, :,tile)
end if
end if
else ! tile 1, 3, 5
tw = tile - 2; te = tile + 1; ts = tile - 1; tn = tile + 2
if(tw < 1 ) tw = tw + 6
if(ts < 1 ) ts = ts + 6
if(tn > 6 ) tn = tn - 6
!--- East bound
if(present(ebound)) then
if(ie == nx) then
ebound(:,:) = data1_all(1, js:je+joff, :,te)
else
ebound(:,:) = data1_all(ie+ioff, js:je+joff, :,tile)
end if
end if
!--- South bound
if(present(sbound)) then
if(js == 1) then
sbound(:,:) = data1_all(is:ie+ioff,ny+joff,:,ts)
else
sbound(:,:) = data1_all(is:ie+ioff, js, :,tile)
end if
end if
!--- West bound
if(present(wbound)) then
if(is == 1) then
wbound(:,:) = sign1*data2_all(nx+joff-js+1:nx-je+1:-1,ny+ioff,:,tw)
else
wbound(:,:) = data1_all(is, js:je+joff,:,tile)
end if
end if
!--- north bound
if(present(nbound)) then
if(je == ny) then
nbound(:,:) = sign2*data2_all(1, ny+ioff-is+1:ny-ie+1:-1,:,tn)
else
nbound(:,:) = data1_all(is:ie+ioff, je+joff, :,tile)
end if
end if
end if
end subroutine fill_cubic_grid_bound
!##############################################################################
! this routine fill the halo points for the cubic grid. ioff and joff is used to distinguish
! T, C, E, or N-cell
subroutine fill_cubic_grid_halo(data, data1_all, data2_all, tile, ioff, joff, sign1, sign2)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
real, dimension(:,:,:,:), intent(in) :: data1_all, data2_all
integer, intent(in) :: tile, ioff, joff, sign1, sign2
integer :: lw, le, ls, ln
if(mod(tile,2) == 0) then ! tile 2, 4, 6
lw = tile - 1; le = tile + 2; ls = tile - 2; ln = tile + 1
if(le > 6 ) le = le - 6
if(ls < 1 ) ls = ls + 6
if(ln > 6 ) ln = ln - 6
data(1-whalo:0, 1:ny+joff, :) = data1_all(nx-whalo+1:nx, 1:ny+joff, :, lw) ! west
do i = 1, ehalo
data(nx+i+ioff, 1:ny+joff, :) = sign1*data2_all(nx+joff:1:-1, i+ioff, :, le) ! east
end do
do i = 1, shalo
data(1:nx+ioff, 1-i, :) = sign2*data2_all(nx-i+1, ny+ioff:1:-1, :, ls) ! south
end do
data(1:nx+ioff, ny+1+joff:ny+nhalo+joff, :) = data1_all(1:nx+ioff, 1+joff:nhalo+joff, :, ln) ! north
else ! tile 1, 3, 5
lw = tile - 2; le = tile + 1; ls = tile - 1; ln = tile + 2
if(lw < 1 ) lw = lw + 6
if(ls < 1 ) ls = ls + 6
if(ln > 6 ) ln = ln - 6
do i = 1, whalo
data(1-i, 1:ny+joff, :) = sign1*data2_all(nx+joff:1:-1, ny-i+1, :, lw) ! west
end do
data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff, :) = data1_all(1+ioff:ehalo+ioff, 1:ny+joff, :, le) ! east
data(1:nx+ioff, 1-shalo:0, :) = data1_all(1:nx+ioff, ny-shalo+1:ny, :, ls) ! south
do i = 1, nhalo
data(1:nx+ioff, ny+i+joff, :) = sign2*data2_all(i+joff, ny+ioff:1:-1, :, ln) ! north
end do
end if
end subroutine fill_cubic_grid_halo
!#####################################################################
subroutine test_nonuniform_mosaic( type )
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: num_contact, ntiles, ntile_per_pe
integer :: i, j, k, n, nxm, nym, ni, nj, shift
integer :: ism, iem, jsm, jem, isc, iec, jsc, jec
integer :: isd, ied, jsd, jed
integer :: indices(4), msize(2)
character(len=128) :: type2
integer, allocatable, dimension(:) :: tile
integer, allocatable, dimension(:) :: pe_start, pe_end, tile1, tile2
integer, allocatable, dimension(:) :: istart1, iend1, jstart1, jend1
integer, allocatable, dimension(:) :: istart2, iend2, jstart2, jend2
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:,:,:) :: global1_all, global2_all
real, allocatable, dimension(:,:,:,:) :: global1, global2, x, y
shift = 0
select case(type)
case('Five-Tile') ! one tile will run on pe 0 and other four tiles will run on pe 1
shift = 1 ! one extra point for symmetry domain
ntiles = 5 ! tile 1 with resolution 2*nx and 2*ny and the tiles are nx and ny.
num_contact = 11
if(npes .NE. 2) then
call mpp_error(NOTE,'TEST_MPP_DOMAINS: Five-Tile mosaic will not be tested because npes is not 2')
return
end if
nxm = 2*nx; nym = 2*ny
layout = 1
if( pe == 0) then
ntile_per_pe = 1
allocate(tile(ntile_per_pe))
tile = 1
indices = (/1,2*nx,1,2*ny/)
ni = 2*nx; nj = 2*ny
else
ntile_per_pe = 4
allocate(tile(ntile_per_pe))
do n = 1, ntile_per_pe
tile(n) = n + 1
end do
indices = (/1,nx,1,ny/)
ni = nx; nj = ny
end if
allocate(pe_start(ntiles), pe_end(ntiles) )
pe_start(1) = 0; pe_start(2:) = 1
pe_end = pe_start
case default
call mpp_error(FATAL, 'TEST_MPP_DOMAINS: no such test: '//type)
end select
allocate(layout2D(2,ntiles), global_indices(4,ntiles) )
do n = 1, ntiles
if(n==1) then
global_indices(:,n) = (/1,2*nx,1,2*ny/)
else
global_indices(:,n) = (/1,nx,1,ny/)
endif
! global_indices(:,n) = indices
layout2D(:,n) = layout
end do
allocate(tile1(num_contact), tile2(num_contact) )
allocate(istart1(num_contact), iend1(num_contact), jstart1(num_contact), jend1(num_contact) )
allocate(istart2(num_contact), iend2(num_contact), jstart2(num_contact), jend2(num_contact) )
!--- define domain
select case(type)
case( 'Five-Tile' )
!--- Contact line 1, between tile 1 (EAST) and tile 2 (WEST)
tile1(1) = 1; tile2(1) = 2
istart1(1) = 2*nx; iend1(1) = 2*nx; jstart1(1) = 1; jend1(1) = ny
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = ny
!--- Contact line 2, between tile 1 (EAST) and tile 4 (WEST)
tile1(2) = 1; tile2(2) = 4
istart1(2) = 2*nx; iend1(2) = 2*nx; jstart1(2) = ny+1; jend1(2) = 2*ny
istart2(2) = 1; iend2(2) = 1; jstart2(2) = 1; jend2(2) = ny
!--- Contact line 3, between tile 1 (SOUTH) and tile 1 (NORTH)
tile1(3) = 1; tile2(3) = 1
istart1(3) = 1; iend1(3) = 2*nx; jstart1(3) = 1; jend1(3) = 1
istart2(3) = 1; iend2(3) = 2*nx; jstart2(3) = 2*ny; jend2(3) = 2*ny
!--- Contact line 4, between tile 1 (WEST) and tile 3 (EAST)
tile1(4) = 1; tile2(4) = 3
istart1(4) = 1; iend1(4) = 1; jstart1(4) = 1; jend1(4) = ny
istart2(4) = nx; iend2(4) = nx; jstart2(4) = 1; jend2(4) = ny
!--- Contact line 5, between tile 1 (WEST) and tile 5 (EAST)
tile1(5) = 1; tile2(5) = 5
istart1(5) = 1; iend1(5) = 1; jstart1(5) = ny+1; jend1(5) = 2*ny
istart2(5) = nx; iend2(5) = nx; jstart2(5) = 1; jend2(5) = ny
!--- Contact line 6, between tile 2 (EAST) and tile 3 (WEST)
tile1(6) = 2; tile2(6) = 3
istart1(6) = nx; iend1(6) = nx; jstart1(6) = 1; jend1(6) = ny
istart2(6) = 1; iend2(6) = 1; jstart2(6) = 1; jend2(6) = ny
!--- Contact line 7, between tile 2 (SOUTH) and tile 4 (NORTH) --- cyclic
tile1(7) = 2; tile2(7) = 4
istart1(7) = 1; iend1(7) = nx; jstart1(7) = 1; jend1(7) = 1
istart2(7) = 1; iend2(7) = nx; jstart2(7) = ny; jend2(7) = ny
!--- Contact line 8, between tile 2 (NORTH) and tile 4 (SOUTH)
tile1(8) = 2; tile2(8) = 4
istart1(8) = 1; iend1(8) = nx; jstart1(8) = ny; jend1(8) = ny
istart2(8) = 1; iend2(8) = nx; jstart2(8) = 1; jend2(8) = 1
!--- Contact line 9, between tile 3 (SOUTH) and tile 5 (NORTH) --- cyclic
tile1(9) = 3; tile2(9) = 5
istart1(9) = 1; iend1(9) = nx; jstart1(9) = 1; jend1(9) = 1
istart2(9) = 1; iend2(9) = nx; jstart2(9) = ny; jend2(9) = ny
!--- Contact line 10, between tile 3 (NORTH) and tile 5 (SOUTH)
tile1(10) = 3; tile2(10) = 5
istart1(10) = 1; iend1(10) = nx; jstart1(10) = ny; jend1(10) = ny
istart2(10) = 1; iend2(10) = nx; jstart2(10) = 1; jend2(10) = 1
!--- Contact line 11, between tile 4 (EAST) and tile 5 (WEST)
tile1(11) = 4; tile2(11) = 5
istart1(11) = nx; iend1(11) = nx; jstart1(11) = 1; jend1(11) = ny
istart2(11) = 1; iend2(11) = 1; jstart2(11) = 1; jend2(11) = ny
msize(1) = 2*nx + whalo + ehalo
msize(2) = 2*ny + shalo + nhalo
call mpp_define_mosaic(global_indices, layout2D, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, memory_size = msize, symmetry = .true. )
end select
!--- setup data
allocate(global1_all(1:nxm,1:nym,nz, ntiles) )
allocate(global1(1-whalo:ni+ehalo,1-shalo:nj+nhalo,nz, ntile_per_pe) )
do n = 1, ntiles
do k = 1, nz
do j = 1, nym
do i = 1, nxm
global1_all(i,j,k,n) = n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
do n = 1, ntile_per_pe
global1(1:ni,1:nj,:,n) = global1_all(1:ni,1:nj,:,tile(n))
end do
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
allocate( x (ism:iem,jsm:jem,nz, ntile_per_pe) )
x = 0.
x(isc:iec,jsc:jec,:,:) = global1(isc:iec,jsc:jec,:,:)
!--- fill up the value at halo points
do n = 1, ntile_per_pe
call fill_five_tile_halo(global1(:,:,:,n), global1_all, tile(n), 0, 0 )
end do
! full update
id = mpp_clock_id( type, flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
do n = 1, ntile_per_pe
call mpp_update_domains( x(:,:,:,n), domain, tile_count = n )
end do
call mpp_clock_end(id)
do n = 1, ntile_per_pe
write(type2, *)type, " at tile_count = ",n
call compare_checksums( x(isd:ied,jsd:jed,:,n), global1(isd:ied,jsd:jed,:,n), trim(type2) )
end do
deallocate(global1_all, global1, x)
!------------------------------------------------------------------
! vector update : BGRID_NE, one extra point in each direction for Five-Tile
!------------------------------------------------------------------
!--- setup data
allocate(global1_all(nxm+shift,nym+shift,nz, ntiles), global2_all(nxm+shift,nym+shift,nz, ntiles) )
allocate(global1(1-whalo:ni+ehalo+shift,1-shalo:nj+nhalo+shift,nz, ntile_per_pe) )
allocate(global2(1-whalo:ni+ehalo+shift,1-shalo:nj+nhalo+shift,nz, ntile_per_pe) )
do n = 1, ntiles
do k = 1, nz
do j = 1, nym+shift
do i = 1, nxm+shift
global1_all(i,j,k,n) = 1.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
global2_all(i,j,k,n) = 2.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
!------------------------------------------------------------------------
! --- make sure consisency on the boundary for Five-Tile mosaic
! --- east boundary will take the value of neighbor tile west,
! --- north boundary will take the value of neighbor tile south.
!------------------------------------------------------------------------
if(type == 'Five-Tile') then
global1_all(nxm+1, 1:ny,:,1) = global1_all(1, 1:ny,:,2) ! east
global1_all(nxm+1,ny+1:nym,:,1) = global1_all(1, 1:ny,:,4) ! east
global1_all(1:nxm+1, nym+1,:,1) = global1_all(1:nxm+1, 1,:,1) ! north
global1_all(nx+1, 1:ny,:,2) = global1_all(1, 1:ny,:,3) ! east
global1_all(1:nx+1, ny+1,:,2) = global1_all(1:nx+1, 1,:,4) ! north
global1_all(nx+1, 1:ny,:,3) = global1_all(1, 1:ny,:,1) ! east
global1_all(1:nx+1, ny+1,:,3) = global1_all(1:nx+1, 1,:,5) ! north
global1_all(nx+1, 1:ny,:,4) = global1_all(1, 1:ny,:,5) ! east
global1_all(1:nx+1, ny+1,:,4) = global1_all(1:nx+1, 1,:,2) ! north
global1_all(nx+1, 1:ny,:,5) = global1_all(1,ny+1:nym,:,1) ! east
global1_all(1:nx+1, ny+1,:,5) = global1_all(1:nx+1, 1,:,3) ! north
global1_all(nx+1, ny+1,:,2) = global1_all(1, 1,:,5) ! northeast
global1_all(nx+1, ny+1,:,3) = global1_all(1, ny+1,:,1) ! northeast
global2_all(nxm+1, 1:ny,:,1) = global2_all(1, 1:ny,:,2) ! east
global2_all(nxm+1,ny+1:nym,:,1) = global2_all(1, 1:ny,:,4) ! east
global2_all(1:nxm+1, nym+1,:,1) = global2_all(1:nxm+1, 1,:,1) ! north
global2_all(nx+1, 1:ny,:,2) = global2_all(1, 1:ny,:,3) ! east
global2_all(1:nx+1, ny+1,:,2) = global2_all(1:nx+1, 1,:,4) ! north
global2_all(nx+1, 1:ny,:,3) = global2_all(1, 1:ny,:,1) ! east
global2_all(1:nx+1, ny+1,:,3) = global2_all(1:nx+1, 1,:,5) ! north
global2_all(nx+1, 1:ny,:,4) = global2_all(1, 1:ny,:,5) ! east
global2_all(1:nx+1, ny+1,:,4) = global2_all(1:nx+1, 1,:,2) ! north
global2_all(nx+1, 1:ny,:,5) = global2_all(1,ny+1:nym,:,1) ! east
global2_all(1:nx+1, ny+1,:,5) = global2_all(1:nx+1, 1,:,3) ! north
global2_all(nx+1, ny+1,:,2) = global2_all(1, 1,:,5) ! northeast
global2_all(nx+1, ny+1,:,3) = global2_all(1, ny+1,:,1) ! northeast
end if
do n = 1, ntile_per_pe
global1(1:ni+shift,1:nj+shift,:,n) = global1_all(1:ni+shift,1:nj+shift,:,tile(n))
global2(1:ni+shift,1:nj+shift,:,n) = global2_all(1:ni+shift,1:nj+shift,:,tile(n))
end do
allocate( x (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
allocate( y (ism:iem+shift,jsm:jem+shift,nz,ntile_per_pe) )
x = 0.; y = 0
x (isc:iec+shift,jsc:jec+shift,:,:) = global1(isc:iec+shift,jsc:jec+shift,:,:)
y (isc:iec+shift,jsc:jec+shift,:,:) = global2(isc:iec+shift,jsc:jec+shift,:,:)
!-----------------------------------------------------------------------
! fill up the value at halo points.
!-----------------------------------------------------------------------
do n = 1, ntile_per_pe
call fill_five_tile_halo(global1(:,:,:,n), global1_all, tile(n), shift, shift)
call fill_five_tile_halo(global2(:,:,:,n), global2_all, tile(n), shift, shift)
end do
id = mpp_clock_id( type//' BGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
do n = 1, ntile_per_pe
call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=BGRID_NE, tile_count = n )
end do
call mpp_clock_end(id)
do n = 1, ntile_per_pe
write(type2, *)type, " at tile_count = ",n
call compare_checksums( x(isd:ied+shift,jsd:jed+shift,:,n), global1(isd:ied+shift,jsd:jed+shift,:,n), &
trim(type2)//' BGRID_NE X')
call compare_checksums( y(isd:ied+shift,jsd:jed+shift,:,n), global2(isd:ied+shift,jsd:jed+shift,:,n), &
trim(type2)//' BGRID_NE Y')
end do
deallocate(global1_all, global2_all, global1, global2, x, y)
!------------------------------------------------------------------
! vector update : CGRID_NE
!------------------------------------------------------------------
!--- setup data
allocate(global1_all(nxm+shift,nym,nz, ntiles), global2_all(nxm,nym+shift,nz, ntiles) )
allocate(global1(1-whalo:ni+ehalo+shift, 1-shalo:nj+nhalo, nz, ntile_per_pe) )
allocate(global2(1-whalo:ni+ehalo, 1-shalo:nj+nhalo+shift, nz, ntile_per_pe) )
do n = 1, ntiles
do k = 1, nz
do j = 1, nym
do i = 1, nxm+shift
global1_all(i,j,k,n) = 1.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
do j = 1, nym+shift
do i = 1, nxm
global2_all(i,j,k,n) = 2.0e3 + n + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
!------------------------------------------------------------------------
! --- make sure consisency on the boundary for Five-Tile mosaic
! --- east boundary will take the value of neighbor tile west,
! --- north boundary will take the value of neighbor tile south.
!------------------------------------------------------------------------
if(type == 'Five-Tile') then
global1_all(nxm+1, 1:ny,:,1) = global1_all(1, 1:ny,:,2) ! east
global1_all(nxm+1,ny+1:nym,:,1) = global1_all(1, 1:ny,:,4) ! east
global1_all(nx+1, 1:ny,:,2) = global1_all(1, 1:ny,:,3) ! east
global1_all(nx+1, 1:ny,:,3) = global1_all(1, 1:ny,:,1) ! east
global1_all(nx+1, 1:ny,:,4) = global1_all(1, 1:ny,:,5) ! east
global1_all(nx+1, 1:ny,:,5) = global1_all(1,ny+1:nym,:,1) ! east
global2_all(1:nxm, nym+1,:,1) = global2_all(1:nxm, 1,:,1) ! north
global2_all(1:nx, ny+1,:,2) = global2_all(1:nx, 1,:,4) ! north
global2_all(1:nx, ny+1,:,3) = global2_all(1:nx, 1,:,5) ! north
global2_all(1:nx, ny+1,:,4) = global2_all(1:nx, 1,:,2) ! north
global2_all(1:nx, ny+1,:,5) = global2_all(1:nx, 1,:,3) ! north
end if
do n = 1, ntile_per_pe
global1(1:ni+shift, 1:nj,:,n) = global1_all(1:ni+shift, 1:nj,:,tile(n))
global2(1:ni, 1:nj+shift,:,n) = global2_all(1:ni, 1:nj+shift,:,tile(n))
end do
allocate( x (ism:iem+shift, jsm:jem,nz,ntile_per_pe) )
allocate( y (ism:iem, jsm:jem+shift,nz,ntile_per_pe) )
x = 0.; y = 0
x (isc:iec+shift, jsc:jec,:,:) = global1(isc:iec+shift, jsc:jec,:,:)
y (isc:iec, jsc:jec+shift,:,:) = global2(isc:iec, jsc:jec+shift,:,:)
!-----------------------------------------------------------------------
! fill up the value at halo points.
!-----------------------------------------------------------------------
do n = 1, ntile_per_pe
call fill_five_tile_halo(global1(:,:,:,n), global1_all, tile(n), shift, 0)
call fill_five_tile_halo(global2(:,:,:,n), global2_all, tile(n), 0, shift)
end do
id = mpp_clock_id( type//' CGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
do n = 1, ntile_per_pe
call mpp_update_domains( x(:,:,:,n), y(:,:,:,n), domain, gridtype=CGRID_NE, tile_count = n )
end do
call mpp_clock_end(id)
do n = 1, ntile_per_pe
write(type2, *)type, " at tile_count = ",n
call compare_checksums( x(isd:ied+shift,jsd:jed,:,n), global1(isd:ied+shift,jsd:jed,:,n), &
trim(type2)//' CGRID_NE X')
call compare_checksums( y(isd:ied,jsd:jed+shift,:,n), global2(isd:ied,jsd:jed+shift,:,n), &
trim(type2)//' CGRID_NE Y')
end do
deallocate(global1_all, global2_all, global1, global2, x, y)
end subroutine test_nonuniform_mosaic
subroutine fill_five_tile_halo(data, data_all, tile, ioff, joff)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
real, dimension(:,:,:,:), intent(in) :: data_all
integer, intent(in) :: tile, ioff, joff
integer :: nxm, nym
nxm = 2*nx; nym = 2*ny
select case(tile)
case(1)
data(nxm+1+ioff:nxm+ehalo+ioff, 1:ny,:) = data_all(1+ioff:ehalo+ioff, 1:ny,:,2) ! east
data(nxm+1+ioff:nxm+ehalo+ioff, ny+1:nym+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,4) ! east
data(1-whalo:0, 1:ny,:) = data_all(nx-whalo+1:nx, 1:ny,:,3) ! west
data(1-whalo:0, ny+1:nym+joff,:) = data_all(nx-whalo+1:nx, 1:ny+joff,:,5) ! west
data(1:nxm+ioff, 1-shalo:0,:) = data_all(1:nxm+ioff, nym-shalo+1:nym,:,1) ! south
data(1:nxm+ioff, nym+1+joff:nym+nhalo+joff,:) = data_all(1:nxm+ioff, 1+joff:nhalo+joff,:,1) ! north
data(nxm+1+ioff:nxm+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,4) ! southeast
data(1-whalo:0, 1-shalo:0,:) = data_all(nx-whalo+1:nx, ny-shalo+1:ny,:,5) ! southwest
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
data(1-whalo:0, nym+1+joff:nym+nhalo+joff,:) = data_all(nx-whalo+1:nx, 1+joff:nhalo+joff,:,3) ! northwest
case(2)
data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,3) ! east
data(1-whalo:0, 1:ny+joff,:) = data_all(nxm-whalo+1:nxm, 1:ny+joff,:,1) ! west
data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,4) ! south
data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,4) ! north
data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,5) ! southeast
data(1-whalo:0, 1-shalo:0,:) = data_all(nxm-whalo+1:nxm, nym-shalo+1:nym,:,1) ! southwest
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
data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nxm-whalo+1:nxm, ny+1+joff:ny+nhalo+joff,:,1) ! northwest
case(3)
data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,1) ! east
data(1-whalo:0, 1:ny+joff,:) = data_all(nx-whalo+1:nx, 1:ny+joff,:,2) ! west
data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,5) ! south
data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,5) ! north
data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, nym-shalo+1:nym,:,1) ! southeast
data(1-whalo:0, 1-shalo:0,:) = data_all(nx-whalo+1:nx, ny-shalo+1:ny,:,4) ! southwest
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
data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nx-whalo+1:nx, 1+joff:nhalo+joff,:,4) ! northwest
case(4)
data(nx+1+ioff:nx+ehalo+ioff, 1:ny+joff,:) = data_all(1+ioff:ehalo+ioff, 1:ny+joff,:,5) ! east
data(1-whalo:0, 1:ny+joff,:) = data_all(nxm-whalo+1:nxm, ny+1:2*ny+joff,:,1) ! west
data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,2) ! south
data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,2) ! north
data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,3) ! southeast
data(1-whalo:0, 1-shalo:0,:) = data_all(nxm-whalo+1:nxm, ny-shalo+1:ny,:,1) ! southwest
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
data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nxm-whalo+1:nxm, 1+joff:nhalo+joff,:,1) ! northwest
case(5)
data(nx+1+ioff:nx+ehalo+ioff, 1: ny+joff,:) = data_all(1+ioff:ehalo+ioff, ny+1:2*ny+joff,:,1) ! east
data(1-whalo:0, 1:ny+joff,:) = data_all(nx-whalo+1:nx, 1:ny+joff,:,4) ! west
data(1:nx+ioff, 1-shalo:0,:) = data_all(1:nx+ioff, ny-shalo+1:ny,:,3) ! south
data(1:nx+ioff, ny+1+joff:ny+nhalo+joff,:) = data_all(1:nx+ioff, 1+joff:nhalo+joff,:,3) ! north
data(nx+1+ioff:nx+ehalo+ioff, 1-shalo:0,:) = data_all(1+ioff:ehalo+ioff, ny-shalo+1:ny,:,1) ! southeast
data(1-whalo:0, 1-shalo:0,:) = data_all(nx-whalo+1:nx, ny-shalo+1:ny,:,2) ! southwest
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
data(1-whalo:0, ny+1+joff:ny+nhalo+joff,:) = data_all(nx-whalo+1:nx, 1+joff:nhalo+joff,:,2) ! northwest
end select
end subroutine fill_five_tile_halo
!#######################################################################################
subroutine test_get_boundary(type)
character(len=*), intent(in) :: type
type(domain2D) :: domain, domain_nonsym
integer :: ntiles, num_contact, npes_per_tile, ntile_per_pe, layout(2)
integer :: n, l, isc, iec, jsc, jec, ism, iem, jsm, jem
integer, allocatable, dimension(:) :: tile, ni, nj, pe_start, pe_end
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real, allocatable, dimension(:,:,:) :: ebuffer, sbuffer, wbuffer, nbuffer
real, allocatable, dimension(:,:,:) :: ebuffer1, sbuffer1, wbuffer1, nbuffer1
real, allocatable, dimension(:,:,:) :: ebuffer2, sbuffer2, wbuffer2, nbuffer2
real, allocatable, dimension(:,:,:) :: ebound, sbound, wbound, nbound
real, allocatable, dimension(:,:,:) :: ebufferx, sbufferx, wbufferx, nbufferx
real, allocatable, dimension(:,:,:) :: ebufferx1, sbufferx1, wbufferx1, nbufferx1
real, allocatable, dimension(:,:,:) :: ebufferx2, sbufferx2, wbufferx2, nbufferx2
real, allocatable, dimension(:,:,:) :: eboundx, sboundx, wboundx, nboundx
real, allocatable, dimension(:,:,:) :: ebuffery, sbuffery, wbuffery, nbuffery
real, allocatable, dimension(:,:,:) :: ebuffery1, sbuffery1, wbuffery1, nbuffery1
real, allocatable, dimension(:,:,:) :: ebuffery2, sbuffery2, wbuffery2, nbuffery2
real, allocatable, dimension(:,:,:) :: eboundy, sboundy, wboundy, nboundy
real, allocatable, dimension(:,:,:,:) :: global_all, global1_all, global2_all
real, allocatable, dimension(:,:,:,:) :: global, global1, global2
real, allocatable, dimension(:,:,:,:) :: x, x1, x2, y, y1, y2
real, allocatable, dimension(:,:) :: u_nonsym, v_nonsym
logical :: folded_north = .false.
logical :: is_torus = .false.
integer :: nx_save, ny_save
nx_save = nx
ny_save = ny
!--- check the type
select case(type)
case ( 'Four-Tile' ) !--- cyclic along both x- and y-direction.
ntiles = 4
num_contact = 8
case ( 'Cubic-Grid' )
ntiles = 6
num_contact = 12
nx = nx_cubic
ny = nx
case ( 'Folded-north' )
folded_north = .true.
ntiles = 1
case ( 'torus' )
is_torus = .true.
ntiles = 1
case default
call mpp_error(FATAL, 'TEST_MPP_DOMAINS: no such test: '//type)
end select
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
allocate(ni(ntiles), nj(ntiles))
ni(:) = nx; nj(:) = ny
if( mod(npes, ntiles) == 0 ) then
npes_per_tile = npes/ntiles
write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
'", each tile will be distributed over ', npes_per_tile, ' processors.'
ntile_per_pe = 1
allocate(tile(ntile_per_pe))
tile = pe/npes_per_tile+1
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
else if ( mod(ntiles, npes) == 0 ) then
ntile_per_pe = ntiles/npes
write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
'", there will be ', ntile_per_pe, ' tiles on each processor.'
allocate(tile(ntile_per_pe))
do n = 1, ntile_per_pe
tile(n) = pe*ntile_per_pe + n
end do
do n = 1, ntiles
pe_start(n) = (n-1)/ntile_per_pe
pe_end(n) = pe_start(n)
end do
layout = 1
else
call mpp_error(NOTE,'TEST_MPP_DOMAINS: npes should be multiple of ntiles or ' // &
'ntiles should be multiple of npes. No test is done for '//trim(type) )
return
end if
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
select case(type)
case("Four-Tile")
call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
layout2D, pe_start, pe_end, .true. )
case("Cubic-Grid")
call define_cubic_mosaic(type, domain, ni, nj, global_indices, layout2D, pe_start, pe_end )
case("Folded-north")
call mpp_define_domains((/1,nx,1,ny/), layout, domain, &
xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, &
whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
symmetry=.true., name='tripolar' )
call mpp_define_domains((/1,nx,1,ny/), layout, domain_nonsym, &
xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, &
whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
symmetry=.false., name='tripolar' )
case("torus")
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, &
yflags=CYCLIC_GLOBAL_DOMAIN, symmetry=.true., name=type)
end select
!--- Test the get_boundary of the data at C-cell center.
allocate(global_all(1:nx+1,1:ny+1,nz, ntiles) )
allocate(global(1:nx+1,1:ny+1,nz, ntile_per_pe) )
global = 0
do l = 1, ntiles
do k = 1, nz
do j = 1, ny+1
do i = 1, nx+1
global_all(i,j,k,l) = l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
do n = 1, ntile_per_pe
global(:,:,:,n) = global_all(:,:,:,tile(n))
end do
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_memory_domain ( domain, ism, iem, jsm, jem )
allocate( x (ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
allocate( x1(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
allocate( x2(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
x = 0.
x(isc:iec+1,jsc:jec+1,:,:) = global(isc:iec+1,jsc:jec+1,:,:)
x1 = x; x2 = x*10
!--- buffer allocation
allocate(ebuffer(jsc:jec+1, nz, ntile_per_pe), wbuffer(jsc:jec+1, nz, ntile_per_pe))
allocate(sbuffer(isc:iec+1, nz, ntile_per_pe), nbuffer(isc:iec+1, nz, ntile_per_pe))
allocate(ebuffer1(jsc:jec+1, nz, ntile_per_pe), wbuffer1(jsc:jec+1, nz, ntile_per_pe))
allocate(sbuffer1(isc:iec+1, nz, ntile_per_pe), nbuffer1(isc:iec+1, nz, ntile_per_pe))
allocate(ebuffer2(jsc:jec+1, nz, ntile_per_pe), wbuffer2(jsc:jec+1, nz, ntile_per_pe))
allocate(sbuffer2(isc:iec+1, nz, ntile_per_pe), nbuffer2(isc:iec+1, nz, ntile_per_pe))
allocate(ebound(jsc:jec+1, nz, ntile_per_pe), wbound(jsc:jec+1, nz, ntile_per_pe))
allocate(sbound(isc:iec+1, nz, ntile_per_pe), nbound(isc:iec+1, nz, ntile_per_pe))
ebound = 0; ebuffer = 0; ebuffer1 = 0; ebuffer2 = 0
sbound = 0; sbuffer = 0; sbuffer1 = 0; sbuffer2 = 0
wbound = 0; wbuffer = 0; wbuffer1 = 0; wbuffer2 = 0
nbound = 0; nbuffer = 0; nbuffer1 = 0; nbuffer2 = 0
do n = 1, ntile_per_pe
if(folded_north .or. is_torus ) then
call mpp_get_boundary(x(:,:,:,n), domain, sbuffer=sbuffer(:,:,n), wbuffer=wbuffer(:,:,n), &
position=CORNER, tile_count=n )
else
call mpp_get_boundary(x(:,:,:,n), domain, ebuffer=ebuffer(:,:,n), sbuffer=sbuffer(:,:,n), wbuffer=wbuffer(:,:,n), &
nbuffer=nbuffer(:,:,n), position=CORNER, tile_count=n )
endif
end do
!--- multiple variable
do n = 1, ntile_per_pe
if(folded_north .or. is_torus) then
call mpp_get_boundary(x1(:,:,:,n), domain, sbuffer=sbuffer1(:,:,n), wbuffer=wbuffer1(:,:,n), &
position=CORNER, tile_count=n, complete = .false. )
call mpp_get_boundary(x2(:,:,:,n), domain, sbuffer=sbuffer2(:,:,n), wbuffer=wbuffer2(:,:,n), &
position=CORNER, tile_count=n, complete = .true. )
else
call mpp_get_boundary(x1(:,:,:,n), domain, ebuffer=ebuffer1(:,:,n), sbuffer=sbuffer1(:,:,n), wbuffer=wbuffer1(:,:,n), &
nbuffer=nbuffer1(:,:,n), position=CORNER, tile_count=n, complete = .false. )
call mpp_get_boundary(x2(:,:,:,n), domain, ebuffer=ebuffer2(:,:,n), sbuffer=sbuffer2(:,:,n), wbuffer=wbuffer2(:,:,n), &
nbuffer=nbuffer2(:,:,n), position=CORNER, tile_count=n, complete = .true. )
endif
end do
!--- compare the buffer.
select case(type)
case("Four-Tile")
do n = 1, ntile_per_pe
call fill_four_tile_bound(global_all, isc, iec, jsc, jec, 1, 1, &
tile(n), ebound(:,:,n), sbound(:,:,n), wbound(:,:,n), nbound(:,:,n) )
end do
case("Cubic-Grid")
do n = 1, ntile_per_pe
call fill_cubic_grid_bound(global_all, global_all, isc, iec, jsc, jec, 1, 1, &
tile(n), 1, 1, ebound(:,:,n), sbound(:,:,n), wbound(:,:,n), nbound(:,:,n) )
end do
case("Folded-north")
!---- folded line update
global_all(nx/2+2:nx, ny+1,:,1) = global_all(nx/2:2:-1, ny+1,:,1)
do n = 1, ntile_per_pe
call fill_folded_north_bound(global_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sbound(:,:,n), wbound(:,:,n) )
end do
case("torus")
do n = 1, ntile_per_pe
call fill_torus_bound(global_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sbound(:,:,n), wbound(:,:,n) )
end do
end select
if(.not. folded_north .AND. .not. is_torus) then
call compare_checksums( ebound, ebuffer(:,:,:), "east bound of "//trim(type) )
call compare_checksums( nbound, nbuffer(:,:,:), "north bound of "//trim(type) )
call compare_checksums( ebound, ebuffer1(:,:,:), "east bound of "//trim(type)//" X1" )
call compare_checksums( nbound, nbuffer1(:,:,:), "north bound of "//trim(type)//" X1" )
call compare_checksums( ebound*10, ebuffer2(:,:,:), "east bound of "//trim(type)//" X2" )
call compare_checksums( nbound*10, nbuffer2(:,:,:), "north bound of "//trim(type)//" X2" )
endif
call compare_checksums( sbound, sbuffer(:,:,:), "south bound of "//trim(type) )
call compare_checksums( wbound, wbuffer(:,:,:), "west bound of "//trim(type) )
call compare_checksums( sbound, sbuffer1(:,:,:), "south bound of "//trim(type)//" X1" )
call compare_checksums( wbound, wbuffer1(:,:,:), "west bound of "//trim(type)//" X1" )
call compare_checksums( sbound*10, sbuffer2(:,:,:), "south bound of "//trim(type)//" X2" )
call compare_checksums( wbound*10, wbuffer2(:,:,:), "west bound of "//trim(type)//" X2" )
!--- release memory
deallocate(global, global_all, x, x1, x2)
deallocate(ebuffer, sbuffer, wbuffer, nbuffer)
deallocate(ebuffer1, sbuffer1, wbuffer1, nbuffer1)
deallocate(ebuffer2, sbuffer2, wbuffer2, nbuffer2)
deallocate(ebound, sbound, wbound, nbound )
!-------------------------------------------------------------------------------------------
!
! Test SCALAR_PAIR BGRID
!
!-------------------------------------------------------------------------------------------
allocate(global1_all(1:nx+1,1:ny+1,nz, ntiles) )
allocate(global2_all(1:nx+1,1:ny+1,nz, ntiles) )
allocate(global1(1:nx+1,1:ny+1,nz, ntile_per_pe) )
allocate(global2(1:nx+1,1:ny+1,nz, ntile_per_pe) )
do l = 1, ntiles
do k = 1, nz
do j = 1, ny+1
do i = 1, nx+1
global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
do n = 1, ntile_per_pe
global1(:,:,:,n) = global1_all(:,:,:,tile(n))
global2(:,:,:,n) = global2_all(:,:,:,tile(n))
end do
allocate( x (ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
allocate( x1(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
allocate( x2(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
allocate( y (ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
allocate( y1(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
allocate( y2(ism:iem+1,jsm:jem+1,nz, ntile_per_pe) )
x = 0.; y = 0
if( trim(type) == "Folded-north" ) then
x(isc+1:iec+1,jsc+1:jec+1,:,:) = global1(isc+1:iec+1,jsc+1:jec+1,:,:)
y(isc+1:iec+1,jsc+1:jec+1,:,:) = global2(isc+1:iec+1,jsc+1:jec+1,:,:)
else
x(isc:iec+1,jsc:jec+1,:,:) = global1(isc:iec+1,jsc:jec+1,:,:)
y(isc:iec+1,jsc:jec+1,:,:) = global2(isc:iec+1,jsc:jec+1,:,:)
endif
x1 = x; x2 = x*10
y1 = y; y2 = y*10
!--- buffer allocation
allocate(ebufferx(jsc:jec+1, nz, ntile_per_pe), wbufferx(jsc:jec+1, nz, ntile_per_pe))
allocate(sbufferx(isc:iec+1, nz, ntile_per_pe), nbufferx(isc:iec+1, nz, ntile_per_pe))
allocate(ebufferx1(jsc:jec+1, nz, ntile_per_pe), wbufferx1(jsc:jec+1, nz, ntile_per_pe))
allocate(sbufferx1(isc:iec+1, nz, ntile_per_pe), nbufferx1(isc:iec+1, nz, ntile_per_pe))
allocate(ebufferx2(jsc:jec+1, nz, ntile_per_pe), wbufferx2(jsc:jec+1, nz, ntile_per_pe))
allocate(sbufferx2(isc:iec+1, nz, ntile_per_pe), nbufferx2(isc:iec+1, nz, ntile_per_pe))
allocate(eboundx(jsc:jec+1, nz, ntile_per_pe), wboundx(jsc:jec+1, nz, ntile_per_pe))
allocate(sboundx(isc:iec+1, nz, ntile_per_pe), nboundx(isc:iec+1, nz, ntile_per_pe))
allocate(ebuffery(jsc:jec+1, nz, ntile_per_pe), wbuffery(jsc:jec+1, nz, ntile_per_pe))
allocate(sbuffery(isc:iec+1, nz, ntile_per_pe), nbuffery(isc:iec+1, nz, ntile_per_pe))
allocate(ebuffery1(jsc:jec+1, nz, ntile_per_pe), wbuffery1(jsc:jec+1, nz, ntile_per_pe))
allocate(sbuffery1(isc:iec+1, nz, ntile_per_pe), nbuffery1(isc:iec+1, nz, ntile_per_pe))
allocate(ebuffery2(jsc:jec+1, nz, ntile_per_pe), wbuffery2(jsc:jec+1, nz, ntile_per_pe))
allocate(sbuffery2(isc:iec+1, nz, ntile_per_pe), nbuffery2(isc:iec+1, nz, ntile_per_pe))
allocate(eboundy(jsc:jec+1, nz, ntile_per_pe), wboundy(jsc:jec+1, nz, ntile_per_pe))
allocate(sboundy(isc:iec+1, nz, ntile_per_pe), nboundy(isc:iec+1, nz, ntile_per_pe))
eboundx = 0; ebufferx = 0; ebufferx1 = 0; ebufferx2 = 0
sboundx = 0; sbufferx = 0; sbufferx1 = 0; sbufferx2 = 0
wboundx = 0; wbufferx = 0; wbufferx1 = 0; wbufferx2 = 0
nboundx = 0; nbufferx = 0; nbufferx1 = 0; nbufferx2 = 0
eboundy = 0; ebuffery = 0; ebuffery1 = 0; ebuffery2 = 0
sboundy = 0; sbuffery = 0; sbuffery1 = 0; sbuffery2 = 0
wboundy = 0; wbuffery = 0; wbuffery1 = 0; wbuffery2 = 0
nboundy = 0; nbuffery = 0; nbuffery1 = 0; nbuffery2 = 0
do n = 1, ntile_per_pe
if(folded_north .or. is_torus) then
call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, sbufferx=sbufferx(:,:,n), wbufferx=wbufferx(:,:,n), &
sbuffery=sbuffery(:,:,n), wbuffery=wbuffery(:,:,n), gridtype=BGRID_NE, tile_count=n, flags = SCALAR_PAIR )
else
call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, ebufferx=ebufferx(:,:,n), sbufferx=sbufferx(:,:,n), &
wbufferx=wbufferx(:,:,n), nbufferx=nbufferx(:,:,n), ebuffery=ebuffery(:,:,n), &
sbuffery=sbuffery(:,:,n), wbuffery=wbuffery(:,:,n), nbuffery=nbuffery(:,:,n), &
gridtype=BGRID_NE, tile_count=n, flags = SCALAR_PAIR )
endif
end do
do n = 1, ntile_per_pe
if(folded_north .or. is_torus) then
call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, sbufferx=sbufferx1(:,:,n), wbufferx=wbufferx1(:,:,n), &
sbuffery=sbuffery1(:,:,n), wbuffery=wbuffery1(:,:,n), &
gridtype=BGRID_NE, tile_count=n, flags = SCALAR_PAIR, complete = .false. )
call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, sbufferx=sbufferx2(:,:,n), wbufferx=wbufferx2(:,:,n), &
sbuffery=sbuffery2(:,:,n), wbuffery=wbuffery2(:,:,n), &
gridtype=BGRID_NE, tile_count=n, flags = SCALAR_PAIR, complete = .true. )
else
call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, ebufferx=ebufferx1(:,:,n), sbufferx=sbufferx1(:,:,n), &
wbufferx=wbufferx1(:,:,n), nbufferx=nbufferx1(:,:,n), ebuffery=ebuffery1(:,:,n), &
sbuffery=sbuffery1(:,:,n), wbuffery=wbuffery1(:,:,n), nbuffery=nbuffery1(:,:,n), &
gridtype=BGRID_NE, tile_count=n, flags = SCALAR_PAIR, complete = .false. )
call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, ebufferx=ebufferx2(:,:,n), sbufferx=sbufferx2(:,:,n), &
wbufferx=wbufferx2(:,:,n), nbufferx=nbufferx2(:,:,n), ebuffery=ebuffery2(:,:,n), &
sbuffery=sbuffery2(:,:,n), wbuffery=wbuffery2(:,:,n), nbuffery=nbuffery2(:,:,n), &
gridtype=BGRID_NE, tile_count=n, flags = SCALAR_PAIR, complete = .true. )
endif
end do
!--- compare the buffer.
select case(type)
case("Four-Tile")
do n = 1, ntile_per_pe
call fill_four_tile_bound(global1_all, isc, iec, jsc, jec, 1, 1, &
tile(n), eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
call fill_four_tile_bound(global2_all, isc, iec, jsc, jec, 1, 1, &
tile(n), eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
end do
case("Cubic-Grid")
do n = 1, ntile_per_pe
call fill_cubic_grid_bound(global1_all, global2_all, isc, iec, jsc, jec, 1, 1, &
tile(n), 1, 1, eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
call fill_cubic_grid_bound(global2_all, global1_all, isc, iec, jsc, jec, 1, 1, &
tile(n), 1, 1, eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
end do
case("Folded-north")
global1_all(nx/2+2:nx, ny+1,:,1) = global1_all(nx/2:2:-1, ny+1,:,1)
global2_all(nx/2+2:nx, ny+1,:,1) = global2_all(nx/2:2:-1, ny+1,:,1)
do n = 1, ntile_per_pe
call fill_folded_north_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundx(:,:,n), wboundx(:,:,n) )
call fill_folded_north_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundy(:,:,n), wboundy(:,:,n) )
end do
case("torus")
do n = 1, ntile_per_pe
call fill_torus_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundx(:,:,n), wboundx(:,:,n) )
call fill_torus_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundy(:,:,n), wboundy(:,:,n) )
end do
end select
if(.not. folded_north .AND. .not. is_torus ) then
call compare_checksums( eboundx, ebufferx(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" X" )
call compare_checksums( nboundx, nbufferx(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" X" )
call compare_checksums( eboundy, ebuffery(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" Y" )
call compare_checksums( nboundy, nbuffery(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" Y" )
call compare_checksums( eboundx, ebufferx1(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" X1" )
call compare_checksums( nboundx, nbufferx1(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" X1" )
call compare_checksums( eboundy, ebuffery1(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" Y1" )
call compare_checksums( nboundy, nbuffery1(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" Y1" )
endif
call compare_checksums( sboundx, sbufferx(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" X" )
call compare_checksums( wboundx, wbufferx(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" X" )
call compare_checksums( sboundy, sbuffery(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" Y" )
call compare_checksums( wboundy, wbuffery(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" Y" )
call compare_checksums( sboundx, sbufferx1(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" X1" )
call compare_checksums( wboundx, wbufferx1(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" X1" )
call compare_checksums( sboundy, sbuffery1(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" Y1" )
call compare_checksums( wboundy, wbuffery1(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" Y1" )
select case(type)
case("Four-Tile")
do n = 1, ntile_per_pe
call fill_four_tile_bound(global1_all*10, isc, iec, jsc, jec, 1, 1, &
tile(n), eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
call fill_four_tile_bound(global2_all*10, isc, iec, jsc, jec, 1, 1, &
tile(n), eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
end do
case("Cubic-Grid")
do n = 1, ntile_per_pe
call fill_cubic_grid_bound(global1_all*10, global2_all*10, isc, iec, jsc, jec, 1, 1, &
tile(n), 1, 1, eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
call fill_cubic_grid_bound(global2_all*10, global1_all*10, isc, iec, jsc, jec, 1, 1, &
tile(n), 1, 1, eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
end do
case("Folded-north")
do n = 1, ntile_per_pe
call fill_folded_north_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
tile(n), sboundx(:,:,n), wboundx(:,:,n) )
call fill_folded_north_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
tile(n), sboundy(:,:,n), wboundy(:,:,n) )
end do
case("torus")
do n = 1, ntile_per_pe
call fill_torus_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
tile(n), sboundx(:,:,n), wboundx(:,:,n) )
call fill_torus_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 1, &
tile(n), sboundy(:,:,n), wboundy(:,:,n) )
end do
end select
if(.not. folded_north .AND. .not. is_torus ) then
call compare_checksums( eboundx, ebufferx2(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" X2" )
call compare_checksums( nboundx, nbufferx2(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" X2" )
call compare_checksums( eboundy, ebuffery2(:,:,:), "east bound of SCALAR_PAIR BGRID " //trim(type)//" Y2" )
call compare_checksums( nboundy, nbuffery2(:,:,:), "north bound of SCALAR_PAIR BGRID "//trim(type)//" Y2" )
endif
call compare_checksums( sboundx, sbufferx2(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" X2" )
call compare_checksums( wboundx, wbufferx2(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" X2" )
call compare_checksums( sboundy, sbuffery2(:,:,:), "south bound of SCALAR_PAIR BGRID "//trim(type)//" Y2" )
call compare_checksums( wboundy, wbuffery2(:,:,:), "west bound of SCALAR_PAIR BGRID " //trim(type)//" Y2" )
!-------------------------------------------------------------------------------------------
!
! Test 2-D Vector BGRID
!
!-------------------------------------------------------------------------------------------
do l = 1, ntiles
do k = 1, nz
do j = 1, ny+1
do i = 1, nx+1
global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
x = 0.; y = 0
eboundx = 0; ebufferx = 0; ebufferx1 = 0; ebufferx2 = 0
sboundx = 0; sbufferx = 0; sbufferx1 = 0; sbufferx2 = 0
wboundx = 0; wbufferx = 0; wbufferx1 = 0; wbufferx2 = 0
nboundx = 0; nbufferx = 0; nbufferx1 = 0; nbufferx2 = 0
eboundy = 0; ebuffery = 0; ebuffery1 = 0; ebuffery2 = 0
sboundy = 0; sbuffery = 0; sbuffery1 = 0; sbuffery2 = 0
wboundy = 0; wbuffery = 0; wbuffery1 = 0; wbuffery2 = 0
nboundy = 0; nbuffery = 0; nbuffery1 = 0; nbuffery2 = 0
x(isc:iec+1,jsc:jec+1,1,:) = global1(isc:iec+1,jsc:jec+1,1,:)
y(isc:iec+1,jsc:jec+1,1,:) = global2(isc:iec+1,jsc:jec+1,1,:)
do n = 1, ntile_per_pe
if(folded_north .or. is_torus ) then
call mpp_get_boundary(x(:,:,1,n), y(:,:,1,n), domain, sbufferx=sbufferx(:,1,n), wbufferx=wbufferx(:,1,n), &
sbuffery=sbuffery(:,1,n), wbuffery=wbuffery(:,1,n), gridtype=BGRID_NE, tile_count=n)
else
call mpp_get_boundary(x(:,:,1,n), y(:,:,1,n), domain, ebufferx=ebufferx(:,1,n), sbufferx=sbufferx(:,1,n), &
wbufferx=wbufferx(:,1,n), nbufferx=nbufferx(:,1,n), ebuffery=ebuffery(:,1,n), &
sbuffery=sbuffery(:,1,n), wbuffery=wbuffery(:,1,n), nbuffery=nbuffery(:,1,n), &
gridtype=BGRID_NE, tile_count=n)
endif
end do
if(folded_north) then
allocate(u_nonsym(ism:iem,jsm:jem), v_nonsym(ism:iem,jsm:jem))
u_nonsym = 0.0; v_nonsym = 0.0
u_nonsym(isc:iec,jsc:jec) = global1(isc+1:iec+1,jsc+1:jec+1,1,1)
v_nonsym(isc:iec,jsc:jec) = global2(isc+1:iec+1,jsc+1:jec+1,1,1)
call mpp_update_domains(u_nonsym, v_nonsym, domain_nonsym, gridtype=BGRID_NE)
!--- comparing boundary data
do i = isc,iec+1
if(i==1) cycle
if(sbufferx(i,1,1) .NE. u_nonsym(i-1,jsc-1)) then
print*,"pe ", mpp_pe(), i, jsc-1, sbufferx(i,1,1), u_nonsym(i-1,jsc-1)
call mpp_error(FATAL, "test_get_boundary: mismatch of sbufferx")
endif
enddo
call mpp_error(NOTE,"test_get_boundary: reproduce non-symmetric halo update for sbufferx")
do i = isc,iec+1
if(i==1) cycle
if(sbuffery(i,1,1) .NE. v_nonsym(i-1,jsc-1)) then
print*,"pe ", mpp_pe(), i, jsc-1, sbufferx(i,1,1), v_nonsym(i-1,jsc-1)
call mpp_error(FATAL, "test_get_boundary: mismatch of sbuffery")
endif
enddo
call mpp_error(NOTE,"test_get_boundary: reproduce non-symmetric halo update for sbuffery")
do j = jsc,jec+1
if(j == 1) cycle
if(wbufferx(j,1,1) .NE. u_nonsym(isc-1,j-1)) then
print*,"pe ", mpp_pe(), isc-1, j, wbufferx(j,1,1), u_nonsym(isc-1,j-1)
call mpp_error(FATAL, "test_get_boundary: mismatch of wbufferx")
endif
enddo
call mpp_error(NOTE,"test_get_boundary: reproduce non-symmetric halo update for wbufferx")
do j = jsc,jec+1
if(j==1) cycle
if(wbuffery(j,1,1) .NE. v_nonsym(isc-1,j-1)) then
print*,"pe ", mpp_pe(), isc-1, j, wbuffery(j,1,1), v_nonsym(isc-1,j-1)
call mpp_error(FATAL, "test_get_boundary: mismatch of wbuffery")
endif
enddo
call mpp_error(NOTE,"test_get_boundary: reproduce non-symmetric halo update for wbuffery")
deallocate(u_nonsym, v_nonsym)
endif
!--- compare the buffer.
select case(type)
case("Four-Tile")
do n = 1, ntile_per_pe
call fill_four_tile_bound(global1_all, isc, iec, jsc, jec, 1, 1, &
tile(n), eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
call fill_four_tile_bound(global2_all, isc, iec, jsc, jec, 1, 1, &
tile(n), eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
end do
case("Cubic-Grid")
do n = 1, ntile_per_pe
call fill_cubic_grid_bound(global1_all, global2_all, isc, iec, jsc, jec, 1, 1, &
tile(n), 1, -1, eboundx(:,:,n), sboundx(:,:,n), wboundx(:,:,n), nboundx(:,:,n) )
call fill_cubic_grid_bound(global2_all, global1_all, isc, iec, jsc, jec, 1, 1, &
tile(n), -1, 1, eboundy(:,:,n), sboundy(:,:,n), wboundy(:,:,n), nboundy(:,:,n) )
end do
case("Folded-north")
global1_all(nx/2+2:nx, ny+1,:,1) = -global1_all(nx/2:2:-1, ny+1,:,1)
global2_all(nx/2+2:nx, ny+1,:,1) = -global2_all(nx/2:2:-1, ny+1,:,1)
global1_all(1, ny+1,:,1) = 0
global2_all(1, ny+1,:,1) = 0
global1_all(nx/2+1, ny+1,:,1) = 0
global2_all(nx/2+1, ny+1,:,1) = 0
global1_all(nx+1, ny+1,:,1) = 0
global2_all(nx+1, ny+1,:,1) = 0
do n = 1, ntile_per_pe
call fill_folded_north_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundx(:,:,n), wboundx(:,:,n) )
call fill_folded_north_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundy(:,:,n), wboundy(:,:,n) )
! set wboundx and wbouny to zero at pole (i=1, nx/2+1, nx+1)
! if( jec == ny ) then
! if( isc == 1 .OR. isc == nx/2+1 .OR. isc == nx+1 ) then
! wboundx(jec+1,:,n) = 0
! wboundy(jec+1,:,n) = 0
! endif
! endif
end do
case("torus")
do n = 1, ntile_per_pe
call fill_torus_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundx(:,:,n), wboundx(:,:,n) )
call fill_torus_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 1, 1, &
tile(n), sboundy(:,:,n), wboundy(:,:,n) )
enddo
end select
if(.not. folded_north .AND. .not. is_torus ) then
call compare_checksums( eboundx(:,1:1,:), ebufferx(:,1:1,:), "east bound of 2-D BGRID " //trim(type)//" X" )
call compare_checksums( nboundx(:,1:1,:), nbufferx(:,1:1,:), "north bound of 2-D BGRID "//trim(type)//" X" )
call compare_checksums( eboundy(:,1:1,:), ebuffery(:,1:1,:), "east bound of 2-D BGRID " //trim(type)//" Y" )
call compare_checksums( nboundy(:,1:1,:), nbuffery(:,1:1,:), "north bound of 2-D BGRID "//trim(type)//" Y" )
endif
call compare_checksums( sboundx(:,1:1,:), sbufferx(:,1:1,:), "south bound of 2-D BGRID "//trim(type)//" X" )
call compare_checksums( wboundx(:,1:1,:), wbufferx(:,1:1,:), "west bound of 2-D BGRID " //trim(type)//" X" )
call compare_checksums( sboundy(:,1:1,:), sbuffery(:,1:1,:), "south bound of 2-D BGRID "//trim(type)//" Y" )
call compare_checksums( wboundy(:,1:1,:), wbuffery(:,1:1,:), "west bound of 2-D BGRID " //trim(type)//" Y" )
!--- release memory
deallocate(global1, global1_all, global2, global2_all)
deallocate(x, y, x1, y1, x2, y2)
deallocate(ebufferx, sbufferx, wbufferx, nbufferx)
deallocate(ebufferx1, sbufferx1, wbufferx1, nbufferx1)
deallocate(ebufferx2, sbufferx2, wbufferx2, nbufferx2)
deallocate(ebuffery, sbuffery, wbuffery, nbuffery)
deallocate(ebuffery1, sbuffery1, wbuffery1, nbuffery1)
deallocate(ebuffery2, sbuffery2, wbuffery2, nbuffery2)
deallocate(eboundx, sboundx, wboundx, nboundx )
deallocate(eboundy, sboundy, wboundy, nboundy )
!-------------------------------------------------------------------------------------------
!
! Test VECTOR CGRID
!
!-------------------------------------------------------------------------------------------
allocate(global1_all(1:nx+1,1:ny, nz, ntiles) )
allocate(global2_all(1:nx, 1:ny+1,nz, ntiles) )
allocate(global1(1:nx+1,1:ny, nz, ntile_per_pe) )
allocate(global2(1:nx, 1:ny+1,nz, ntile_per_pe) )
do l = 1, ntiles
do k = 1, nz
do j = 1, ny
do i = 1, nx+1
global1_all(i,j,k,l) = 1.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
do j = 1, ny+1
do i = 1, nx
global2_all(i,j,k,l) = 2.0e3 + l + i*1.0e-3 + j*1.0e-6 + k*1.0e-9
end do
end do
end do
end do
do n = 1, ntile_per_pe
global1(:,:,:,n) = global1_all(:,:,:,tile(n))
global2(:,:,:,n) = global2_all(:,:,:,tile(n))
end do
allocate( x (ism:iem+1,jsm:jem, nz, ntile_per_pe) )
allocate( x1(ism:iem+1,jsm:jem, nz, ntile_per_pe) )
allocate( x2(ism:iem+1,jsm:jem, nz, ntile_per_pe) )
allocate( y (ism:iem, jsm:jem+1,nz, ntile_per_pe) )
allocate( y1(ism:iem, jsm:jem+1,nz, ntile_per_pe) )
allocate( y2(ism:iem, jsm:jem+1,nz, ntile_per_pe) )
x = 0.; y = 0
x(isc:iec+1,jsc:jec, :,:) = global1(isc:iec+1,jsc:jec, :,:)
y(isc:iec, jsc:jec+1,:,:) = global2(isc:iec, jsc:jec+1,:,:)
x1 = x; x2 = x*10
y1 = y; y2 = y*10
!--- buffer allocation
allocate(ebufferx(jec-jsc+1, nz, ntile_per_pe), wbufferx(jec-jsc+1, nz, ntile_per_pe))
allocate(sbufferx(iec-isc+2, nz, ntile_per_pe), nbufferx(iec-isc+2, nz, ntile_per_pe))
allocate(ebufferx1(jec-jsc+1, nz, ntile_per_pe), wbufferx1(jec-jsc+1, nz, ntile_per_pe))
allocate(sbufferx1(iec-isc+2, nz, ntile_per_pe), nbufferx1(iec-isc+2, nz, ntile_per_pe))
allocate(ebufferx2(jec-jsc+1, nz, ntile_per_pe), wbufferx2(jec-jsc+1, nz, ntile_per_pe))
allocate(sbufferx2(iec-isc+2, nz, ntile_per_pe), nbufferx2(iec-isc+2, nz, ntile_per_pe))
allocate(ebuffery(jec-jsc+2, nz, ntile_per_pe), wbuffery(jec-jsc+2, nz, ntile_per_pe))
allocate(sbuffery(iec-isc+1, nz, ntile_per_pe), nbuffery(iec-isc+1, nz, ntile_per_pe))
allocate(ebuffery1(jec-jsc+2, nz, ntile_per_pe), wbuffery1(jec-jsc+2, nz, ntile_per_pe))
allocate(sbuffery1(iec-isc+1, nz, ntile_per_pe), nbuffery1(iec-isc+1, nz, ntile_per_pe))
allocate(ebuffery2(jec-jsc+2, nz, ntile_per_pe), wbuffery2(jec-jsc+2, nz, ntile_per_pe))
allocate(sbuffery2(iec-isc+1, nz, ntile_per_pe), nbuffery2(iec-isc+1, nz, ntile_per_pe))
allocate(eboundx(jec-jsc+1, nz, ntile_per_pe), wboundx(jec-jsc+1, nz, ntile_per_pe))
allocate(sboundy(iec-isc+1, nz, ntile_per_pe), nboundy(iec-isc+1, nz, ntile_per_pe))
eboundx = 0; ebufferx = 0; ebufferx1 = 0; ebufferx2 = 0
wboundx = 0; wbufferx = 0; wbufferx1 = 0; wbufferx2 = 0
sboundy = 0; sbuffery = 0; sbuffery1 = 0; sbuffery2 = 0
nboundy = 0; nbuffery = 0; nbuffery1 = 0; nbuffery2 = 0
do n = 1, ntile_per_pe
if(folded_north .or. is_torus) then
call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, wbufferx=wbufferx(:,:,n), &
sbuffery=sbuffery(:,:,n), gridtype=CGRID_NE, tile_count=n )
else
call mpp_get_boundary(x(:,:,:,n), y(:,:,:,n), domain, ebufferx=ebufferx(:,:,n), wbufferx=wbufferx(:,:,n), &
sbuffery=sbuffery(:,:,n), nbuffery=nbuffery(:,:,n), gridtype=CGRID_NE, tile_count=n )
endif
end do
do n = 1, ntile_per_pe
if( folded_north .or. is_torus ) then
call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, wbufferx=wbufferx1(:,:,n), &
sbuffery=sbuffery1(:,:,n), gridtype=CGRID_NE, tile_count=n, &
complete = .false. )
call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, wbufferx=wbufferx2(:,:,n), &
sbuffery=sbuffery2(:,:,n), gridtype=CGRID_NE, tile_count=n, &
complete = .true. )
else
call mpp_get_boundary(x1(:,:,:,n), y1(:,:,:,n), domain, ebufferx=ebufferx1(:,:,n), wbufferx=wbufferx1(:,:,n), &
sbuffery=sbuffery1(:,:,n), nbuffery=nbuffery1(:,:,n), gridtype=CGRID_NE, tile_count=n, &
complete = .false. )
call mpp_get_boundary(x2(:,:,:,n), y2(:,:,:,n), domain, ebufferx=ebufferx2(:,:,n), wbufferx=wbufferx2(:,:,n), &
sbuffery=sbuffery2(:,:,n), nbuffery=nbuffery2(:,:,n), gridtype=CGRID_NE, tile_count=n, &
complete = .true. )
endif
end do
!--- compare the buffer.
select case(type)
case("Four-Tile")
do n = 1, ntile_per_pe
call fill_four_tile_bound(global1_all, isc, iec, jsc, jec, 1, 0, &
tile(n), ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
call fill_four_tile_bound(global2_all, isc, iec, jsc, jec, 0, 1, &
tile(n), sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
end do
case("Cubic-Grid")
do n = 1, ntile_per_pe
call fill_cubic_grid_bound(global1_all, global2_all, isc, iec, jsc, jec, 1, 0, &
tile(n), 1, -1, ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
call fill_cubic_grid_bound(global2_all, global1_all, isc, iec, jsc, jec, 0, 1, &
tile(n), -1, 1, sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
end do
case("Folded-north")
do n = 1, ntile_per_pe
call fill_folded_north_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 0, &
tile(n), wbound=wboundx(:,:,n) )
call fill_folded_north_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 0, 1, &
tile(n), sbound=sboundy(:,:,n) )
end do
case("torus")
do n = 1, ntile_per_pe
call fill_torus_bound(global1_all(:,:,:,1), isc, iec, jsc, jec, 1, 0, &
tile(n), wbound=wboundx(:,:,n) )
call fill_torus_bound(global2_all(:,:,:,1), isc, iec, jsc, jec, 0, 1, &
tile(n), sbound=sboundy(:,:,n) )
end do
end select
if(.not. folded_north .and. .not. is_torus ) then
call compare_checksums( eboundx, ebufferx(:,:,:), "east bound of CGRID " //trim(type)//" X" )
call compare_checksums( nboundy, nbuffery(:,:,:), "north bound of CGRID "//trim(type)//" Y" )
call compare_checksums( eboundx, ebufferx1(:,:,:), "east bound of CGRID " //trim(type)//" X1" )
call compare_checksums( nboundy, nbuffery1(:,:,:), "north bound of CGRID "//trim(type)//" Y1" )
endif
call compare_checksums( wboundx, wbufferx(:,:,:), "west bound of CGRID " //trim(type)//" X" )
call compare_checksums( sboundy, sbuffery(:,:,:), "south bound of CGRID "//trim(type)//" Y" )
call compare_checksums( wboundx, wbufferx1(:,:,:), "west bound of CGRID " //trim(type)//" X1" )
call compare_checksums( sboundy, sbuffery1(:,:,:), "south bound of CGRID "//trim(type)//" Y1" )
select case(type)
case("Four-Tile")
do n = 1, ntile_per_pe
call fill_four_tile_bound(global1_all*10, isc, iec, jsc, jec, 1, 0, &
tile(n), ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
call fill_four_tile_bound(global2_all*10, isc, iec, jsc, jec, 0, 1, &
tile(n), sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
end do
case("Cubic-Grid")
do n = 1, ntile_per_pe
call fill_cubic_grid_bound(global1_all*10, global2_all*10, isc, iec, jsc, jec, 1, 0, &
tile(n), 1, -1, ebound=eboundx(:,:,n), wbound=wboundx(:,:,n) )
call fill_cubic_grid_bound(global2_all*10, global1_all*10, isc, iec, jsc, jec, 0, 1, &
tile(n), -1, 1, sbound=sboundy(:,:,n), nbound=nboundy(:,:,n) )
end do
case("Folded-north")
do n = 1, ntile_per_pe
call fill_folded_north_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 0, &
tile(n), wbound=wboundx(:,:,n) )
call fill_folded_north_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 0, 1, &
tile(n), sbound=sboundy(:,:,n) )
end do
case("torus")
do n = 1, ntile_per_pe
call fill_torus_bound(global1_all(:,:,:,1)*10, isc, iec, jsc, jec, 1, 0, &
tile(n), wbound=wboundx(:,:,n) )
call fill_torus_bound(global2_all(:,:,:,1)*10, isc, iec, jsc, jec, 0, 1, &
tile(n), sbound=sboundy(:,:,n) )
end do
end select
if(.not. folded_north .and. .not. is_torus ) then
call compare_checksums( eboundx, ebufferx2(:,:,:), "east bound of CGRID " //trim(type)//" X2" )
call compare_checksums( nboundy, nbuffery2(:,:,:), "north bound of CGRID "//trim(type)//" Y2" )
endif
call compare_checksums( wboundx, wbufferx2(:,:,:), "west bound of CGRID " //trim(type)//" X2" )
call compare_checksums( sboundy, sbuffery2(:,:,:), "south bound of CGRID "//trim(type)//" Y2" )
!--- release memory
deallocate(global1, global1_all, global2, global2_all)
deallocate(x, y, x1, y1, x2, y2)
deallocate(ebufferx, sbufferx, wbufferx, nbufferx)
deallocate(ebufferx1, sbufferx1, wbufferx1, nbufferx1)
deallocate(ebufferx2, sbufferx2, wbufferx2, nbufferx2)
deallocate(ebuffery, sbuffery, wbuffery, nbuffery)
deallocate(ebuffery1, sbuffery1, wbuffery1, nbuffery1)
deallocate(ebuffery2, sbuffery2, wbuffery2, nbuffery2)
deallocate(eboundx, sboundy, wboundx, nboundy )
nx = nx_save
ny = ny_save
end subroutine test_get_boundary
!######################################################################################
subroutine define_fourtile_mosaic(type, domain, ni, nj, global_indices, layout, pe_start, pe_end, symmetry )
character(len=*), intent(in) :: type
type(domain2d), intent(inout) :: domain
integer, intent(in) :: global_indices(:,:), layout(:,:)
integer, intent(in) :: ni(:), nj(:)
integer, intent(in) :: pe_start(:), pe_end(:)
logical, intent(in) :: symmetry
integer, dimension(8) :: istart1, iend1, jstart1, jend1, tile1
integer, dimension(8) :: istart2, iend2, jstart2, jend2, tile2
integer :: ntiles, num_contact, msize(2)
ntiles = 4
num_contact = 8
if(size(pe_start(:)) .NE. 4 .OR. size(pe_end(:)) .NE. 4 ) call mpp_error(FATAL, &
"define_fourtile_mosaic: size of pe_start and pe_end should be 4")
if(size(global_indices,1) .NE. 4) call mpp_error(FATAL, &
"define_fourtile_mosaic: size of first dimension of global_indices should be 4")
if(size(global_indices,2) .NE. 4) call mpp_error(FATAL, &
"define_fourtile_mosaic: size of second dimension of global_indices should be 4")
if(size(layout,1) .NE. 2) call mpp_error(FATAL, &
"define_fourtile_mosaic: size of first dimension of layout should be 2")
if(size(layout,2) .NE. 4) call mpp_error(FATAL, &
"define_fourtile_mosaic: size of second dimension of layout should be 4")
if(size(ni(:)) .NE. 4 .OR. size(nj(:)) .NE. 4) call mpp_error(FATAL, &
"define_fourtile_mosaic: size of ni and nj should be 4")
!--- Contact line 1, between tile 1 (EAST) and tile 2 (WEST)
tile1(1) = 1; tile2(1) = 2
istart1(1) = ni(1); iend1(1) = ni(1); jstart1(1) = 1; jend1(1) = nj(1)
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = nj(2)
!--- Contact line 2, between tile 1 (SOUTH) and tile 3 (NORTH) --- cyclic
tile1(2) = 1; tile2(2) = 3
istart1(2) = 1; iend1(2) = ni(1); jstart1(2) = 1; jend1(2) = 1
istart2(2) = 1; iend2(2) = ni(3); jstart2(2) = nj(3); jend2(2) = nj(3)
!--- Contact line 3, between tile 1 (WEST) and tile 2 (EAST) --- cyclic
tile1(3) = 1; tile2(3) = 2
istart1(3) = 1; iend1(3) = 1; jstart1(3) = 1; jend1(3) = nj(1)
istart2(3) = ni(2); iend2(3) = ni(2); jstart2(3) = 1; jend2(3) = nj(2)
!--- Contact line 4, between tile 1 (NORTH) and tile 3 (SOUTH)
tile1(4) = 1; tile2(4) = 3
istart1(4) = 1; iend1(4) = ni(1); jstart1(4) = nj(1); jend1(4) = nj(1)
istart2(4) = 1; iend2(4) = ni(3); jstart2(4) = 1; jend2(4) = 1
!--- Contact line 5, between tile 2 (SOUTH) and tile 4 (NORTH) --- cyclic
tile1(5) = 2; tile2(5) = 4
istart1(5) = 1; iend1(5) = ni(2); jstart1(5) = 1; jend1(5) = 1
istart2(5) = 1; iend2(5) = ni(4); jstart2(5) = nj(4); jend2(5) = nj(4)
!--- Contact line 6, between tile 2 (NORTH) and tile 4 (SOUTH)
tile1(6) = 2; tile2(6) = 4
istart1(6) = 1; iend1(6) = ni(2); jstart1(6) = nj(2); jend1(6) = nj(2)
istart2(6) = 1; iend2(6) = ni(4); jstart2(6) = 1; jend2(6) = 1
!--- Contact line 7, between tile 3 (EAST) and tile 4 (WEST)
tile1(7) = 3; tile2(7) = 4
istart1(7) = ni(3); iend1(7) = ni(3); jstart1(7) = 1; jend1(7) = nj(3)
istart2(7) = 1; iend2(7) = 1; jstart2(7) = 1; jend2(7) = nj(4)
!--- Contact line 8, between tile 3 (WEST) and tile 4 (EAST) --- cyclic
tile1(8) = 3; tile2(8) = 4
istart1(8) = 1; iend1(8) = 1; jstart1(8) = 1; jend1(8) = nj(3)
istart2(8) = ni(4); iend2(8) = ni(4); jstart2(8) = 1; jend2(8) = nj(4)
msize(1) = maxval(ni(:)/layout(1,:)) + whalo + ehalo + 1 ! make sure memory domain size is no smaller than
msize(2) = maxval(nj(:)/layout(2,:)) + shalo + nhalo + 1 ! data domain size
call mpp_define_mosaic(global_indices, layout, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name = type, memory_size = msize, symmetry = symmetry )
return
end subroutine define_fourtile_mosaic
!#######################################################################################
!--- define mosaic domain for cubic grid
subroutine define_cubic_mosaic(type, domain, ni, nj, global_indices, layout, pe_start, pe_end, use_memsize)
character(len=*), intent(in) :: type
type(domain2d), intent(inout) :: domain
integer, intent(in) :: global_indices(:,:), layout(:,:)
integer, intent(in) :: ni(:), nj(:)
integer, intent(in) :: pe_start(:), pe_end(:)
logical, optional, intent(in) :: use_memsize
integer, dimension(12) :: istart1, iend1, jstart1, jend1, tile1
integer, dimension(12) :: istart2, iend2, jstart2, jend2, tile2
integer :: ntiles, num_contact, msize(2)
logical :: use_memsize_local
use_memsize_local = .true.
if(present(use_memsize)) use_memsize_local = use_memsize
ntiles = 6
num_contact = 12
if(size(pe_start(:)) .NE. 6 .OR. size(pe_end(:)) .NE. 6 ) call mpp_error(FATAL, &
"define_cubic_mosaic: size of pe_start and pe_end should be 6")
if(size(global_indices,1) .NE. 4) call mpp_error(FATAL, &
"define_cubic_mosaic: size of first dimension of global_indices should be 4")
if(size(global_indices,2) .NE. 6) call mpp_error(FATAL, &
"define_cubic_mosaic: size of second dimension of global_indices should be 6")
if(size(layout,1) .NE. 2) call mpp_error(FATAL, &
"define_cubic_mosaic: size of first dimension of layout should be 2")
if(size(layout,2) .NE. 6) call mpp_error(FATAL, &
"define_cubic_mosaic: size of second dimension of layout should be 6")
if(size(ni(:)) .NE. 6 .OR. size(nj(:)) .NE. 6) call mpp_error(FATAL, &
"define_cubic_mosaic: size of ni and nj should be 6")
!--- Contact line 1, between tile 1 (EAST) and tile 2 (WEST)
tile1(1) = 1; tile2(1) = 2
istart1(1) = ni(1); iend1(1) = ni(1); jstart1(1) = 1; jend1(1) = nj(1)
istart2(1) = 1; iend2(1) = 1; jstart2(1) = 1; jend2(1) = nj(2)
!--- Contact line 2, between tile 1 (NORTH) and tile 3 (WEST)
tile1(2) = 1; tile2(2) = 3
istart1(2) = 1; iend1(2) = ni(1); jstart1(2) = nj(1); jend1(2) = nj(1)
istart2(2) = 1; iend2(2) = 1; jstart2(2) = nj(3); jend2(2) = 1
!--- Contact line 3, between tile 1 (WEST) and tile 5 (NORTH)
tile1(3) = 1; tile2(3) = 5
istart1(3) = 1; iend1(3) = 1; jstart1(3) = 1; jend1(3) = nj(1)
istart2(3) = ni(5); iend2(3) = 1; jstart2(3) = nj(5); jend2(3) = nj(5)
!--- Contact line 4, between tile 1 (SOUTH) and tile 6 (NORTH)
tile1(4) = 1; tile2(4) = 6
istart1(4) = 1; iend1(4) = ni(1); jstart1(4) = 1; jend1(4) = 1
istart2(4) = 1; iend2(4) = ni(6); jstart2(4) = nj(6); jend2(4) = nj(6)
!--- Contact line 5, between tile 2 (NORTH) and tile 3 (SOUTH)
tile1(5) = 2; tile2(5) = 3
istart1(5) = 1; iend1(5) = ni(2); jstart1(5) = nj(2); jend1(5) = nj(2)
istart2(5) = 1; iend2(5) = ni(3); jstart2(5) = 1; jend2(5) = 1
!--- Contact line 6, between tile 2 (EAST) and tile 4 (SOUTH)
tile1(6) = 2; tile2(6) = 4
istart1(6) = ni(2); iend1(6) = ni(2); jstart1(6) = 1; jend1(6) = nj(2)
istart2(6) = ni(4); iend2(6) = 1; jstart2(6) = 1; jend2(6) = 1
!--- Contact line 7, between tile 2 (SOUTH) and tile 6 (EAST)
tile1(7) = 2; tile2(7) = 6
istart1(7) = 1; iend1(7) = ni(2); jstart1(7) = 1; jend1(7) = 1
istart2(7) = ni(6); iend2(7) = ni(6); jstart2(7) = nj(6); jend2(7) = 1
!--- Contact line 8, between tile 3 (EAST) and tile 4 (WEST)
tile1(8) = 3; tile2(8) = 4
istart1(8) = ni(3); iend1(8) = ni(3); jstart1(8) = 1; jend1(8) = nj(3)
istart2(8) = 1; iend2(8) = 1; jstart2(8) = 1; jend2(8) = nj(4)
!--- Contact line 9, between tile 3 (NORTH) and tile 5 (WEST)
tile1(9) = 3; tile2(9) = 5
istart1(9) = 1; iend1(9) = ni(3); jstart1(9) = nj(3); jend1(9) = nj(3)
istart2(9) = 1; iend2(9) = 1; jstart2(9) = nj(5); jend2(9) = 1
!--- Contact line 10, between tile 4 (NORTH) and tile 5 (SOUTH)
tile1(10) = 4; tile2(10) = 5
istart1(10) = 1; iend1(10) = ni(4); jstart1(10) = nj(4); jend1(10) = nj(4)
istart2(10) = 1; iend2(10) = ni(5); jstart2(10) = 1; jend2(10) = 1
!--- Contact line 11, between tile 4 (EAST) and tile 6 (SOUTH)
tile1(11) = 4; tile2(11) = 6
istart1(11) = ni(4); iend1(11) = ni(4); jstart1(11) = 1; jend1(11) = nj(4)
istart2(11) = ni(6); iend2(11) = 1; jstart2(11) = 1; jend2(11) = 1
!--- Contact line 12, between tile 5 (EAST) and tile 6 (WEST)
tile1(12) = 5; tile2(12) = 6
istart1(12) = ni(5); iend1(12) = ni(5); jstart1(12) = 1; jend1(12) = nj(5)
istart2(12) = 1; iend2(12) = 1; jstart2(12) = 1; jend2(12) = nj(6)
msize(1) = maxval(ni(:)/layout(1,:)) + whalo + ehalo + 1 ! make sure memory domain size is no smaller than
msize(2) = maxval(nj(:)/layout(2,:)) + shalo + nhalo + 1 ! data domain size
if(use_memsize_local) then
call mpp_define_mosaic(global_indices, layout, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, symmetry = .true., whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name = trim(type), memory_size = msize )
else
call mpp_define_mosaic(global_indices, layout, domain, ntiles, num_contact, tile1, tile2, &
istart1, iend1, jstart1, jend1, istart2, iend2, jstart2, jend2, &
pe_start, pe_end, symmetry = .true., whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name = trim(type) )
endif
return
end subroutine define_cubic_mosaic
!#######################################################################################
subroutine fill_regular_refinement_halo( data, data_all, ni, nj, tm, te, tse, ts, tsw, tw, tnw, tn, tne, ioff, joff )
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
real, dimension(:,:,:,:), intent(in) :: data_all
integer, dimension(:), intent(in) :: ni, nj
integer, intent(in) :: tm, te, tse, ts, tsw, tw, tnw, tn, tne
integer, intent(in) :: ioff, joff
if(te>0) data (ni(tm)+1+ioff:ni(tm)+ehalo+ioff, 1:nj(tm)+joff, :) = &
data_all(1+ioff:ehalo+ioff, 1:nj(te)+joff, :,te) ! east
if(ts>0) data (1:ni(tm)+ioff, 1-shalo:0, :) = &
data_all(1:ni(ts)+ioff, nj(ts)-shalo+1:nj(ts), :,ts) ! south
if(tw>0) data (1-whalo:0, 1:nj(tm)+joff, :) = &
data_all(ni(tw)-whalo+1:ni(tw), 1:nj(tw)+joff, :,tw) ! west
if(tn>0) data (1:ni(tm)+ioff, nj(tm)+1+joff:nj(tm)+nhalo+joff, :) = &
data_all(1:ni(tn)+ioff, 1+joff:nhalo+joff, :,tn) ! north
if(tse>0)data (ni(tm)+1+ioff:ni(tm)+ehalo+ioff, 1-shalo:0, :) = &
data_all(1+ioff:ehalo+ioff, nj(tse)-shalo+1:nj(tse), :,tse) ! southeast
if(tsw>0)data (1-whalo:0, 1-shalo:0, :) = &
data_all(ni(tsw)-whalo+1:ni(tsw), nj(tsw)-shalo+1:nj(tsw), :,tsw) ! southwest
if(tne>0)data (ni(tm)+1+ioff:ni(tm)+ehalo+ioff, nj(tm)+1+joff:nj(tm)+nhalo+joff, :) = &
data_all(1+ioff:ehalo+ioff, 1+joff:nhalo+joff, :,tnw) ! northeast
if(tnw>0)data (1-whalo:0, nj(tm)+1+joff:nj(tm)+nhalo+joff, :) = &
data_all(ni(tnw)-whalo+1:ni(tnw), 1+joff:nhalo+joff, :,tne) ! northwest
end subroutine fill_regular_refinement_halo
!##############################################################################
! this routine fill the halo points for the refined cubic grid. ioff and joff is used to distinguish
! T, C, E, or N-cell
subroutine fill_cubicgrid_refined_halo(data, data1_all, data2_all, ni, nj, tile, ioff, joff, sign1, sign2)
real, dimension(1-whalo:,1-shalo:,:), intent(inout) :: data
real, dimension(:,:,:,:), intent(in) :: data1_all, data2_all
integer, dimension(:), intent(in) :: ni, nj
integer, intent(in) :: tile, ioff, joff, sign1, sign2
integer :: lw, le, ls, ln
if(mod(tile,2) == 0) then ! tile 2, 4, 6
lw = tile - 1; le = tile + 2; ls = tile - 2; ln = tile + 1
if(le > 6 ) le = le - 6
if(ls < 1 ) ls = ls + 6
if(ln > 6 ) ln = ln - 6
if( nj(tile) == nj(lw) ) then
data(1-whalo:0, 1:nj(tile)+joff, :) = data1_all(ni(lw)-whalo+1:ni(lw), 1:nj(lw)+joff, :, lw) ! west
end if
if( nj(tile) == ni(le) ) then
do i = 1, ehalo
data(ni(tile)+i+ioff, 1:nj(tile)+joff, :) = sign1*data2_all(ni(le)+joff:1:-1, i+ioff, :, le) ! east
end do
end if
if(ni(tile) == nj(ls) ) then
do i = 1, shalo
data(1:ni(tile)+ioff, 1-i, :) = sign2*data2_all(ni(ls)-i+1, nj(ls)+ioff:1:-1, :, ls) ! south
end do
end if
if(ni(tile) == ni(ln) ) then
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
end if
else ! tile 1, 3, 5
lw = tile - 2; le = tile + 1; ls = tile - 1; ln = tile + 2
if(lw < 1 ) lw = lw + 6
if(ls < 1 ) ls = ls + 6
if(ln > 6 ) ln = ln - 6
if(nj(tile) == ni(lw) ) then
do i = 1, whalo
data(1-i, 1:nj(tile)+joff, :) = sign1*data2_all(ni(lw)+joff:1:-1, nj(lw)-i+1, :, lw) ! west
end do
end if
if(nj(tile) == nj(le) ) then
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
end if
if(ni(tile) == ni(ls) ) then
data(1:ni(tile)+ioff, 1-shalo:0, :) = data1_all(1:ni(ls)+ioff, nj(ls)-shalo+1:nj(ls), :, ls) ! south
end if
if(ni(tile) == nj(ln) ) then
do i = 1, nhalo
data(1:ni(tile)+ioff, nj(tile)+i+joff, :) = sign2*data2_all(i+joff, nj(ln)+ioff:1:-1, :, ln) ! north
end do
end if
end if
end subroutine fill_cubicgrid_refined_halo
!##################################################################################
subroutine test_subset_update( )
real, allocatable, dimension(:,:,:) :: x
type(domain2D) :: domain
real, allocatable :: global(:,:,:)
integer :: i, xhalo, yhalo
integer :: is, ie, js, je, isd, ied, jsd, jed
! integer :: pes9(9)=(/1,2,3,4,5,6,7,8,9/)
integer :: pes9(9)=(/0,2,4,10,12,14,20,22,24/)
integer :: ni, nj
if(mpp_npes() < 25) then
call mpp_error(FATAL,"test_mpp_domains: test_subset_update will&
& not be done when npes < 25")
return
endif
call mpp_declare_pelist(pes9)
if(any(mpp_pe()==pes9)) then
call mpp_set_current_pelist(pes9)
layout = (/3,3/)
ni = 3; nj =3
call mpp_define_domains((/1,ni,1,nj/), layout, domain, xhalo=1&
&, yhalo=1, xflags=CYCLIC_GLOBAL_DOMAIN, yflags&
&=CYCLIC_GLOBAL_DOMAIN, name='subset domain')
call mpp_get_compute_domain(domain, is, ie, js, je)
print*, "pe=", mpp_pe(), is, ie, js, je
allocate(global(0:ni+1,0:nj+1,nz) )
global = 0
do k = 1,nz
do j = 1,nj
do i = 1,ni
global(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
global(0, 1:nj,:) = global(ni, 1:nj,:)
global(ni+1, 1:nj,:) = global(1, 1:nj,:)
global(0:ni+1, 0, :) = global(0:ni+1, nj, :)
global(0:ni+1, nj+1,:) = global(0:ni+1, 1, :)
!set up x array
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
allocate( x (isd:ied,jsd:jed,nz) )
x = 0.
x (is:ie,js:je,:) = global(is:ie,js:je,:)
!full update
print *, 'here'
call mpp_update_domains( x, domain)
print *, 'finish'
call compare_checksums( x, global(isd:ied,jsd:jed,:), '9pe subset' )
deallocate(x, global)
call mpp_deallocate_domain(domain)
endif
call mpp_set_current_pelist()
end subroutine test_subset_update
!##################################################################################
subroutine test_halo_update( type )
character(len=*), intent(in) :: type
real, allocatable, dimension(:,:,:) :: x, x1, x2, x3, x4
real, allocatable, dimension(:,:,:) :: y, y1, y2, y3, y4
type(domain2D) :: domain
real, allocatable :: global1(:,:,:), global2(:,:,:), global(:,:,:)
logical, allocatable :: maskmap(:,:)
integer :: shift, i, xhalo, yhalo
logical :: is_symmetry, folded_south, folded_west, folded_east
integer :: is, ie, js, je, isd, ied, jsd, jed
! when testing maskmap option, nx*ny should be able to be divided by both npes and npes+1
if(type == 'Masked' .or. type == 'Masked symmetry') then
if(mod(nx*ny, npes) .NE. 0 .OR. mod(nx*ny, npes+1) .NE. 0 ) then
call mpp_error(NOTE,'TEST_MPP_DOMAINS: nx*ny can not be divided by both npes and npes+1, '//&
'Masked test_halo_update will not be tested')
return
end if
end if
if(type == 'Folded xy_halo' ) then
xhalo = max(whalo, ehalo); yhalo = max(shalo, nhalo)
allocate(global(1-xhalo:nx+xhalo,1-yhalo:ny+yhalo,nz) )
else
allocate(global(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz) )
end if
global = 0
do k = 1,nz
do j = 1,ny
do i = 1,nx
global(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
if(index(type, 'symmetry') == 0) then
is_symmetry = .false.
else
is_symmetry = .true.
end if
select case(type)
case( 'Simple', 'Simple symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type, symmetry = is_symmetry )
case( 'Cyclic', 'Cyclic symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=CYCLIC_GLOBAL_DOMAIN, &
name=type, symmetry = is_symmetry )
global(1-whalo:0, 1:ny,:) = global(nx-whalo+1:nx, 1:ny,:)
global(nx+1:nx+ehalo, 1:ny,:) = global(1:ehalo, 1:ny,:)
global(1-whalo:nx+ehalo, 1-shalo:0,:) = global(1-whalo:nx+ehalo, ny-shalo+1:ny,:)
global(1-whalo:nx+ehalo, ny+1:ny+nhalo,:) = global(1-whalo:nx+ehalo, 1:nhalo,:)
case( 'Folded-north', 'Folded-north symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, &
name=type, symmetry = is_symmetry )
call fill_folded_north_halo(global, 0, 0, 0, 0, 1)
case( 'Folded-south symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_SOUTH_EDGE, &
name=type, symmetry = is_symmetry )
call fill_folded_south_halo(global, 0, 0, 0, 0, 1)
case( 'Folded-west symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=FOLD_WEST_EDGE, yflags=CYCLIC_GLOBAL_DOMAIN, &
name=type, symmetry = is_symmetry )
call fill_folded_west_halo(global, 0, 0, 0, 0, 1)
case( 'Folded-east symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=FOLD_EAST_EDGE, yflags=CYCLIC_GLOBAL_DOMAIN, &
name=type, symmetry = is_symmetry )
call fill_folded_east_halo(global, 0, 0, 0, 0, 1)
case( 'Folded xy_halo' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, xhalo=xhalo, yhalo=yhalo, &
xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, name=type, symmetry = is_symmetry )
global(1-xhalo:0, 1:ny,:) = global(nx-xhalo+1:nx, 1:ny,:)
global(nx+1:nx+xhalo, 1:ny,:) = global(1:xhalo, 1:ny,:)
global(1-xhalo:nx+xhalo,ny+1:ny+yhalo,:) = global(nx+xhalo:1-xhalo:-1, ny:ny-yhalo+1:-1,:)
case( 'Masked', 'Masked symmetry' )
!with fold and cyclic, assign to npes+1 and mask out the top-rightdomain
call mpp_define_layout( (/1,nx,1,ny/), npes+1, layout )
allocate( maskmap(layout(1),layout(2)) )
maskmap(:,:) = .TRUE.; maskmap(layout(1),layout(2)) = .FALSE.
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, &
maskmap=maskmap, name=type, symmetry = is_symmetry )
deallocate(maskmap)
!we need to zero out the global data on the missing domain.
!this logic assumes top-right, in an even division
if( mod(nx,layout(1)).NE.0 .OR. mod(ny,layout(2)).NE.0 )call mpp_error( FATAL, &
'TEST_MPP_DOMAINS: test for masked domains needs (nx,ny) to divide evenly on npes+1 PEs.' )
global(nx-nx/layout(1)+1:nx,ny-ny/layout(2)+1:ny,:) = 0
call fill_folded_north_halo(global, 0, 0, 0, 0, 1)
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
!set up x array
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
allocate( x (isd:ied,jsd:jed,nz) )
allocate( x1(isd:ied,jsd:jed,nz) )
allocate( x2(isd:ied,jsd:jed,nz) )
allocate( x3(isd:ied,jsd:jed,nz) )
allocate( x4(isd:ied,jsd:jed,nz) )
x = 0.
x (is:ie,js:je,:) = global(is:ie,js:je,:)
x1 = x; x2 = x; x3 = x; x4 = x
!full update
id = mpp_clock_id( type, flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, domain )
call mpp_clock_end (id)
call compare_checksums( x, global(isd:ied,jsd:jed,:), type )
!partial update
id = mpp_clock_id( type//' partial', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x1, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x2, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x3, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x4, domain, NUPDATE+EUPDATE, complete=.true. )
call mpp_clock_end (id)
call compare_checksums( x1(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x1' )
call compare_checksums( x2(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x2' )
call compare_checksums( x3(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x3' )
call compare_checksums( x4(is:ied,js:jed,:), global(is:ied,js:jed,:), type//' partial x4' )
!--- test vector update for FOLDED and MASKED case.
if(type == 'Simple' .or. type == 'Simple symmetry' .or. type == 'Cyclic' .or. type == 'Cyclic symmetry') then
deallocate(x,x1,x2,x3,x4)
return
end if
!------------------------------------------------------------------
! vector update : BGRID_NE
!------------------------------------------------------------------
shift = 0
if(is_symmetry) then
shift = 1
deallocate(global)
allocate(global(1-whalo:nx+ehalo+shift,1-shalo:ny+nhalo+shift,nz) )
global = 0.0
do k = 1,nz
do j = 1,ny+1
do i = 1,nx+1
global(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
if(type == 'Masked symmetry') then
global(nx-nx/layout(1)+1:nx+1,ny-ny/layout(2)+1:ny+1,:) = 0
endif
deallocate(x, x1, x2, x3, x4)
allocate( x (isd:ied+1,jsd:jed+1,nz) )
allocate( x1(isd:ied+1,jsd:jed+1,nz) )
allocate( x2(isd:ied+1,jsd:jed+1,nz) )
allocate( x3(isd:ied+1,jsd:jed+1,nz) )
allocate( x4(isd:ied+1,jsd:jed+1,nz) )
endif
folded_south = .false.
folded_west = .false.
folded_east = .false.
select case (type)
case ('Folded-north', 'Masked')
!fill in folded north edge, cyclic east and west edge
call fill_folded_north_halo(global, 1, 1, 0, 0, -1)
case ('Folded xy_halo')
!fill in folded north edge, cyclic east and west edge
global(1-xhalo:0, 1:ny,:) = global(nx-xhalo+1:nx, 1:ny,:)
global(nx+1:nx+xhalo, 1:ny,:) = global(1:xhalo, 1:ny,:)
global(1-xhalo:nx+xhalo-1,ny+1:ny+yhalo,:) = -global(nx+xhalo-1:1-xhalo:-1,ny-1:ny-yhalo:-1,:)
global(nx+xhalo, ny+1:ny+yhalo,:) = -global(nx-xhalo, ny-1:ny-yhalo:-1,:)
case ('Folded-north symmetry', 'Masked symmetry' )
call fill_folded_north_halo(global, 1, 1, 1, 1, -1)
case ('Folded-south symmetry' )
folded_south = .true.
call fill_folded_south_halo(global, 1, 1, 1, 1, -1)
case ('Folded-west symmetry' )
folded_west = .true.
call fill_folded_west_halo(global, 1, 1, 1, 1, -1)
case ('Folded-east symmetry' )
folded_east = .true.
call fill_folded_east_halo(global, 1, 1, 1, 1, -1)
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
x = 0.
x(is:ie+shift,js:je+shift,:) = global(is:ie+shift,js:je+shift,:)
!set up y array
allocate( y (isd:ied+shift,jsd:jed+shift,nz) )
allocate( y1(isd:ied+shift,jsd:jed+shift,nz) )
allocate( y2(isd:ied+shift,jsd:jed+shift,nz) )
allocate( y3(isd:ied+shift,jsd:jed+shift,nz) )
allocate( y4(isd:ied+shift,jsd:jed+shift,nz) )
y = x; x1 = x; x2 = x; x3 = x; x4 = x
y = x; y1 = x; y2 = x; y3 = x; y4 = x
id = mpp_clock_id( type//' vector BGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, y, domain, gridtype=BGRID_NE)
call mpp_update_domains( x1, y1, domain, gridtype=BGRID_NE, complete=.false. )
call mpp_update_domains( x2, y2, domain, gridtype=BGRID_NE, complete=.false. )
call mpp_update_domains( x3, y3, domain, gridtype=BGRID_NE, complete=.false. )
call mpp_update_domains( x4, y4, domain, gridtype=BGRID_NE, complete=.true. )
call mpp_clock_end (id)
!redundant points must be equal and opposite
if(folded_south) then
global(nx/2+shift, 1,:) = 0. !pole points must have 0 velocity
global(nx+shift , 1,:) = 0. !pole points must have 0 velocity
global(nx/2+1+shift:nx-1+shift, 1,:) = -global(nx/2-1+shift:1+shift:-1, 1,:)
global(1-whalo:shift, 1,:) = -global(nx-whalo+1:nx+shift, 1,:)
global(nx+1+shift:nx+ehalo+shift, 1,:) = -global(1+shift:ehalo+shift, 1,:)
!--- the following will fix the +0/-0 problem on altix
if(shalo >0) global(shift,1,:) = 0. !pole points must have 0 velocity
else if(folded_west) then
global(1, ny/2+shift, :) = 0. !pole points must have 0 velocity
global(1, ny+shift, :) = 0. !pole points must have 0 velocity
global(1, ny/2+1+shift:ny-1+shift, :) = -global(1, ny/2-1+shift:1+shift:-1, :)
global(1, 1-shalo:shift, :) = -global(1, ny-shalo+1:ny+shift, :)
global(1, ny+1+shift:ny+nhalo+shift, :) = -global(1, 1+shift:nhalo+shift, :)
!--- the following will fix the +0/-0 problem on altix
if(whalo>0) global(1, shift, :) = 0. !pole points must have 0 velocity
else if(folded_east) then
global(nx+shift, ny/2+shift, :) = 0. !pole points must have 0 velocity
global(nx+shift, ny+shift, :) = 0. !pole points must have 0 velocity
global(nx+shift, ny/2+1+shift:ny-1+shift, :) = -global(nx+shift, ny/2-1+shift:1+shift:-1, :)
global(nx+shift, 1-shalo:shift, :) = -global(nx+shift, ny-shalo+1:ny+shift, :)
global(nx+shift, ny+1+shift:ny+nhalo+shift, :) = -global(nx+shift, 1+shift:nhalo+shift, :)
if(ehalo >0) global(nx+shift, shift, :) = 0. !pole points must have 0 velocity
else
global(nx/2+shift, ny+shift,:) = 0. !pole points must have 0 velocity
global(nx+shift , ny+shift,:) = 0. !pole points must have 0 velocity
global(nx/2+1+shift:nx-1+shift, ny+shift,:) = -global(nx/2-1+shift:1+shift:-1, ny+shift,:)
if(type == 'Folded xy_halo') then
global(1-xhalo:shift, ny+shift,:) = -global(nx-xhalo+1:nx+shift, ny+shift,:)
global(nx+1+shift:nx+xhalo+shift, ny+shift,:) = -global(1+shift:xhalo+shift, ny+shift,:)
else
global(1-whalo:shift, ny+shift,:) = -global(nx-whalo+1:nx+shift, ny+shift,:)
global(nx+1+shift:nx+ehalo+shift, ny+shift,:) = -global(1+shift:ehalo+shift, ny+shift,:)
end if
!--- the following will fix the +0/-0 problem on altix
if(nhalo >0) global(shift,ny+shift,:) = 0. !pole points must have 0 velocity
endif
call compare_checksums( x, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X' )
call compare_checksums( y, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y' )
call compare_checksums( x1, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X1' )
call compare_checksums( x2, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X2' )
call compare_checksums( x3, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X3' )
call compare_checksums( x4, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE X4' )
call compare_checksums( y1, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y1' )
call compare_checksums( y2, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y2' )
call compare_checksums( y3, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y3' )
call compare_checksums( y4, global(isd:ied+shift,jsd:jed+shift,:), type//' BGRID_NE Y4' )
deallocate(global, x, x1, x2, x3, x4, y, y1, y2, y3, y4)
!------------------------------------------------------------------
! vector update : CGRID_NE
!------------------------------------------------------------------
!--- global1 is x-component and global2 is y-component
if(type == 'Folded xy_halo') then
allocate(global1(1-xhalo:nx+xhalo, 1-yhalo:ny+yhalo, nz))
allocate(global2(1-xhalo:nx+xhalo, 1-yhalo:ny+yhalo, nz))
else
allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz))
allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz))
end if
allocate(x (isd:ied+shift,jsd:jed,nz), y (isd:ied,jsd:jed+shift,nz) )
allocate(x1(isd:ied+shift,jsd:jed,nz), y1(isd:ied,jsd:jed+shift,nz) )
allocate(x2(isd:ied+shift,jsd:jed,nz), y2(isd:ied,jsd:jed+shift,nz) )
allocate(x3(isd:ied+shift,jsd:jed,nz), y3(isd:ied,jsd:jed+shift,nz) )
allocate(x4(isd:ied+shift,jsd:jed,nz), y4(isd:ied,jsd:jed+shift,nz) )
global1 = 0.0
global2 = 0.0
do k = 1,nz
do j = 1,ny
do i = 1,nx+shift
global1(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
do j = 1,ny+shift
do i = 1,nx
global2(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
if(type == 'Masked' .or. type == 'Masked symmetry') then
global1(nx-nx/layout(1)+1:nx+shift,ny-ny/layout(2)+1:ny,:) = 0
global2(nx-nx/layout(1)+1:nx,ny-ny/layout(2)+1:ny+shift,:) = 0
end if
select case (type)
case ('Folded-north', 'Masked')
!fill in folded north edge, cyclic east and west edge
call fill_folded_north_halo(global1, 1, 0, 0, 0, -1)
call fill_folded_north_halo(global2, 0, 1, 0, 0, -1)
case ('Folded xy_halo')
global1(1-xhalo:0, 1:ny,:) = global1(nx-xhalo+1:nx, 1:ny,:)
global1(nx+1:nx+xhalo, 1:ny,:) = global1(1:xhalo, 1:ny,:)
global2(1-xhalo:0, 1:ny,:) = global2(nx-xhalo+1:nx, 1:ny,:)
global2(nx+1:nx+xhalo, 1:ny,:) = global2(1:xhalo, 1:ny,:)
global1(1-xhalo:nx+xhalo-1, ny+1:ny+yhalo,:) = -global1(nx+xhalo-1:1-xhalo:-1, ny:ny-yhalo+1:-1,:)
global1(nx+xhalo, ny+1:ny+yhalo,:) = -global1(nx-xhalo, ny:ny-yhalo+1:-1,:)
global2(1-xhalo:nx+xhalo, ny+1:ny+yhalo,:) = -global2(nx+xhalo:1-xhalo:-1, ny-1:ny-yhalo:-1,:)
case ('Folded-north symmetry')
call fill_folded_north_halo(global1, 1, 0, 1, 0, -1)
call fill_folded_north_halo(global2, 0, 1, 0, 1, -1)
case ('Folded-south symmetry')
call fill_folded_south_halo(global1, 1, 0, 1, 0, -1)
call fill_folded_south_halo(global2, 0, 1, 0, 1, -1)
case ('Folded-west symmetry')
call fill_folded_west_halo(global1, 1, 0, 1, 0, -1)
call fill_folded_west_halo(global2, 0, 1, 0, 1, -1)
case ('Folded-east symmetry')
call fill_folded_east_halo(global1, 1, 0, 1, 0, -1)
call fill_folded_east_halo(global2, 0, 1, 0, 1, -1)
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
x = 0.; y = 0.
x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
x1 = x; x2 = x; x3 = x; x4 = x
y1 = y; y2 = y; y3 = y; y4 = y
id = mpp_clock_id( type//' vector CGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, y, domain, gridtype=CGRID_NE)
call mpp_update_domains( x1, y1, domain, gridtype=CGRID_NE, complete=.false. )
call mpp_update_domains( x2, y2, domain, gridtype=CGRID_NE, complete=.false. )
call mpp_update_domains( x3, y3, domain, gridtype=CGRID_NE, complete=.false. )
call mpp_update_domains( x4, y4, domain, gridtype=CGRID_NE, complete=.true. )
call mpp_clock_end (id)
!redundant points must be equal and opposite
if(folded_south) then
global2(nx/2+1:nx, 1,:) = -global2(nx/2:1:-1, 1,:)
global2(1-whalo:0, 1,:) = -global2(nx-whalo+1:nx, 1, :)
global2(nx+1:nx+ehalo, 1,:) = -global2(1:ehalo, 1, :)
else if(folded_west) then
global1(1, ny/2+1:ny, :) = -global1(1, ny/2:1:-1, :)
global1(1, 1-shalo:0, :) = -global1(1, ny-shalo+1:ny, :)
global1(1, ny+1:ny+nhalo, :) = -global1(1, 1:nhalo, :)
else if(folded_east) then
global1(nx+shift, ny/2+1:ny, :) = -global1(nx+shift, ny/2:1:-1, :)
global1(nx+shift, 1-shalo:0, :) = -global1(nx+shift, ny-shalo+1:ny, :)
global1(nx+shift, ny+1:ny+nhalo, :) = -global1(nx+shift, 1:nhalo, :)
else
global2(nx/2+1:nx, ny+shift,:) = -global2(nx/2:1:-1, ny+shift,:)
if(type == 'Folded xy_halo') then
global2(1-xhalo:0, ny+shift,:) = -global2(nx-xhalo+1:nx, ny+shift,:)
global2(nx+1:nx+xhalo, ny+shift,:) = -global2(1:xhalo, ny+shift,:)
else
global2(1-whalo:0, ny+shift,:) = -global2(nx-whalo+1:nx, ny+shift,:)
global2(nx+1:nx+ehalo, ny+shift,:) = -global2(1:ehalo, ny+shift,:)
end if
endif
call compare_checksums( x, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X' )
call compare_checksums( y, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y' )
call compare_checksums( x1, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X1' )
call compare_checksums( x2, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X2' )
call compare_checksums( x3, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X3' )
call compare_checksums( x4, global1(isd:ied+shift,jsd:jed, :), type//' CGRID_NE X4' )
call compare_checksums( y1, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y1' )
call compare_checksums( y2, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y2' )
call compare_checksums( y3, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y3' )
call compare_checksums( y4, global2(isd:ied, jsd:jed+shift,:), type//' CGRID_NE Y4' )
deallocate(global1, global2, x, x1, x2, x3, x4, y, y1, y2, y3, y4)
end subroutine test_halo_update
subroutine set_corner_zero( data, isd, ied, jsd, jed, isc, iec, jsc, jec )
integer, intent(in) :: isd, ied, jsd, jed
integer, intent(in) :: isc, iec, jsc, jec
real, dimension(isd:,jsd:,:), intent(inout) :: data
data (isd :isc-1, jsd :jsc-1,:) = 0
data (isd :isc-1, jec+1:jed, :) = 0
data (iec+1:ied , jsd :jsc-1,:) = 0
data (iec+1:ied , jec+1:jed, :) = 0
end subroutine set_corner_zero
!##################################################################################
subroutine test_update_edge( type )
character(len=*), intent(in) :: type
real, allocatable, dimension(:,:,:) :: x, x2, a
real, allocatable, dimension(:,:,:) :: y, y2, b
type(domain2D) :: domain
real, allocatable :: global1(:,:,:), global2(:,:,:), global(:,:,:)
logical, allocatable :: maskmap(:,:)
integer :: shift, i, xhalo, yhalo
logical :: is_symmetry, folded_south, folded_west, folded_east
integer :: is, ie, js, je, isd, ied, jsd, jed
integer :: id_update
allocate(global(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz) )
global = 0
do k = 1,nz
do j = 1,ny
do i = 1,nx
global(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
if(index(type, 'symmetry') == 0) then
is_symmetry = .false.
else
is_symmetry = .true.
end if
select case(type)
case( 'Cyclic' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=CYCLIC_GLOBAL_DOMAIN, &
name=type, symmetry = is_symmetry )
global(1-whalo:0, 1:ny,:) = global(nx-whalo+1:nx, 1:ny,:)
global(nx+1:nx+ehalo, 1:ny,:) = global(1:ehalo, 1:ny,:)
global(1:nx, 1-shalo:0,:) = global(1:nx, ny-shalo+1:ny,:)
global(1:nx, ny+1:ny+nhalo,:) = global(1:nx, 1:nhalo, :)
case( 'Folded-north', 'Folded-north symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, &
name=type, symmetry = is_symmetry )
call fill_folded_north_halo(global, 0, 0, 0, 0, 1)
!--- set the corner to 0
call set_corner_zero(global, 1-whalo, nx+ehalo, 1-shalo, ny+ehalo, 1, nx, 1, ny)
case default
call mpp_error( FATAL, 'test_update_edge: no such test: '//type )
end select
!set up x array
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
allocate( x (isd:ied,jsd:jed,nz) )
allocate( a (isd:ied,jsd:jed,nz) )
allocate( x2 (isd:ied,jsd:jed,nz) )
x2 (isd:ied,jsd:jed,:) = global(isd:ied,jsd:jed,:)
call set_corner_zero(x2, isd, ied, jsd, jed, is, ie, js, je)
x = 0.
x (is:ie,js:je,:) = global(is:ie,js:je,:)
!full update
id = mpp_clock_id( type, flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, domain, flags=EDGEUPDATE)
call mpp_clock_end (id)
call compare_checksums( x, x2, type )
deallocate(x2)
a = 0
a(is:ie,js:je,:) = global(is:ie,js:je,:)
id_update = mpp_start_update_domains( a, domain, flags=EDGEUPDATE)
call mpp_complete_update_domains(id_update, a, domain, flags=EDGEUPDATE)
call compare_checksums( x, a, type//" nonblock")
!--- test vector update for FOLDED and MASKED case.
if( type == 'Cyclic' ) then
deallocate(global, x, a)
return
end if
!------------------------------------------------------------------
! vector update : BGRID_NE
!------------------------------------------------------------------
shift = 0
if(is_symmetry) then
shift = 1
deallocate(global)
allocate(global(1-whalo:nx+ehalo+shift,1-shalo:ny+nhalo+shift,nz) )
global = 0.0
do k = 1,nz
do j = 1,ny+1
do i = 1,nx+1
global(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
deallocate(x,a)
allocate( x (isd:ied+1,jsd:jed+1,nz) )
allocate( a (isd:ied+1,jsd:jed+1,nz) )
endif
select case (type)
case ('Folded-north')
!fill in folded north edge, cyclic east and west edge
call fill_folded_north_halo(global, 1, 1, 0, 0, -1)
case ('Folded-north symmetry')
call fill_folded_north_halo(global, 1, 1, 1, 1, -1)
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
x = 0.
a = 0.
x(is:ie+shift,js:je+shift,:) = global(is:ie+shift,js:je+shift,:)
a(is:ie+shift,js:je+shift,:) = global(is:ie+shift,js:je+shift,:)
!set up y array
allocate( y (isd:ied+shift,jsd:jed+shift,nz) )
allocate( b (isd:ied+shift,jsd:jed+shift,nz) )
b = x
y = x
id = mpp_clock_id( type//' vector BGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, y, domain, flags=EDGEUPDATE, gridtype=BGRID_NE)
call mpp_clock_end (id)
!--nonblocking update
id_update = mpp_start_update_domains(a,b, domain, flags=EDGEUPDATE, gridtype=BGRID_NE)
call mpp_complete_update_domains(id_update, a,b, domain, flags=EDGEUPDATE, gridtype=BGRID_NE)
!redundant points must be equal and opposite
global(nx/2+shift, ny+shift,:) = 0. !pole points must have 0 velocity
global(nx+shift , ny+shift,:) = 0. !pole points must have 0 velocity
global(nx/2+1+shift:nx-1+shift, ny+shift,:) = -global(nx/2-1+shift:1+shift:-1, ny+shift,:)
global(1-whalo:shift, ny+shift,:) = -global(nx-whalo+1:nx+shift, ny+shift,:)
global(nx+1+shift:nx+ehalo+shift, ny+shift,:) = -global(1+shift:ehalo+shift, ny+shift,:)
!--- the following will fix the +0/-0 problem on altix
if(nhalo >0) global(shift,ny+shift,:) = 0. !pole points must have 0 velocity
allocate( x2 (isd:ied+shift,jsd:jed+shift,nz) )
x2 (isd:ied+shift,jsd:jed+shift,:) = global(isd:ied+shift,jsd:jed+shift,:)
call set_corner_zero(x2, isd, ied+shift, jsd, jed+shift, is, ie+shift, js, je+shift)
call compare_checksums( x, x2, type//' BGRID_NE X' )
call compare_checksums( y, x2, type//' BGRID_NE Y' )
call compare_checksums( a, x2, type//' BGRID_NE X nonblock' )
call compare_checksums( b, x2, type//' BGRID_NE Y nonblock' )
deallocate(global, x, y, x2, a, b)
!------------------------------------------------------------------
! vector update : CGRID_NE
!------------------------------------------------------------------
!--- global1 is x-component and global2 is y-component
allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz))
allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz))
allocate(x (isd:ied+shift,jsd:jed,nz), y (isd:ied,jsd:jed+shift,nz) )
allocate(x2 (isd:ied+shift,jsd:jed,nz), y2 (isd:ied,jsd:jed+shift,nz) )
allocate(a (isd:ied+shift,jsd:jed,nz), b (isd:ied,jsd:jed+shift,nz) )
global1 = 0.0
global2 = 0.0
do k = 1,nz
do j = 1,ny
do i = 1,nx+shift
global1(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
do j = 1,ny+shift
do i = 1,nx
global2(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
select case (type)
case ('Folded-north')
!fill in folded north edge, cyclic east and west edge
call fill_folded_north_halo(global1, 1, 0, 0, 0, -1)
call fill_folded_north_halo(global2, 0, 1, 0, 0, -1)
!--- set the corner to 0
global1(1-whalo:0, 1-shalo:0, :) = 0
global1(1-whalo:0, ny+1:ny+nhalo, :) = 0
global1(nx+1:nx+ehalo, 1-shalo:0, :) = 0
global1(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
global2(1-whalo:0, 1-shalo:0, :) = 0
global2(1-whalo:0, ny+1:ny+nhalo, :) = 0
global2(nx+1:nx+ehalo, 1-shalo:0, :) = 0
global2(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
case ('Folded-north symmetry')
call fill_folded_north_halo(global1, 1, 0, 1, 0, -1)
call fill_folded_north_halo(global2, 0, 1, 0, 1, -1)
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
x = 0.; y = 0.
x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
a = 0.; b = 0.
a(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
b(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
id = mpp_clock_id( type//' vector CGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, y, domain, flags=EDGEUPDATE, gridtype=CGRID_NE)
call mpp_clock_end (id)
!--nonblocking
id_update = mpp_start_update_domains( a, b, domain, flags=EDGEUPDATE, gridtype=CGRID_NE)
call mpp_complete_update_domains(id_update, a, b, domain, flags=EDGEUPDATE, gridtype=CGRID_NE)
!redundant points must be equal and opposite
global2(nx/2+1:nx, ny+shift,:) = -global2(nx/2:1:-1, ny+shift,:)
global2(1-whalo:0, ny+shift,:) = -global2(nx-whalo+1:nx, ny+shift,:)
global2(nx+1:nx+ehalo, ny+shift,:) = -global2(1:ehalo, ny+shift,:)
x2(isd:ied+shift,jsd:jed,:) = global1(isd:ied+shift,jsd:jed,:)
y2(isd:ied,jsd:jed+shift,:) = global2(isd:ied,jsd:jed+shift,:)
call set_corner_zero(x2, isd, ied+shift, jsd, jed, is, ie+shift, js, je)
call set_corner_zero(y2, isd, ied, jsd, jed+shift, is, ie, js, je+shift)
call compare_checksums( x, x2, type//' CGRID_NE X' )
call compare_checksums( y, y2, type//' CGRID_NE Y' )
call compare_checksums( a, x2, type//' CGRID_NE X nonblock' )
call compare_checksums( b, y2, type//' CGRID_NE Y nonblock' )
deallocate(global1, global2, x, y, x2, y2, a, b)
end subroutine test_update_edge
!##################################################################################
subroutine test_update_nonsym_edge( type )
character(len=*), intent(in) :: type
real, allocatable, dimension(:,:,:) :: x, x2
real, allocatable, dimension(:,:,:) :: y, y2
type(domain2D) :: domain
real, allocatable :: global1(:,:,:), global2(:,:,:)
integer :: shift, i, xhalo, yhalo
logical :: is_symmetry
integer :: is, ie, js, je, isd, ied, jsd, jed
type(mpp_group_update_type) :: group_update
if(index(type, 'symmetry') == 0) then
shift = 0
is_symmetry = .false.
else
shift = 1
is_symmetry = .true.
end if
select case(type)
case( 'Folded-north', 'Folded-north symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE, &
name=type, symmetry = is_symmetry )
case default
call mpp_error( FATAL, 'test_update_edge: no such test: '//type )
end select
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
!------------------------------------------------------------------
! vector update : CGRID_NE
!------------------------------------------------------------------
!--- global1 is x-component and global2 is y-component
allocate(global1(1-whalo:nx+ehalo+shift, 1-shalo:ny+nhalo, nz))
allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo+shift, nz))
allocate(x (isd:ied+shift,jsd:jed,nz), y (isd:ied,jsd:jed+shift,nz) )
allocate(x2 (isd:ied+shift,jsd:jed,nz), y2 (isd:ied,jsd:jed+shift,nz) )
global1 = 0.0
global2 = 0.0
do k = 1,nz
do j = 1,ny
do i = 1,nx+shift
global1(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
do j = 1,ny+shift
do i = 1,nx
global2(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
select case (type)
case ('Folded-north')
!fill in folded north edge, cyclic east and west edge
call fill_folded_north_halo(global1, 1, 0, 0, 0, -1)
call fill_folded_north_halo(global2, 0, 1, 0, 0, -1)
!--- set the corner to 0
global1(1-whalo:0, 1-shalo:0, :) = 0
global1(1-whalo:0, ny+1:ny+nhalo, :) = 0
global1(nx+1:nx+ehalo, 1-shalo:0, :) = 0
global1(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
global2(1-whalo:0, 1-shalo:0, :) = 0
global2(1-whalo:0, ny+1:ny+nhalo, :) = 0
global2(nx+1:nx+ehalo, 1-shalo:0, :) = 0
global2(nx+1:nx+ehalo, ny+1:ny+nhalo, :) = 0
case ('Folded-north symmetry')
call fill_folded_north_halo(global1, 1, 0, 1, 0, -1)
call fill_folded_north_halo(global2, 0, 1, 0, 1, -1)
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
!redundant points must be equal and opposite
global2(nx/2+1:nx, ny+shift,:) = -global2(nx/2:1:-1, ny+shift,:)
global2(1-whalo:0, ny+shift,:) = -global2(nx-whalo+1:nx, ny+shift,:)
! global2(nx+1:nx+ehalo, ny+shift,:) = -global2(1:ehalo, ny+shift,:)
x2 = 0.0; y2 = 0.0
if(is_symmetry) then
x2(isd:ie+shift,jsd:je,:) = global1(isd:ie+shift,jsd:je,:)
y2(isd:ie,jsd:je+shift,:) = global2(isd:ie,jsd:je+shift,:)
else
x2(isd:ie+shift,js:je,:) = global1(isd:ie+shift,js:je,:)
y2(is:ie,jsd:je+shift,:) = global2(is:ie,jsd:je+shift,:)
endif
x = 0.; y = 0.
x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
call mpp_create_group_update(group_update, x, y, domain, gridtype=CGRID_NE, &
flags=WUPDATE+SUPDATE+NONSYMEDGEUPDATE, whalo=1, ehalo=1, shalo=1, nhalo=1)
call mpp_do_group_update(group_update, domain, x(is,js,1))
call compare_checksums( x, x2, type//' CGRID_NE X' )
call compare_checksums( y, y2, type//' CGRID_NE Y' )
call mpp_sync()
x = 0.; y = 0.
x(is:ie+shift,js:je, :) = global1(is:ie+shift,js:je, :)
y(is:ie ,js:je+shift,:) = global2(is:ie, js:je+shift,:)
call mpp_start_group_update(group_update, domain, x(is,js,1))
call mpp_complete_group_update(group_update, domain, x(is,js,1))
call compare_checksums( x, x2, type//' CGRID_NE X nonblock' )
call compare_checksums( y, y2, type//' CGRID_NE Y nonblock' )
deallocate(global1, global2, x, y, x2, y2)
call mpp_clear_group_update(group_update)
end subroutine test_update_nonsym_edge
!##################################################################################
subroutine test_cyclic_offset( type )
character(len=*), intent(in) :: type
real, allocatable, dimension(:,:,:) :: x, x1, x2, x3, x4
real, allocatable, dimension(:,:,:) :: y, y1, y2, y3, y4
type(domain2D) :: domain
real, allocatable :: global1(:,:,:), global2(:,:,:), global(:,:,:)
integer :: i, j, k, jj, ii
integer :: is, ie, js, je, isd, ied, jsd, jed
character(len=128) :: type2
allocate(global(1-whalo:nx+ehalo,1-shalo:ny+nhalo,nz))
global = 0
do k = 1,nz
do j = 1,ny
do i = 1,nx
global(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
end do
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
select case(type)
case( 'x_cyclic_offset' )
write(type2, *)type, ' x_cyclic=', x_cyclic_offset
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, &
name=type, x_cyclic_offset = x_cyclic_offset)
do j = 1, ny
jj = mod(j + x_cyclic_offset + ny, ny)
if(jj==0) jj = ny
global(1-whalo:0,j,:) = global(nx-whalo+1:nx, jj,:) ! West
jj = mod(j - x_cyclic_offset + ny, ny)
if(jj==0) jj = ny
global(nx+1:nx+ehalo,j,:) = global(1:ehalo,jj,:) ! East
end do
case( 'y_cyclic_offset' )
write(type2, *)type, ' y_cyclic = ', y_cyclic_offset
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, yflags=CYCLIC_GLOBAL_DOMAIN, &
name=type, y_cyclic_offset = y_cyclic_offset)
do i = 1, nx
ii = mod(i + y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! South
ii = mod(i - y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! NORTH
end do
case( 'torus_x_offset' )
write(type2, *)type, ' x_cyclic = ', x_cyclic_offset
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, &
yflags=CYCLIC_GLOBAL_DOMAIN, name=type, &
x_cyclic_offset = x_cyclic_offset)
do j = 1, ny
jj = mod(j + x_cyclic_offset + ny, ny)
if(jj==0) jj = ny
global(1-whalo:0,j,:) = global(nx-whalo+1:nx, jj,:) ! West
jj = mod(j - x_cyclic_offset + ny, ny)
if(jj==0) jj = ny
global(nx+1:nx+ehalo,j,:) = global(1:ehalo,jj,:) ! East
end do
global(1:nx,1-shalo:0,:) = global(1:nx, ny-shalo+1:ny,:) ! South
global(1:nx,ny+1:ny+nhalo,:) = global(1:nx, 1:nhalo, :) ! NORTH
do j = 1, shalo
jj = mod(ny-j+1 + x_cyclic_offset + ny, ny)
if(jj==0) jj = ny
global(1-whalo:0, 1-j,:) = global(nx-whalo+1:nx, jj, :) ! Southwest
jj = mod(ny-j+1-x_cyclic_offset+ny,ny)
if(jj==0) jj = ny
global(nx+1:nx+ehalo, 1-j,:) = global(1:ehalo, jj, :) ! Southeast
end do
do j = 1, nhalo
jj = mod(j + x_cyclic_offset + ny, ny)
if(jj==0) jj = ny
global(1-whalo:0, ny+j,:) = global(nx-whalo+1:nx, jj, :) ! northwest
jj = mod(j - x_cyclic_offset+ny,ny)
if(jj==0) jj = ny
global(nx+1:nx+ehalo, ny+j,:) = global(1:ehalo, jj, :) ! northeast
end do
case( 'torus_y_offset' )
write(type2, *)type, ' y_cyclic = ', y_cyclic_offset
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, &
yflags=CYCLIC_GLOBAL_DOMAIN, name=type, &
y_cyclic_offset = y_cyclic_offset)
do i = 1, nx
ii = mod(i + y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! South
ii = mod(i - y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! NORTH
end do
global(1-whalo:0,1:ny,:) = global(nx-whalo+1:nx, 1:ny,:) ! West
global(nx+1:nx+ehalo,1:ny,:) = global(1:ehalo, 1:ny, :) ! East
do i = 1, whalo
ii = mod(nx-i+1 + y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(1-i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! southwest
ii = mod(nx-i+1 - y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(1-i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! northwest
end do
do i = 1, ehalo
ii = mod(i + y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(nx+i, 1-shalo:0,:) = global(ii, ny-shalo+1:ny,:) ! southeast
ii = mod(i - y_cyclic_offset + nx, nx)
if(ii==0) ii = nx
global(nx+i,ny+1:ny+nhalo,:) = global(ii,1:nhalo,:) ! northeast
end do
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
!set up x array
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
allocate( x (isd:ied,jsd:jed,nz) )
allocate( x1(isd:ied,jsd:jed,nz) )
allocate( x2(isd:ied,jsd:jed,nz) )
allocate( x3(isd:ied,jsd:jed,nz) )
allocate( x4(isd:ied,jsd:jed,nz) )
x = 0.
x (is:ie,js:je,:) = global(is:ie,js:je,:)
x1 = x; x2 = x; x3 = x; x4 = x
!full update
id = mpp_clock_id( type, flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, domain )
call mpp_clock_end (id)
call compare_checksums( x, global(isd:ied,jsd:jed,:), trim(type2) )
!partial update
id = mpp_clock_id( type//' partial', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x1, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x2, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x3, domain, NUPDATE+EUPDATE, complete=.false. )
call mpp_update_domains( x4, domain, NUPDATE+EUPDATE, complete=.true. )
call mpp_clock_end (id)
call compare_checksums( x1(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x1' )
call compare_checksums( x2(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x2' )
call compare_checksums( x3(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x3' )
call compare_checksums( x4(is:ied,js:jed,:), global(is:ied,js:jed,:), trim(type2)//' partial x4' )
!--- test vector update for FOLDED and MASKED case.
deallocate(x,x1,x2,x3,x4)
!------------------------------------------------------------------
! vector update : BGRID_NE
!------------------------------------------------------------------
!--- global1 is x-component and global2 is y-component
allocate(global1(1-whalo:nx+ehalo, 1-shalo:ny+nhalo, nz))
allocate(global2(1-whalo:nx+ehalo, 1-shalo:ny+nhalo, nz))
allocate(x (isd:ied,jsd:jed,nz), y (isd:ied,jsd:jed,nz) )
allocate(x1(isd:ied,jsd:jed,nz), y1(isd:ied,jsd:jed,nz) )
allocate(x2(isd:ied,jsd:jed,nz), y2(isd:ied,jsd:jed,nz) )
allocate(x3(isd:ied,jsd:jed,nz), y3(isd:ied,jsd:jed,nz) )
allocate(x4(isd:ied,jsd:jed,nz), y4(isd:ied,jsd:jed,nz) )
where (global >0)
global1 = 1000 + global
global2 = 2000 + global
elsewhere
global1 = 0
global2 = 0
end where
x = 0.; y = 0
x(is:ie,js:je,:) = global1(is:ie,js:je,:)
y(is:ie,js:je,:) = global2(is:ie,js:je,:)
x1 = x; x2 = x; x3 = x; x4 = x
y1 = y; y2 = y; y3 = y; y4 = y
id = mpp_clock_id( type//' vector BGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, y, domain, gridtype=BGRID_NE)
call mpp_update_domains( x1, y1, domain, gridtype=BGRID_NE, complete=.false. )
call mpp_update_domains( x2, y2, domain, gridtype=BGRID_NE, complete=.false. )
call mpp_update_domains( x3, y3, domain, gridtype=BGRID_NE, complete=.false. )
call mpp_update_domains( x4, y4, domain, gridtype=BGRID_NE, complete=.true. )
call mpp_clock_end (id)
!redundant points must be equal and opposite
call compare_checksums( x, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X' )
call compare_checksums( y, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y' )
call compare_checksums( x1, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X1' )
call compare_checksums( x2, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X2' )
call compare_checksums( x3, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X3' )
call compare_checksums( x4, global1(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE X4' )
call compare_checksums( y1, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y1' )
call compare_checksums( y2, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y2' )
call compare_checksums( y3, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y3' )
call compare_checksums( y4, global2(isd:ied,jsd:jed,:), trim(type2)//' BGRID_NE Y4' )
!------------------------------------------------------------------
! vector update : CGRID_NE
!------------------------------------------------------------------
x = 0.; y = 0.
x(is:ie,js:je,:) = global1(is:ie,js:je,:)
y(is:ie,js:je,:) = global2(is:ie,js:je,:)
x1 = x; x2 = x; x3 = x; x4 = x
y1 = y; y2 = y; y3 = y; y4 = y
id = mpp_clock_id( type//' vector CGRID_NE', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_update_domains( x, y, domain, gridtype=CGRID_NE)
call mpp_update_domains( x1, y1, domain, gridtype=CGRID_NE, complete=.false. )
call mpp_update_domains( x2, y2, domain, gridtype=CGRID_NE, complete=.false. )
call mpp_update_domains( x3, y3, domain, gridtype=CGRID_NE, complete=.false. )
call mpp_update_domains( x4, y4, domain, gridtype=CGRID_NE, complete=.true. )
call mpp_clock_end (id)
call compare_checksums( x, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X' )
call compare_checksums( y, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y' )
call compare_checksums( x1, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X1' )
call compare_checksums( x2, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X2' )
call compare_checksums( x3, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X3' )
call compare_checksums( x4, global1(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE X4' )
call compare_checksums( y1, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y1' )
call compare_checksums( y2, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y2' )
call compare_checksums( y3, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y3' )
call compare_checksums( y4, global2(isd:ied,jsd:jed,:), trim(type2)//' CGRID_NE Y4' )
deallocate(global1, global2, x, x1, x2, x3, x4, y, y1, y2, y3, y4)
end subroutine test_cyclic_offset
subroutine test_global_field( type )
character(len=*), intent(in) :: type
real, allocatable, dimension(:,:,:) :: x, gcheck
type(domain2D) :: domain
real, allocatable :: global1(:,:,:)
integer :: ishift, jshift, ni, nj, i, j, position
integer, allocatable :: pelist(:)
integer :: is, ie, js, je, isd, ied, jsd, jed
!--- set up domain
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
select case(type)
case( 'Non-symmetry' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type )
case( 'Symmetry center', 'Symmetry corner', 'Symmetry east', 'Symmetry north' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type, symmetry = .true. )
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type//' in test_global_field' )
end select
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
!--- determine if an extra point is needed
ishift = 0; jshift = 0
position = CENTER
select case(type)
case ('Symmetry corner')
ishift = 1; jshift = 1; position=CORNER
case ('Symmetry east')
ishift = 1; jshift = 0; position=EAST
case ('Symmetry north')
ishift = 0; jshift = 1; position=NORTH
end select
ie = ie+ishift; je = je+jshift
ied = ied+ishift; jed = jed+jshift
ni = nx+ishift; nj = ny+jshift
allocate(global1(1-whalo:ni+ehalo, 1-shalo:nj+nhalo, nz))
global1 = 0.0
do k = 1,nz
do j = 1,nj
do i = 1,ni
global1(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
enddo
allocate( gcheck(ni, nj, nz) )
allocate( x (isd:ied,jsd:jed,nz) )
x(:,:,:) = global1(isd:ied,jsd:jed,:)
!--- test the data on data domain
gcheck = 0.
id = mpp_clock_id( type//' global field on data domain', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_global_field( domain, x, gcheck, position=position )
call mpp_clock_end (id)
!compare checksums between global and x arrays
call compare_checksums( global1(1:ni,1:nj,:), gcheck, type//' mpp_global_field on data domain' )
!--- Since in the disjoint redistribute mpp test, pelist1 = (npes/2+1 .. npes-1)
!--- will be declared. But for the x-direction global field, mpp_sync_self will
!--- be called. For some pe count, pelist1 will be set ( only on pe of pelist1 )
!--- in the mpp_sync_self call, later when calling mpp_declare_pelist(pelist1),
!--- deadlock will happen. For example npes = 6 and layout = (2,3), pelist = (4,5)
!--- will be set in mpp_sync_self. To solve the problem, some explicit mpp_declare_pelist
!--- on all pe is needed for those partial pelist. But for y-update, it is ok.
!--- because the pelist in y-update is not continous.
allocate(pelist(0:layout(1)-1))
do j = 0, layout(2)-1
do i = 0, layout(1)-1
pelist(i) = j*layout(1) + i
end do
call mpp_declare_pelist(pelist)
end do
deallocate(pelist)
!xupdate
gcheck = 0.
call mpp_clock_begin(id)
call mpp_global_field( domain, x, gcheck, flags = XUPDATE, position=position )
call mpp_clock_end (id)
!compare checksums between global and x arrays
call compare_checksums( global1(1:ni,js:je,:), gcheck(1:ni,js:je,:), &
type//' mpp_global_field xupdate only on data domain' )
!yupdate
gcheck = 0.
call mpp_clock_begin(id)
call mpp_global_field( domain, x, gcheck, flags = YUPDATE, position=position )
call mpp_clock_end (id)
!compare checksums between global and x arrays
call compare_checksums( global1(is:ie,1:nj,:), gcheck(is:ie,1:nj,:), &
type//' mpp_global_field yupdate only on data domain' )
call mpp_clock_begin(id)
call mpp_global_field( domain, x, gcheck, position=position )
call mpp_clock_end (id)
!compare checksums between global and x arrays
call compare_checksums( global1(1:ni,1:nj,:), gcheck, &
type//' mpp_global_field on data domain' )
!--- test the data on compute domain
gcheck = 0.
id = mpp_clock_id( type//' global field on compute domain', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
call mpp_global_field( domain, x(is:ie, js:je, :), gcheck, position=position )
call mpp_clock_end (id)
!compare checksums between global and x arrays
call compare_checksums( global1(1:ni,1:nj,:), gcheck, type//' mpp_global_field on compute domain' )
!xupdate
gcheck = 0.
call mpp_clock_begin(id)
call mpp_global_field( domain, x(is:ie, js:je,:), gcheck, flags = XUPDATE, position=position )
call mpp_clock_end (id)
!compare checksums between global and x arrays
call compare_checksums( global1(1:ni,js:je,:), gcheck(1:ni,js:je,:), &
type//' mpp_global_field xupdate only on compute domain' )
!yupdate
gcheck = 0.
call mpp_clock_begin(id)
call mpp_global_field( domain, x(is:ie, js:je,:), gcheck, flags = YUPDATE, position=position )
call mpp_clock_end (id)
!compare checksums between global and x arrays
call compare_checksums( global1(is:ie,1:nj,:), gcheck(is:ie,1:nj,:), &
type//' mpp_global_field yupdate only on compute domain' )
deallocate(global1, gcheck, x)
end subroutine test_global_field
!--- test mpp_global_sum, mpp_global_min and mpp_global_max
subroutine test_global_reduce (type)
character(len=*), intent(in) :: type
real :: lsum, gsum, lmax, gmax, lmin, gmin
integer :: ni, nj, ishift, jshift, position
integer :: is, ie, js, je, isd, ied, jsd, jed
type(domain2D) :: domain
real, allocatable, dimension(:,:,:) :: global1, x
real, allocatable, dimension(:,:) :: global2D
!--- set up domain
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
select case(type)
case( 'Simple' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type )
case( 'Simple symmetry center', 'Simple symmetry corner', 'Simple symmetry east', 'Simple symmetry north' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type, symmetry = .true. )
case( 'Cyclic symmetry center', 'Cyclic symmetry corner', 'Cyclic symmetry east', 'Cyclic symmetry north' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name=type, symmetry = .true., xflags=CYCLIC_GLOBAL_DOMAIN, yflags=CYCLIC_GLOBAL_DOMAIN )
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type//' in test_global_field' )
end select
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
!--- determine if an extra point is needed
ishift = 0; jshift = 0; position = CENTER
select case(type)
case ('Simple symmetry corner', 'Cyclic symmetry corner')
ishift = 1; jshift = 1; position = CORNER
case ('Simple symmetry east', 'Cyclic symmetry east' )
ishift = 1; jshift = 0; position = EAST
case ('Simple symmetry north', 'Cyclic symmetry north')
ishift = 0; jshift = 1; position = NORTH
end select
ie = ie+ishift; je = je+jshift
ied = ied+ishift; jed = jed+jshift
ni = nx+ishift; nj = ny+jshift
allocate(global1(1-whalo:ni+ehalo, 1-shalo:nj+nhalo, nz))
global1 = 0.0
do k = 1,nz
do j = 1,nj
do i = 1,ni
global1(i,j,k) = k + i*1e-3 + j*1e-6
end do
end do
enddo
!--- NOTE: even though the domain is cyclic, no need to apply cyclic condition on the global data
allocate( x (isd:ied,jsd:jed,nz) )
allocate( global2D(ni,nj))
x(:,:,:) = global1(isd:ied,jsd:jed,:)
do j = 1, nj
do i = 1, ni
global2D(i,j) = sum(global1(i,j,:))
enddo
enddo
!test mpp_global_sum
if(type(1:6) == 'Simple') then
gsum = sum( global2D(1:ni,1:nj) )
else
gsum = sum( global2D(1:nx, 1:ny) )
endif
id = mpp_clock_id( type//' sum', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
lsum = mpp_global_sum( domain, x, position = position )
call mpp_clock_end (id)
if( pe.EQ.mpp_root_pe() )print '(a,2es15.8,a,es12.4)', type//' Fast sum=', lsum, gsum
!test exact mpp_global_sum
id = mpp_clock_id( type//' exact sum', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
lsum = mpp_global_sum( domain, x, BITWISE_EXACT_SUM, position = position )
call mpp_clock_end (id)
!--- The following check will fail on altix in normal mode, but it is ok
!--- in debugging mode. It is ok on irix.
call compare_data_scalar(lsum, gsum, FATAL, type//' mpp_global_exact_sum')
!test mpp_global_min
gmin = minval(global1(1:ni, 1:nj, :))
id = mpp_clock_id( type//' min', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
lmin = mpp_global_min( domain, x, position = position )
call mpp_clock_end (id)
call compare_data_scalar(lmin, gmin, FATAL, type//' mpp_global_min')
!test mpp_global_max
gmax = maxval(global1(1:ni, 1:nj, :))
id = mpp_clock_id( type//' max', flags=MPP_CLOCK_SYNC+MPP_CLOCK_DETAILED )
call mpp_clock_begin(id)
lmax = mpp_global_max( domain, x, position = position )
call mpp_clock_end (id)
call compare_data_scalar(lmax, gmax, FATAL, type//' mpp_global_max' )
deallocate(global1, x)
end subroutine test_global_reduce
subroutine test_parallel ( )
integer :: npes, layout(2), i, j, k,is, ie, js, je, isd, ied, jsd, jed
real, dimension(:,:), allocatable :: field, lfield
real, dimension(:,:,:), allocatable :: field3d, lfield3d
type(domain2d) :: domain
integer, dimension(:), allocatable :: pelist1 , pelist2
logical :: group1, group2
character(len=128) :: mesg
npes = mpp_npes()
allocate(pelist1(npes-mpes), pelist2(mpes))
pelist1 = (/(i, i = 0, npes-mpes -1)/)
pelist2 = (/(i, i = npes-mpes, npes - 1)/)
call mpp_declare_pelist(pelist1)
call mpp_declare_pelist(pelist2)
group1 = .FALSE. ; group2 = .FALSE.
if(any(pelist1==pe)) group1 = .TRUE.
if(any(pelist2==pe)) group2 = .TRUE.
mesg = 'parallel checking'
if(group1) then
call mpp_set_current_pelist(pelist1)
call mpp_define_layout( (/1,nx,1,ny/), npes-mpes, layout )
else if(group2) then
call mpp_set_current_pelist(pelist2)
call mpp_define_layout( (/1,nx,1,ny/), mpes, layout )
endif
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo)
call mpp_set_current_pelist()
call mpp_get_compute_domain(domain, is, ie, js, je)
call mpp_get_data_domain(domain, isd, ied, jsd, jed)
allocate(lfield(is:ie,js:je),field(isd:ied,jsd:jed))
allocate(lfield3d(is:ie,js:je,nz),field3d(isd:ied,jsd:jed,nz))
do i = is, ie
do j = js, je
lfield(i,j) = real(i)+real(j)*0.001
enddo
enddo
do i = is, ie
do j = js, je
do k = 1, nz
lfield3d(i,j,k) = real(i)+real(j)*0.001+real(k)*0.00001
enddo
enddo
enddo
field = 0.0
field3d = 0.0
field(is:ie,js:je)= lfield(is:ie,js:je)
field3d(is:ie,js:je,:) = lfield3d(is:ie,js:je,:)
call mpp_update_domains(field,domain)
call mpp_update_domains(field3d,domain)
call mpp_check_field(field, pelist1, pelist2,domain, '2D '//mesg, w_halo = whalo, &
s_halo = shalo, e_halo = ehalo, n_halo = nhalo)
call mpp_check_field(field3d, pelist1, pelist2,domain, '3D '//mesg, w_halo = whalo, &
s_halo = shalo, e_halo = ehalo, n_halo = nhalo)
end subroutine test_parallel
subroutine test_modify_domain( )
type(domain2D) :: domain2d_no_halo, domain2d_with_halo
integer :: is1, ie1, js1, je1, isd1, ied1, jsd1, jed1
integer :: is2, ie2, js2, je2, isd2, ied2, jsd2, jed2
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain2d_no_halo, &
yflags=CYCLIC_GLOBAL_DOMAIN, xhalo=0, yhalo=0)
call mpp_get_compute_domain(domain2d_no_halo, is1, ie1, js1, je1)
call mpp_get_data_domain(domain2d_no_halo, isd1, ied1, jsd1, jed1)
call mpp_modify_domain(domain2d_no_halo, domain2d_with_halo, whalo=whalo,ehalo=ehalo,shalo=shalo,nhalo=nhalo)
call mpp_get_compute_domain(domain2d_with_halo, is2, ie2, js2, je2)
call mpp_get_data_domain(domain2d_with_halo, isd2, ied2, jsd2, jed2)
if( is1 .NE. is2 .OR. ie1 .NE. ie2 .OR. js1 .NE. js2 .OR. je1 .NE. je2 ) then
print*, "at pe ", pe, " compute domain without halo: ", is1, ie1, js1, je1, &
" is not equal to the domain with halo ", is2, ie2, js2, je2
call mpp_error(FATAL, "compute domain mismatch between domain without halo and domain with halo")
end if
if( isd1-whalo .NE. isd2 .OR. ied1+ehalo .NE. ied2 .OR. jsd1-shalo .NE. jsd2 .OR. jed1+nhalo .NE. jed2 ) then
print*, "at pe ", pe, "halo is w=",whalo,",e=",ehalo,",s=",shalo,"n=",nhalo, &
",data domain without halo is ",isd1, ied1, jsd1, jed1, &
", data domain with halo is ", isd2, ied2, jsd2, jed2
call mpp_error(FATAL, "compute domain mismatch between data domain without halo and data domain with halo")
else
if( pe.EQ.mpp_root_pe() )call mpp_error( NOTE, 'test_modify_domain: OK.' )
end if
return
end subroutine test_modify_domain
subroutine compare_checksums( a, b, string )
real, intent(in), dimension(:,:,:) :: a, b
character(len=*), intent(in) :: string
integer(LONG_KIND) :: sum1, sum2
integer :: i, j, k
! z1l can not call mpp_sync here since there might be different number of tiles on each pe.
! mpp_sync()
call mpp_sync_self()
if(size(a,1) .ne. size(b,1) .or. size(a,2) .ne. size(b,2) .or. size(a,3) .ne. size(b,3) ) &
call mpp_error(FATAL,'compare_chksum: size of a and b does not match')
do k = 1, size(a,3)
do j = 1, size(a,2)
do i = 1, size(a,1)
if(a(i,j,k) .ne. b(i,j,k)) then
write(*,'(a,i3,a,i3,a,i3,a,i3,a,f20.9,a,f20.9)') trim(string)//" at pe ", mpp_pe(), &
", at point (",i,", ", j, ", ", k, "), a = ", a(i,j,k), ", b = ", b(i,j,k)
call mpp_error(FATAL, trim(string)//': point by point comparison are not OK.')
endif
enddo
enddo
enddo
sum1 = mpp_chksum( a, (/pe/) )
sum2 = mpp_chksum( b, (/pe/) )
if( sum1.EQ.sum2 )then
if( pe.EQ.mpp_root_pe() )call mpp_error( NOTE, trim(string)//': OK.' )
!--- in some case, even though checksum agree, the two arrays
! actually are different, like comparing (1.1,-1.2) with (-1.1,1.2)
!--- hence we need to check the value point by point.
else
call mpp_error( FATAL, trim(string)//': chksums are not OK.' )
end if
end subroutine compare_checksums
!###########################################################################
subroutine compare_checksums_2D( a, b, string )
real, intent(in), dimension(:,:) :: a, b
character(len=*), intent(in) :: string
integer(LONG_KIND) :: sum1, sum2
integer :: i, j
! z1l can not call mpp_sync here since there might be different number of tiles on each pe.
! mpp_sync()
call mpp_sync_self()
if(size(a,1) .ne. size(b,1) .or. size(a,2) .ne. size(b,2) ) &
call mpp_error(FATAL,'compare_chksum_2D: size of a and b does not match')
do j = 1, size(a,2)
do i = 1, size(a,1)
if(a(i,j) .ne. b(i,j)) then
print*, "a =", a(i,j)
print*, "b =", b(i,j)
write(*,'(a,i3,a,i3,a,i3,a,f20.9,a,f20.9)')"at the pe ", mpp_pe(), &
", at point (",i,", ", j, "),a=", a(i,j), ",b=", b(i,j)
call mpp_error(FATAL, trim(string)//': point by point comparison are not OK.')
endif
enddo
enddo
sum1 = mpp_chksum( a, (/pe/) )
sum2 = mpp_chksum( b, (/pe/) )
if( sum1.EQ.sum2 )then
if( pe.EQ.mpp_root_pe() )call mpp_error( NOTE, trim(string)//': OK.' )
!--- in some case, even though checksum agree, the two arrays
! actually are different, like comparing (1.1,-1.2) with (-1.1,1.2)
!--- hence we need to check the value point by point.
else
call mpp_error( FATAL, trim(string)//': chksums are not OK.' )
end if
end subroutine compare_checksums_2D
!###########################################################################
subroutine compare_data_scalar( a, b, action, string )
real, intent(in) :: a, b
integer, intent(in) :: action
character(len=*), intent(in) :: string
if( a .EQ. b)then
if( pe.EQ.mpp_root_pe() )call mpp_error( NOTE, trim(string)//': data comparison are OK.' )
else
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
call mpp_error( action, trim(string)//': data comparison are not OK.' )
end if
end subroutine compare_data_scalar
subroutine test_get_neighbor_1d
type(domain1d) :: dmn1d
integer npes, peN, peS
npes = mpp_npes()
call mpp_define_domains((/1,npes/), npes, dmn1d)
call mpp_get_neighbor_pe(dmn1d, direction=+1, pe=peN)
call mpp_get_neighbor_pe(dmn1d, direction=-1, pe=peS)
print '(a,i2,a,2i3)', 'PE: ', mpp_pe(), ' R/L pes: ', peN, peS
end subroutine test_get_neighbor_1d
subroutine test_get_neighbor_non_cyclic
type(domain2d) :: domain
integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
nx = 10
ny = 20
halo = 2
npes = mpp_npes()
if( npes .NE. 8 ) then
call mpp_error(NOTE, 'test_mpp_domains: test_get_neighbor_non_cyclic '// &
' will be performed only when npes = 8')
return
end if
call mpp_define_layout( (/1,nx, 1,ny/), npes, layout )
call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo)
call mpp_get_neighbor_pe(domain, direction=NORTH, pe=peN)
call mpp_get_neighbor_pe(domain, direction=SOUTH, pe=peS)
call mpp_get_neighbor_pe(domain, direction=EAST, pe=peE)
call mpp_get_neighbor_pe(domain, direction=WEST, pe=peW)
call mpp_get_neighbor_pe(domain, direction=NORTH_EAST, pe=peNE)
call mpp_get_neighbor_pe(domain, direction=NORTH_WEST, pe=peNW)
call mpp_get_neighbor_pe(domain, direction=SOUTH_EAST, pe=peSE)
call mpp_get_neighbor_pe(domain, direction=SOUTH_WEST, pe=peSW)
print '(a,i2,a,2i2,a,8i3)','PE: ', mpp_pe(), ' layout (non-cyclic): ', layout, &
& ' N/S/E/W/NE/SE/SW/NW pes: ', peN, peS, peE, peW, peNE, peSE, peSW, peNW
end subroutine test_get_neighbor_non_cyclic
subroutine test_get_neighbor_cyclic
type(domain2d) :: domain
integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
nx = 10
ny = 20
halo = 2
npes = mpp_npes()
if( npes .NE. 8 ) then
call mpp_error(NOTE, 'test_mpp_domains: test_get_neighbor_cyclic '// &
' will be performed only when npes = 8')
return
end if
call mpp_define_layout( (/1,nx, 1,ny/), npes, layout )
call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo, &
xflags=CYCLIC_GLOBAL_DOMAIN, yflags=CYCLIC_GLOBAL_DOMAIN)
call mpp_get_neighbor_pe(domain, direction=NORTH, pe=peN)
call mpp_get_neighbor_pe(domain, direction=SOUTH, pe=peS)
call mpp_get_neighbor_pe(domain, direction=EAST, pe=peE)
call mpp_get_neighbor_pe(domain, direction=WEST, pe=peW)
call mpp_get_neighbor_pe(domain, direction=NORTH_EAST, pe=peNE)
call mpp_get_neighbor_pe(domain, direction=NORTH_WEST, pe=peNW)
call mpp_get_neighbor_pe(domain, direction=SOUTH_EAST, pe=peSE)
call mpp_get_neighbor_pe(domain, direction=SOUTH_WEST, pe=peSW)
print '(a,i2,a,2i2,a,8i3)','PE: ', mpp_pe(), ' layout (cyclic) : ', layout, &
& ' N/S/E/W/NE/SE/SW/NW pes: ', peN, peS, peE, peW, peNE, peSE, peSW, peNW
end subroutine test_get_neighbor_cyclic
subroutine test_get_neighbor_folded_north
type(domain2d) :: domain
integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
nx = 10
ny = 20
halo = 2
npes = mpp_npes()
if( npes .NE. 8 ) then
call mpp_error(NOTE, 'test_mpp_domains: test_get_neighbor_folded_north '// &
' will be performed only when npes = 8')
return
end if
call mpp_define_layout( (/1,nx, 1,ny/), npes, layout )
call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo, &
xflags=CYCLIC_GLOBAL_DOMAIN, yflags=FOLD_NORTH_EDGE)
call mpp_get_neighbor_pe(domain, direction=NORTH, pe=peN)
call mpp_get_neighbor_pe(domain, direction=SOUTH, pe=peS)
call mpp_get_neighbor_pe(domain, direction=EAST, pe=peE)
call mpp_get_neighbor_pe(domain, direction=WEST, pe=peW)
call mpp_get_neighbor_pe(domain, direction=NORTH_EAST, pe=peNE)
call mpp_get_neighbor_pe(domain, direction=NORTH_WEST, pe=peNW)
call mpp_get_neighbor_pe(domain, direction=SOUTH_EAST, pe=peSE)
call mpp_get_neighbor_pe(domain, direction=SOUTH_WEST, pe=peSW)
print '(a,i2,a,2i2,a,8i3)','PE: ', mpp_pe(), ' layout (folded N) : ', layout, &
& ' N/S/E/W/NE/SE/SW/NW pes: ', peN, peS, peE, peW, peNE, peSE, peSW, peNW
end subroutine test_get_neighbor_folded_north
subroutine test_get_neighbor_mask
logical, allocatable :: mask(:,:)
integer :: im, jm, n_remove
type(domain2d) :: domain
integer nx, ny,layout(2), halo, peN, peS, peE, peW, peNE, peNW, peSE, peSW, npes
nx = 10
ny = 20
halo = 2
npes = mpp_npes()
n_remove = 2
if( npes .NE. 8 ) then
call mpp_error(NOTE, 'test_mpp_domains: test_get_neighbor_mask '// &
' will be performed only when npes = 8')
return
end if
call mpp_define_layout( (/1,nx, 1,ny/), npes+n_remove, layout )
allocate(mask(layout(1), layout(2)))
mask = .TRUE. ! activate domains
im = min(layout(1), ceiling(layout(1)/2.0))
jm = min(layout(2), ceiling(layout(2)/2.0))
mask(im ,jm ) = .FALSE. ! deactivate domain
mask(im ,jm-1) = .FALSE. ! deactivate domain
print '(a,2i3,a,2i3)', 'Masked out domains ', im, jm, ' and ', im,jm-1
call mpp_define_domains((/1,nx, 1,ny/), layout, domain, xhalo=halo, yhalo=halo, &
maskmap=mask)
call mpp_get_neighbor_pe(domain, direction=NORTH, pe=peN)
call mpp_get_neighbor_pe(domain, direction=SOUTH, pe=peS)
call mpp_get_neighbor_pe(domain, direction=EAST, pe=peE)
call mpp_get_neighbor_pe(domain, direction=WEST, pe=peW)
call mpp_get_neighbor_pe(domain, direction=NORTH_EAST, pe=peNE)
call mpp_get_neighbor_pe(domain, direction=NORTH_WEST, pe=peNW)
call mpp_get_neighbor_pe(domain, direction=SOUTH_EAST, pe=peSE)
call mpp_get_neighbor_pe(domain, direction=SOUTH_WEST, pe=peSW)
print '(a,i3,a,2i3,a,8i3)','PE: ', mpp_pe(), ' layout (mask ) : ', layout, &
& ' N/S/E/W/NE/SE/SW/NW pes: ', peN, peS, peE, peW, peNE, peSE, peSW, peNW
end subroutine test_get_neighbor_mask
subroutine test_define_mosaic_pelist(type, ntile)
character(len=*), intent(in) :: type
integer, intent(in) :: ntile
integer :: npes, root_pe, start_pe, n, ntile_per_pe
integer, dimension(:), allocatable :: pe1_start, pe1_end, pe2_start, pe2_end
integer, dimension(:), allocatable :: sizes, costpertile
root_pe = mpp_root_pe()
npes = mpp_npes()
allocate(sizes(ntile), pe1_start(ntile), pe1_end(ntile), pe2_start(ntile), pe2_end(ntile),costpertile(ntile) )
costpertile = 1
sizes = nx*ny
if(npes ==1) then
pe1_start = root_pe; pe1_end = root_pe
end if
select case(type)
case('One tile')
pe1_start = root_pe; pe1_end = npes+root_pe-1
case('Two uniform tile')
if(mod(npes,2) .NE. 0 .AND. npes .NE. 1) then
call mpp_error(NOTE, 'test_define_mosaic_pelist: npes can not be divided by 2, no test for '//type )
return
end if
if(npes .NE. 1) then
pe1_start(1) = root_pe; pe1_end(1) = npes/2+root_pe-1
pe1_start(2) = npes/2+root_pe; pe1_end(2) = npes+root_pe-1
end if
case('Two nonuniform tile')
if(mod(npes,3) .NE. 0 .AND. npes .NE. 1) then
call mpp_error(NOTE, 'test_define_mosaic_pelist: npes can not be divided by 3, no test for '//type )
return
end if
sizes(1) = 2*nx*ny
if(npes .NE. 1) then
pe1_start(1) = root_pe; pe1_end(1) = npes/3*2+root_pe-1
pe1_start(2) = npes/3*2+root_pe; pe1_end(2) = npes+root_pe-1
end if
case('Ten tile')
if(mod(npes,10) .NE. 0 .AND. npes .NE. 1 .AND. mod(10,npes) .NE. 0) then
call mpp_error(NOTE, 'test_define_mosaic_pelist: npes can not be divided by 10(or reverse), no test for '//type )
return
end if
if(mod(10, npes)==0) then
ntile_per_pe = ntile/npes
do n = 1, ntile
pe1_start(n) = root_pe+(n-1)/ntile_per_pe; pe1_end(n) = pe1_start(n)
end do
else if(mod(npes,10) == 0) then
do n = 1, ntile
pe1_start(n) = npes/10*(n-1)+root_pe; pe1_end(n) = npes/10*n+root_pe-1
end do
end if
case('Ten tile with nonuniform cost')
if(mod(npes,15) .NE. 0 .AND. npes .NE. 1) then
call mpp_error(NOTE, 'test_define_mosaic_pelist: npes can not be divided by 15, no test for '//type )
return
end if
costpertile(1:5) = 2; costpertile(6:ntile) = 1
if(npes .NE. 1) then
start_pe = root_pe
do n = 1, ntile
pe1_start(n) = start_pe
pe1_end(n) = start_pe + npes/15*costpertile(n)-1
start_pe = pe1_end(n) + 1
end do
end if
case default
call mpp_error(FATAL,"test_define_mosaic_pelist: "//type//" is an invalid type")
end select
call mpp_define_mosaic_pelist( sizes, pe2_start, pe2_end, costpertile=costpertile)
if( ANY(pe1_start .NE. pe2_start) .OR. ANY(pe1_end .NE. pe2_end) ) then
call mpp_error(FATAL,"test_define_mosaic_pelist: test failed for "//trim(type) )
else
call mpp_error(NOTE,"test_define_mosaic_pelist: test successful for "//trim(type) )
end if
end subroutine test_define_mosaic_pelist
!###############################################################################
subroutine test_update_nest_domain( type )
character(len=*), intent(in) :: type
logical :: cubic_grid, concurrent
logical :: is_fine_pe, is_coarse_pe
integer :: n, i, j, k, l
integer :: ntiles, num_contact, npes_per_tile
integer :: isc_coarse, iec_coarse, jsc_coarse, jec_coarse
integer :: isd_coarse, ied_coarse, jsd_coarse, jed_coarse
integer :: isd_fine, ied_fine, jsd_fine, jed_fine
integer :: isc_fine, iec_fine, jsc_fine, jec_fine
integer :: x_refine, y_refine, nx_coarse, ny_coarse
integer :: nxc_fine, nyc_fine, nxc_coarse, nyc_coarse
integer :: isw_f, iew_f, jsw_f, jew_f, isw_c, iew_c, jsw_c, jew_c
integer :: ise_f, iee_f, jse_f, jee_f, ise_c, iee_c, jse_c, jee_c
integer :: iss_f, ies_f, jss_f, jes_f, iss_c, ies_c, jss_c, jes_c
integer :: isn_f, ien_f, jsn_f, jen_f, isn_c, ien_c, jsn_c, jen_c
integer :: isw_f2, iew_f2, jsw_f2, jew_f2, isw_c2, iew_c2, jsw_c2, jew_c2, tile_w2
integer :: ise_f2, iee_f2, jse_f2, jee_f2, ise_c2, iee_c2, jse_c2, jee_c2, tile_e2
integer :: iss_f2, ies_f2, jss_f2, jes_f2, iss_c2, ies_c2, jss_c2, jes_c2, tile_s2
integer :: isn_f2, ien_f2, jsn_f2, jen_f2, isn_c2, ien_c2, jsn_c2, jen_c2, tile_n2
integer :: is_c, ie_c, js_c, je_c, is_f, ie_f, js_f, je_f
integer :: is_c2, ie_c2, js_c2, je_c2, is_f2, ie_f2, js_f2, je_f2
integer :: nx_fine, ny_fine, tile, position, ishift, jshift
integer :: layout_fine(2)
integer, allocatable :: pelist(:)
integer, allocatable :: pelist_coarse(:)
integer, allocatable :: pelist_fine(:)
integer, allocatable :: pe_start(:), pe_end(:)
integer, allocatable :: layout2D(:,:), global_indices(:,:)
real, allocatable :: x(:,:,:)
real, allocatable :: wbuffer(:,:,:), wbuffer2(:,:,:)
real, allocatable :: ebuffer(:,:,:), ebuffer2(:,:,:)
real, allocatable :: sbuffer(:,:,:), sbuffer2(:,:,:)
real, allocatable :: nbuffer(:,:,:), nbuffer2(:,:,:)
real, allocatable :: buffer(:,:,:), buffer2(:,:,:)
character(len=32) :: position_name
type(domain2d) :: domain_coarse, domain_fine
type(nest_domain_type) :: nest_domain
select case(type)
case ( 'Cubic-Grid' )
if( nx_cubic == 0 ) then
call mpp_error(NOTE,'test_update_nest_domain: for Cubic_grid mosaic, nx_cubic is zero, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
if( nx_cubic .NE. ny_cubic ) then
call mpp_error(NOTE,'test_update_nest_domain: for Cubic_grid mosaic, nx_cubic does not equal ny_cubic, '//&
'No test is done for Cubic-Grid mosaic. ' )
return
endif
nx = nx_cubic
ny = ny_cubic
ntiles = 6
num_contact = 12
cubic_grid = .true.
case default
call mpp_error(FATAL, 'test_update_nest_domain: no such test: '//type)
end select
npes = mpp_npes()
if(mod(npes_coarse,ntiles) .NE. 0) call mpp_error(FATAL, "test_mpp_domains: npes_coarse should be divided by ntiles")
!--- npes_coarse + npes_fine (concurrent) == npes or npes_coarse = npes_fine = npes (series)
npes = mpp_npes()
allocate(pelist(npes))
call mpp_get_current_pelist(pelist)
allocate(pelist_coarse(npes_coarse))
allocate(pelist_fine(npes_fine))
if( npes_coarse + npes_fine == mpp_npes() ) then
concurrent = .true.
pelist_coarse(1:npes_coarse) = pelist(1:npes_coarse)
pelist_fine(1:npes_fine) = pelist(npes_coarse+1:npes_coarse+npes_fine)
else if(npes_coarse == npes_fine .AND. npes_coarse == npes) then
concurrent = .false.
pelist_fine = pelist
pelist_coarse = pelist
else
call mpp_error(FATAL, 'test_update_nest_domain: either npes_fine+npes_coarse=npes or npes_fine=npes_coarse=npes')
endif
call mpp_declare_pelist(pelist_fine, "fine grid")
call mpp_declare_pelist(pelist_coarse, "coarse grid")
is_fine_pe = ANY(pelist_fine(:) == mpp_pe())
is_coarse_pe = ANY(pelist_coarse(:) == mpp_pe())
!--- first define the coarse grid mosaic domain.
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
if(is_coarse_pe) then
npes_per_tile = npes_coarse/ntiles
call mpp_set_current_pelist(pelist_coarse)
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
if( cubic_grid ) then
call define_cubic_mosaic(type, domain_coarse, (/nx,nx,nx,nx,nx,nx/), (/ny,ny,ny,ny,ny,ny/), &
global_indices, layout2D, pe_start, pe_end )
endif
call mpp_get_compute_domain(domain_coarse, isc_coarse, iec_coarse, jsc_coarse, jec_coarse)
call mpp_get_data_domain(domain_coarse, isd_coarse, ied_coarse, jsd_coarse, jed_coarse)
endif
!--- define the fine grid mosaic doamin
nx_fine = iend_fine - istart_fine + 1
ny_fine = jend_fine - jstart_fine + 1
if(is_fine_pe) then
call mpp_set_current_pelist(pelist_fine)
call mpp_define_layout( (/1,nx_fine,1,ny_fine/), npes_fine, layout_fine )
call mpp_define_domains((/1,nx_fine,1,ny_fine/), layout_fine, domain_fine, &
whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
symmetry=.true., name="fine grid domain")
call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine)
call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine)
endif
!--- define the nest domain
call mpp_set_current_pelist()
!--- for concurrent run, need to broadcast domain
if( concurrent ) then
call mpp_broadcast_domain(domain_fine)
call mpp_broadcast_domain(domain_coarse)
endif
!--- make sure the integer refinement
nx_coarse = iend_coarse - istart_coarse + 1
ny_coarse = jend_coarse - jstart_coarse + 1
if( mod(nx_fine,nx_coarse) .NE. 0 ) call mpp_error(FATAL, &
"test_mpp_domains: The refinement in x-direction is not integer for type="//trim(type) )
x_refine = nx_fine/nx_coarse
if( mod(ny_fine,ny_coarse) .NE. 0 ) call mpp_error(FATAL, &
"test_mpp_domains: The refinement in y-direction is not integer for type="//trim(type) )
y_refine = ny_fine/ny_coarse
call mpp_define_nest_domains(nest_domain, domain_fine, domain_coarse, tile_fine, tile_coarse, &
istart_fine, iend_fine, jstart_fine, jend_fine, &
istart_coarse, iend_coarse, jstart_coarse, jend_coarse, &
pelist, extra_halo, name="nest_domain")
!---------------------------------------------------------------------------
!
! Coarse to Fine
!
!---------------------------------------------------------------------------
do l = 1, 4 ! T, E, C, N
select case(l)
case(1)
position = CENTER
position_name = "CENTER"
case(2)
position = EAST
position_name = "EAST"
case(3)
position = CORNER
position_name = "CORNER"
case(4)
position = NORTH
position_name = "NORTH"
end select
call mpp_get_domain_shift(domain_coarse, ishift, jshift, position)
!--- first check the index is correct or not
if(is_fine_pe) then
!--- The index from nest domain
call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine, position=position)
call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine, position=position)
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)
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)
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)
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)
!-- The assumed index
isw_f2 = 0; iew_f2 = -1; jsw_f2 = 0; jew_f2 = -1
isw_c2 = 0; iew_c2 = -1; jsw_c2 = 0; jew_c2 = -1
ise_f2 = 0; iee_f2 = -1; jse_f2 = 0; jee_f2 = -1
ise_c2 = 0; iee_c2 = -1; jse_c2 = 0; jee_c2 = -1
iss_f2 = 0; ies_f2 = -1; jss_f2 = 0; jes_f2 = -1
iss_c2 = 0; ies_c2 = -1; jss_c2 = 0; jes_c2 = -1
isn_f2 = 0; ien_f2 = -1; jsn_f2 = 0; jen_f2 = -1
isn_c2 = 0; ien_c2 = -1; jsn_c2 = 0; jen_c2 = -1
!--- west
if( isc_fine == 1 ) then
isw_f2 = isd_fine; iew_f2 = isc_fine - 1
jsw_f2 = jsd_fine; jew_f2 = jed_fine
isw_c2 = istart_coarse-whalo
iew_c2 = istart_coarse
jsw_c2 = jstart_coarse + (jsc_fine - jstart_fine)/y_refine - shalo
jew_c2 = jstart_coarse + (jec_fine - jstart_fine)/y_refine + nhalo
endif
!--- east
if( iec_fine == nx_fine+ishift ) then
ise_f2 = iec_fine+1; iee_f2 = ied_fine
jse_f2 = jsd_fine; jee_f2 = jed_fine
ise_c2 = iend_coarse+ishift
iee_c2 = iend_coarse+ehalo+ishift
jse_c2 = jstart_coarse + (jsc_fine - jstart_fine)/y_refine - shalo
jee_c2 = jstart_coarse + (jec_fine - jstart_fine)/y_refine + nhalo
endif
!--- south
if( jsc_fine == 1 ) then
iss_f2 = isd_fine; ies_f2 = ied_fine
jss_f2 = jsd_fine; jes_f2 = jsc_fine - 1
iss_c2 = istart_coarse + (isc_fine - istart_fine)/x_refine - whalo
ies_c2 = istart_coarse + (iec_fine - istart_fine)/x_refine + ehalo
jss_c2 = jstart_coarse-shalo
jes_c2 = jstart_coarse
endif
!--- north
if( jec_fine == ny_fine+jshift ) then
isn_f2 = isd_fine; ien_f2 = ied_fine
jsn_f2 = jec_fine+1; jen_f2 = jed_fine
isn_c2 = istart_coarse + (isc_fine - istart_fine)/x_refine - whalo
ien_c2 = istart_coarse + (iec_fine - istart_fine)/x_refine + ehalo
jsn_c2 = jend_coarse+jshift
jen_c2 = jend_coarse+nhalo+jshift
endif
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. &
isw_c .NE. isw_c2 .OR. iew_c .NE. iew_c2 .OR. jsw_c .NE. jsw_c2 .OR. jew_c .NE. jew_c2 ) then
call mpp_error(FATAL, "test_mpp_domains: west buffer index mismatch for "//trim(position_name))
endif
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. &
ise_c .NE. ise_c2 .OR. iee_c .NE. iee_c2 .OR. jse_c .NE. jse_c2 .OR. jee_c .NE. jee_c2 ) then
call mpp_error(FATAL, "test_mpp_domains: east buffer index mismatch for "//trim(position_name))
endif
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. &
iss_c .NE. iss_c2 .OR. ies_c .NE. ies_c2 .OR. jss_c .NE. jss_c2 .OR. jes_c .NE. jes_c2 ) then
call mpp_error(FATAL, "test_mpp_domains: south buffer index mismatch for "//trim(position_name))
endif
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. &
isn_c .NE. isn_c2 .OR. ien_c .NE. ien_c2 .OR. jsn_c .NE. jsn_c2 .OR. jen_c .NE. jen_c2 ) then
call mpp_error(FATAL, "test_mpp_domains: north buffer index mismatch for "//trim(position_name))
endif
endif
if(is_coarse_pe) then
call mpp_get_compute_domain(domain_coarse, isc_coarse, iec_coarse, jsc_coarse, jec_coarse, position=position)
call mpp_get_data_domain(domain_coarse, isd_coarse, ied_coarse, jsd_coarse, jed_coarse, position=position)
allocate(x(isd_coarse:ied_coarse, jsd_coarse:jed_coarse, nz))
x = 0
npes_per_tile = npes_coarse/ntiles
tile = mpp_pe()/npes_per_tile + 1
do k = 1, nz
do j = jsc_coarse, jec_coarse
do i = isc_coarse, iec_coarse
x(i,j,k) = tile + i*1.e-3 + j*1.e-6 + k*1.e-9
enddo
enddo
enddo
else
allocate(x(isd_fine:ied_fine, jsd_fine:jed_fine, nz))
x = 0
do k = 1, nz
do j = jsc_fine, jec_fine
do i = isc_fine, iec_fine
x(i,j,k) = i*1.e+6 + j*1.e+3 + k
enddo
enddo
enddo
endif
if(is_fine_pe) then
if( iew_c .GE. isw_c .AND. jew_c .GE. jsw_c ) then
allocate(wbuffer(isw_c:iew_c, jsw_c:jew_c,nz))
allocate(wbuffer2(isw_c:iew_c, jsw_c:jew_c,nz))
else
allocate(wbuffer(1,1,1))
allocate(wbuffer2(1,1,1))
endif
wbuffer = 0; wbuffer2 = 0
if( iee_c .GE. ise_c .AND. jee_c .GE. jse_c ) then
allocate(ebuffer(ise_c:iee_c, jse_c:jee_c,nz))
allocate(ebuffer2(ise_c:iee_c, jse_c:jee_c,nz))
else
allocate(ebuffer(1,1,1))
allocate(ebuffer2(1,1,1))
endif
ebuffer = 0; ebuffer2 = 0
if( ies_c .GE. iss_c .AND. jes_c .GE. jss_c ) then
allocate(sbuffer(iss_c:ies_c, jss_c:jes_c,nz))
allocate(sbuffer2(iss_c:ies_c, jss_c:jes_c,nz))
else
allocate(sbuffer(1,1,1))
allocate(sbuffer2(1,1,1))
endif
sbuffer = 0; sbuffer2 = 0
if( ien_c .GE. isn_c .AND. jen_c .GE. jsn_c ) then
allocate(nbuffer(isn_c:ien_c, jsn_c:jen_c,nz))
allocate(nbuffer2(isn_c:ien_c, jsn_c:jen_c,nz))
else
allocate(nbuffer(1,1,1))
allocate(nbuffer2(1,1,1))
endif
nbuffer = 0; nbuffer2 = 0
endif
call mpp_update_nest_fine(x, nest_domain, wbuffer, sbuffer, ebuffer, nbuffer, position=position)
!--- compare with the assumed value.
if( is_fine_pe ) then
if( iew_c .GE. isw_c .AND. jew_c .GE. jsw_c ) then
do k = 1, nz
do j = jsw_c, jew_c
do i = isw_c, iew_c
wbuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
enddo
enddo
enddo
endif
call compare_checksums(wbuffer, wbuffer2, trim(type)//' west buffer '//trim(position_name))
if( ies_c .GE. iss_c .AND. jes_c .GE. jss_c ) then
do k = 1, nz
do j = jss_c, jes_c
do i = iss_c, ies_c
sbuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
enddo
enddo
enddo
endif
call compare_checksums(sbuffer, sbuffer2, trim(type)//' south buffer '//trim(position_name))
if( iee_c .GE. ise_c .AND. jee_c .GE. jse_c ) then
do k = 1, nz
do j = jse_c, jee_c
do i = ise_c, iee_c
ebuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
enddo
enddo
enddo
endif
call compare_checksums(ebuffer, ebuffer2, trim(type)//' east buffer '//trim(position_name))
if( ien_c .GE. isn_c .AND. jen_c .GE. jsn_c ) then
do k = 1, nz
do j = jsn_c, jen_c
do i = isn_c, ien_c
nbuffer2(i,j,k) = tile_coarse + i*1.e-3 + j*1.e-6 + k*1.e-9
enddo
enddo
enddo
endif
call compare_checksums(nbuffer, nbuffer2, trim(type)//' north buffer '//trim(position_name))
endif
if(is_fine_pe) then
deallocate(wbuffer, ebuffer, sbuffer, nbuffer)
deallocate(wbuffer2, ebuffer2, sbuffer2, nbuffer2)
endif
deallocate(x)
enddo
!---------------------------------------------------------------------------
! check fine to coarse
!---------------------------------------------------------------------------
if(is_fine_pe) then
call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine)
call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine)
endif
if(is_coarse_pe) then
call mpp_get_compute_domain(domain_coarse, isc_coarse, iec_coarse, jsc_coarse, jec_coarse)
call mpp_get_data_domain(domain_coarse, isd_coarse, ied_coarse, jsd_coarse, jed_coarse)
endif
do l = 1, 4 ! T, E, C, N
select case(l)
case(1)
position = CENTER
position_name = "CENTER"
case(2)
position = EAST
position_name = "EAST"
case(3)
position = CORNER
position_name = "CORNER"
case(4)
position = NORTH
position_name = "NORTH"
end select
call mpp_get_domain_shift(domain_coarse, ishift, jshift, position)
if(is_fine_pe) then
call mpp_get_compute_domain(domain_fine, isc_fine, iec_fine, jsc_fine, jec_fine,position=position)
call mpp_get_data_domain(domain_fine, isd_fine, ied_fine, jsd_fine, jed_fine,position=position)
allocate(x(isd_fine:ied_fine, jsd_fine:jed_fine, nz))
x = 0
do k = 1, nz
do j = jsc_fine, jec_fine+jshift
do i = isc_fine, iec_fine+ishift
x(i,j,k) = i*1.e+6 + j*1.e+3 + k
enddo
enddo
enddo
else
allocate(x(isd_coarse:ied_coarse+ishift, jsd_coarse:jed_coarse+jshift, nz))
x = 0
npes_per_tile = npes_coarse/ntiles
tile = mpp_pe()/npes_per_tile + 1
do k = 1, nz
do j = jsc_coarse, jec_coarse+jshift
do i = isc_coarse, iec_coarse+ishift
x(i,j,k) = tile + i*1.e-3 + j*1.e-6 + k*1.e-9
enddo
enddo
enddo
endif
if(is_coarse_pe) then
!--- The index from nest domain
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)
npes_per_tile = npes_coarse/ntiles
tile = mpp_pe()/npes_per_tile + 1
!-- The assumed index
is_c2 = max(istart_coarse, isc_coarse)
ie_c2 = min(iend_coarse, iec_coarse)
js_c2 = max(jstart_coarse, jsc_coarse)
je_c2 = min(jend_coarse, jec_coarse)
if( tile == tile_coarse .AND. ie_c .GE. is_c .AND. je_c .GE. js_c ) then
is_f2 = istart_fine + (is_c2 - istart_coarse)*x_refine
ie_f2 = istart_fine + (ie_c2 - istart_coarse + 1)*x_refine - 1
js_f2 = jstart_fine + (js_c2 - jstart_coarse)*y_refine
je_f2 = jstart_fine + (je_c2 - jstart_coarse + 1)*y_refine - 1
ie_f2 = ie_f2 + ishift; je_f2 = je_f2 + jshift
ie_c2 = ie_c2 + ishift; je_c2 = je_c2 + jshift
else
is_f2 = 0; ie_f2 = -1; js_f2 = 0; je_f2 = -1
is_c2 = 0; ie_c2 = -1; js_c2 = 0; je_c2 = -1
endif
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. &
is_c .NE. is_c2 .OR. ie_c .NE. ie_c2 .OR. js_c .NE. js_c2 .OR. je_c .NE. je_c2 ) then
call mpp_error(FATAL, "test_mpp_domains: fine to coarse buffer index mismatch")
endif
endif
if(is_coarse_pe) then
if( ie_f .GE. is_f .AND. je_f .GE. js_f ) then
allocate(buffer (is_f:ie_f, js_f:je_f,nz))
allocate(buffer2(is_f:ie_f, js_f:je_f,nz))
do k = 1, nz
do j = js_f, je_f
do i = is_f, ie_f
buffer2(i,j,k) = i*1.e+6 + j*1.e+3 + k
enddo
enddo
enddo
else
allocate(buffer (1,1,1))
allocate(buffer2(1,1,1))
buffer2 = 0
endif
buffer = 0
endif
call mpp_update_nest_coarse(x, nest_domain, buffer, position=position)
!--- compare with assumed value
if( is_coarse_pe) then
call compare_checksums(buffer, buffer2, trim(type)//' fine to coarse buffer '//trim(position_name))
endif
if(allocated(buffer)) deallocate(buffer)
if(allocated(buffer2)) deallocate(buffer2)
if(allocated(x)) deallocate(x)
enddo
deallocate(pelist, pelist_fine, pelist_coarse)
deallocate(layout2D, global_indices, pe_start, pe_end )
end subroutine test_update_nest_domain
subroutine test_get_boundary_ad(type)
use mpp_mod, only : mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
use mpp_domains_mod, only : CGRID_NE
use mpp_domains_mod, only : mpp_get_boundary
use mpp_domains_mod, only : mpp_get_boundary_ad
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: ntiles, num_contact, npes_per_tile, ntile_per_pe, layout(2)
integer :: n, l, isc, iec, jsc, jec, ism, iem, jsm, jem
integer, allocatable, dimension(:) :: tile, ni, nj, pe_start, pe_end
integer, allocatable, dimension(:,:) :: layout2D, global_indices
real*8, allocatable, dimension(:,:,:) :: x_ad, y_ad, x_fd, y_fd, x_save, y_save
real*8, allocatable, dimension(:,:) :: ebufferx2_ad, wbufferx2_ad
real*8, allocatable, dimension(:,:) :: sbuffery2_ad, nbuffery2_ad
real*8 :: ad_sum, fd_sum
integer :: shift,i,j,k,pe
!--- check the type
ntiles = 4
num_contact = 8
allocate(layout2D(2,ntiles), global_indices(4,ntiles), pe_start(ntiles), pe_end(ntiles) )
allocate(ni(ntiles), nj(ntiles))
ni(:) = nx; nj(:) = ny
if( mod(npes, ntiles) == 0 ) then
npes_per_tile = npes/ntiles
write(outunit,*)'NOTE from test_uniform_mosaic ==> For Mosaic "', trim(type), &
'", each tile will be distributed over ', npes_per_tile, ' processors.'
ntile_per_pe = 1
allocate(tile(ntile_per_pe))
tile = pe/npes_per_tile+1
call mpp_define_layout( (/1,nx,1,ny/), npes_per_tile, layout )
do n = 1, ntiles
pe_start(n) = (n-1)*npes_per_tile
pe_end(n) = n*npes_per_tile-1
end do
else
call mpp_error(NOTE,'TEST_MPP_DOMAINS: npes should be multiple of ntiles or ' // &
'ntiles should be multiple of npes. No test is done for '//trim(type) )
return
end if
do n = 1, ntiles
global_indices(:,n) = (/1,nx,1,ny/)
layout2D(:,n) = layout
end do
call define_fourtile_mosaic(type, domain, (/nx,nx,nx,nx/), (/ny,ny,ny,ny/), global_indices, &
layout2D, pe_start, pe_end, .true. )
call mpp_get_compute_domain( domain, isc, iec, jsc, jec )
call mpp_get_memory_domain( domain, ism, iem, jsm, jem )
deallocate(layout2D, global_indices, pe_start, pe_end )
deallocate(ni, nj)
shift = 1
allocate( x_ad (ism:iem+shift,jsm:jem ,nz) )
allocate( x_fd (ism:iem+shift,jsm:jem ,nz) )
allocate( x_save(ism:iem+shift,jsm:jem ,nz) )
allocate( y_ad (ism:iem ,jsm:jem+shift,nz) )
allocate( y_fd (ism:iem ,jsm:jem+shift,nz) )
allocate( y_save(ism:iem ,jsm:jem+shift,nz) )
allocate(ebufferx2_ad(jec-jsc+1, nz), wbufferx2_ad(jec-jsc+1, nz))
allocate(sbuffery2_ad(iec-isc+1, nz), nbuffery2_ad(iec-isc+1, nz))
pe = mpp_pe()
x_fd=0; y_fd=0
do k = 1,nz
do j = jsc,jec
do i = isc,iec
x_fd(i,j,k)= i*j
y_fd(i,j,k)= i*j
end do
end do
end do
x_save=x_fd
y_save=y_fd
ebufferx2_ad = 0
wbufferx2_ad = 0
sbuffery2_ad = 0
nbuffery2_ad = 0
call mpp_get_boundary(x_fd, y_fd, domain, ebufferx=ebufferx2_ad(:,:), wbufferx=wbufferx2_ad(:,:), &
sbuffery=sbuffery2_ad(:,:), nbuffery=nbuffery2_ad(:,:), gridtype=CGRID_NE, &
complete = .true. )
fd_sum = 0.
do k = 1,nz
do j = jsc,jec
do i = isc,iec
fd_sum = fd_sum + x_fd(i,j,k)*x_fd(i,j,k)
end do
end do
end do
do k = 1,nz
do j = jsc,jec
do i = isc,iec
fd_sum = fd_sum + y_fd(i,j,k)*y_fd(i,j,k)
end do
end do
end do
do k = 1,nz
do i = 1,jec-jsc+1
fd_sum = fd_sum + ebufferx2_ad(i,k)*ebufferx2_ad(i,k)
end do
end do
do k = 1,nz
do i = 1,jec-jsc+1
fd_sum = fd_sum + wbufferx2_ad(i,k)*wbufferx2_ad(i,k)
end do
end do
do k = 1,nz
do i = 1,iec-isc+1
fd_sum = fd_sum + sbuffery2_ad(i,k)*sbuffery2_ad(i,k)
end do
end do
do k = 1,nz
do i = 1,iec-isc+1
fd_sum = fd_sum + nbuffery2_ad(i,k)*nbuffery2_ad(i,k)
end do
end do
call mpp_sum( fd_sum )
x_ad = x_fd
y_ad = y_fd
call mpp_get_boundary_ad(x_ad, y_ad, domain, ebufferx=ebufferx2_ad(:,:), wbufferx=wbufferx2_ad(:,:), &
sbuffery=sbuffery2_ad(:,:), nbuffery=nbuffery2_ad(:,:), gridtype=CGRID_NE, &
complete = .true. )
ad_sum = 0.
do k = 1,nz
do j = jsc,jec
do i = isc,iec
ad_sum = ad_sum + x_ad(i,j,k)*x_save(i,j,k)
end do
end do
end do
do k = 1,nz
do j = jsc,jec
do i = isc,iec
ad_sum = ad_sum + y_ad(i,j,k)*y_save(i,j,k)
end do
end do
end do
call mpp_sum( ad_sum )
if( pe.EQ.mpp_root_pe() ) then
if (abs(ad_sum-fd_sum)/fd_sum.lt.1E-7) then
print*, "Passed Adjoint Dot Test: mpp_get_boundary_ad"
endif
endif
deallocate (x_ad, y_ad, x_fd, y_fd, x_save, y_save)
deallocate (ebufferx2_ad, wbufferx2_ad)
deallocate (sbuffery2_ad, nbuffery2_ad)
end subroutine test_get_boundary_ad
subroutine test_halo_update_ad( type )
use mpp_mod, only : mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
use mpp_domains_mod, only : CGRID_NE
use mpp_domains_mod, only : mpp_update_domains, mpp_update_domains_ad
character(len=*), intent(in) :: type
type(domain2D) :: domain
integer :: shift, i, j, k
logical :: is_symmetry
integer :: is, ie, js, je, isd, ied, jsd, jed, pe
real*8, allocatable, dimension(:,:,:) :: x_ad, y_ad, x_fd, y_fd, x_save, y_save
real*8 :: ad_sum, fd_sum
if(index(type, 'symmetry') == 0) then
is_symmetry = .false.
else
is_symmetry = .true.
end if
select case(type)
case( 'Simple', 'Simple symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type, symmetry = is_symmetry )
case( 'Cyclic', 'Cyclic symmetry' )
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, xflags=CYCLIC_GLOBAL_DOMAIN, yflags=CYCLIC_GLOBAL_DOMAIN, &
name=type, symmetry = is_symmetry )
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type )
end select
!set up x array
call mpp_get_compute_domain( domain, is, ie, js, je )
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
shift=1
!---test 3d single fields----------------------------------------------------------
allocate( x_fd(isd:ied,jsd:jed,nz) )
allocate( x_ad(isd:ied,jsd:jed,nz) )
allocate( x_save(isd:ied,jsd:jed,nz) )
x_fd = 0.; x_ad = 0.; x_save = 0.
do k = 1,nz
do j = js,je
do i = is,ie
x_fd(i,j,k) = i*j
end do
end do
end do
x_save = x_fd
!full update
call mpp_update_domains( x_fd, domain )
fd_sum = 0.
do k = 1,nz
do j = jsd,jed
do i = isd,ied
fd_sum = fd_sum + x_fd(i,j,k)*x_fd(i,j,k)
end do
end do
end do
call mpp_sum( fd_sum )
x_ad = x_fd
call mpp_update_domains_ad( x_ad, domain )
ad_sum = 0.
do k = 1,nz
do j = jsd,jed
do i = isd,ied
ad_sum = ad_sum + x_ad(i,j,k)*x_save(i,j,k)
end do
end do
end do
call mpp_sum( ad_sum )
pe = mpp_pe()
if( pe.EQ.mpp_root_pe() ) then
if (abs(ad_sum-fd_sum)/fd_sum.lt.1E-7) then
print*, "Passed Adjoint Dot Test: mpp_update_domains_ad(single 3D field)"
endif
endif
deallocate (x_ad, x_fd, x_save)
!---test 3d vector fields----------------------------------------------------------
allocate( x_ad (isd:ied+shift,jsd:jed ,nz) )
allocate( x_fd (isd:ied+shift,jsd:jed ,nz) )
allocate( x_save(isd:ied+shift,jsd:jed ,nz) )
allocate( y_ad (isd:ied ,jsd:jed+shift,nz) )
allocate( y_fd (isd:ied ,jsd:jed+shift,nz) )
allocate( y_save(isd:ied ,jsd:jed+shift,nz) )
x_fd=0; y_fd=0
do k = 1,nz
do j = js,je
do i = is,ie
x_fd(i,j,k)=i*j
y_fd(i,j,k)=i*j
end do
end do
end do
call mpp_update_domains( x_fd, y_fd, domain, gridtype=CGRID_NE)
x_save=x_fd
y_save=y_fd
fd_sum = 0.
do k = 1,nz
do j = jsd,jed
do i = isd,ied+shift
fd_sum = fd_sum + x_fd(i,j,k)*x_fd(i,j,k)
end do
end do
end do
do k = 1,nz
do j = jsd,jed+shift
do i = isd,ied
fd_sum = fd_sum + y_fd(i,j,k)*y_fd(i,j,k)
end do
end do
end do
call mpp_sum( fd_sum )
x_ad = x_fd
y_ad = y_fd
call mpp_update_domains_ad( x_ad, y_ad, domain, gridtype=CGRID_NE)
ad_sum = 0.
do k = 1,nz
do j = jsd,jed
do i = isd,ied+shift
ad_sum = ad_sum + x_ad(i,j,k)*x_save(i,j,k)
end do
end do
end do
do k = 1,nz
do j = jsd,jed+shift
do i = isd,ied
ad_sum = ad_sum + y_ad(i,j,k)*y_save(i,j,k)
end do
end do
end do
call mpp_sum( ad_sum )
if( pe.EQ.mpp_root_pe() ) then
if (abs(ad_sum-fd_sum)/fd_sum.lt.1E-7) then
print*, "Passed Adjoint Dot Test: mpp_update_domains_ad(vector 3D fields)"
endif
endif
deallocate (x_ad, y_ad, x_fd, y_fd, x_save, y_save)
end subroutine test_halo_update_ad
subroutine test_global_reduce_ad (type)
use mpp_mod, only : mpp_pe, mpp_npes, mpp_root_pe, mpp_sum
use mpp_domains_mod, only : mpp_global_sum_tl, mpp_global_sum_ad
character(len=*), intent(in) :: type
real :: gsum_tl, gsum_ad
real*8 :: gsum_tl_save, gsum_ad_save
real :: gsum_tl_bit, gsum_ad_bit
real*8 :: gsum_tl_save_bit, gsum_ad_save_bit
integer :: i,j,k, ishift, jshift, position
integer :: isd, ied, jsd, jed
type(domain2D) :: domain
real, allocatable, dimension(:,:,:) :: x, x_ad, x_ad_bit
!--- set up domain
call mpp_define_layout( (/1,nx,1,ny/), npes, layout )
select case(type)
case( 'Simple' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type )
case( 'Simple symmetry center', 'Simple symmetry corner', 'Simple symmetry east', 'Simple symmetry north' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, &
shalo=shalo, nhalo=nhalo, name=type, symmetry = .true. )
case( 'Cyclic symmetry center', 'Cyclic symmetry corner', 'Cyclic symmetry east', 'Cyclic symmetry north' )
call mpp_define_domains( (/1,nx,1,ny/), layout, domain, whalo=whalo, ehalo=ehalo, shalo=shalo, nhalo=nhalo, &
name=type, symmetry = .true., xflags=CYCLIC_GLOBAL_DOMAIN, yflags=CYCLIC_GLOBAL_DOMAIN )
case default
call mpp_error( FATAL, 'TEST_MPP_DOMAINS: no such test: '//type//' in test_global_field' )
end select
call mpp_get_data_domain ( domain, isd, ied, jsd, jed )
!--- determine if an extra point is needed
ishift = 0; jshift = 0; position = CENTER
select case(type)
case ('Simple symmetry corner', 'Cyclic symmetry corner')
ishift = 1; jshift = 1; position = CORNER
case ('Simple symmetry east', 'Cyclic symmetry east' )
ishift = 1; jshift = 0; position = EAST
case ('Simple symmetry north', 'Cyclic symmetry north')
ishift = 0; jshift = 1; position = NORTH
end select
ied = ied+ishift; jed = jed+jshift
allocate( x(isd:ied,jsd:jed,nz), x_ad(isd:ied,jsd:jed,nz), x_ad_bit(isd:ied,jsd:jed,nz) )
x=0.
do k = 1,nz
do j = jsd, jed
do i = isd, ied
x(i,j,k) = i+j+k
enddo
enddo
enddo
gsum_tl = mpp_global_sum( domain, x, position = position )
gsum_tl_bit = mpp_global_sum( domain, x, flags=BITWISE_EXACT_SUM )
gsum_tl_save = gsum_tl*gsum_tl
gsum_tl_save_bit = gsum_tl_bit*gsum_tl_bit
gsum_ad = gsum_tl
gsum_ad_bit = gsum_tl_bit
x_ad = 0.
x_ad_bit = 0.
call mpp_global_sum_ad( domain, x_ad, gsum_ad, position = position )
call mpp_global_sum_ad( domain, x_ad_bit, gsum_ad_bit, flags = BITWISE_EXACT_SUM )
gsum_ad_save = 0.
gsum_ad_save_bit = 0.
do k = 1,nz
do j = jsd, jed
do i = isd, ied
gsum_ad_save = gsum_ad_save + x_ad(i,j,k)*x(i,j,k)
gsum_ad_save_bit = gsum_ad_save_bit + x_ad_bit(i,j,k)*x(i,j,k)
enddo
enddo
enddo
call mpp_sum( gsum_ad_save )
call mpp_sum( gsum_ad_save_bit )
pe = mpp_pe()
if( pe.EQ.mpp_root_pe() ) then
if (abs(gsum_ad_save-gsum_tl_save)/gsum_tl_save.lt.1E-7) then
print*, "Passed Adjoint Dot Test: mpp_global_sum_ad"
endif
if (abs(gsum_ad_save_bit-gsum_tl_save_bit)/gsum_tl_save_bit.lt.1E-7) then
print*, "Passed Adjoint Dot Test: mpp_global_sum_ad, flags=BITWISE_EXACT_SUM"
endif
endif
deallocate(x, x_ad, x_ad_bit)
end subroutine test_global_reduce_ad
end program test_mpp_domains