! $Id: arrayscatter.H,v 1.3 2007/06/14 18:47:42 ltakacs Exp $

#ifdef NAME_
#undef NAME_
#endif

#define NAME_ ArrayScatter_

#include "overload.macro"


  subroutine SUB_(local_array, global_array, grid, mask, depe, hw, rc),3

! Mask is really a permutation on the first dimension

    TYPE_(kind=EKIND_),         intent(  OUT) :: local_array  DIMENSIONS_
    TYPE_(kind=EKIND_), target, intent(IN   ) :: global_array DIMENSIONS_
    type (ESMF_Grid)                          :: grid
    integer, optional,          intent(IN   ) :: mask(:)
    integer, optional,          intent(IN   ) :: depe
    integer, optional,          intent(IN   ) :: hw
    integer, optional,          intent(  OUT) :: rc
    
! Local variables

    integer                               :: status
    character(len=ESMF_MAXSTR)            :: IAm='ArrayScatter'

    TYPE_(kind=EKIND_),    pointer        :: myglob DIMENSIONS_ => null()
    TYPE_(kind=EKIND_),    pointer        :: VAR(:)
    type(ESMF_DELayout)                   :: LAYOUT
    type(ESMF_AxisIndex),  pointer        :: AI(:,:)
    integer, dimension(:), allocatable    :: SENDCOUNTS, DISPLS, KK
    integer                               :: nDEs
    integer                               :: recvcount
    integer                               :: I, J, K, II,  JJ, de, deId
    integer                               :: I1, IN, J1, JN
    integer                               :: gridRank
    integer                               :: LX, LY
    integer                               :: srcPE
    integer                               :: MYHW, ISZ, JSZ, ISZL

! Works only on 1D and D arrays

    ASSERT_(RANK_ <= 2)

! Optional change of source PE. Default=root

    if(present(depe)) then
       srcPE = depe 
    else
       srcPE = root
    end if

! Optional single halo width

    if(present(hw)) then
       myhw = hw
    else
       myhw = 0
    end if

! Some halo limitations

    if(myhw > 0) then
       ASSERT_(RANK_ == 2        ) ! No halo allowed on 1D
       ASSERT_(.not.present(MASK)) ! No halo allowed if 1st dim is permutted
    end if

! Get grid and layout information

    call ESMF_GridGet    (GRID,   dimCount=gridRank, rc=STATUS);VERIFY_(STATUS)
    call ESMF_GridGet    (GRID,   delayout=layout,   rc=STATUS);VERIFY_(STATUS)
    call ESMF_DELayoutGet(LAYOUT, localDE =deId,     rc=STATUS);VERIFY_(STATUS)
    call ESMF_DELayoutGet(LAYOUT, deCount =nDEs,     rc=STATUS);VERIFY_(STATUS)

    allocate (AI(1:nDEs,gridRank),  stat=status)
    VERIFY_(STATUS)
    allocate (sendcounts(0:nDEs-1), stat=status)
    VERIFY_(STATUS)

    if (gridRank == 3) then
       call ESMF_GridGetAllAxisIndex(grid, &
                                     horzRelLoc=ESMF_CELL_CENTER, &
                                     vertRelLoc=ESMF_CELL_CELL, &
                                     globalAI=AI, rc=status)
    else
       call ESMF_GridGetAllAxisIndex(grid, &
                                     horzRelLoc=ESMF_CELL_CENTER, &
                                     globalAI=AI, rc=status)
    end if
    VERIFY_(STATUS)

    ISZ = size(GLOBAL_ARRAY,1)

#if (RANK_ == 2)
       JSZ = size(GLOBAL_ARRAY,2)
#else
       JSZ = 1
#endif

! Compute count to be sent to each PE

    if(present(mask)) then
       sendcounts = 0
       do II = 1,ISZ
          sendcounts(mask(ii)) = sendcounts(mask(ii)) + 1
       enddo
       sendcounts = sendcounts*JSZ

    else
       do I = 1,nDEs
          LX = AI(I,1)%max - AI(I,1)%min + 1 + 2*MYHW
