ESMF_ArrayRedistEx.F90 Source File


Source Code

! $Id$
!
! Earth System Modeling Framework
! Copyright (c) 2002-2023, University Corporation for Atmospheric Research,
! Massachusetts Institute of Technology, Geophysical Fluid Dynamics
! Laboratory, University of Michigan, National Centers for Environmental
! Prediction, Los Alamos National Laboratory, Argonne National Laboratory,
! NASA Goddard Space Flight Center.
! Licensed under the University of Illinois-NCSA License.
!
!==============================================================================

!==============================================================================
!ESMF_MULTI_PROC_EXAMPLE        String used by test script to count examples.
!==============================================================================

program ESMF_ArrayRedistEx
#include "ESMF.h"

  use ESMF
  use ESMF_TestMod

  
  implicit none
  
  ! local variables
  integer:: rc, petCount, localPet
  type(ESMF_VM):: vm
  type(ESMF_DistGrid):: srcDistGrid, dstDistGrid
  type(ESMF_Array):: srcArray, dstArray
  type(ESMF_Array):: srcArray1, dstArray1
  type(ESMF_Array):: srcArray2
  type(ESMF_ArraySpec):: arrayspec, arrayspec3d, arrayspec4d
  type(ESMF_RouteHandle):: redistHandle
  integer :: finalrc, result
  character(ESMF_MAXSTR) :: testname
  character(ESMF_MAXSTR) :: failMsg

  
  integer:: counter,i,j
  real(ESMF_KIND_R8), pointer:: farray2d(:,:)

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------

  write(failMsg, *) "Example failure"
  write(testname, *) "Example ESMF_ArrayRedistEx"


! ------------------------------------------------------------------------------
! ------------------------------------------------------------------------------
  finalrc = ESMF_SUCCESS
  call ESMF_Initialize(vm=vm, defaultlogfilename="ArrayRedistEx.Log", &
                    logkindflag=ESMF_LOGKIND_MULTI, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_VMGet(vm, localPet=localPet, petCount=petCount, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  
  if (petCount /= 4) then
    finalrc = ESMF_FAILURE
    goto 10
  endif
  
! ------------------------------------------------------------------------------
! ------------------------------------------------------------------------------

!BOE
!
! \subsubsection{Communication -- Redist}
! \label{Array:Redist}
! 
! Arrays used in different models often cover the same index space region,
! however, the distribution of the Arrays may be different, e.g. the models
! run on exclusive sets of PETs. Even if the Arrays are defined on the same
! list of PETs the decomposition may be different.
!EOE
!BOC
  srcDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/10,20/), &
    regDecomp=(/4,1/), rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/10,20/), &
    regDecomp=(/1,4/), rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! The number of elements covered by {\tt srcDistgrid} is identical to the number
! of elements covered by {\tt dstDistgrid} -- in fact the index space regions
! covered by both DistGrid objects are congruent. However, the decomposition
! defined by {\tt regDecomp}, and consequently the distribution of source and
! destination, are different.
!EOE
!BOC
  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE

! \paragraph{Default Mode}
! \label{Array:Redist:DefaultMode}
!
! By construction {\tt srcArray} and {\tt dstArray} are of identical type and
! kind. Further the number of exclusive elements matches between both Arrays.
! These are the prerequisites for the application of an Array redistribution
! in {\em default} mode. In order to increase performance of the actual 
! redistribution the communication pattern is precomputed once, and stored in
! an {\tt ESMF\_RouteHandle} object.
!EOE
!BOC
  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
!BOE
! The {\tt redistHandle} can now be used repeatedly to transfer data from
! {\tt srcArray} to {\tt dstArray}.
!EOE
!BOC
  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE
! \begin{sloppypar}
! The use of the precomputed {\tt redistHandle} is {\em not} restricted to
! the ({\tt srcArray}, {\tt dstArray}) pair. Instead the {\tt redistHandle}
! can be used to redistribute data between any two Arrays that are compatible
! with the Array pair used during precomputation. I.e. any pair of Arrays that
! matches {\tt srcArray} and {\tt dstArray} in {\em type}, {\em kind}, and 
! memory layout of the {\em distributed} dimensions. However, the size, number, 
! and index order of {\em undistributed} dimensions may be different.
! See section \ref{RH:Reusability} for a more detailed discussion of
! RouteHandle reusability.
! \end{sloppypar}
!
! The transferability of RouteHandles between Array pairs can greatly reduce
! the number of communication store calls needed.
! In a typical application Arrays are often defined on the same decomposition,
! typically leading to congruent distributed dimensions. For these Arrays, while
! they may not have the same shape or size in the undistributed dimensions,
! RouteHandles are reusable.
!
! For the current case, the {\tt redistHandle} was precomputed for simple 2D
! Arrays without undistributed dimensions. The RouteHandle transferability
! rule allows us to use this same RouteHandle to redistribute between two 
! 3D Array that are built on the same 2D DistGrid, but have an undistributed
! dimension. Note that the undistributed dimension does not have to be in the
! same position on source and destination. Here the undistributed dimension is
! in position 2 for {\tt srcArray1}, and in position 1 for {\tt dstArray1}.
!EOE
!BOC
  call ESMF_ArraySpecSet(arrayspec3d, typekind=ESMF_TYPEKIND_R8, rank=3, rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  srcArray1 = ESMF_ArrayCreate(arrayspec=arrayspec3d, distgrid=srcDistgrid, &
    distgridToArrayMap=(/1,3/), undistLBound=(/1/), undistUBound=(/10/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  dstArray1 = ESMF_ArrayCreate(arrayspec=arrayspec3d, distgrid=dstDistgrid, &
    distgridToArrayMap=(/2,3/), undistLBound=(/1/), undistUBound=(/10/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOE

!BOC
  call ESMF_ArrayRedist(srcArray=srcArray1, dstArray=dstArray1, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! The following variation of the code shows that the same RouteHandle can be
! applied to an Array pair even when the number of undistributed dimensions does
! not match between source and destination Array, as long as to the total
! {\em number} of undistributed {\em elements} matches.
!
! We prepare a source Array with {\em two} undistributed dimensions, in position
! 1 and 3, of size $2$ and $5$, respectively. Thus there are $2 \times 5=10$
! undistributed source elements. The destination array is the same as before
! with only a {\em single} undistributed dimension in position 1
! of size $10$.
!EOE
!BOC
  call ESMF_ArraySpecSet(arrayspec4d, typekind=ESMF_TYPEKIND_R8, rank=4, rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  srcArray2 = ESMF_ArrayCreate(arrayspec=arrayspec4d, distgrid=srcDistgrid, &
    distgridToArrayMap=(/2,4/), undistLBound=(/1,1/), undistUBound=(/2,5/), &
    rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOC
  call ESMF_ArrayRedist(srcArray=srcArray2, dstArray=dstArray1, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! When done, the resources held by {\tt redistHandle} need to be deallocated
! by the user code before the RouteHandle becomes inaccessible.
!EOE
!BOC
  call ESMF_ArrayRedistRelease(routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  
  call ESMF_ArrayDestroy(srcArray2, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_ArrayDestroy(srcArray1, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_ArrayDestroy(dstArray1, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_ArrayDestroy(dstArray, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_DistGridDestroy(dstDistgrid, rc=rc) ! destroy the DistGrid object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  
!BOE
! \paragraph{Transpose Mode}
! \label{Array:Redist:TransposeMode}
!
! \begin{sloppypar}
! In default mode, i.e. without providing the optional
! {\tt srcToDstTransposeMap} argument, {\tt ESMF\_ArrayRedistStore()} does not
! require equal number of dimensions in source and destination Array. Only the
! total number of elements must match.
! Specifying {\tt srcToDstTransposeMap} switches {\tt ESMF\_ArrayRedistStore()}
! into {\em transpose} mode. In this mode each dimension of {\tt srcArray}
! is uniquely associated with a dimension in {\tt dstArray}, and the sizes of 
! associated dimensions must match for each pair.
! \end{sloppypar}
! 
!EOE
!BOC
  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/20,10/), &
      rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_ArrayGet(srcArray, farrayPtr=farray2d, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  counter = localPet*100
  do j=lbound(farray2d,2),ubound(farray2d,2)
    do i=lbound(farray2d,1),ubound(farray2d,1)
      farray2d(i,j) = Real(counter, ESMF_KIND_R8)
      counter = counter+1
    enddo
  enddo
  
!  call ESMF_ArrayPrint(srcArray)
  
!BOE
! This {\tt dstArray} object covers a 20 x 10 index space while the
! {\tt srcArray}, defined further up, covers a 10 x 20 index space. Setting
! {\tt srcToDstTransposeMap = (/2,1/)} will associate the first and second 
! dimension of {\tt srcArray} with the second and first dimension of
! {\tt dstArray}, respectively. This corresponds to a transpose of dimensions.
! Since the decomposition and distribution of dimensions may be different for
! source and destination redistribution may occur at the same time.
!EOE
!BOC
  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/2,1/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!  call ESMF_ArrayPrint(dstArray)

  call ESMF_ArrayRedistRelease(routehandle=redistHandle, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  
  call ESMF_ArrayDestroy(srcArray, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_DistGridDestroy(srcDistgrid, rc=rc) ! destroy the DistGrid object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_ArrayDestroy(dstArray, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_DistGridDestroy(dstDistgrid, rc=rc) ! destroy the DistGrid object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! \begin{sloppypar}
! The transpose mode of {\tt ESMF\_ArrayRedist()} is not limited to
! distributed dimensions of Arrays. The {\tt srcToDstTransposeMap} argument
! can be used to transpose undistributed dimensions in the same manner.
! Furthermore transposing distributed and undistributed dimensions between
! Arrays is also supported.
! \end{sloppypar}
!
! The {\tt srcArray} used in the following examples is of rank 4 with 2 
! distributed and 2 undistributed dimensions. The distributed dimensions
! are the two first dimensions of the Array and are distributed according to the
! {\tt srcDistgrid} which describes a total index space region of 100 x 200
! elements. The last two Array dimensions are undistributed dimensions of size
! 2 and 3, respectively.
!EOE
!BOC
  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=4, rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  srcDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/100,200/), &
    rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, &
    undistLBound=(/1,1/), undistUBound=(/2,3/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! The first {\tt dstArray} to consider is defined on a DistGrid that also 
! describes a 100 x 200 index space region. The distribution indicated
! by {\tt dstDistgrid} may be different from the source distribution. Again
! the first two Array dimensions are associated with the DistGrid dimensions in
! sequence. Furthermore, the last two Array dimensions are undistributed
! dimensions, however, the sizes are 3 and 2, respectively.
!EOE
!BOC
  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/100,200/), &
    rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    undistLBound=(/1,1/), undistUBound=(/3,2/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! The desired mapping between {\tt srcArray} and {\tt dstArray} dimensions
! is expressed by {\tt srcToDstTransposeMap = (/1,2,4,3/)}, transposing only
! the two undistributed dimensions.
!EOE
!BOC
  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/1,2,4,3/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_ArrayRedistRelease(routehandle=redistHandle, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  
  call ESMF_ArrayDestroy(dstArray, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! Next consider a {\tt dstArray} that is defined on the same {\tt dstDistgrid},
! but with a different order of Array dimensions. The desired order is
! specified during Array creation using the argument 
! {\tt distgridToArrayMap = (/2,3/)}. This map associates the first and second
! DistGrid dimensions with the second and third Array dimensions, respectively,
! leaving Array dimensions one and four undistributed.
!EOE  

!BOC
  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    distgridToArrayMap=(/2,3/), undistLBound=(/1,1/), undistUBound=(/3,2/), &
    rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  
!BOE
! Again the sizes of the undistributed dimensions are chosen in reverse order
! compared to {\tt srcArray}. The desired transpose mapping in this case will
! be {\tt srcToDstTransposeMap = (/2,3,4,1/)}.
!EOE

!BOC
  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/2,3,4,1/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_ArrayRedistRelease(routehandle=redistHandle, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  
  call ESMF_ArrayDestroy(dstArray, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_DistGridDestroy(dstDistgrid, rc=rc) ! destroy the DistGrid object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! Finally consider the case where {\tt dstArray} is constructed on a 
! 200 x 3 index space and where the undistributed dimensions are of size
! 100 and 2.
!EOE

!BOC
  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/200,3/), &
    rc=rc)
!EOC  
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    undistLBound=(/1,1/), undistUBound=(/100,2/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! By construction {\tt srcArray} and {\tt dstArray} hold the same number of
! elements, albeit in a very different layout. Nevertheless, with a
! {\tt srcToDstTransposeMap} that maps matching dimensions from source to
! destination, the following Array redistribution becomes a well defined
! operation between {\tt srcArray} and {\tt dstArray}.
!EOE

!BOC
  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/3,1,4,2/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_ArrayRedistRelease(routehandle=redistHandle, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! The {\tt srcToDstTransposeMap} mechanism supports negative map entries.
! Negative entries indicate that the order of elements is to be reversed when
! going from source to destination.
! Using the same {\tt srcArray} and {\tt dstArray} objects as in the previous
! example, the following code maps the first {\tt srcArray} dimension to the
! third {\tt dstArray} dimension, as before. However, the ordering of
! the elements along this dimension is reversed between source and destination.
!EOE

!BOC
  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/-3,1,4,2/), rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
!BOC
  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)
!EOC
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

  call ESMF_ArrayRedistRelease(routehandle=redistHandle, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!-------------------------

  call ESMF_ArrayDestroy(srcArray, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_DistGridDestroy(srcDistgrid, rc=rc) ! destroy the DistGrid object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_ArrayDestroy(dstArray, rc=rc) ! destroy the Array object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)
  call ESMF_DistGridDestroy(dstDistgrid, rc=rc) ! destroy the DistGrid object
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(endflag=ESMF_END_ABORT)

!BOE
! Redistribution of multi-tile Arrays is supported, although not shown as an
! example here. In {\em default} mode, the
! index space defined by both source and destination Arrays must match,
! regardless of how it is comprised by tiles. In particular, there is no
! restriction on the number of source and desination tiles, as long as both
! sides define the same global index space.
!
! The situation is different in {\em transpose} mode. Here the number of source
! and destination tiles must match. In this case, the redistribution is defined
! tile-by-tile in order. If the provided 
! {\tt srcToDstTransposeMap} is of size {\tt rank}, it is used for all of the
! tiles. The other supported option is where {\tt srcToDstTransposeMap} is of
! size $rank \times tileCount$. In that case each source-destination tile-pair
! has its own transpose map.
!EOE

! ------------------------------------------------------------------------------
! ------------------------------------------------------------------------------
10 continue
  ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors in the log
  ! file that the scripts grep for.
  call ESMF_STest((finalrc.eq.ESMF_SUCCESS), testname, failMsg, result, ESMF_SRCLINE)

  call ESMF_Finalize(rc=rc)

  if (rc/=ESMF_SUCCESS) finalrc = ESMF_FAILURE
  if (finalrc==ESMF_SUCCESS) then
    print *, "PASS: ESMF_ArrayRedistEx.F90"
  else
    print *, "FAIL: ESMF_ArrayRedistEx.F90"
  endif
! ------------------------------------------------------------------------------
! ------------------------------------------------------------------------------

end program