#if (RANK_ == 1)
          sendcounts(I-1) = LX
#else
          LY = AI(I,2)%max - AI(I,2)%min + 1 + 2*MYHW
          sendcounts(I-1) = LX*LY
#endif
       end do
    end if

! Count I will recieve

    recvcount = sendcounts(deID)

! Put VAR together at the srcPE 

    if (deId == srcPE) then

       allocate(DISPLS(0:nDEs          ), stat=status)
       VERIFY_(STATUS)

! Compute displacements into the VAR vector

       displs(0) = 0
       do I = 1,nDEs
          displs(I) = displs(I-1) + sendcounts(I-1)
       end do
!ALT       ASSERT_(displs(nDEs) == (ISZ+2*myhw)*(JSZ+2*myhw))

! If there is a halo, make a haloed copy of the global array.
!   otherwise just copy the pointer.

       myglob => global_array
       
#if (RANK_ == 2)
       if (myhw > 0) then
          allocate(myglob(1-myhw:isz+myhw,1-myhw:jsz+myhw), stat=status)
          VERIFY_(STATUS)
          myglob(1:isz,1:jsz) = GLOBAL_ARRAY

! Fill the halo (I is cyclic)
       
          do j=1,myhw
             myglob(1  -j,:) = myglob(isz-j+1,:)
             myglob(isz+j,:) = myglob(    j  ,:)
             myglob(:,1  -j) = MAPL_Undef
             myglob(:,jsz+j) = MAPL_Undef
          enddo
       endif
#endif

! Fill the VAR vector
       
       if (present(mask)) then
          allocate(VAR(0:displs(nDEs)-1), stat=status)
          VERIFY_(STATUS)
          allocate(KK (0:nDEs-1        ), stat=status)
          VERIFY_(STATUS)
          KK = DISPLS(0:nDEs-1)

          do I=1,ISZ
             K = MASK(I)
             II = KK(K)
#if (RANK_ == 1)
             VAR(II) = MYGLOB(I)
#else
             LX = AI(K+1,1)%max - AI(K+1,1)%min + 1 
             do J=1,JSZ
                VAR(II+LX*(J-1)) = MYGLOB(I,J)
             end do
#endif
             KK(MASK(I)) = KK(MASK(I)) + 1 
          end do

          deallocate(KK, stat=status)
          VERIFY_(STATUS)

       else

#if (RANK_ == 1)
          var => myglob
#else
          allocate(VAR(0:displs(nDEs)-1), stat=status)
          VERIFY_(STATUS)

          do I = 1,nDEs
             I1 = AI(I,1)%min - myhw
             IN = AI(I,1)%max + myhw
             J1 = AI(I,2)%min - myhw
             JN = AI(I,2)%max + myhw

             K = displs(I-1)
             do JJ=J1,JN
                do II=I1,IN
                   var(K) = MYglob(II,JJ)
                   K = K+1
                end do
             end do
          end do
#endif

       endif !  present(mask)

       if (myhw > 0) then
          deallocate(myglob, stat=status)
          VERIFY_(STATUS)
       end if
    
    end if !  I am srcPE


! Do the communications
    
    call MAPL_CommsScatterV(layout, var, sendcounts, displs, &
                            local_array, recvcount, srcPE, status)
    VERIFY_(STATUS)

! Clean-up

    if (deId == srcPE) then
       deallocate(displs, stat=status)
       VERIFY_(STATUS)
       if(present(mask) .or. RANK_ == 2) then
          deallocate(VAR, stat=status)
          VERIFY_(STATUS)
       end if
    endif

    deallocate(sendcounts, stat=status)
    VERIFY_(STATUS)
    deallocate(AI,         stat=status)
    VERIFY_(STATUS)

! All done

    RETURN_(ESMF_SUCCESS)
  end subroutine SUB_

#undef NAME_
#undef DIMENSIONS_
#undef RANK_
#undef VARTYPE_