next up previous contents
Next: 4 Infrastructure: Utilities Up: ESMF_refdoc Previous: 2 Superstructure   Contents

Subsections

3 Infrastructure: Fields and Grids

16 Overview of Infrastructure Data Handling

The ESMF infrastructure data classes are part of the framework's hierarchy of structures for handling Earth system model data and metadata on parallel platforms. The hierarchy is in complexity; the simplest data class in the infrastructure represents a distributed array and the most complex data class represents a bundle of physical fields that are discretized on the same grid. Data class methods are called both from user-written code and from other classes internal to the framework.

Data classes are distributed over DEs, or Decomposition Elements. A DE represents a piece of a decomposition. A DELayout is a collection of DEs with some associated connectivity that describes a specific distribution. For example, the distribution of a grid divided into four segments in the x-dimension would be expressed in ESMF as a DELayout with four DEs lying along an x-axis. This abstract concept enables a data decomposition to be defined in terms of threads, MPI processes, virtual decomposition elements, or combinations of these without changes to user code. This is a primary strategy for ensuring optimal performance and portability for codes using the ESMF for communications.

ESMF data classes are useful because they provide a standard, convenient way for developers to collect together information related to model or observational data. The information assembled in a data class includes a data pointer, a set of attributes (e.g. units, although attributes can also be user-defined), and a description of an associated grid. The same set of information within an ESMF data object can be used by the framework to arrange intercomponent data transfers, to perform I/O, for communications such as gathers and scatters, for simplification of interfaces within user code, for debugging, and for other functions. This unifies and organizes codes overall so that the user need not define different representations of metadata for the same field for I/O and for component coupling.

Since it is critical that users be able to introduce ESMF into their codes easily and incrementally, ESMF data classes can be created based on native Fortran pointers. Likewise, there are methods for retrieving native Fortran pointers from within ESMF data objects. This allows the user to perform allocations using ESMF, and to retrieve Fortran arrays later for optimized model calculations. The ESMF data classes do not have associated differential operators or other mathematical methods.

For flexibility, it is not necessary to build an ESMF data object all at once. For example, it's possible to create a field but to defer allocation of the associated field data until a later time.


Key Features
Hierarchy of data structures designed specifically for the Earth system domain and high performance, parallel computing.
Multi-use ESMF structures simplify user code overall.
Data objects support incremental construction and deferred allocation.
Native Fortran arrays can be associated with or retrieved from ESMF data objects, for ease of adoption, convenience, and performance.

16.1 Infrastructure Data Classes

The main classes that are used for model and observational data manipulation are as follows:

16.2 Object Model

The following is a simplified UML diagram showing the relationships among ESMF Field, Grid and Bundle classes. See Appendix A, A Brief Introduction to UML, for a translation table that lists the symbols in the diagram and their meaning.

\includegraphics{Bundle_obj}

16.3 Design and Implementation Notes

  1. In communication methods such as Regrid, Redist, Scatter, etc. the Bundle and Field code cascades down through the Array code, so that the actual computations exist in only one place in the source.

17 Bundle Class

17.1 Description

The Bundle class represents ``bundles'' of Fields that are discretized on the same Grid and distributed in the same manner. Fields within a Bundle may be located at different locations relative to the vertices of their common Grid. The Fields in a Bundle may be of different dimensions, as long as the Grid dimensions that are distributed are the same. For example, a surface Field on a distributed lat/lon Grid and a 3D Field with an added vertical dimension on the same distributed lat/lon Grid can be included in the same Bundle.

Bundles currently function mainly as convenient containers for storing Fields. Bundles can be created and destroyed, can have attributes added or retrieved, and can have Fields added or retrieved. Methods include a variety of queries that return information about the attributes and the Fields that a Bundle contains. The Fortran data pointer of a Field within a Bundle can be obtained by passing the Bundle a Field name.

Memory layout information is stored in a BundleDataMap object which is attached to the Bundle. It can be accessed by querying the Bundle. Although we have made the BundleDataMap public, many of the memory layout options have not been implemented.

Bundles are one of the data objects that can be added to States, which are used for sending to or receiving data from other components.

In the future Bundles will serve as a mechanism for performance optimization. ESMF will take advantage of the similarities of the Fields within a Bundle in order to implement collective communication, IO, and regridding. See Section 17.4 for a description of features that are being planned.

17.2 Bundle Options

17.2.1 ESMF_PackFlag

DESCRIPTION:
Specifies whether a Bundle is packed or not. A packed Bundle contains an array in which all the data in its constituent Fields is packed contiguously. Bundles that are not packed are not guaranteed to carry a contiguous array of their data. This flag is not yet implemented; the value is always set to ESMF_NO_PACKED_DATA.

Valid values are:

ESMF_PACKED_DATA
Contains a packed array.
ESMF_NO_PACKED_DATA
Does not contain a packed array.

17.3 Use and Examples

Examples of creating, destroying and accessing Bundles and their constituent Fields are provided in this section, along with some notes on Bundle methods.

17.3.1 Bundle Creation

After creating multiple Fields, a Bundle can be created by passing a list of the Fields into the method ESMF_BundleCreate(). The Bundle will contain references to the Fields. An empty Bundle can also be created and Fields added singularly or in groups.

The feature which requests a packed Array be created from the combined Field data arrays is not implemented in this version of the framework.

17.3.2 Accessing Bundle Data

To access data in a Bundle the user can provide a Field name and retrieve the Field's Fortran data pointer. Alternatively, the user can retrieve the data in the form of an ESMF Field and use the Field-level interfaces.

The packed Array feature of Bundles is not implemented in this version of the Framework.

17.3.3 Bundle Deletion

The user must call ESMF_BundleDestroy() before deleting any of the Fields it contains. Because Fields can be shared by multiple Bundles and States, they are not deleted by this call.

See the following code fragments for examples of how to create new Bundles.

 
     ! Example program showing various ways to create a Bundle object.
 
     program ESMF_BundleCreateEx
 
     ! ESMF Framework module
     use ESMF_Mod
 
     implicit none
     
     ! Local variables
     integer :: i, rc, fieldcount
     type(ESMF_Grid) :: grid
     type(ESMF_ArraySpec) :: arrayspec
     !type(ESMF_FieldDataMap) :: datamap
     type(ESMF_DELayout) :: delayout
     type(ESMF_VM) :: vm
     character (len = ESMF_MAXSTR) :: bname1, fname1, fname2
     type(ESMF_Field) :: field(10), returnedfield1, returnedfield2, simplefield
     type(ESMF_Bundle) :: bundle1, bundle2, bundle3
   !real (selected_real_kind(6,45)), dimension(:,:), pointer :: f90ptr1, f90ptr2
     integer :: counts(2)
     real(ESMF_KIND_R8) :: min_coord(2), max_coord(2)

!   !  Create several Fields and add them to a new Bundle.
 
!    counts = (/ 100, 200 /)
!    min_coord = (/  0.0,  0.0 /)
!    max_coord = (/ 50.0, 60.0 /)
    delayout = ESMF_DELayoutCreate(vm, rc=rc)
    grid = ESMF_GridCreateShapeTile(minIndex=(/1,1/), maxIndex=(/100,200/), &
                                  regDecomp=(/2,2/), name="atmgrid", rc=rc)

    call ESMF_ArraySpecSet(arrayspec, 2, ESMF_TYPEKIND_R8, rc=rc)
    if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE

    field(1) = ESMF_FieldCreate(grid, arrayspec, &
                                staggerloc=ESMF_STAGGERLOC_CENTER, &
                                name="pressure", rc=rc)

    field(2) = ESMF_FieldCreate(grid, arrayspec, &
                                staggerloc=ESMF_STAGGERLOC_CENTER, &
                                name="temperature", rc=rc)

    field(3) = ESMF_FieldCreate(grid, arrayspec, &
                                staggerloc=ESMF_STAGGERLOC_CENTER, &
                                name="heat flux", rc=rc)

    bundle1 = ESMF_BundleCreate(3, field, name="atmosphere data", rc=rc)

    print *, "Bundle example 1 returned"

!-------------------------------------------------------------------------
!   !  Create an empty Bundle and then add a single field to it.


    simplefield = ESMF_FieldCreate(grid, arrayspec, &
                                staggerloc=ESMF_STAGGERLOC_CENTER, name="rh", rc=rc)

    bundle2 = ESMF_BundleCreate(name="time step 1", rc=rc)

    call ESMF_BundleAddField(bundle2, simplefield, rc)

    call ESMF_BundleGet(bundle2, fieldCount=fieldcount, rc=rc)

    print *, "Bundle example 2 returned, fieldcount =", fieldcount

!-------------------------------------------------------------------------
!   !  Create an empty Bundle and then add multiple fields to it.


    bundle3 = ESMF_BundleCreate(name="southern hemisphere", rc=rc)

    call ESMF_BundleAddField(bundle3, 3, field, rc)

    call ESMF_BundleGet(bundle3, fieldCount=fieldcount, rc=rc)

    print *, "Bundle example 3 returned, fieldcount =", fieldcount

!-------------------------------------------------------------------------
!   !  Get a Field back from a Bundle, first by name and then by index.
!   !  Also get the Bundle name.

    call ESMF_BundleGetField(bundle1, "pressure", returnedfield1, rc)

    call ESMF_FieldGet(returnedfield1, name=fname1, rc=rc)

    call ESMF_BundleGetField(bundle1, 2, returnedfield2, rc)

    call ESMF_FieldGet(returnedfield2, name=fname2, rc=rc)

    call ESMF_BundleGet(bundle1, name=bname1, rc=rc)

    print *, "Bundle example 4 returned, field names = ", &
                   trim(fname1), ", ", trim(fname2)
    print *, "Bundle name = ", trim(bname1)

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

     call ESMF_BundleDestroy(bundle1, rc=rc)

     call ESMF_BundleDestroy(bundle2, rc=rc)

     call ESMF_BundleDestroy(bundle3, rc=rc)

     do i=1, 3
         call ESMF_FieldDestroy(field(i),rc=rc)

     enddo

     call ESMF_FieldDestroy(simplefield, rc=rc)

     end program ESMF_BundleCreateEx

17.4 Restrictions and Future Work

  1. No mathematical operators. The Bundle class does not support differential or other mathematical operators. We do not anticipate providing this functionality in the near future.

  2. Limited validation and print options. We are planning to increase the number of validity checks available for Bundles as soon as possible. We also will be working on print options.

  3. Limited communication support. Only a subset of the communication routines are currently supported for Bundles, and the Fields contained in the Bundles must currently have the same structure (e.g. same halo width, same dimensionality). Support for more variable data will be added in a later release. For those routines not implemented yet, or for those Bundles which contain Fields with differing data, the user can loop over the Fields in the Bundle and call the Field level communication routines instead.

  4. Packed data not supported. One of the options that we are currently working on for Bundles is packing. Packing means that the data from all the Fields that comprise the Bundle are copied into a single Array and manipulated collectively. This operation can be done without destroying the original Field data. Packing is being designed to facilitate optimized regridding, data communication, and IO operations. It will be possible to collectively manipulate all the Fields within a Bundle at once, rather than operating on each Field separately. This will reduce the latency overhead of the communication.

  5. Interleaving Fields within a Bundle. Data locality is important for performance on some computing platforms. An interleave option will allow the user to create a packed Bundle in which Fields are either concatenated in memory or in which Field elements are interleaved.

17.5 Design and Implementation Notes

  1. Fields in a Bundle reference the same Grid. In order to reduce memory requirements and ensure consistency, the Fields within a Bundle all reference the same Grid object.

17.6 Class API: Basic Bundle Methods

17.6.1 ESMF_BundleAddField - Add a Field to a Bundle


INTERFACE:

       ! Private name; call using ESMF_BundleAddField()
       subroutine ESMF_BundleAddOneField(bundle, field, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle
       type(ESMF_Field), intent(inout) :: field
       integer, intent(out), optional :: rc
DESCRIPTION:

Adds a single field to an existing bundle. The field must be associated with the same ESMF_Grid as the other ESMF_Fields in the bundle. The field is referenced by the bundle, not copied.

The arguments are:

bundle
The ESMF_Bundle to add the ESMF_Field to.
field
The ESMF_Field to add.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.2 ESMF_BundleAddField - Add a list of Fields to a Bundle


INTERFACE:

       ! Private name; call using ESMF_BundleAddField()
       subroutine ESMF_BundleAddFieldList(bundle, fieldCount, fieldList, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle        
       integer, intent(in) :: fieldCount
       type(ESMF_Field), dimension(:), intent(inout) :: fieldList
       integer, intent(out), optional :: rc
DESCRIPTION:

Adds a fieldList to an existing ESMF_Bundle. The items added from the ESMF_fieldList must be associated with the same ESMF_Grid as the other ESMF_Fields in the bundle. The items in the fieldList are referenced by the bundle, not copied.

The arguments are:

bundle
ESMF_Bundle to add ESMF_Fields to.
fieldCount
Number of ESMF_Fields to be added to the ESMF_Bundle; must be equal to or less than the number of items in the fieldList.
fieldList
Array of existing ESMF_Fields. The first fieldCount items will be added to the ESMF_Bundle.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.3 ESMF_BundleCreate - Create a Bundle from existing Fields


INTERFACE:

       ! Private name; call using ESMF_BundleCreate()
       function ESMF_BundleCreateNew(fieldCount, fieldList, &
                                     packflag, bundleinterleave, name, iospec, rc)
RETURN VALUE:
       type(ESMF_Bundle) :: ESMF_BundleCreateNew
ARGUMENTS:
       integer, intent(in) :: fieldCount           
       type(ESMF_Field), dimension (:) :: fieldList
       type(ESMF_PackFlag), intent(in), optional :: packflag 
       type(ESMF_InterleaveFlag), intent(in), optional :: bundleinterleave
       character (len = *), intent(in), optional :: name 
       type(ESMF_IOSpec), intent(in), optional :: iospec
       integer, intent(out), optional :: rc
DESCRIPTION:

Creates an ESMF_Bundle from a list of existing ESMF_Fields stored in a fieldList. All items in the fieldList must be associated with the same ESMF_Grid. Returns a new ESMF_Bundle.

The arguments are:

fieldCount
Number of fields to be added to the new ESMF_Bundle. Must be equal to or less than the number of ESMF_Fields in the fieldList.
fieldList
Array of existing ESMF_Fields. The first ESMF_FieldCount items will be added to the new ESMF_Bundle.
[packflag]
The packing option is not yet implemented. See Section 17.4 for a description of packing, and Section 17.2.1 for anticipated values. The current implementation corresponds to the value ESMF_NO_PACKED_DATA, which means that every ESMF_Field is referenced separately rather than being copied into a single contiguous buffer. This is the case no matter what value, if any, is passed in for this argument.
[bundleinterleave]
The interleave option is not yet implemented. See Section 17.4 for a brief description of interleaving, and Section [*] for anticipated values. The flag is not applicable to the current implementation, since it applies only to packed data (see the packflag argument).
[name]
ESMF_Bundle name. A default name is generated if one is not specified.
[iospec]
The ESMF_IOSpec is not yet used by ESMF_Bundles. Any values passed in will be ignored.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.4 ESMF_BundleCreate - Create a Bundle with no Fields


INTERFACE:

       ! Private name; call using ESMF_BundleCreate()
       function ESMF_BundleCreateNoFields(grid, name, iospec, rc)
RETURN VALUE:
       type(ESMF_Bundle) :: ESMF_BundleCreateNoFields
ARGUMENTS:
       type(ESMF_Grid), intent(in), optional :: grid
       character (len = *), intent(in), optional :: name 
       type(ESMF_IOSpec), intent(in), optional :: iospec
       integer, intent(out), optional :: rc
DESCRIPTION:

Creates an ESMF_Bundle with no associated ESMF_Fields.

The arguments are:

[grid]
The ESMF_Grid which all ESMF_Fields added to this ESMF_Bundle must be associated with. If not specified now, the grid associated with the first ESMF_Field added will be used as the reference grid for the ESMF_Bundle.
[name]
ESMF_Bundle name. A default name is generated if one is not specified.
[iospec]
The ESMF_IOSpec is not yet used by ESMF_Bundles. Any values passed in will be ignored.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.5 ESMF_BundleDestroy - Free all resources associated with a Bundle


INTERFACE:

       subroutine ESMF_BundleDestroy(bundle, rc)
ARGUMENTS:
       type(ESMF_Bundle) :: bundle
       integer, intent(out), optional :: rc
DESCRIPTION:

Releases resources associated with the bundle. This method does not destroy the ESMF_Fields that the bundle contains. The bundle should be destroyed before the ESMF_Fields within it are.

bundle
An ESMF_Bundle object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.6 ESMF_BundleGet - Return information about a Bundle


INTERFACE:

       subroutine ESMF_BundleGet(bundle, grid, fieldCount, name, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle
       type(ESMF_Grid), intent(out), optional :: grid
       integer, intent(out), optional :: fieldCount
       character (len = *), intent(out), optional :: name
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns information about the bundle. If the ESMF_Bundle was originally created without specifying a name, a unique name will have been generated by the framework.

The arguments are:

bundle
The ESMF_Bundle object to query.
[grid]
The ESMF_Grid associated with the bundle.
[fieldCount]
Number of ESMF_Fields in the bundle.
[name]
A character string where the bundle name is returned.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.7 ESMF_BundleGetAttribute - Retrieve an attribute


INTERFACE:

       subroutine ESMF_BundleGetAttribute(bundle, name, <value argument>, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle  
       character (len = *), intent(in) :: name
       <value argument>, see below for supported values
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns an attribute from the bundle. Supported values for <value argument> are:

integer(ESMF_KIND_I4), intent(out) :: value
integer(ESMF_KIND_I4), dimension(:), intent(out) :: valueList
integer(ESMF_KIND_I8), intent(out) :: value
integer(ESMF_KIND_I8), dimension(:), intent(out) :: valueList
real (ESMF_KIND_R4), intent(out) :: value
real (ESMF_KIND_R4), dimension(:), intent(out) :: valueList
real (ESMF_KIND_R8), intent(out) :: value
real (ESMF_KIND_R8), dimension(:), intent(out) :: valueList
type(ESMF_Logical), intent(out) :: value
type(ESMF_Logical), dimension(:), intent(out) :: valueList
character (len = *), intent(out), value

The arguments are:

bundle
An ESMF_Bundle object.
name
The name of the attribute to retrieve.
<value argument>
The value of the named attribute.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.8 ESMF_BundleGetAttributeCount - Query the number of attributes


INTERFACE:

       subroutine ESMF_BundleGetAttributeCount(bundle, count, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle  
       integer, intent(out) :: count   
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns the number of attributes associated with the given bundle in the argument count.

The arguments are:

bundle
An ESMF_Bundle object.
count
The number of attributes associated with this object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.9 ESMF_BundleGetAttributeInfo - Query Bundle attributes by name


INTERFACE:

       ! Private name; call using ESMF_BundleGetAttributeInfo()
       subroutine ESMF_BundleGetAttrInfoByName(bundle, name, typekind, count, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(in) :: bundle  
       character(len=*), intent(in) :: name
       type(ESMF_TypeKind), intent(out), optional :: typekind
       integer, intent(out), optional :: count   
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns information associated with the named attribute, including typekind and item count.

The arguments are:

bundle
An ESMF_Bundle object.
name
The name of the attribute to query.
[typekind]
The typekind of the attribute.
[count]
The number of items in this attribute. For character types, the length of the character string.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.10 ESMF_BundleGetAttributeInfo - Query Bundle attributes by index number


INTERFACE:

       ! Private name; call using ESMF_BundleGetAttributeInfo()
       subroutine ESMF_BundleGetAttrInfoByNum(bundle, attributeIndex, name, &
         typekind, count, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle  
       integer, intent(in) :: attributeIndex
       character(len=*), intent(out), optional :: name
       type(ESMF_TypeKind), intent(out), optional :: typekind
       integer, intent(out), optional :: count   
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns information associated with the indexed attribute, including typekind and item count.

The arguments are:

bundle
An ESMF_Bundle object.
attributeIndex
The index number of the attribute to query.
name
Returns the name of the attribute.
[typekind]
The typekind of the attribute.
[count]
Returns the number of items in this attribute. For character types, the length of the character string.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.11 ESMF_BundleGetField - Retrieve a Field by name


INTERFACE:

       ! Private name; call using ESMF_BundleGetField()
       subroutine ESMF_BundleGetFieldByName(bundle, name, field, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle
       character (len = *), intent(in) :: name
       type(ESMF_Field), intent(out) :: field
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns a field from a bundle using the field's name.

The arguments are:

bundle
ESMF_Bundle to query for ESMF_Field.
name
ESMF_Field name.
field
Returned ESMF_Field.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.12 ESMF_BundleGetField - Retrieve a Field by index number


INTERFACE:

       ! Private name; call using ESMF_BundleGetField()
       subroutine ESMF_BundleGetFieldByNum(bundle, fieldIndex, field, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle
       integer, intent(in) :: fieldIndex
       type(ESMF_Field), intent(out) :: field
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns a field from a bundle by index number.

The arguments are:

bundle
ESMF_Bundle to query for ESMF_Field.
fieldIndex
ESMF_Field index number; first fieldIndex is 1.
field
Returned ESMF_Field.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.13 ESMF_BundleGetFieldNames - Return all Field names in a Bundle


INTERFACE:

       subroutine ESMF_BundleGetFieldNames(bundle, nameList, nameCount, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle 
       character (len = *), intent(out) :: nameList(:)
       integer, intent(out), optional :: nameCount     
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns an array of ESMF_Field names in an ESMF_Bundle.

The arguments are:

bundle
An ESMF_Bundle object.
nameList
An array of character strings where each ESMF_Field name is returned. Must be at least as long as nameCount.
[nameCount]
A count of how many ESMF_Field names were returned. Same as the number of ESMF_Fields in the ESMF_Bundle.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.14 ESMF_BundlePrint - Print information about a Bundle


INTERFACE:

       subroutine ESMF_BundlePrint(bundle, options, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle
       character (len=*), intent(in), optional :: options
       integer, intent(out), optional :: rc
DESCRIPTION:

Prints diagnostic information about the bundle to stdout.

The arguments are:

bundle
An ESMF_Bundle object.
[options]
Print options are not yet supported.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.15 ESMF_BundleSetAttribute - Set an attribute


INTERFACE:

       subroutine ESMF_BundleSetAttribute(bundle, name, <value argument>, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle  
       character (len = *), intent(in) :: name
       <value argument>, see below for supported values
       integer, intent(out), optional :: rc
DESCRIPTION:

Attaches an attribute to the bundle. The attribute has a name and either a value or a valueList. Supported values for the <value argument> are:

integer(ESMF_KIND_I4), intent(in) :: value
integer(ESMF_KIND_I4), dimension(:), intent(in) :: valueList
integer(ESMF_KIND_I8), intent(in) :: value
integer(ESMF_KIND_I8), dimension(:), intent(in) :: valueList
real (ESMF_KIND_R4), intent(in) :: value
real (ESMF_KIND_R4), dimension(:), intent(in) :: valueList
real (ESMF_KIND_R8), intent(in) :: value
real (ESMF_KIND_R8), dimension(:), intent(in) :: valueList
type(ESMF_Logical), intent(in) :: value
type(ESMF_Logical), dimension(:), intent(in) :: valueList
character (len = *), intent(in), value

The arguments are:

bundle
An ESMF_Bundle object.
name
The name of the attribute to set.
<value argument>
The value of the attribute to set.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.16 ESMF_BundleSetGrid - Associate a Grid with an empty Bundle


INTERFACE:

       subroutine ESMF_BundleSetGrid(bundle, grid, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(inout) :: bundle
       type(ESMF_Grid), intent(in) :: grid
       integer, intent(out), optional :: rc
DESCRIPTION:

Sets the grid for a bundle that contains no ESMF_Fields. All ESMF_Fields added to this bundle must be associated with the same ESMF_Grid. Returns an error if there is already an ESMF_Grid associated with the bundle.

The arguments are:

bundle
An ESMF_Bundle object.
grid
The ESMF_Grid which all ESMF_Fields added to this ESMF_Bundle must have.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

17.6.17 ESMF_BundleValidate - Check validity of a Bundle


INTERFACE:

       subroutine ESMF_BundleValidate(bundle, options, rc)
ARGUMENTS:
       type(ESMF_Bundle), intent(in) :: bundle
       character (len=*), intent(in), optional :: options 
       integer, intent(out), optional :: rc
DESCRIPTION:

Validates that the bundle is internally consistent. Currently this method determines if the bundle is uninitialized or already destroyed. The method returns an error code if problems are found.

The arguments are:

bundle
ESMF_Bundle to validate.
[options]
Validation options are not yet supported.
[rc]
Return code; equals ESMF_SUCCESS if the bundle is valid.

18 Field Class

18.1 Description

An ESMF Field represents a physical field, such as temperature. The motivation for including Fields in ESMF is that bundles of Fields are the entities that are normally exchanged when coupling Components.

The ESMF Field class contains discretized field data, a reference to its associated grid, and metadata. The Field class maintains the relationship of how a data array maps onto a grid (e.g. one item per cell located at the cell center, one item per cell located at the NW corner, one item per cell vertex). This means that different Fields which are on the same underlying ESMF Grid but have different staggerings can share the same Grid object without needing to replicate it multiple times.

ESMF does not currently support vector fields, so the components of a vector field must be stored as separate Field objects.

The Field class provides methods for initialization, setting and retrieving data values, general data redistribution and regridding, standard communication methods such as gather and scatter, and manipulation of attributes. Field methods are called from objects internal to the framework and can also be called from user code.

18.2 Use and Examples

A Field serves as an annotator of data, since it carries a description of the grid it is associated with and metadata such as name and units. Fields can be used in this capacity alone, as convenient, descriptive containers into which arrays can be placed and retrieved. However, for most codes the primary use of Fields is in the context of import and export States, which are the objects that carry coupling information between Components. Fields enable data to be self-describing, and a State holding ESMF Fields contains data in a standard format that is easy to query and manipulate.

The information that is necessary for describing a Field to another Component is similar to the information needed to write history files. Another use of Fields is as a mechanism for writing out data to files for history and restart.

The sections below go into more detail about Field usage.

18.2.1 Field Creation

Fields can be created and destroyed at any time during application execution. However, these Field methods require some time to complete. We do not recommend that the user create or destroy Fields inside performance-critical computational loops.

All versions of the ESMF_FieldCreate() routines require a Grid object as input, or require a Grid be added before most operations involving Fields can be performed. The Grid contains the information needed to know which Decomposition Elements (DEs) are participating in the processing of this Field, and which subsets of the data are local to a particular DE.

The details of how the create process happens depends on which of the variants of the ESMF_FieldCreate() call is used. Some of the variants are discussed below.

There are versions of the ESMF_FieldCreate() interface which create the Field based on the input Grid. The ESMF can allocate the proper amount of space but not assign initial values. The user code can then get the pointer to the uninitialized buffer and set the initial data values.

Other versions of the ESMF_FieldCreate() interface allow user code to attach arrays that have already been allocated by the user. Empty Fields can also be created in which case the data can be added at some later time.

For versions of Create which do not specify data values, user code can create an ArraySpec object, which contains information about the Type, TypeKind, and Rank of the data values in the array. Then at Field create time, the appropriate amount of memory is allocated to contain the data which is local to each DE.

18.2.2 Field Deletion

There is a ESMF_FieldDestroy() method which releases any data buffers which were allocated or internally referenced by this Field, and deletes the Field object. Since a single Grid reference can be shared by multiple Fields, the internal Grid is not deleted by this call. Field provides copy behavior through creation and set interface, the internally referenced ESMF_Array object will be deleted upon Field destruction.

18.2.3 Create Field with Grid and Arrayspec

The user has already created an ESMF_Grid and an ESMF_Arrayspec with data. This create associates the two objects.

    grid = ESMF_GridCreateShapeTile(minIndex=(/1,1/), maxIndex=(/10,20/), &
                                  regDecomp=(/2,2/), name="atmgrid", rc=rc)
    if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE

    call ESMF_GridGet(grid, distgrid=distgrid, rc=rc)
    if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE

    call ESMF_ArraySpecSet(arrayspec, 2, ESMF_TYPEKIND_R4, rc)
    if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE

    field1 = ESMF_FieldCreate(grid, arrayspec, &
                         staggerloc=ESMF_STAGGERLOC_CENTER, name="pressure", rc=rc)
    if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE

18.2.4 Use ESMF_ArrayCreate to reset Field internal Array

It's often necessary to reset the data array contained within a field. The following examples demonstrate different ways of creating ESMF_Array and reset the existing ESMF_Array of a ESMF_Field. User can reset the ESMF_Array inside an existing Field by construct a proper shape ESMF_Array arrayspec, distgrid are objects created from previous examples.

    call ESMF_GridGet(grid, staggerloc=ESMF_STAGGERLOC_CENTER, &
        computationalEdgeLWidth=compEdgeLWdith, &
        computationalEdgeUWidth=compEdgeUWdith, rc=rc)
    if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE
    array2 = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, staggerLoc=0, &
            computationalEdgeLWidth=compEdgeLWdith, &
            computationalEdgeUWidth=compEdgeUWdith, rc=rc)
    if(rc .ne. ESMF_SUCCESS) finalrc = ESMF_FAILURE

    call ESMF_FieldSetArray(field1, array2, rc=rc)
    if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE

18.2.5 Destroy a Field

When finished with an ESMF_Field, the destroy method removes it. However, the objects inside the ESMF_Field that has external reference should be deleted separately, since objects can be added to more than one ESMF_Field, for example the same ESMF_Grid can be used in multiple ESMF_Fields.

    call ESMF_FieldDestroy(field1, rc=rc)

18.2.6 Set the Fortran data pointer in a Field

Through the ESMF_FieldSetDataPtr interface user can reset the intrinsic Fortran data pointer contained in the internal ESMF_Array object of a ESMF_Field. ESMF_FieldSetDataPtr is an overloaded interface based on the type, kind, and rank of the input fortran pointer argument. In this example, a rank 3 ESMF_KIND_R8 fortran data pointer is used. This method creates an internally referenced ESMF_Array inside the field. The previous ESMF_Array will be deleted if it was internally referenced by the field, otherwise it's replaced by the newly created array.

    allocate(farray(xdim,ydim,zdim))

    call ESMF_FieldSetDataPtr(f8, farray, rc=rc)

18.2.7 Reset the Grid in a Field

User can reset the internal ESMF_Grid object of a ESMF_Field through ESMF_FieldSetGrid interface. Invalid Grid will be rejected, check return code for status.

    grid = ESMF_GridCreateShapeTile(minIndex=(/1,1,1/), maxIndex=(/4*xdim-1,ydim-1,zdim-1/), &
                              regDecomp=(/4,1,1/), name="grid", rc=rc)
    if(rc .ne. ESMF_SUCCESS) finalrc = ESMF_FAILURE
    
    call ESMF_FieldSetGrid(f8, grid=grid, rc=rc)

18.3 Restrictions and Future Work

  1. No mathematical operators. The Fields class does not currently support advanced operations on fields, such as differential or other mathematical operators.

  2. No vector Fields. ESMF does not currently support storage of multiple vector Field components in the same Field component, although that support is planned. At this time users need to create a separate Field object to represent each vector component.

18.4 Design and Implementation Notes

  1. Some methods which have a Field interface are actually implemented at the underlying Grid or Array level; they are inherited by the Field class. This allows the user API (Application Programming Interface) to present functions at the level which is most consistent to the application without restricting where inside the ESMF the actual implementation is done.

  2. The Field class is implemented in Fortran, and as such is defined inside the framework by a Field derived type and a set of subprograms (functions and subroutines) which operate on that derived type. The Field class itself is very thin; it is a container class which groups a Grid, an Array, and a FieldDataMap object together. As a programming convienence, the parts of the Field which refer to data which is local to a single DE are grouped in a LocalField sub-derived type, but it is not a true class in that there are no LocalField methods which operate on it. In general, any derived type members which are not in the LocalField subtype describe global information about the Field.

  3. Fields follow the framework-wide convention of the unison creation and operation rule: All PETs which are part of the currently executing VM must create the same Fields at the same point in their execution. Since an early user request was that global object creation not impose the overhead of a barrier or synchronization point, Field creation does no inter-PET communication. For this to work, each PET must query the total number of PETs in this VM, and which local PET number it is. It can then compute which DE(s) are part of the local decomposition, and any global information can be computed in unison by all PETs independently of the others. In this way the overhead of communication is avoided, at the cost of more difficulty in diagnosing program bugs which result from not all PETs executing the same create calls.

  4. Related to the item above, the user request to not impose inter-PET communication at object creation time means that requirement FLD 1.5.1, that all Fields will have unique names, and if not specified, the framework will generate a unique name for it, is difficult or impossible to support. A part of this requirement has been implememted; a unique object counter is maintained in the Base object class, and if a name is not given at create time a name such as "Field003" is generated which is guarenteed to not be repeated by the framework. However, it is impossible to error check that the user has not replicated a name, and it is possible under certain conditions that if not all PETs have created the same number of objects, that the counters on different PETs may not stay synchronized. This remains an open issue.

18.5 Class API: Basic Field Methods

18.5.1 ESMF_FieldDestroy - Free all resources associated with a Field


INTERFACE:

       subroutine ESMF_FieldDestroy(field, rc)
ARGUMENTS:
       type(ESMF_Field) :: field       
       integer, intent(out), optional :: rc
DESCRIPTION:

Releases all resources associated with the ESMF_Field.

The arguments are:

field
Pointer to an ESMF_Field object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.2 ESMF_FieldGet - Return info associated with a Field


INTERFACE:

       subroutine ESMF_FieldGet(field, grid, array, &
                                typekind, rank, staggerloc, &
                                gridToFieldMap, ungriddedLBound, &
                                ungriddedUBound, maxHaloLWidth, &
                                maxHaloUWidth, name, iospec, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field    
       type(ESMF_Grid), intent(out), optional :: grid     
       type(ESMF_Array), intent(out), optional :: array     
       type(ESMF_TypeKind), intent(out), optional :: typekind
       integer, intent(out), optional :: rank
       type(ESMF_StaggerLoc), intent(out), optional :: staggerloc 
       integer, intent(out), optional :: gridToFieldMap(:)    
       integer, intent(out), optional :: ungriddedLBound(:)
       integer, intent(out), optional :: ungriddedUBound(:)
       integer, intent(out), optional :: maxHaloLWidth(:)
       integer, intent(out), optional :: maxHaloUWidth(:)
       character(len=*), intent(out), optional :: name
       type(ESMF_IOSpec), intent(out), optional :: iospec ! NOT IMPLEMENTED
       integer, intent(out), optional :: rc
DESCRIPTION:

Query an ESMF_Field for various things. All arguments after the Field are optional. To select individual items use the named_argument=value syntax.

The arguments are:

ftype
Pointer to an ESMF_Field object.
[grid]
ESMF_Grid.
[array]
ESMF_Array.
[typekind]
TypeKind specifier for Field.
[rank]
Rank of Field data.
[staggerloc]
Stagger location of data in grid cells. For valid values and interpretation of results see Section 22.5.3.
[gridToFieldMap]
List that contains as many elements as is indicated by the grid's rank. The list elements map each dimension of the Grid object to a dimension in the Field's Array by specifying the appropriate Array dimension index. The default is to map all of the grid's dimensions against the lower dimensions of the Field's Array in sequence, i.e. gridDimmap = (/1, 2, .../). Unmapped dimensions are undistributed dimensions. The total undistributed dimensions are the total Array dimensions - the distributed dimensions in the Grid (distRank). All gridToFieldMap entries must be greater than or equal to one and smaller than or equal to the Array rank. It is erroneous to specify the same entry multiple times unless it is zero. If the Array rank is less than the Grid dimCount then the default gridToFieldMap will contain zeros for the dimCount. A zero entry in the dimmap indicates that the particular Grid dimension will be replicating the Array across the DEs along this direction.
[ungriddedLBound]
Lower bounds of the ungridded dimensions of the Field.
[ungriddedUBound]
Upper bounds of the ungridded dimensions of the Field.
[maxHaloLWidth]
Lower bound of halo region. Defaults to 0. ! NOT IMPLEMENTED
[maxHaloUWidth]
Upper bound of halo region. Defaults to 0. ! NOT IMPLEMENTED
[name]
Name of queried item.
[iospec]
ESMF_IOSpec object which contains settings for options ! NOT IMPLEMENTED
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.3 ESMF_FieldGetArray - Get data Array associated with the Field


INTERFACE:

       subroutine ESMF_FieldGetArray(field, array, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field      
       type(ESMF_Array), intent(out) :: array
       integer, intent(out), optional :: rc
DESCRIPTION:

Get data in ESMF_Array form.

The arguments are:

field
An ESMF_Field object.
[array]
Field ESMF_Array.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.4 ESMF_FieldGetAttribute - Retrieve an attribute


INTERFACE:

       subroutine ESMF_FieldGetAttribute(field, name, <value argument>, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field  
       character (len = *), intent(in) :: name
       <value argument>, see below for supported values
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns an attribute from the field. Supported values for <value argument> are:

integer(ESMF_KIND_I4), intent(out) :: value
integer(ESMF_KIND_I4), dimension(:), intent(out) :: valueList
integer(ESMF_KIND_I8), intent(out) :: value
integer(ESMF_KIND_I8), dimension(:), intent(out) :: valueList
real (ESMF_KIND_R4), intent(out) :: value
real (ESMF_KIND_R4), dimension(:), intent(out) :: valueList
real (ESMF_KIND_R8), intent(out) :: value
real (ESMF_KIND_R8), dimension(:), intent(out) :: valueList
type(ESMF_Logical), intent(out) :: value
type(ESMF_Logical), dimension(:), intent(out) :: valueList
character (len = *), intent(out), value

The arguments are:

field
An ESMF_Field object.
name
The name of the attribute to retrieve.
<value argument>
The value of the named attribute.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.5 ESMF_FieldGetAttributeCount - Query the number of attributes


INTERFACE:

       subroutine ESMF_FieldGetAttributeCount(field, count, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field  
       integer, intent(out) :: count   
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns the number of attributes associated with the given field in the argument count.

The arguments are:

field
An ESMF_Field object.
count
The number of attributes associated with this object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.6 ESMF_FieldGetAttributeInfo - Query Field attributes by name


INTERFACE:

       ! Private name; call using ESMF_FieldGetAttributeInfo()
       subroutine ESMF_FieldGetAttrInfoByName(field, name, typekind, count, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field  
       character(len=*), intent(in) :: name
       type(ESMF_TypeKind), intent(out), optional :: typekind
       integer, intent(out), optional :: count   
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns information associated with the named attribute, including typekind and count.

The arguments are:

field
An ESMF_Field object.
name
The name of the attribute to query.
[typekind]
The typekind of the attribute.
[count]
The number of items in this attribute. For character types, the length of the character string.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.7 ESMF_FieldGetAttributeInfo - Query Field attributes by index number


INTERFACE:

       ! Private name; call using ESMF_FieldGetAttributeInfo()
       subroutine ESMF_FieldGetAttrInfoByNum(field, attributeIndex, name, &
         typekind, count, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field  
       integer, intent(in) :: attributeIndex
       character(len=*), intent(out), optional :: name
       type(ESMF_TypeKind), intent(out), optional :: typekind
       integer, intent(out), optional :: count   
       integer, intent(out), optional :: rc
DESCRIPTION:

Returns information associated with the indexed attribute, including name, typekind and count.

The arguments are:

field
An ESMF_Field object.
attributeIndex
The index number of the attribute to query.
name
Returns the name of the attribute.
[typekind]
The typekind of the attribute.
[count]
Returns the number of items in this attribute. For character types, this is the length of the character string.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.8 ESMF_FieldPrint - Print the contents of a Field


INTERFACE:

       subroutine ESMF_FieldPrint(field, options, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field 
       character (len = *), intent(in), optional :: options
       integer, intent(out), optional :: rc
DESCRIPTION:

Prints information about the field to stdout. This subroutine goes through the internal data members of a field data type and prints information of each data member.

The arguments are:

field
[options]
Print options are not yet supported.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.9 ESMF_FieldSetArray - Set data Array associated with the Field


INTERFACE:

       subroutine ESMF_FieldSetArray(field, array, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field      
       type(ESMF_Array), intent(in) :: array
       integer, intent(out), optional :: rc
DESCRIPTION:

Set data in ESMF_Array form.

The arguments are:

field
An ESMF_Field object.
[array]
ESMF_Array containing data.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.10 ESMF_FieldSetAttribute - Set an attribute


INTERFACE:

       subroutine ESMF_FieldSetAttribute(field, name, <value argument>, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field  
       character (len = *), intent(in) :: name
       <value argument>, see below for supported values
       integer, intent(out), optional :: rc
DESCRIPTION:

Attaches an attribute to the field. The attribute has a name and either a value or a valueList. Supported values for the <value argument> are:

integer(ESMF_KIND_I4), intent(in) :: value
integer(ESMF_KIND_I4), dimension(:), intent(in) :: valueList
integer(ESMF_KIND_I8), intent(in) :: value
integer(ESMF_KIND_I8), dimension(:), intent(in) :: valueList
real (ESMF_KIND_R4), intent(in) :: value
real (ESMF_KIND_R4), dimension(:), intent(in) :: valueList
real (ESMF_KIND_R8), intent(in) :: value
real (ESMF_KIND_R8), dimension(:), intent(in) :: valueList
type(ESMF_Logical), intent(in) :: value
type(ESMF_Logical), dimension(:), intent(in) :: valueList
character (len = *), intent(in), value

The arguments are:

field
An ESMF_Field object.
name
The name of the attribute to set.
<value argument>
The value of the attribute to set.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

18.5.11 ESMF_FieldValidate - Check validity of a Field


INTERFACE:

       subroutine ESMF_FieldValidate(field, options, rc)
ARGUMENTS:
       type(ESMF_Field), intent(inout) :: field 
       character (len = *), intent(in), optional :: options 
       integer, intent(out), optional :: rc
DESCRIPTION:

Validates that the field is internally consistent. Currently this method determines if the field is uninitialized or already destroyed. It validates the contained array and grid objects. The code also checks if the array and grid sizes agree. This check compares the distgrid contained in array and grid; then it proceeds to compare the computational bounds contained in array and grid.

The method returns an error code if problems are found.

The arguments are:

field
ESMF_Field to validate.
[options]
Validation options are not yet supported.
[rc]
Return code; equals ESMF_SUCCESS if the field is valid.

18.6 Class API: Field Overloads for Fortran Arrays

18.6.1 ESMF_FieldCreate - Create a new Field from Grid and ArraySpec


INTERFACE:

       ! Private name; call using ESMF_FieldCreate()
       function ESMF_FieldCreateNew(grid, arrayspec, allocflag, staggerloc, &
                                    gridToFieldMap, ungriddedLBound, &
                                    ungriddedUBound, maxHaloLWidth, &
                                    maxHaloUWidth, name, iospec, rc)
RETURN VALUE:
       type(ESMF_Field) :: ESMF_FieldCreateNew
ARGUMENTS:
       type(ESMF_Grid) :: grid
       type(ESMF_ArraySpec), intent(inout) :: arrayspec
       type(ESMF_AllocFlag), intent(in), optional :: allocflag
       type(ESMF_StaggerLoc), intent(in), optional :: staggerloc
       integer, intent(in), optional :: gridToFieldMap(:)
       integer, intent(in), optional :: ungriddedLBound(:)
       integer, intent(in), optional :: ungriddedUBound(:)
       integer, intent(in), optional :: maxHaloLWidth(:)
       integer, intent(in), optional :: maxHaloUWidth(:)
       character (len=*), intent(in), optional :: name
       type(ESMF_IOSpec), intent(in), optional :: iospec
       integer, intent(out), optional :: rc
DESCRIPTION:

An interface function to ESMF_FieldCreate(). Create an ESMF_Field and allocate space internally for a gridded ESMF_Array. Return a new ESMF_Field.

The arguments are:

grid
Pointer to an ESMF_Grid object.
arrayspec
ESMF_Data specification.
[allocflag]
Whether to allocate space for the array. See Section 9.1.1 for possible values. Default is ESMF_ALLOC.
[staggerloc]
Relative location of data per grid cell/vertex in the grid. If specified here, takes precedence over the same setting in the datamap argument.
[gridToFieldMap]
List that contains as many elements as is indicated by the grid's' rank. The list elements map each dimension of the Grid object to a dimension in the Field's Array by specifying the appropriate Array' dimension index. The default is to map all of the grid's dimensions' against the lower dimensions of the Field's Array in sequence, i.e.' gridToFieldMap = (/1, 2, .../). Unmapped dimensions are undistributed dimensions. The total undistributed dimensions are the total Array dimensions - the distributed dimensions in the Grid (distRank). All gridToFieldMap entries must be greater than or equal to one and smaller than or equal to the Array rank. It is erroneous to specify the same entry multiple times unless it is zero. If the Array rank is less than the Grid dimCount then the default gridToFieldMap will contain zeros for the dimCount. A zero entry in the dimmap indicates that the particular Grid dimension will be replicating the Array across the DEs along this direction.
[ungriddedLBound]
Lower bounds of the ungridded dimensions of the Field.
[ungriddedUBound]
Upper bounds of the ungridded dimensions of the Field.
[maxHaloLWidth]
Lower bound of halo region. Defaults to 0. ! NOT IMPLEMENTED
[maxHaloUWidth]
Upper bound of halo region. Defaults to 0. ! NOT IMPLEMENTED
[name]
Field name.
[iospec]
I/O specification. ! NOT IMPLEMENTED
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19 Array Class

19.1 Description

The ESMF_Array class is an index space based, distributed data storage class. It provides DE-local memory allocations within DE-centric index regions and defines the relationship to the index space described by DistGrid. The Array class offers common communication patterns within the index space formalism. As part of the ESMF index space layer Array has close relationship to the DistGrid and DELayout classes.

19.2 Use and Examples

An ESMF_Array is a distributed object that must exist on all PETs of the current context. Each PET-local instance of an Array object contains memory allocations for all PET-local DEs. There may be 0, 1, or more DEs per PET and the number of DEs per PET can differ between PETs for the same Array object. Memory allocations may be provided for each PET by the user during Array creation or can be allocated as part of the Array create call. Many of the concepts of the proposed ESMF_Array class are illustrated by the following examples.

19.2.1 Array from native Fortran90 array with 1 DE per PET

The create call of the ESMF_Array class has been overloaded extensively to facilitate the need for generality while keeping simple cases simple. The following program demonstrates one of the simpler cases, where existing local Fortran90 arrays are to be used to provide the PET-local memory allocations for the Array object.

program ESMF_ArrayFarrayEx

  use ESMF_Mod
  
  implicit none

The Fortran90 language provides a variety of ways to define and allocate an array. Actual Fortran90 array objects must either be explicit-shape or deferred-shape. In the first case the memory allocation and deallocation is automatic from the user's perspective and the details of the allocation (static or dynamic, heap or stack) are left to the compiler. (Compiler flags may be used to control some of the details). In the second case, i.e. for deferred-shape actual objects, the array definition must include the pointer or allocatable attribute and it is the user's responsibility to allocate memory. While it is also the user's responsibility to deallocate memory for arrays with pointer attribute the compiler will automatically deallocate allocatable arrays under certain circumstances defined by the Fortran standard.

The ESMF_ArrayCreate() interface has been written to accept native Fortran90 arrays of any flavor as a means to allow user-contolled memory management. The Array create call will check on each PET if sufficient memory has been provided by the specified Fortran90 arrays and will indicate an error if a problem is detected. However, the Array create call cannot validate the lifetime of the provided memory allocations. If, for instance, an Array object was created in a subroutine from an automatic explicit-shape array or an allocatable array, the memory allocations referenced by the Array object will be automatically deallocated on return from the subroutine unless provissions are made by the application writer to prevent such behavior. The Array object cannot contol when memory that has been provided by the user during Array creation becomes deallocated, however, the Array will indicate an error if it's memory references have been invalidated.

The easiest, portable way to provide safe native Fortran90 memory allocations to Array create is to use arrays with the pointer attribute. Memory allocated for an array pointer will not be deallocated automatically. However, in this case the possibility of memory leaks becomes an issue of concern. The deallocation of memory provided to an Array in form of a native Fortan90 allocation will remain the users responsibility.

None of the concerns discussed above are an issue in this example where the native Fortran90 array farray is defined in the main program. All different types of array memory allocation are demonstrated in this example. First farrayE is defined as a 2D explicit-shape array on each PET which will automatically provide memory for $10\times 10$ elements.

  ! local variables
  real(ESMF_KIND_R8)          :: farrayE(10,10)     ! explicit shape F90 array

Then an allocatable array farrayA is declared which will be used to show user-controlled dynamic memory allocation.

  real(ESMF_KIND_R8), allocatable :: farrayA(:,:)   ! allocatable F90 array

Finally an array with pointer attribute farrayP is declared, also used for user-controlled dynamic memory allocation.

  real(ESMF_KIND_R8), pointer :: farrayP(:,:)       ! F90 array pointer

A matching array pointer must also be available to gain access to the arrays held by an Array object.

  real(ESMF_KIND_R8), pointer :: farrayPtr(:,:)     ! matching F90 array pointer 
  type(ESMF_DistGrid)         :: distgrid           ! DistGrid object
  type(ESMF_Array)            :: array              ! Array object
  integer                     :: rc

  call ESMF_Initialize(rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)

On each PET farrayE can be accessed directly to initialize the entire PET-local array.

  farrayE = 12.45d0 ! initialize to some value

In order to create an Array object a DistGrid must first be created that describes the total index space and how it is decomposed and distributed. In the simplest case only the minIndex and maxIndex of the total space must be provided.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/40,10/), rc=rc)

This example is assumed to run on 4 PETs. The default 2D decomposition will then be into 4 x 1 DEs as to ensure 1 DE per PET.

Now the Array object can be created using the farrayE and the DistGrid just created.

  array = ESMF_ArrayCreate(farray=farrayE, distgrid=distgrid, rc=rc)

The 40 x 10 index space defined by the minIndex and maxIndex arguments paired with the default decomposition will result in the following distributed Array.

  
         +---------------------------> 2nd dimension
         |   (1,1)-------+
         |     |         |
         |     |   DE 0  |   <--- farray on PET 0
         |     |         |
         |     +------(10,10)
         |  (11,1)-------+
         |     |         |
         |     |   DE 1  |   <--- farray on PET 1
         |     |         |
         |     +------(20,10)
         |  (21,1)-------+
         |     |         |
         |     |   DE 2  |   <--- farray on PET 2
         |     |         |
         |     +------(30,10)
         |  (31,1)-------+
         |     |         |
         |     |   DE 3  |   <--- farray on PET 3
         |     |         |
         |     +------(40,10)
         v
       1st dimension

Providing farrayE during Array creation does not change anything about the actual farrayE object. This means that each PET can use its local farrayE directly to access the memory referenced by the Array object.

  print *, farrayE

Another way of accessing the memory associated with an Array object is to use ArrayGet() to obtain an Fortran90 pointer that references the PET-local array.

  call ESMF_ArrayGet(array, farrayPtr=farrayPtr, rc=rc)

  print *, farrayPtr

Finally the Array object must be destroyed. The PET-local memory of the farrayEs will remain in user control and will not be altered by ArrayDestroy().

  call ESMF_ArrayDestroy(array, rc=rc)

Since the memory allocation for each farrayE is automatic there is nothing more to do.

The interaction between farrayE and the Array class is representative also for the two other cases farrayA and farrayP. The only difference is in the handling of memory allocations.

  allocate(farrayA(10,10))    ! user controlled allocation
  farrayA = 23.67d0           ! initialize to some value
  array = ESMF_ArrayCreate(farray=farrayA, distgrid=distgrid, rc=rc)

  print *, farrayA            ! print PET-local farrayA directly
  call ESMF_ArrayGet(array, farrayPtr=farrayPtr, rc=rc)  ! obtain array pointer
  print *, farrayPtr          ! print PET-local piece of Array through pointer
  call ESMF_ArrayDestroy(array, rc=rc) ! destroy the Array
  deallocate(farrayA)         ! user controlled de-allocation

The farrayP case is identical.

  allocate(farrayP(10,10))    ! user controlled allocation
  farrayP = 56.81d0           ! initialize to some value
  array = ESMF_ArrayCreate(farray=farrayP, distgrid=distgrid, rc=rc)

  print *, farrayP            ! print PET-local farrayA directly
  call ESMF_ArrayGet(array, farrayPtr=farrayPtr, rc=rc)  ! obtain array pointer
  print *, farrayPtr          ! print PET-local piece of Array through pointer
  call ESMF_ArrayDestroy(array, rc=rc) ! destroy the Array
  deallocate(farrayP)         ! user controlled de-allocation

To wrap things up the DistGrid object is destroyed and ESMF can be finalized.

  call ESMF_DistGridDestroy(distgrid, rc=rc) ! destroy the DistGrid

  call ESMF_Finalize(rc=rc)

end program

19.2.2 Array from native Fortran90 array with elements for halo

The example of the previous section showed how easy it is to create an Array object from existing PET-local Fortran90 arrays. The example did, however, not define any halos around the DE-local regions. The following code demonstrates how an Array object with space for a halo can be set up.

program ESMF_ArrayFarrayHaloEx

  use ESMF_Mod
  
  implicit none

The allocatable array farrayA will be used to provide the PET-local Fortran90 array for this example.

  ! local variables
  real(ESMF_KIND_R8), allocatable :: farrayA(:,:)   ! allocatable F90 array
  real(ESMF_KIND_R8), pointer :: farrayPtr(:,:)     ! matching F90 array pointer
  type(ESMF_DistGrid)         :: distgrid           ! DistGrid object
  type(ESMF_Array)            :: array              ! Array object
  integer                     :: rc, i, j
  real                        :: localSum

  call ESMF_Initialize(rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)

The Array is to cover the exact same index space as in the previous example. Furthermore decomposition and distribution are also kept the same. Hence the same DistGrid object will be created and it is expected to execute this example with 4 PETs.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/40,10/), rc=rc)

This DistGrid describes a 40 x 10 index space that will be decomposed into 4 DEs when executed on 4 PETs, associating 1 DE per PET. Each DE-local exclusive region contains 10 x 10 elements. The DistGrid also stores and provides information about the relationship between DEs in index space, however, DistGrid does not contain information about halos. Arrays contain halo information and it is possible to create multiple Arrays covering the same index space with identical decomposition and distribution using the same DistGrid object, while defining different, Array-specific halo regions.

The extra memory required to cover the halo in the Array object must be taken into account when allocating the PET-local farrayA arrays. For a halo of 2 elements in each direction the following allocation will suffice.

  allocate(farrayA(14,14))    ! Fortran90 array with halo: 14 = 10 + 2 * 2

The farrayA can now be used to create an Array object with enough space for a two element halo in each direction. The Array creation method checks for each PET that the local Fortran90 array can accomodate the requested regions.

The default behavior of ArrayCreate() is to center the exclusive region within the total region. Consequently the following call will provide the 2 extra elements on each side of the exclusive 10 x 10 region without having to specify any additional arguments.

  array = ESMF_ArrayCreate(farray=farrayA, distgrid=distgrid, rc=rc)

The exclusive Array region on each PET can be accessed through a suitable Fortran90 array pointer. See section 19.2.6 for more details on Array regions.

  call ESMF_ArrayGet(array, farrayPtr=farrayPtr, rc=rc)

Following Array bounds convention, which by default puts the beginning of the exclusive region at (1, 1, ...), the following loop will add up the values of the local exclusive region for each DE, regardless of how the bounds were chosen for the original PET-local farrayA arrays.

  localSum = 0.
  do j=1, 10
    do i=1, 10
      localSum = localSum + farrayPtr(i, j)
    enddo
  enddo

Elements with $i$ or $j$ in the [-1,0] or [11,12] ranges are located outside the exclusive region and may be used to define extra computational points or halo operations.

Cleanup and shut down ESMF.

  call ESMF_ArrayDestroy(array, rc=rc)
  deallocate(farrayA)
  call ESMF_DistGridDestroy(distgrid, rc=rc)

  call ESMF_Finalize(rc=rc)

end program

19.2.3 Array from ESMF_LocalArray

Alternative to the direct usage of Fortran90 arrays during Array creation it is also possible to first create an ESMF_LocalArray and create the Array from it. While this may seem more burdensome for the 1 DE per PET cases discussed in the previous sections it allows a straight forward generallization to the multiple DE per PET case. The following example first recaptures the previous example using an ESMF_LocalArray and then expands to the multiple DE per PET case.

program ESMF_ArrayLarrayEx

  use ESMF_Mod
  
  implicit none

The current ESMF_LocalArray interface requires Fortran90 arrays to be defined with pointer attribute.

  ! local variables
  real(ESMF_KIND_R8), pointer :: farrayP(:,:)       ! F90 array pointer
  real(ESMF_KIND_R8), pointer :: farrayPtr(:,:)     ! matching F90 array pointer 
  type(ESMF_LocalArray)       :: larray             ! ESMF_LocalArray object
  type(ESMF_LocalArray)       :: larrayRef          ! ESMF_LocalArray object
  type(ESMF_DistGrid)         :: distgrid           ! DistGrid object
  type(ESMF_Array)            :: array              ! Array object
  integer                     :: rc, i, j, de
  real                        :: localSum
  type(ESMF_LocalArray), allocatable :: larrayList(:)      ! ESMF_LocalArray object list
  type(ESMF_LocalArray), allocatable :: larrayRefList(:)   ! ESMF_LocalArray object list
  
  type(ESMF_VM):: vm
  integer:: localPet, petCount

  call ESMF_Initialize(vm=vm, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)
  call ESMF_VMGet(vm, localPet=localPet, petCount=petCount, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)
  
  if (petCount /= 4) goto 10 ! TODO: use EXAMPLES_MULTI_ONLY once available

DistGrid and array allocation remains unchanged.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/40,10/), rc=rc)

  allocate(farrayP(14,14))    ! allocate Fortran90 array on each PET with halo

Now instead of directly creating an Array object using the PET-local farrayPs an ESMF_LocalArray object will be created on each PET.

  larray = ESMF_LocalArrayCreate(farrayP, ESMF_DATA_REF, rc=rc)

The Array object can now be created from larray. The Array creation method checks for each PET that the LocalArray can accomodate the requested regions.

  array = ESMF_ArrayCreate(larrayList=(/larray/), distgrid=distgrid, rc=rc)

Once created there is no difference in how the Array object can be used. The exclusive Array region on each PET can be accessed through a suitable Fortran90 array pointer as before.

  call ESMF_ArrayGet(array, farrayPtr=farrayPtr, rc=rc)

Alternatively it is also possible (independent of how the Array object was created) to obtain the reference to the array allocation held by Array in form of an ESMF_LocalArry object. The farrayPtr can then be extracted using LocalArray methods.

  call ESMF_ArrayGet(array, larray=larrayRef, rc=rc)

  call ESMF_LocalArrayGet(larrayRef, farrayPtr, rc=rc)

Either way the farrayPtr reference can be used now to add up the values of the local exclusive region for each DE. The following loop works regardless of how the bounds were chosen for the original PET-local farrayP arrays and consequently the PET-local larray objects.

  localSum = 0.
  do j=1, 10
    do i=1, 10
      localSum = localSum + farrayPtr(i, j)
    enddo
  enddo
  print *, "localSum=", localSum

Cleanup.

  call ESMF_ArrayDestroy(array, rc=rc)
  call ESMF_LocalArrayDestroy(larray, rc=rc)
  deallocate(farrayP)   ! use the pointer that was used in allocate statement
  call ESMF_DistGridDestroy(distgrid, rc=rc)

While the usage of LocalArrays is unnecessarily cumbersome for 1 DE per PET Arrays, it provides a straight forward path for extenting the interfaces to multiple DEs per PET.

In the following example a 8 x 8 index space will be decomposed into 2 x 4 = 8 DEs. The situation is captured by the following DistGrid object.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/8,8/), &
    regDecomp=(/2,4/), rc=rc)

The distgrid object created in this manner will contain 8 DEs no matter how many PETs are available during execution. Assuming an execution on 4 PETs will result in the following distribution of the decomposition.

   
    +---------------------------------------> 2nd dimension
    |  (1,1)
    |    +-----------+-----------+-----------+-----------+
    |    | DE0, PET0 | DE2, PET1 | DE4, PET2 | DE6, PET3 |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    |           |           |           |           |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    |           |           |           |           |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    |           |           |           |           |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    +-----------+-----------+-----------+-----------+
    |    | DE1, PET0 | DE3, PET1 | DE5, PET2 | DE7, PET3 |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    |           |           |           |           |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    |           |           |           |           |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    |           |           |           |           |
    |    |  *    *   |  *    *   |  *    *   |  *    *   |
    |    +-----------+-----------+-----------+-----------+
    |                                                    (8,8)
    v 
   1st dimension

Obviously each PET is associated with 2 DEs. Each PET must allocate enough space for all its DEs. This is done by allocating as many DE-local arrays as there are DEs on the PET. The reference to these array allocations is passed into ArrayCreate via a LocalArray list argument that holds as many elements as there are DEs on the PET. Here each PET must allocate for two DEs.

  allocate(larrayList(2))   ! 2 DEs per PET
  allocate(farrayP(4, 2))   ! without halo each DE is of size 4 x 2 
  farrayP = 123.456d0
  larrayList(1) = ESMF_LocalArrayCreate(farrayP, ESMF_DATA_REF, rc=rc)  ! 1st DE
  allocate(farrayP(4, 2))   ! without halo each DE is of size 4 x 2 
  farrayP = 456.789d0
  larrayList(2) = ESMF_LocalArrayCreate(farrayP, ESMF_DATA_REF, rc=rc)  ! 2nd DE

Notice that it is perfectly fine to re-use farrayP for all allocations of DE-local Fortran90 arrays. The allocated memory can be deallocated at the end using the array pointer contained in the larrayList.

With this information an Array object can be created. The distgrid object indicates 2 DEs for each PET and ArrayCreate() expects to find two LocalArray elements in larrayList.

  array = ESMF_ArrayCreate(larrayList=larrayList, distgrid=distgrid, rc=rc)

Usage of a LocalArray list is the only way to provide a list of variable length of Fortran90 array allocations to ArrayCreate() for each PET. The array object created by the above call is an ESMF distributed object. As such it must follow the ESMF convention that requires that the call to ESMF_ArrayCreate() must be issued in unison by all PETs of the current context. Each PET only calls ArrayCreate() once, even if there are multiple DEs per PET.

The ArrayGet() method provides access to the list of LocalArrays on each PET.

  allocate(larrayRefList(2))
  call ESMF_ArrayGet(array, larrayList=larrayRefList, rc=rc)

Finally, access to the actual Fortran90 pointers is done on a per DE basis. Generally each PET will loop over its DEs.

  do de=1, 2
    call ESMF_LocalArrayGet(larrayRefList(de), farrayPtr, rc=rc)
    localSum = 0.
    do j=1, 2
      do i=1, 4
        localSum = localSum + farrayPtr(i, j)
      enddo
    enddo
    print *, "localSum=", localSum
  enddo

Note: If the VM associates multiple PEs with a PET the application writter may decide to use OpenMP loop parallelization on the de loop.

Cleanup requires that the PET-local deallocations are done before the pointers to the actual Fortran90 arrays are lost. Notice that larrayList is used to obtain the pointers used in the deallocate statement. Pointers obtained from the larrayRefList, while pointing to the same data, cannot be used to deallocated the array allocations!

  do de=1, 2
    call ESMF_LocalArrayGet(larrayList(de), farrayPtr, rc=rc)
    deallocate(farrayPtr)
    call ESMF_LocalArrayDestroy(larrayList(de), rc=rc)
  enddo
  deallocate(larrayList)
  deallocate(larrayRefList)
  call ESMF_ArrayDestroy(array, rc=rc)
  call ESMF_DistGridDestroy(distgrid, rc=rc)

With that ESMF can be shut down cleanly.

  call ESMF_Finalize(rc=rc)

end program

19.2.4 Array creation with automatic memory allocation

The examples of the previous sections made the user responsible for providing memory allocations for the PET-local regions of the Array object. The user was able to use any of the Fortran90 array methods or go through the ESMF_LocalArray interfaces to obtain memory allocations before passing them into ArrayCreate(). Alternatively, users may wish for ESMF to handle memory allocation of an Array object directly. The following example shows the interfaces that are available to the user to do just this.

To create an ESMF_Array object without providing an existing Fortran90 array or ESMF_LocalArray the type, kind and rank (tkr) of the Array must be specified in form of an ESMF_ArraySpec argument. Here a 2D Array of double precision real numbers is to be created:

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)

Further an ESMF_DistGrid argument must be constructed that holds information about the entire domain (patchwork) and the decomposition into DE-local exclusive regions. The following line creates a DistGrid for a 5x5 global LR domain that is decomposed into 2 x 3 = 6 DEs.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), rc=rc)

This is enough information to create a Array object with default settings.

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, rc=rc)

The array object created by the above call is an ESMF distributed object. As such it must follow the ESMF convention that requires that the call to ESMF_ArrayCreate() must be issued in unison by all PETs of the current context.

The index space covered by the Array object and the decomposition into DE-local exclusive regions, as it is described by the DistGrid object, is illustrated in the following diagram. Each asterix (*) represents a single element.

   
    +---------------------------------------> 2nd dimension
    |  (1,1)
    |    +-----------+-----------+------+
    |    | DE 0      | DE 2      | DE 4 |
    |    |           |           |      |
    |    |  *    *   |  *    *   |  *   |
    |    |           |           |      |
    |    |  *    *   |  *    *   |  *   |
    |    |           |           |      |
    |    |  *    *   |  *    *   |  *   |
    |    +-----------+-----------+------+
    |    |           |           |      |
    |    | DE 1      | DE 3      | DE 5 |
    |    |           |           |      |
    |    |  *    *   |  *    *   |  *   |
    |    |           |           |      |
    |    |  *    *   |  *    *   |  *   |
    |    +-----------+-----------+------+
    |                                 (5,5)
    v 
   1st dimension

19.2.5 Native language memory access - the most general way

The exact decomposition of the index space covered by the array object into DEs is contained in the distgrid object. Further, the layout of the DEs across the PETs of the component is stored in the delayout contained within the distgrid object. In the above example a default DELayout was created during the ESMF_DistGridCreate() call (see the refDoc / proposal for ESMF_DELayout and ESMF_DistGrid for details).

In order to use the array object it is necessary to know the local DEs located on each calling PET.

  call ESMF_ArrayGet(array, localDeCount=localDeCount, rc=rc)
  allocate(localDeList(localDeCount))
  call ESMF_ArrayGet(array, localDeList=localDeList, rc=rc)

In general it must be assumed that there may be multiple DEs associated with the calling PET, i.e. localDeCount >= 1. The situation where there is exactly one DE for each PET, i.e. localDeCount = 1 on every PET, is merely a special case of the more general formulation.

Consequently, in order to gain access to the DE-local memory segments that have been allocated on each PET by the ArrayCreate() call the Array must be queried for a list of LocalArray objects, each element corresponding to one PET-local DE.

  allocate(larrayList(localDeCount))
  call ESMF_ArrayGet(array, larrayList=larrayList, rc=rc)

Now each PET can loop through its local list of DEs and access the associated memory through a suitable Fortran90 pointer. In the current example the native pointer myF90Array must be declared as
real(ESMF_KIND_R8), pointer:: myF90Array(:,:)
in order to match the arrayspec that was used to create the array object. The following loop uses the native language access to initialize the entire memory chunks of all PET-local DEs to 0 using Fortran90 array syntax.

  do de=1, localDeCount
    call ESMF_LocalArrayGet(larrayList(de), myF90Array, ESMF_DATA_REF, rc=rc)
    myF90Array = 0.
  enddo


19.2.6 Regions and default bounds

Each ESMF_Array object is decomposed into DEs as specified by the associated ESMF_DistGrid object. Each piece of this decomposition, i.e. each DE, holds a chunk of the Array data in its own local piece of memory. The details of the Array decomposition are described in the following paragraphs.

At the center of the Array decomposition is the ESMF_DistGrid class. The DistGrid object specified during Array creation contains three essential pieces of information:

Each element of an Array is associated with a single DE. The union of elements associated with a DE, as defined by the DistGrid above, corresponds to a LR chunk of index space, called the exclusive region of the DE.

There is a hierarchy of four regions that can be identified for each DE in an Array object. Their definition and relationship to each other is as follows:

  
     +-totalLBound(:)----------------------------------+
     |\                                                |
     | \ <--- totalLWidth(:)                           |
     |  \                                              |
     |   +-computationalLBound(:)------------------+   |
     |   |\                                        |   |
     |   | \ <--- computationalLWidth(:)           |   |
     |   |  \                                      |   |
     |   |   +-exclusiveLBound(:)-------------+    |   |
     |   |   |                                |    |   |
     |   |   |     +------+      +-----+      |    |   |
     |   |   |     |      |      |     |      |    |   |
     |   |   |     |      +------+     |      |    |   |
     |   |   |     | "Interior Region" |      |    |   |
     |   |   |     +-----+             |      |    |   |
     |   |   |           |             |      |    |   |
     |   |   |           +-------------+      |    |   |
     |   |   |                                |    |   |
     |   |   | "Exclusive Region"             |    |   |
     |   |   +-------------exclusiveUBound(:)-+    |   |
     |   |                                     \   |   |
     |   |           computationalUWidth(:) --> \  |   |
     |   |                                       \ |   |
     |   | "Computational Region"                 \|   |
     |   +------------------computationalUBound(:)-+   |
     |                                              \  | 
     |                             totalUWidth(:) -> \ | 
     | "Total Region"                                 \| 
     +--------------------------------- totalUBound(:)-+

With the following definitions:

  
   computationalLWidth(:) = exclusiveLBound(:) - computationalLBound(:)
   computationalUWidth(:) = computationalUBound(:) - exclusiveLBound(:)
and
  
   totalLWidth(:) = computationalLBound(:) - totalLBound(:)
   totalUWidth(:) = totalUBound(:) - computationalUBound(:)

The exclusive region is determined during Array creation by the DistGrid argument. Optional arguments may be used to specify the computational region when the Array is created, by default it will be set equal to the exclusive region. The total region, i.e. the actual memory allocation for each DE, is also determined during Array creation. When creating the Array object from existing Fortran90 arrays the total region is set equal to the memory provided by the Fortran90 arrays. Otherwise the default is to allocate as much memory as is needed to accomodate the union of the DE-local exclusive and computational region. Finally it is also possible to use optional arguments to the ArrayCreate() call to specify the total region of the object explicitly.

The ESMF_ArrayCreate() call checks that the input parameters are consistent and will result in an Array that fulfills all of the above mentioned requirements for its DE-local regions.

Once an Array object has been created the exclusive and total regions are fixed. The computational region, however, may be adjusted within the limits of the total region using the ArraySet() call.

The interior region is very different from the other regions in that it cannot be specified. The interior region for each DE is a consequence of the choices made for the other regions collectively across all DEs into which an Array object is decomposed. An Array object can be queried for its DE-local interior regions as to offer additional information to the user necessary to write more efficient code. See section [*](not yet implemented) for more details.

By default the bounds of each DE-local total region are defined as to put the start of the DE-local exclusive region at the "origin" of the local index space, i.e. at (1, 1, ..., 1). With that definition the following loop will access each element of the DE-local memory segment for each PET-local DE of the Array object used in the previous sections and print its content.

  do de=1, localDeCount
    call ESMF_LocalArrayGet(larrayList(de), myF90Array, ESMF_DATA_REF, rc=rc)
    do i=1, size(myF90Array, 1)
      do j=1, size(myF90Array, 2)
        print *, "PET-local DE=", de, ": array(",i,",",j,")=", myF90Array(i,j)
      enddo
    enddo
  enddo

19.2.7 Array bounds

The loop over Array elements at the end of the last section only works correctly because of the default definition of the computational and total regions used in the example. In general, without such specific knowledge about an Array object, it is necessary to use a more formal approach to access its regions with DE-local indices.

The DE-local exclusive region takes a central role in the definition of Array bounds. Even as the computational region may adjust during the course of execution the exclusive region remains unchanged. Furthermore the exclusive region is identical for all stagger locations (discussed in a later section) and as such provides a unique reference frame for the index space of all Arrays associated with the same DistGrid.

There is a choice between two indexing options that needs to be made during Array creation. By default each DE-local exclusive region starts at (1, 1, ..., 1). However, for some computational kernels it may be more convenient to choose the index bounds of the DE-local exclusive regions to match the index space coordinates as they are defined in the corresponding DistGrid object. The second option is only available if the DistGrid object does not contain any non-contiguous decompositions (such as cyclically decomposed dimensions).

The following example code demonstrates the safe way of dereferencing the DE-local exclusive regions of the previously created array object.

  allocate(exclusiveUBound(2, localDeCount))  ! dimCount=2
  allocate(exclusiveLBound(2, localDeCount))  ! dimCount=2
  call ESMF_ArrayGet(array, indexflag=indexflag, &
    exclusiveLBound=exclusiveLBound, exclusiveUBound=exclusiveUBound, rc=rc)
  if (indexflag == ESMF_INDEX_DELOCAL) then
    ! this is the default
!    print *, "DE-local exclusive regions start at (1,1)"
    do de=1, localDeCount
      call ESMF_LocalArrayGet(larrayList(de), myF90Array, ESMF_DATA_REF, rc=rc)
      do i=1, exclusiveUBound(1, de)
        do j=1, exclusiveUBound(2, de)
!          print *, "DE-local exclusive region for PET-local DE=", de, &
!            ": array(",i,",",j,")=", myF90Array(i,j)
        enddo
      enddo
    enddo
  else if (indexflag == ESMF_INDEX_GLOBAL) then
    ! only if set during ESMF_ArrayCreate()
!    print *, "DE-local exclusive regions of this Array have global bounds"
    do de=1, localDeCount
      call ESMF_LocalArrayGet(larrayList(de), myF90Array, ESMF_DATA_REF, rc=rc)
      do i=exclusiveLBound(1, de), exclusiveUBound(1, de)
        do j=exclusiveLBound(2, de), exclusiveUBound(2, de)
!          print *, "DE-local exclusive region for PET-local DE=", de, &
!            ": array(",i,",",j,")=", myF90Array(i,j)
        enddo
      enddo
    enddo
  endif
  call ESMF_ArrayDestroy(array, rc=rc) ! destroy the array object

Obviously the second branch of this simple code will work for either case, however, if a complex computational kernel was written assuming ESMF_INDEX_DELOCAL type bounds the second branch would simply be used to indicate the problem and bail out.

The advantage of the ESMF_INDEX_GLOBAL index option is that the Array bounds directly contain information on where the DE-local Array piece is located in a global index space sense. When the ESMF_INDEX_DELOCAL option is used the correspondence between local and global index space must be made by querying the associated DistGrid for the DE-local indexList arguments.

19.2.8 Computational region and extra elements for halo or padding

In the previous examples the computational region of array was chosen by default to be identical to the exclusive region defined by the DistGrid argument during Array creation. In the following the same arrayspec and distgrid objects as before will be used to create an Array but now a larger computational region shall be defined around each DE-local exclusive region. Furthermore, extra space will be defined around the computational region of each DE to accommodate a halo and/or serve as memory padding.

In this example the indexflag argument is set to ESMF_INDEX_GLOBAL indicating that the bounds of the exclusive region correspond to the index space coordinates as they are defined by the DistGrid object.

The same arrayspec and distgrid objects as before are used which also allows the reuse of the already allocated larrayList variable.

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, &
    computationalLWidth=(/0,3/), computationalUWidth=(/1,1/), &
    totalLWidth=(/1,4/), totalUWidth=(/3,1/), &
    indexflag=ESMF_INDEX_GLOBAL, rc=rc)

Obtain the larrayList on every PET.

  call ESMF_ArrayGet(array, larrayList=larrayList, rc=rc)

The bounds of DE 1 for array are shown in the following diagram to illustrate the situation. Notice that the totalLWidth and totalUWidth arguments in the ArrayCreate() call define the total region with respect to the exclusive region given for each DE by the distgrid argument.

        +-(3,-3)---------------------------------+ 
        |\                                       | 
        | +-(4,-2)-+-(4,1)--------------------+--+ 
        | |        |                          |  | 
        | |        |                          |  | 
        | |        |          DE 1            |  | 
        | |        |                          |  | 
        | |        |                          |  | 
        | |        | Exclusive Region         |  | 
        | |        +--------------------(5,2)-+  | 
        | | Computational Region                 | 
        | +-------------------------------(6,3)--+ 
        |                                        | 
        | Total Region                           | 
        +---------------------------------(8,3)--+

When working with this array it is possible for the computational kernel to overstep the exclusive region for both read/write access (computational region) and potentially read-only access into the total region outside of the computational region, if a halo operation provides valid entries for these elements.

The Array object can be queried for absolute bounds

  allocate(computationalLBound(2, localDeCount))  ! dimCount=2
  allocate(computationalUBound(2, localDeCount))  ! dimCount=2
  allocate(totalLBound(2, localDeCount))          ! dimCount=2
  allocate(totalUBound(2, localDeCount))          ! dimCount=2
  call ESMF_ArrayGet(array, exclusiveLBound=exclusiveLBound, &
    exclusiveUBound=exclusiveUBound, computationalLBound=computationalLBound, &
    computationalUBound=computationalUBound, totalLBound=totalLBound, &
    totalUBound=totalUBound, rc=rc)

or for the relative widths.

  allocate(computationalLWidth(2, localDeCount))  ! dimCount=2
  allocate(computationalUWidth(2, localDeCount))  ! dimCount=2
  allocate(totalLWidth(2, localDeCount))          ! dimCount=2
  allocate(totalUWidth(2, localDeCount))          ! dimCount=2
  call ESMF_ArrayGet(array, computationalLWidth=computationalLWidth, &
    computationalUWidth=computationalUWidth, totalLWidth=totalLWidth, &
    totalUWidth=totalUWidth, rc=rc)

Either way the dereferencing of Array data is centered around the DE-local exclusive region:

  do de=1, localDeCount
    call ESMF_LocalArrayGet(larrayList(de), myF90Array, ESMF_DATA_REF, rc=rc)
    ! initialize the DE-local array
    myF90Array = 0.1d0 * localDeList(de)
    ! first time through the total region of array    
!    print *, "myF90Array bounds for DE=", localDeList(de), lbound(myF90Array), &
!      ubound(myF90Array)
    do j=exclusiveLBound(2, de), exclusiveUBound(2, de)
      do i=exclusiveLBound(1, de), exclusiveUBound(1, de)
!        print *, "Excl region DE=", localDeList(de), ": array(",i,",",j,")=", &
!          myF90Array(i,j)
      enddo
    enddo
    do j=computationalLBound(2, de), computationalUBound(2, de)
      do i=computationalLBound(1, de), computationalUBound(1, de)
!        print *, "Excl region DE=", localDeList(de), ": array(",i,",",j,")=", &
!          myF90Array(i,j)
      enddo
    enddo
    do j=totalLBound(2, de), totalUBound(2, de)
      do i=totalLBound(1, de), totalUBound(1, de)
!        print *, "Total region DE=", localDeList(de), ": array(",i,",",j,")=", &
!          myF90Array(i,j)
      enddo
    enddo

    ! second time through the total region of array    
    do j=exclusiveLBound(2, de)-totalLWidth(2, de), &
      exclusiveUBound(2, de)+totalUWidth(2, de)
      do i=exclusiveLBound(1, de)-totalLWidth(1, de), &
        exclusiveUBound(1, de)+totalUWidth(1, de)
!        print *, "Excl region DE=", localDeList(de), ": array(",i,",",j,")=", &
!          myF90Array(i,j)
      enddo
    enddo
  enddo

19.2.9 1D and 3D Arrays

All previous examples were written for the 2D case. There is, however, no restriction within the Array or DistGrid class that limits the dimensionality of Array objects beyond the language specific limitations (7D for Fortran).

In order to create an n-dimensional Array the rank indicated by both the arrayspec and the distgrid arguments specified during Array create must be equal to n. A 1D Array of double precision real data hence requires the following arrayspec.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=1, rc=rc)

The index space covered by the Array and the decomposition description is provided to the Array create method by the distgrid argument. The index space in this example has 16 elements and covers the interval $[-10, 5]$. It is decomposed into as many DEs as there are PETs in the current context.

  distgrid1D = ESMF_DistGridCreate(minIndex=(/-10/), maxIndex=(/5/), &
    regDecomp=(/petCount/), rc=rc)

A 1D Array object with default regions can now be created.

  array1D = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid1D, rc=rc)

The creation of a 3D Array proceeds analogous to the 1D case. The rank of the arrayspec must be changed to 3

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=3, rc=rc)

and an appropriate 3D DistGrid object must be created

  distgrid3D = ESMF_DistGridCreate(minIndex=(/1,1,1/), maxIndex=(/16,16,16/), &
    regDecomp=(/4,4,4/), rc=rc)

before an Array object can be created.

  array3D = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid3D, rc=rc)

The distgrid3D object decomposes the 3-dimensional index space into $4\times 4\times 4 = 64$ DEs. These DEs are laid out across the computational resources (PETs) of the current component according to a default DELayout that is created during the DistGrid create call. Notice that in the index space proposal a DELayout does not have a sense of dimensionality. The DELayout function is simply to map DEs to PETs. The DistGrid maps chunks of index space against DEs and thus its rank is equal to the number of index space dimensions.

The previously defined DistGrid and the derived Array object decompose the index space along all three dimension. It is, however, not a requirement that the decomposition be along all dimensions. An Array with the same 3D index space could as well be decomposed along just one or along two of the dimensions. The following example shows how for the same index space only the last two dimensions are decomposed while the first Array dimension has full extent on all DEs.

  call ESMF_ArrayDestroy(array3D, rc=rc)
  call ESMF_DistGridDestroy(distgrid3D, rc=rc)
  distgrid3D = ESMF_DistGridCreate(minIndex=(/1,1,1/), maxIndex=(/16,16,16/), &
    regDecomp=(/1,4,4/), rc=rc)
  array3D = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid3D, rc=rc)

Finally, the definition and usage of the stagger location index as it was described in sections [*] and [*] for the 2D case applies without change to 1D, 3D or any other dimensionality. Connections defined in the DistGrid object may utilize the stagger location index in order to express characteristics of the index space topology. The concept is completely rank independent.

19.2.10 Working with Arrays of different rank

Assume a computational kernel that involves the array3D object as it was created at the end of the previous section. Assume further that the kernel also involves a 2D Array on a 16x16 index space where each point (j,k) was interacting with each (i,j,k) column of the 3D Array. An efficient formulation would require that the decomposition of the 2D Array must match that of the 3D Array and further the DELayout be identical. The following code shows how this can be accomplished.

  call ESMF_DistGridGet(distgrid3D, delayout=delayout, rc=rc) ! get DELayout
  distgrid2D = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/16,16/), &
    regDecomp=(/4,4/), delayout=delayout, rc=rc)
  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)
  array2D = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid2D, rc=rc)

Now the following kernel is sure to work with array3D and array2D.

  call ESMF_DELayoutGet(delayout, localDeCount=localDeCount, rc=rc)
  allocate(larrayList1(localDeCount))
  call ESMF_ArrayGet(array3D, larrayList=larrayList1, rc=rc)
  allocate(larrayList2(localDeCount))
  call ESMF_ArrayGet(array2D, larrayList=larrayList2, rc=rc)
  do de=1, localDeCount
    call ESMF_LocalArrayGet(larrayList1(de), myF90Array3D, ESMF_DATA_REF, &
      rc=rc)
    myF90Array3D = 0.1d0 * de ! initialize
    call ESMF_LocalArrayGet(larrayList2(de), myF90Array2D, ESMF_DATA_REF, &
      rc=rc)
    myF90Array2D = 0.5d0 * de ! initialize
    do k=1, 4
      do j=1, 4
        dummySum = 0.d0
        do i=1, 16
          dummySum = dummySum + myF90Array3D(i,j,k) ! sum up the (j,k) column
        enddo
        dummySum = dummySum * myF90Array2D(j,k) ! multiply with local 2D element
!        print *, "dummySum(",j,k,")=",dummySum
      enddo
    enddo
  enddo

19.2.11 Array and DistGrid rank - 2D+1 Arrays

All of the Array create interfaces require the specification of at least the arrayspec and the distgrid arguments. Both arguments contain a sense of dimensionality. The relationship between these two arguments deserves extra attention.

The arrayspec argument is of type ESMF_ArraySpec and determines, among other things, the rank of the Array, i.e. the dimensionality of the actual data storage. This means, for example, that the rank of a native language array extracted from an Array object is equal to the rank specified by the arrayspec argument. It is also equal to the rank that is returned as by the ESMF_ArrayGet() call. The arrayspec argument does not determine, however, how the Array dimensions are decomposed and distributed.

The rank specification contained in the distgrid argument, which is of type ESMF_DistGrid, on the other hand has no affect on the rank of the Array. The dimCount specified by the DistGrid object, which may be equal, greater or less than the Array rank, determines the dimensionality of the decomposition.

While there is no constraint between DistGrid dimCount and Array rank, there is an important relationship between the two, resulting in the concept of index space dimensionality. Array dimensions can be arbitrarily mapped against DistGrid dimension, rendering them decomposed dimensions. The index space dimensionality is equal to the number of decomposed Array dimensions.

Array dimensions that are not mapped to DistGrid dimensions are considered extra or tensor dimensions of the Array. They are not part of the index space. The mapping is specified during ESMF_ArrayCreate() via the the distgridToArrayMap argument. DistGrid dimensions that have not been associated with Array dimensions are replicating dimensions. The Array will be replicated across the DEs that lie along replication DistGrid dimensions.

Array tensor dimensions can be used to store multi-dimensional data for each Array index space element. A special purpose of tensor dimensions is to store multiple data arrays in the same Array object. It is, for example, possible to store array1 and array2 of section [*] in a single Array object using one tensor dimension of size 2. The same distgrid object as before can be used to create the Array.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), rc=rc)

The rank in the arrayspec argument, however, must change from 2 to 3 in order to provide for the extra Array dimension.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=3, rc=rc)

During Array creation with extra dimension(s) it is necessary to specify the bounds of these tensor dimension(s). This requires two additional arguments, undistLBound and undistUBound, which are vectors in order to accommodate higher order tensor dimensions. The other arguments remain unchanged and apply across all tensor components.

The optional arguments used in the following call are identical to those used to create array1 of section [*]. This will set the total region and the stagger location of both tensor components to be those of array1.

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, &
    totalLWidth=(/0,1/), totalUWidth=(/0,1/), staggerLoc=1, &
    undistLBound=(/1/), undistUBound=(/2/), rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)

This will create array with 2+1 dimensions. The 2D DistGrid is used to describe decomposition into DEs with 2 Array dimensions mapped to the DistGrid dimensions resulting in a 2D index space. The extra Array dimension provides storeage for multiple 2D user data arrays that are kept in a single Array object. By default the distgrid dimensions are associated with the first Array dimensions in sequence. For the example above this means that the first 2 Array dimensions are decomposed according to the provided 2D DistGrid. The 3rd Array dimension does not have an associated DistGrid dimension, rendering it a tensor dimension.

The optional arguments that were used to create array ensure that the total region is large enough to accommodate the arrays for tensor component 1 and 2. The Array class provides a special Set() method that allows to individually address tensor elements in an Array and set staggerLoc and vectorDim arguments.

  call ESMF_ArraySet(array, tensorIndex=(/2/), staggerLoc=2, rc=rc)

Native language access to an Array with tensor dimensions is in principle the same as without extra dimensions.

  call ESMF_ArrayGet(array, localDeCount=localDeCount, rc=rc)
  allocate(larrayList(localDeCount))
  call ESMF_ArrayGet(array, larrayList=larrayList, rc=rc)

The following loop shows how a Fortran pointer to the DE-local data chunks can be obtained and used to set data values in the exclusive regions. The myF90Array3D variable must be of rank 3 to match the Array rank of array. However, variables such as exclusiveUBound that store the information about the decomposition, remain to be allocated for a 2D decomposition.

  call ESMF_ArrayGet(array, exclusiveLBound=exclusiveLBound, &
    exclusiveUBound=exclusiveUBound, rc=rc)
  do de=1, localDeCount
    call ESMF_LocalArrayGet(larrayList(de), myF90Array3D, ESMF_DATA_REF, rc=rc)
    myF90Array3D = 0.0 ! initialize
    myF90Array3D(exclusiveLBound(1,de):exclusiveUBound(1,de), &
      exclusiveLBound(2,de):exclusiveUBound(2,de), 1) = 5.1 ! dummy assignment
    myF90Array3D(exclusiveLBound(1,de):exclusiveUBound(1,de), &
      exclusiveLBound(2,de):exclusiveUBound(2,de), 2) = 2.5 ! dummy assignment
  enddo
  deallocate(larrayList)

For some applications the default association rules between DistGrid and Array dimensions may not satisfy the user's needs. The optional distgridToArrayMap argument may be used during Array creation to explicitly specify the mapping between Array and DistGrid dimensions. To demonstrate this the following lines of code reproduce the above example but with rearranged dimensions. Here the distgridToArrayMap argument is a list with two elements corresponding to the DistGrid dimCount of 2. The first element indicates which Array dimension the first DistGrid dimension is mapped against. Here the 1st DistGrid dimension maps against the 3rd Array and the 2nd DistGrid dimension maps against the 1st Array dimension. This leaves the 2nd Array dimension to be the extra or tensor dimension of the created Array object.

  call ESMF_ArrayDestroy(array, rc=rc)
  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, &
    distgridToArrayMap=(/3, 1/), totalLWidth=(/0,1/), totalUWidth=(/0,1/), &
    undistLBound=(/1/), undistUBound=(/2/), rc=rc)
  call ESMF_ArraySet(array, tensorIndex=(/1/), staggerLoc=1, rc=rc)
  call ESMF_ArraySet(array, tensorIndex=(/2/), staggerLoc=2, rc=rc)

Operations on the Array object as a whole are unchanged by the different mapping of dimensions.

When working with Arrays that contain explicitly mapped Array and DistGrid dimensions it is critical to understand that width and bound arguments are always defined in terms of the DistGrid dimension order. The Array dimensions indicate how the data is actually stored in the Array object, and that can be different for each Array, even if the same DistGrid is used. The decomposition defined by the DistGrid, however, does not change and is the same for each Array that uses it, regardless of the dimension order in the Array. The DistGrid dimension order thus becomes a common reference frame for all Arrays that use the same DistGrid.

The distgridToArrrayMap argument optionally provided during Array create indicates the DistGrid to Array dimension mapping. Depending on the formulation of the computational kernel, the inverse mapping, i.e. Array to DistGrid dimension mapping, is just as important. The ESMF_ArrayGet() call offers both mappings as distgridToArrrayMap and arrayToDistGridMap, respectively. The number of elements in arrayToDistGridMap is equal to the rank of the Array. Each element corresponds to an Array dimension and indicates the associated DistGrid dimension by an integer number. An entry of "0" indicates an extra Array dimension.

The association between Array and DistGrid dimensions becomes critical for correct native language access to the Array. In the following example the inverse mapping information is used to determine the correct bounds of the Array dimensions and to verify that the kernel's assumption about which Array dimension is a tensor dimension is correct.

  allocate(arrayToDistGridMap(3))  ! arrayRank = 3
  call ESMF_ArrayGet(array, arrayToDistGridMap=arrayToDistGridMap, &
    exclusiveLBound=exclusiveLBound, exclusiveUBound=exclusiveUBound, &
    localDeCount=localDeCount, rc=rc)  
  if (arrayToDistGridMap(2) /= 0) then   ! check if extra dimension at expected index
    ! indicate problem and bail out
  endif
  ! obtain larrayList for local DEs
  allocate(larrayList(localDeCount))
  call ESMF_ArrayGet(array, larrayList=larrayList, rc=rc)
  ! prepare inverse distgridToArrayMap variables for kernel loop
  idm1=arrayToDistGridMap(1)
  idm3=arrayToDistGridMap(3)
  do de=1, localDeCount
    call ESMF_LocalArrayGet(larrayList(de), myF90Array3D, ESMF_DATA_REF, rc=rc)
    myF90Array3D(exclusiveLBound(idm1,de):exclusiveUBound(idm1,de), &
      1, exclusiveLBound(idm3,de):exclusiveUBound(idm3,de)) = 10.5 ! dummy assignment
    myF90Array3D(exclusiveLBound(idm1,de):exclusiveUBound(idm1,de), &
      2, exclusiveLBound(idm3,de):exclusiveUBound(idm3,de)) = 23.3 ! dummy assignment
  enddo
  deallocate(exclusiveLBound, exclusiveUBound)
  deallocate(arrayToDistGridMap)
  deallocate(larrayList)
  call ESMF_ArrayDestroy(array, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)

19.2.12 Arrays with replicated dimensions

Thus far most examples demonstrated cases where the DistGrid dimCount was equal to the Array rank. The previous section introduced the concept of Array tensor dimensions when dimCount < rank. In this section dimCount and rank are assumed completely unconstrained and the relationship to distgridToArrayMap and arrayToDistGridMap will be discussed.

The Array class allows completely arbitrary mapping between Array and DistGrid dimensions. Most cases considered in the previous sections used the default mapping which assigns the DistGrid dimensions in sequence to the lower Array dimensions. Extra Array dimensions, if present, are considered non-distributed tensor dimensions for which the optional undistLBound and undistUBound arguments must be specified.

The optional distgridToArrayMap argument provides the option to override the default DistGrid to Array dimension mapping. The entries of the distgridToArrayMap array correspond to the DistGrid dimensions in sequence and assign a unique Array dimension to each DistGrid dimension. DistGrid and Array dimensions are indexed starting at 1 for the lowest dimension. A value of "0" in the distgridToArrayMap array indicates that the respective DistGrid dimension is not mapped against any Array dimension. What this means is that the Array will be replicated along this DistGrid dimension.

As a first example consider the case where a 1D Array

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=1, rc=rc)

is created on the 2D DistGrid used during the previous section.

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, rc=rc)

Here the default DistGrid to Array dimension mapping is used which assigns the Array dimensions in sequence to the DistGrid dimensions starting with dimension "1". Extra DistGrid dimensions are considerd replicator dimensions because the Array will be replicated along those dimensions. In the above example the 2nd DistGrid dimension will cause 1D Array pieces to be replicated along the DEs of the 2nd DistGrid dimension. Replication in the context of ESMF_ArrayCreate() does not mean that data values are communicated and replicated between different DEs, but it means that different DEs provide memory allocations for identical exclusive elements.

Access to the data storage of an Array that has been replicated along DistGrid dimensions is the same as for Arrays without replication.

  call ESMF_ArrayGet(array, localDeCount=localDeCount, rc=rc)

  allocate(larrayList(localDeCount))
  allocate(localDeList(localDeCount))
  call ESMF_ArrayGet(array, larrayList=larrayList, localDeList=localDeList, &
    rc=rc)

The array object was created without additional padding which means that the bounds of the Fortran array pointer correspond to the bounds of the exclusive region. The following loop will cycle through all local DEs, print the DE number as well as the Fortran array pointer bounds. The bounds should be:

            lbound       ubound
  
   DE 0:      1            3         --+
   DE 2:      1            3         --|  1st replication set
   DE 4:      1            3         --+
  
   DE 1:      1            2         --+
   DE 3:      1            2         --|  2nd replication set
   DE 5:      1            2         --+

  do de=1, localDeCount
    call ESMF_LocalArrayGet(larrayList(de), myF90Array1D, ESMF_DATA_REF, &
      rc=rc)

    print *, "DE ",localDeList(de)," [", lbound(myF90Array1D), &
      ubound(myF90Array1D),"]"
  enddo
  deallocate(larrayList)
  deallocate(localDeList)
  call ESMF_ArrayDestroy(array, rc=rc)

The Fortran array pointer in the above loop was of rank 1 because the Array object was of rank 1. However, the distgrid object associated with array is 2-dimensional! Consequently DistGrid based information queried from array will be 2D. The distgridToArrayMap and arrayToDistGridMap arrays provide the necessary mapping to correctly associate DistGrid based information with Array dimensions.

The next example creates a 2D Array

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)

on the previously used 2D DistGrid. By default, i.e. without the distgridToArrayMap argument, both DistGrid dimensions would be associated with the two Array dimensions. However, the distgridToArrayMap specified in the following call will only associate the second DistGrid dimension with the first Array dimension. This will render the first DistGrid dimension a replicator dimension and the second Array dimension a tensor dimension for which 1D undistLBound and undistUBound arguments must be supplied.

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, &
    distgridToArrayMap=(/0,1/), undistLBound=(/11/), undistUBound=(/14/), rc=rc)

  call ESMF_ArrayDestroy(array, rc=rc)

Finally, the same arrayspec and distgrid arguments are used to create a 2D Array that is fully replicated in both dimensions of the DistGrid. Both Array dimensions are now tensor dimensions and both DistGrid dimensions are replicator dimensions.

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, &
    distgridToArrayMap=(/0,0/), undistLBound=(/11,21/), undistUBound=(/14,22/), &
    rc=rc)

The result will be an Array with local lower bound (/11,21/) and upper bound (/14,22/) on all 6 DEs of the DistGrid.

  call ESMF_ArrayDestroy(array, rc=rc)

  call ESMF_DistGridDestroy(distgrid, rc=rc)

Replicated Arrays can also be created from existing local Fortran arrays. The following Fortran array allocation will provide a 3 x 10 array on each PET.

  allocate(myF90Array2D(3,10))

Assuming a petCount of 4 the following DistGrid defines a 2D index space that is distributed across the PETs along the first dimension.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/40,10/), rc=rc)

The following call creates an Array object on the above distgrid using the locally existing myF90Array2D Fortran arrays. The difference compared to the case with automatic memory allocation is that instead of arrayspec the Fortran array is provided as argument. Futhermore, the undistLBound and undistUBound arguments can be omitted, defaulting into Array tensor dimension lower bound of 1 and an upper bound equal to the size of the respective Fortran array dimension.

  array = ESMF_ArrayCreate(farray=myF90Array2D, distgrid=distgrid, &
    distgridToArrayMap=(/0,2/), rc=rc)

The array object associates the 2nd DistGrid dimension with the 2nd Array dimension. The first DistGrid dimension is not associated with any Array dimension and will lead to replication of the Array along the DEs of this direction.

  call ESMF_ArrayDestroy(array, rc=rc)

  call ESMF_DistGridDestroy(distgrid, rc=rc)


19.2.13 Communication - Scatter and Gather

It is a common situation, particularily in legacy code, that an ESMF Array object must be filled with data originating from a large Fortran array stored on a single PET.

  if (localPet == 0) then
    allocate(farray(10,20,30))
    do k=1, 30
      do j=1, 20
        do i=1, 10
          farray(i, j, k) = k*1000 + j*100 +  i
        enddo
      enddo
    enddo
  endif

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1,1/), maxIndex=(/10,20,30/), &
    rc=rc)

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_I4, rank=3, rc=rc)

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, rc=rc)

The ESMF_ArrayScatter() method provides a convenient way of scattering array data from a single root PET across the DEs of an ESMF Array object.

  call ESMF_ArrayScatter(array, farray=farray, rootPet=0, rc=rc)

  if (localPet == 0) then
    deallocate(farray)
  endif

The destination of the ArrayScatter() operation are all the DEs of a single patch. For multi-patch Arrays the destination patch can be specified. The shape of the scattered Fortran array must match the shape of the destination patch in the ESMF Array.

Gathering data decomposed and distributed across the DEs of an ESMF Array object into a single Fortran array on root PET is accomplished by calling ESMF_ArrayGather().

  if (localPet == 3) then
    allocate(farray(10,20,30))
  endif
  
  call ESMF_ArrayGather(array, farray=farray, rootPet=3, rc=rc)

  if (localPet == 3) then
    deallocate(farray)
  endif

The source of the ArrayGather() operation are all the DEs of a single patch. For multi-patch Arrays the source patch can be specified. The shape of the gathered Fortran array must match the shape of the source patch in the ESMF Array.

The ESMF_ArrayScatter() operation allows to fill entire replicated Array objects with data coming from a single root PET.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), rc=rc)

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)

  array = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=distgrid, &
    distgridToArrayMap=(/0,0/), undistLBound=(/11,21/), undistUBound=(/14,22/), &
    rc=rc)

The shape of the Fortran source array used in the Scatter() call must be that of the contracted Array, i.e. contracted DistGrid dimensions do not count. For the array just created this means that the source array on rootPet must be of shape 4 x 2.

  if (localPet == 0) then
    allocate(myF90Array2D(4,2))
    do j=1,2
      do i=1,4
        myF90Array2D(i,j) = i * 100.d0 + j * 1.2345d0 ! initialize
      enddo
    enddo
  endif
  
  call ESMF_ArrayScatter(array, farray=myF90Array2D, rootPet=0, rc=rc)

  if (localPet == 0) then
    deallocate(myF90Array2D)
  endif

This will have filled each local 4 x 2 Array piece with the replicated data of myF90Array2D.

  call ESMF_ArrayDestroy(array, rc=rc)

  call ESMF_DistGridDestroy(distgrid, rc=rc)

As a second example for the use of Scatter() and Gather() consider the following replicated Array created from existing local Fortran arrays.

  allocate(myF90Array2D(3,10))
  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/40,10/), rc=rc)

  array = ESMF_ArrayCreate(farray=myF90Array2D, distgrid=distgrid, &
    distgridToArrayMap=(/0,2/), rc=rc)

The array object associates the 2nd DistGrid dimension with the 2nd Array dimension. The first DistGrid dimension is not associated with any Array dimension and will lead to replication of the Array along the DEs of this direction. Still, the local arrays that comprise the array object refer to independent pieces of memory and can be initialized indpendently.

  myF90Array2D = localPet ! initialize

However, the notion of replication becomes visible when an array of shape 3 x 10 on root PET 0 is scattered across the Array object.

  if (localPet == 0) then
    allocate(myF90Array2D2(5:7,11:20))
  
    do j=11,20
      do i=5,7
        myF90Array2D2(i,j) = i * 100.d0 + j * 1.2345d0 ! initialize
      enddo
    enddo
  endif
  
  call ESMF_ArrayScatter(array, farray=myF90Array2D2, rootPet=0, rc=rc)

  if (localPet == 0) then
    deallocate(myF90Array2D2)
  endif

The Array pieces on every DE will receive the same source data, resulting in a replication of data along DistGrid dimension 1.

When the inverse operation, i.e. ESMF_ArrayGather(), is applied to a replicated Array an intrinsic ambiguity needs to be considered. ESMF defines the gathering of data of a replicated Array as the collection of data originating from the numerically higher DEs. This means that data in replicated elements associated with numerically lower DEs will be ignored during ESMF_ArrayGather(). For the current example this means that changing the Array contents on PET 1, which here corresponds to DE 1,

  if (localPet == 1) then
    myF90Array2D = real(1.2345, ESMF_KIND_R8)
  endif

will not affect the result of

  allocate(myF90Array2D2(3,10))
  myF90Array2D2 = 0.d0    ! initialize to a known value
  call ESMF_ArrayGather(array, farray=myF90Array2D2, rootPet=0, rc=rc)

The result remains completely defined by the unmodified values of Array in DE 3, the numerically highest DE. However, overriding the DE-local Array piece on DE 3

  if (localPet==3) then
    myF90Array2D = real(5.4321, ESMF_KIND_R8)
  endif

will change the outcome of

  call ESMF_ArrayGather(array, farray=myF90Array2D2, rootPet=0, rc=rc)

as expected.

  deallocate(myF90Array2D2)

  call ESMF_ArrayDestroy(array, rc=rc)

  call ESMF_DistGridDestroy(distgrid, rc=rc)


19.2.14 Communication - 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.

  srcDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/10,20/), &
    regDecomp=(/4,1/), rc=rc)

  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/10,20/), &
    regDecomp=(/1,4/), rc=rc)

The number of elements covered by srcDistgrid is identical to the number of elements covered by dstDistgrid - in fact the index space regions covered by both DistGrid objects are congruent.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)

  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, rc=rc)

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, rc=rc)

By construction srcArray and dstArray are of identical type and kind. Further the number of exclusive elements matches between both Arrays. These are the prerequesites for the application of an Array redistribution in default mode. In order to increase performance of the actual redistribution the communication patter must be precomputed and stored.

  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

The redistHandle can now be used repeatedly on the srcArray, dstArray pair to redistributed data from source to destination Array.

  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

The use of the redistHandle is not restricted to srcArray and dstArray. The redistHandle can be applied to redistribute data between any Array pairs that are congruent to the Array pair used during precomputation. Arrays are congruent if they are defined on matching DistGrids and the shape of local array allocations match for all DEs.

The resources held by redistHandle need to be deallocated by the user code before the handle becomes inaccessible.

  call ESMF_RouteHandleRelease(routehandle=redistHandle, rc=rc)

In default mode, i.e. without providing the optional srcToDstTransposeMap argument, ESMF_ArrayRedistStore() does not require equal number of dimensions in source and destination Array. Only the total number of elements must match.

Specifying srcToDstTransposeMap switches ESMF_ArrayRedistStore() into transpose mode. In this mode each dimension of srcArray is uniquely associated with a dimension in dstArray. The sizes of associated dimensions must match for each pair.

  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/20,10/), rc=rc)

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, rc=rc)

This dstArray object covers a 20 x 10 index space while the srcArray, defined further up, covers a 10 x 20 index space. Setting srcToDstTransposeMap = (/2,1/) will associate the first and second dimension of srcArray with the second and first dimension of 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.

  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/2,1/), rc=rc)

  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

The transpose mode of ESMF_ArrayRedist() is not limited to distributed dimensions of Arrays. The srcToDstTransposeMap argument can be used to transpose undistributed dimensions in the same manner. Furthermore transposing distributed and undistributed dimensions between Arrays is also supported.

The 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 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.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=4, rc=rc)

  srcDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/100,200/), &
    rc=rc)

  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, &
    undistLBound=(/1,1/), undistUBound=(/2,3/), rc=rc)

The first dstArray to consider is defined on a DistGrid that also describes a 100 x 200 index space region. The distribution indicated by 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.

  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/100,200/), &
    rc=rc)

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    undistLBound=(/1,1/), undistUBound=(/3,2/), rc=rc)

The desired mapping between srcArray and dstArray dimensions is expressed by srcToDstTransposeMap = (/1,2,4,3/), transposing only the two undistributed dimensions.

  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/1,2,4,3/), rc=rc)

  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

Next consider a dstArray that is defined on the same dstDistgrid, but with a different order of Array dimensions. The desired order is specified during Array creation using the argument 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.

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    distgridToArrayMap=(/2,3/), undistLBound=(/1,1/), undistUBound=(/3,2/), &
    rc=rc)

Again the sizes of the undistributed dimensions are chosen in reverse order compared to srcArray. The desired transpose mapping in this case will be srcToDstTransposeMap = (/2,3,4,1/).

  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/2,3,4,1/), rc=rc)

  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

Finally consider the case where dstArray is constructed on a 200 x 3 index space and where the undistributed dimensions are of size 100 and 2.

  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/200,3/), &
    rc=rc)

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    undistLBound=(/1,1/), undistUBound=(/100,2/), rc=rc)

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

  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, srcToDstTransposeMap=(/3,1,4,2/), rc=rc)

  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

The default mode of Array redistribution, i.e. without providing a srcToDstTransposeMap to ESMF_ArrayRedistStore(), also supports undistributed Array dimensions. The requirement in this case is that the total undistributed element count, i.e. the product of the sizes of all undistributed dimensions, be the same for source and destination Array. In this mode the number of undistributed dimensions need not match between source and destination.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=4, rc=rc)

  srcDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/10,20/), &
    regDecomp=(/4,1/), rc=rc)

  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, &
    undistLBound=(/1,1/), undistUBound=(/2,4/), rc=rc)

  dstDistgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/10,20/), &
    regDecomp=(/1,4/), rc=rc)

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    distgridToArrayMap=(/2,3/), undistLBound=(/1,1/), undistUBound=(/2,4/), &
    rc=rc)

Both srcArray and dstArray have two undistributed dimensions and a total count of undistributed elements of $ 2 \times 4 = 8$.

The Array redistribution operation is defined in terms of sequentialized undistributed dimensions. In the above case this means that a unique sequence index will be assigned to each of the 8 undistributed elements. The sequence indices will be 1, 2, ..., 8, where sequence index 1 is assigned to the first element in the first (i.e. fastest varying in memory) undistributed dimension. The following undistributed elements are labeled in consecutive order as they are stored in memory.

  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

The redistribution operation by default applies the identity operation between the elements of undistributed dimensions. This means that source element with sequence index 1 will be mapped against destination element with sequence index 1 and so forth. Because of the way source and destination Arrays in the current example were constructed this corresponds to a mapping of dimensions 3 and 4 on srcArray to dimensions 1 and 4 on dstArray, respectively.

  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

Array redistribution does not require the same number of undistributed dimensions in source and destination Array, merely the total number of undistributed elements must match.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=3, rc=rc)

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    distgridToArrayMap=(/1,3/), undistLBound=(/11/), undistUBound=(/18/), &
    rc=rc)

This dstArray object only has a single undistributed dimension, while the srcArray, defined further back, has two undistributed dimensions. However, the total undistributed element count for both Arrays is 8.

  call ESMF_ArrayRedistStore(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)

In this case the default identity operation between the elements of undistributed dimensions corresponds to a merging of dimensions 3 and 4 on srcArray into dimension 2 on dstArray.

  call ESMF_ArrayRedist(srcArray=srcArray, dstArray=dstArray, &
    routehandle=redistHandle, rc=rc)


19.2.15 Communication - SparseMatMul

Sparse matrix multiplication is a fundamental Array communication method. One frequently used application of this method is the interpolation between pairs of Arrays. The principle is this: the value of each element in the exclusive region of the destination Array is expressed as a linear combination of potentially all the exclusive elements of the source Array. Naturally most of the coefficients of these linear combinations will be zero and it is more efficient to store explicit information about the non-zero elements than to keep track of all the coefficients.

There is a choice to be made with respect to the format in which to store the information about the non-zero elements. One option is to store the value of each coefficient together with the corresponding destination element index and source element index. Destination and source indices could be expressed in terms of the corresponding DistGrid patch index together with the coordinate tuple within the patch. While this format may be the most natural way to express elements in the source and destination Array, it has two major drawbacks. First the coordinate tuple is dimCount specific and second the format is extremly bulky. For 2D source and destination Arrays it would require 6 integers to store the source and destination element information for each non-zero coefficient and matters get worse for higher dimensions.

Both problems can be circumvented by interpreting source and destination Arrays as sequentialized strings or vectors of elements. This is done by assigning a unique sequence index to each exclusive element in both Arrays. With that the operation of updating the elements in the destination Array as linear combinations of source Array elements takes the form of a sparse matrix multiplication.

The default sequence index rule assigns index $1$ to the minIndex corner element of the first patch of the DistGrid on which the Array is defined. It then increments the sequence index by $1$ for each element running through the DistGrid dimensions by order. The index space position of the DistGrid patches does not affect the sequence labeling of elements. The default sequence indices for

  srcDistgrid = ESMF_DistGridCreate(minIndex=(/-1,0/), maxIndex=(/1,3/), rc=rc)

for each element are:

     -------------------------------------> 2nd dim
     |
     |   +------+------+------+------+
     |   |(-1,0)|      |      |(-1,3)|
     |   |      |      |      |      |
     |   |   1  |   4  |   7  |  10  |
     |   +------+------+------+------+
     |   |      |      |      |      |
     |   |      |      |      |      |
     |   |   2  |   5  |   8  |  11  |
     |   +------+------+------+------+
     |   | (1,0)|      |      | (1,3)|
     |   |      |      |      |      |
     |   |   3  |   6  |   9  |  12  |
     |   +------+------+------+------+
     |
     v
    1st dim

The assigned sequence indices are decomposition and distribution invariant by construction. Furthermore, when an Array is created with extra elements per DE on a DistGrid the sequence indices (which only cover the exclusive elements) remain unchanged.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)

  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, &
    totalLWidth=(/1,1/), totalUWidth=(/1,1/), indexflag=ESMF_INDEX_GLOBAL, &
    rc=rc)

The extra padding of 1 element in each direction around the exclusive elements on each DE are "invisible" to the Array spare matrix multiplication method. These extra elements are either updated by the computational kernel or by Array halo operations (not yet implemented!).

An alternative way to assign sequence indices to all the elements in the patches covered by a DistGrid object is to use a special ESMF_DistGridCreate() call. This call has been specifically designed for 1D cases with arbitrary, user-supplied sequence indices.

  seqIndexList(1) = localPet*10
  seqIndexList(2) = localPet*10 + 1
  dstDistgrid = ESMF_DistGridCreate(arbSeqIndexList=seqIndexList, rc=rc)

This call to ESMF_DistGridCreate() is collective across the current VM. The arbSeqIndexList argument specifies the PET-local arbitrary sequence indices that need to be covered by the local DE. The resulting DistGrid has one local DE per PET which covers the entire PET-local index range. The user supplied sequence indices must be unique, but the sequence may be interrupted. The four DEs of dstDistgrid have the following local 1D index space coordinates (given between "()") and sequence indices:

    covered by DE 0    covered by DE 1   covered by DE 2   covered by DE 3
    on PET 0           on PET 1          on PET 2          on PET 3
    ----------------------------------------------------------------------
    (1) : 0            (1) : 10          (1) : 20          (1) : 30
    (2) : 1            (2) : 11          (2) : 21          (2) : 31

Again the DistGrid object provides the sequence index labeling for the exclusive elements of an Array created on the DistGrid regardless of extra, non-exclusive elements.

  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, rc=rc)

With the definition of sequence indices, either by the default rule or as user provided arbitrary sequence indices, it is now possible to uniquely identify each exclusive element in the source and destination Array by a single integer number. Specifying a pair of source and destination elements takes two integer number regardless of the number of dimensions.

The information required to carry out a sparse matrix multiplication are the pair of source and destination sequence indices and the associated multiplication factor for each pair. ESMF requires this information in form of two Fortran arrays. The factors are stored in a 1D array of the appropriate type and kind, e.g. real(ESMF_KIND_R8)::factorList(:). Array sparse matrix multiplications are only supported between Arrays of the same type and kind using factors of identical type and kind. The sequence index pairs associated with the factors provided by factorList are stored in a 2D Fortran array of default integer kind of the shape integer::factorIndexList(2,:). The sequence indices of the source Array elements are stored in the first row of factorIndexList while the sequence indices of the destination Array elements are stored in the second row.

Each PET in the current VM must call into ESMF_ArraySparseMatMulStore() to precompute and store the communication pattern for the sparse matrix multiplication. The multiplication factors may be provided in parallel, i.e. multiple PETs may specify factorList and factorIndexList arguments when calling into ESMF_ArraySparseMatMulStore(). PETs that do not provide factors either call with factorList and factorIndexList arguments containing zero elements or issue the call omitting both arguments.

  if (localPet == 0) then
    allocate(factorList(1))               ! PET 0 specifies 1 factor
    allocate(factorIndexList(2,1))
    factorList = (/0.2/)                  ! factors
    factorIndexList(1,:) = (/5/)          ! seq indices into srcArray
    factorIndexList(2,:) = (/30/)         ! seq indices into dstArray
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, factorList=factorList, &
      factorIndexList=factorIndexList, rc=rc)
      
    deallocate(factorList)
    deallocate(factorIndexList)
  else if (localPet == 1) then
    allocate(factorList(3))               ! PET 1 specifies 3 factor
    allocate(factorIndexList(2,3))
    factorList = (/0.5, 0.5, 0.8/)        ! factors
    factorIndexList(1,:) = (/8, 2, 12/)   ! seq indices into srcArray
    factorIndexList(2,:) = (/11, 11, 30/) ! seq indices into dstArray
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, factorList=factorList, &
      factorIndexList=factorIndexList, rc=rc)
      
    deallocate(factorList)
    deallocate(factorIndexList)
  else
    ! PETs 2 and 3 do not provide factors
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, rc=rc)
      
  endif

The RouteHandle object sparseMatMulHandle produced by ESMF_ArraySparseMatMulStore() can now be used to call ESMF_ArraySparseMatMul() collectively across all PETs of the current VM to perform

     dstArray = 0.0
     do n=1, size(combinedFactorList)
         dstArray(combinedFactorIndexList(2, n)) += 
           combinedFactorList(n) * srcArray(combinedFactorIndexList(1, n))
     enddo
in parallel. Here combinedFactorList and combinedFactorIndexList are the combined lists defined by the respective local lists provided by PETs 0 and 1 in parallel. For this example

  call ESMF_ArraySparseMatMul(srcArray=srcArray, dstArray=dstArray, &
    routehandle=sparseMatMulHandle, rc=rc)

will initialize the entire dstArray to 0.0 and then update two elements:

   on DE 1:
   dstArray(2) = 0.5 * srcArray(0,0)  +  0.5 * srcArray(0,2)

and

   on DE 3:
   dstArray(1) = 0.2 * srcArray(0,1)  +  0.8 * srcArray(1,3).

The call to ESMF_ArraySparseMatMul() does provide the option to turn the default dstArray initialization off. If argument zeroflag is set to ESMF_FALSE

  call ESMF_ArraySparseMatMul(srcArray=srcArray, dstArray=dstArray, &
    routehandle=sparseMatMulHandle, zeroflag=ESMF_FALSE, rc=rc)

skips the initialization and elements in dstArray are updated according to:

     do n=1, size(combinedFactorList)
         dstArray(combinedFactorIndexList(2, n)) += 
           combinedFactorList(n) * srcArray(combinedFactorIndexList(1, n)).
     enddo

The resources held by sparseMatMulHandle need to be deallocated by the user code before the handle becomes inaccessible.

  call ESMF_RouteHandleRelease(routehandle=sparseMatMulHandle, rc=rc)

The Array sparse matrix multiplication also applies to Arrays with undistributed dimensions. The undistributed dimensions are interpreted in a sequentialized manner, much like the distributed dimensions, introducing a second sequence index for source and destination elements. Sequence index 1 is assigned to the first element in the first (i.e. fastest varying in memory) undistributed dimension. The following undistributed elements are labeled in consecutive order as they are stored in memory.

In the simplest case the Array sparse matrix multiplication will apply an identity matrix to the vector of sequentialized undistributed Array elements for every non-zero element in the sparse matrix. The requirement in this case is that the total undistributed element count, i.e. the product of the sizes of all undistributed dimensions, be the same for source and destination Array.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=3, rc=rc)
  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, &
    totalLWidth=(/1,1/), totalUWidth=(/1,1/), indexflag=ESMF_INDEX_GLOBAL, &
    distgridToArrayMap=(/1,2/), undistLBound=(/1/), undistUBound=(/2/), rc=rc)

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)
  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    distgridToArrayMap=(/2/), undistLBound=(/1/), undistUBound=(/2/), rc=rc)

Setting up factorList and factorIndexList is identical to the case for Arrays without undistributed dimensions. Also the call to ESMF_ArraySparseMatMulStore() remains unchanged. Internally, however, the source and destination Arrays are checked to make sure the total undistributed element count matches.

  if (localPet == 0) then
    allocate(factorList(1))               ! PET 0 specifies 1 factor
    allocate(factorIndexList(2,1))
    factorList = (/0.2/)                  ! factors
    factorIndexList(1,:) = (/5/)          ! seq indices into srcArray
    factorIndexList(2,:) = (/30/)         ! seq indices into dstArray
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, factorList=factorList, &
      factorIndexList=factorIndexList, rc=rc)
      
    deallocate(factorList)
    deallocate(factorIndexList)
  else if (localPet == 1) then
    allocate(factorList(3))               ! PET 1 specifies 3 factor
    allocate(factorIndexList(2,3))
    factorList = (/0.5, 0.5, 0.8/)        ! factors
    factorIndexList(1,:) = (/8, 2, 12/)   ! seq indices into srcArray
    factorIndexList(2,:) = (/11, 11, 30/) ! seq indices into dstArray
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, factorList=factorList, &
      factorIndexList=factorIndexList, rc=rc)
      
    deallocate(factorList)
    deallocate(factorIndexList)
  else
    ! PETs 2 and 3 do not provide factors
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, rc=rc)  
  endif

The call into the ESMF_ArraySparseMatMul() operation is completely transparent with respect to whether source and/or destination Arrays contain undistributed dimensions.

  call ESMF_ArraySparseMatMul(srcArray=srcArray, dstArray=dstArray, &
    routehandle=sparseMatMulHandle, rc=rc)

This operation will initialize the entire dstArray to 0.0 and then update four elements:

   on DE 1:
   dstArray[1](2) = 0.5 * srcArray(0,0)[1]  +  0.5 * srcArray(0,2)[1],
   dstArray[2](2) = 0.5 * srcArray(0,0)[2]  +  0.5 * srcArray(0,2)[2]

and

   on DE 3:
   dstArray[1](1) = 0.2 * srcArray(0,1)[1]  +  0.8 * srcArray(1,3)[1],
   dstArray[2](1) = 0.2 * srcArray(0,1)[2]  +  0.8 * srcArray(1,3)[2].

Here indices between "()" refer to distributed dimensions while indices between "[]" correspond to undistributed dimensions.

In a more general version of the Array sparse matrix multiplication the total undistributed element count, i.e. the product of the sizes of all undistributed dimensions, need not be the same for source and destination Array. In this formulation each non-zero element of the sparse matrix is identified with a unique element in the source and destination Array. This requires a generalization of the factorIndexList argument which now must contain four integer numbers for each element. These numbers in sequence are the sequence index of the distributed dimensions and the sequence index of the undistributed dimensions of the element in the source Array, followed by the sequence index of the distributed dimensions and the sequence index of the undistributed dimensions of the element in the destination Array.

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=3, rc=rc)
  srcArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=srcDistgrid, &
    totalLWidth=(/1,1/), totalUWidth=(/1,1/), indexflag=ESMF_INDEX_GLOBAL, &
    distgridToArrayMap=(/1,2/), undistLBound=(/1/), undistUBound=(/2/), rc=rc)

  call ESMF_ArraySpecSet(arrayspec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc)
  dstArray = ESMF_ArrayCreate(arrayspec=arrayspec, distgrid=dstDistgrid, &
    distgridToArrayMap=(/2/), undistLBound=(/1/), undistUBound=(/4/), rc=rc)

Setting up factorList is identical to the previous cases since there is still only one value associated with each non-zero matrix element. However, each entry in factorIndexList now has 4 instead of just 2 components.

  if (localPet == 0) then
    allocate(factorList(1))               ! PET 0 specifies 1 factor
    allocate(factorIndexList(4,1))
    factorList = (/0.2/)                  ! factors
    factorIndexList(1,:) = (/5/)          ! seq indices into srcArray
    factorIndexList(2,:) = (/1/)          ! undistr. seq indices into srcArray
    factorIndexList(3,:) = (/30/)         ! seq indices into dstArray
    factorIndexList(4,:) = (/2/)          ! undistr. seq indices into dstArray
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, factorList=factorList, &
      factorIndexList=factorIndexList, rc=rc)
      
    deallocate(factorList)
    deallocate(factorIndexList)
  else if (localPet == 1) then
    allocate(factorList(3))               ! PET 1 specifies 3 factor
    allocate(factorIndexList(4,3))
    factorList = (/0.5, 0.5, 0.8/)        ! factors
    factorIndexList(1,:) = (/8, 2, 12/)   ! seq indices into srcArray
    factorIndexList(2,:) = (/2, 1, 1/)    ! undistr. seq indices into srcArray
    factorIndexList(3,:) = (/11, 11, 30/) ! seq indices into dstArray
    factorIndexList(4,:) = (/4, 4, 2/)    ! undistr. seq indices into dstArray
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, factorList=factorList, &
      factorIndexList=factorIndexList, rc=rc)
      
    deallocate(factorList)
    deallocate(factorIndexList)
  else
    ! PETs 2 and 3 do not provide factors
    
    call ESMF_ArraySparseMatMulStore(srcArray=srcArray, dstArray=dstArray, &
      routehandle=sparseMatMulHandle, rc=rc)  
  endif

The call into the ESMF_ArraySparseMatMul() operation remains unchanged.

  call ESMF_ArraySparseMatMul(srcArray=srcArray, dstArray=dstArray, &
    routehandle=sparseMatMulHandle, rc=rc)

This operation will initialize the entire dstArray to 0.0 and then update two elements:

   on DE 1:
   dstArray[4](2) = 0.5 * srcArray(0,0)[1]  +  0.5 * srcArray(0,2)[2],

and

   on DE 3:
   dstArray[2](1) = 0.2 * srcArray(0,1)[1]  +  0.8 * srcArray(1,3)[1],

Here indices in $()$ refer to distributed dimensions while indices in $[]$ correspond to undistributed dimensions.

19.3 Restrictions and Future Work

19.4 Design and Implementation Notes

The Array class is part of the ESMF index space layer and is built ontop of the DistGrid and DELayout classes. The DELayout class introduces the notion of decomposition elements (DEs) and their layout across the available PETs. The DistGrid describes how index space is decomposed by assigning logically rectangular index space pieces or DE-local tiles to the DEs. The Array finally associates a local memory allocation with each local DE.

The following is a list of implementation specific details about the current ESMF Array.

19.5 Class API

19.5.1 ESMF_ArrayCreate - Create Array object from Fortran90 array


INTERFACE:

   ! Private name; call using ESMF_ArrayCreate() 
   function ESMF_ArrayCreateAssmdShape<rank><type><kind>(farray, & 
   distgrid, distgridToArrayMap, computationalEdgeLWidth, & 
   computationalEdgeUWidth, computationalLWidth, & 
   computationalUWidth, totalLWidth, & 
   totalUWidth, indexflag, staggerLoc, vectorDim, & 
   undistLBound, undistUBound, name, rc)
ARGUMENTS:
   <type> (ESMF_KIND_<kind>),dimension(<rank>),intent(in),target :: farray 
   type(ESMF_DistGrid), intent(in) :: distgrid 
   integer, intent(in), optional :: distgridToArrayMap(:) 
   integer, intent(in), optional :: computationalEdgeLWidth(:) 
   integer, intent(in), optional :: computationalEdgeUWidth(:) 
   integer, intent(in), optional :: computationalLWidth(:) 
   integer, intent(in), optional :: computationalUWidth(:) 
   integer, intent(in), optional :: totalLWidth(:) 
   integer, intent(in), optional :: totalUWidth(:) 
   type(ESMF_IndexFlag), intent(in), optional :: indexflag 
   integer, intent(in), optional :: staggerLoc 
   integer, intent(in), optional :: vectorDim 
   integer, intent(in), optional :: undistLBound(:) 
   integer, intent(in), optional :: undistUBound(:) 
   character (len=*), intent(in), optional :: name 
   integer, intent(out), optional :: rc
RETURN VALUE:
   type(ESMF_Array) :: ESMF_ArrayCreateAssmdShapemrankDmtypekind
DESCRIPTION:

Create an ESMF_Array object from an existing local native Fortran90 array according to distgrid. Besides farray each PET must issue this call with identical arguments in order to create a consistent Array object. The local arrays provided must be dimensioned according to the DE-local total region. Bounds of the exclusive regions are set as specified in the distgrid argument. Bounds for array dimensions that are not distributed can be chosen freely using the undistLBound and undistUBound arguments.

This interface requires a 1 DE per PET decomposition. The Array object will not be created and an error will be returned if this condition is not met.

The not distributed Array dimensions form a tensor of rank = array.rank - distgrid.dimCount. By default all tensor elements are associated with stagger location 0. The widths of the computational region are set to the provided value, or zero by default, for all tensor elements. Use ESMF_ArraySet() to change these default settings after the Array object has been created.

The return value is the newly created ESMF_Array object.

The arguments are:

farray
Valid native Fortran90 array, i.e. memory must be associated with the actual argument. The type/kind/rank information of farray will be used to set Array's properties accordingly. The shape of farray will be checked against the information contained in the distgrid.
distgrid
ESMF_DistGrid object that describes how the array is decomposed and distributed over DEs. The dimCount of distgrid must be smaller or equal to the rank of farray.
[distgridToArrayMap]
List that contains as many elements as is indicated by distgrids's dimCount. The list elements map each dimension of the DistGrid object to a dimension in farray by specifying the appropriate Array dimension index. The default is to map all of distgrid's dimensions against the lower dimensions of the farray argument in sequence, i.e. distgridToArrayMap = (/1, 2, .../). Unmapped farray dimensions are not decomposed dimensions and form a tensor of rank = Array.rank - DistGrid.dimCount. All distgridToArrayMap entries must be greater than or equal to zero and smaller than or equal to the Array rank. It is erroneous to specify the same entry multiple times unless it is zero. If the Array rank is less than the DistGrid dimCount then the default distgridToArrayMap will contain zeros for the dimCount - rank rightmost entries. A zero entry in the distgridToArrayMap indicates that the particular DistGrid dimension will be replicating the Array across the DEs along this direction.
[computationalEdgeLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the computational region with respect to the lower corner of the exclusive region for DEs that are located on the edge of a patch. The default is a zero vector.
[computationalEdgeUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the computational region with respect to the upper corner of the exclusive region for DEs that are located on the edge of a patch. The default is a zero vector.
[computationalLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the computational region with respect to the lower corner of the exclusive region. The default is a zero vector.
[computationalUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the computational region with respect to the upper corner of the exclusive region. The default is a zero vector.
[totalLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the total memory region with respect to the lower corner of the computational region. The default is to accommodate the union of exclusive and computational region exactly.
[totalUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the total memory region with respect to the upper corner of the computational region. The default is a vector that contains the remaining number of elements in each direction as to fit the union of exclusive and computational region into the memory region provided by the farray argument.
[indexflag]
Indicate how DE-local indices are defined. By default each DE's exclusive region is placed to start at the local index space origin, i.e. (1, 1, ..., 1). Alternatively the DE-local index space can be aligned with the global index space, if a global index space is well defined by the associated DistGrid. See section 9.1.7 for a list of valid indexflag options.
[staggerLoc]
Stagger location is an arbitrary integer index. This information is used to correctly apply connection transformations of the corresponding DistGrid during halo operations.
[vectorDim]
If the data stored in this Array object is a component of a vector field then the vectorDim argument may be used to identify the dimension along which the vector component is aligned. This information is used to correctly apply the signChangeVector defined in the connection transformations of the corresponding DistGrid during halo operations.
[undistLBound]
Lower bounds for the array dimensions that are not distributed. By default lbound is 1.
[undistUBound]
Upper bounds for the array dimensions that are not distributed. By default ubound is equal to the extent of the corresponding dimension in farray.
[name]
Name of the Array object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.2 ESMF_ArrayCreate - Create Array object from a list of LocalArray objects


INTERFACE:

   ! Private name; call using ESMF_ArrayCreate()
   function ESMF_ArrayCreateLocalArray(larrayList, distgrid, distgridToArrayMap, &
     computationalEdgeLWidth, computationalEdgeUWidth, computationalLWidth, &
     computationalUWidth, totalLWidth, totalUWidth, &
     indexflag, staggerLoc, vectorDim, undistLBound, undistUBound, name, rc)
ARGUMENTS:
        type(ESMF_LocalArray), intent(in) :: larrayList(:)
        type(ESMF_DistGrid), intent(in) :: distgrid
        integer, intent(in), optional :: distgridToArrayMap(:)
        integer, intent(in), optional :: computationalEdgeLWidth(:)
        integer, intent(in), optional :: computationalEdgeUWidth(:)
        integer, intent(in), optional :: computationalLWidth(:)
        integer, intent(in), optional :: computationalUWidth(:)
        integer, intent(in), optional :: totalLWidth(:)
        integer, intent(in), optional :: totalUWidth(:)
        type(ESMF_IndexFlag), intent(in), optional :: indexflag
        integer, intent(in), optional :: staggerLoc
        integer, intent(in), optional :: vectorDim
        integer, intent(in), optional :: undistLBound(:)
        integer, intent(in), optional :: undistUBound(:)
        character (len=*), intent(in), optional :: name
        integer, intent(out), optional :: rc
RETURN VALUE:
     type(ESMF_Array) :: ESMF_ArrayCreateLocalArray
DESCRIPTION:

Create an ESMF_Array object from existing ESMF_LocalArray objects according to distgrid. Besides larrayList each PET must issue this call with identical arguments in order to create a consistent Array object. The local arrays provided must be dimensioned according to the DE-local total region. Bounds of the exclusive regions are set as specified in the distgrid argument. Bounds for array dimensions that are not distributed can be chosen freely using the undistLBound and undistUBound arguments.

This interface is able to handle multiple DEs per PET.

The not distributed Array dimensions form a tensor of rank = array.rank - distgrid.dimCount. By default all tensor elements are associated with stagger location 0. The widths of the computational region are set to the provided value, or zero by default, for all tensor elements. Use ESMF_ArraySet() to change these default settings after the Array object has been created.

The return value is the newly created ESMF_Array object.

The arguments are:

larrayList
List of valid ESMF_LocalArray objects, i.e. memory must be associated with the actual arguments. The type/kind/rank information of all larrayList elements must be identical and will be used to set Array's properties accordingly. The shape of each larrayList element will be checked against the information contained in the distgrid.
distgrid
ESMF_DistGrid object that describes how the array is decomposed and distributed over DEs. The dimCount of distgrid must be smaller or equal to the rank specified in arrayspec, otherwise a runtime ESMF error will be raised.
[distgridToArrayMap]
List that contains as many elements as is indicated by distgrids's dimCount. The list elements map each dimension of the DistGrid object to a dimension in the larrayList elements by specifying the appropriate Array dimension index. The default is to map all of distgrid's dimensions against the lower dimensions of the larrayList elements in sequence, i.e. distgridToArrayMap = (/1, 2, .../). Unmapped dimensions in the larrayList elements are not decomposed dimensions and form a tensor of rank = Array.rank - DistGrid.dimCount. All distgridToArrayMap entries must be greater than or equal to zero and smaller than or equal to the Array rank. It is erroneous to specify the same entry multiple times unless it is zero. If the Array rank is less than the DistGrid dimCount then the default distgridToArrayMap will contain zeros for the dimCount - rank rightmost entries. A zero entry in the distgridToArrayMap indicates that the particular DistGrid dimension will be replicating the Array across the DEs along this direction.
[computationalEdgeLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the computational region with respect to the lower corner of the exclusive region for DEs that are located on the edge of a patch.
[computationalEdgeUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the computational region with respect to the upper corner of the exclusive region for DEs that are located on the edge of a patch.
[computationalLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the computational region with respect to the lower corner of the exclusive region. The default is a zero vector.
[computationalUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the computational region with respect to the upper corner of the exclusive region. The default is a zero vector.
[totalLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the total memory region with respect to the lower corner of the computational region. The default is to accommodate the union of exclusive and computational region exactly.
[totalUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the total memory region with respect to the upper corner of the exclusive region. The default is a vector that contains the remaining number of elements in each direction as to fit the union of exclusive and computational region into the memory region provided by the larrayList argument.
[indexflag]
Indicate how DE-local indices are defined. By default each DE's' exclusive region is placed to start at the local index space origin, i.e. (1, 1, ..., 1). Alternatively the DE-local index space can be aligned with the global index space, if a global index space is well defined by the associated DistGrid. See section 9.1.7 for a list of valid indexflag options.
[staggerLoc]
Stagger location is an arbitrary integer index. This information is used to correctly apply connection transformations of the corresponding DistGrid during halo operations.
[vectorDim]
If the data stored in this Array object is a component of a vector field then the vectorDim argument may be used to identify the dimension along which the vector component is aligned. This information is used to correctly apply the signChangeVector defined in the connection transformations of the corresponding DistGrid during halo operations.
[undistLBound]
Lower bounds for the array dimensions that are not distributed. By default lbound is 1.
[undistUBound]
Upper bounds for the array dimensions that are not distributed. By default ubound is equal to the extent of the corresponding dimension in larrayList.
[name]
Name of the Array object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.3 ESMF_ArrayCreate - Create Array object from specification and allocate memory


INTERFACE:

   ! Private name; call using ESMF_ArrayCreate()
   function ESMF_ArrayCreateAllocate(arrayspec, distgrid, distgridToArrayMap, &
     computationalEdgeLWidth, computationalEdgeUWidth, &
     computationalLWidth, computationalUWidth, totalLWidth, totalUWidth, &
     indexflag, staggerLoc, vectorDim, undistLBound, undistUBound, name, rc)
ARGUMENTS:
        type(ESMF_ArraySpec), intent(inout) :: arrayspec
        type(ESMF_DistGrid), intent(in) :: distgrid
        integer, intent(in), optional :: distgridToArrayMap(:)
        integer, intent(in), optional :: computationalEdgeLWidth(:)
        integer, intent(in), optional :: computationalEdgeUWidth(:)
        integer, intent(in), optional :: computationalLWidth(:)
        integer, intent(in), optional :: computationalUWidth(:)
        integer, intent(in), optional :: totalLWidth(:)
        integer, intent(in), optional :: totalUWidth(:)
        type(ESMF_IndexFlag), intent(in), optional :: indexflag
        integer, intent(in), optional :: staggerLoc
        integer, intent(in), optional :: vectorDim
        integer, intent(in), optional :: undistLBound(:)
        integer, intent(in), optional :: undistUBound(:)
        character (len=*), intent(in), optional :: name
        integer, intent(out), optional :: rc
RETURN VALUE:
     type(ESMF_Array) :: ESMF_ArrayCreateAllocate
DESCRIPTION:

Create an ESMF_Array object and allocate uninitialized data space according to arrayspec and distgrid. Each PET must issue this call with identical arguments in order to create a consistent Array object. DE-local allocations are made according to the total region defined by the arguments to this call: distgrid and the optional Width arguments.

The return value is the newly created ESMF_Array object.

The arguments are:

arrayspec
ESMF_ArraySpec object containing the type/kind/rank information.
distgrid
ESMF_DistGrid object that describes how the array is decomposed and distributed over DEs. The dimCount of distgrid must be smaller or equal to the rank specified in arrayspec, otherwise a runtime ESMF error will be raised.
[distgridToArrayMap]
List that contains as many elements as is indicated by distgrids's dimCount. The list elements map each dimension of the DistGrid object to a dimension in the newly allocated Array object by specifying the appropriate Array dimension index. The default is to map all of distgrid's dimensions against the lower dimensions of the Array object in sequence, i.e. distgridToArrayMap = (/1, 2, .../). Unmapped dimensions in the Array object are not decomposed dimensions and form a tensor of rank = Array.rank - DistGrid.dimCount. All distgridToArrayMap entries must be greater than or equal to zero and smaller than or equal to the Array rank. It is erroneous to specify the same entry multiple times unless it is zero. If the Array rank is less than the DistGrid dimCount then the default distgridToArrayMap will contain zeros for the dimCount - rank rightmost entries. A zero entry in the distgridToArrayMap indicates that the particular DistGrid dimension will be replicating the Array across the DEs along this direction.
[computationalEdgeLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the computational region with respect to the lower corner of the exclusive region for DEs that are located on the edge of a patch.
[computationalEdgeUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the computational region with respect to the upper corner of the exclusive region for DEs that are located on the edge of a patch.
[computationalLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the computational region with respect to the lower corner of the exclusive region. The default is a zero vector.
[computationalUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the computational region with respect to the upper corner of the exclusive region. The default is a zero vector.
[totalMemoryLWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the lower corner of the total memory region with respect to the lower corner of the computational region. The default is to accommodate the union of exclusive and computational region.
[totalMemoryUWidth]
This vector argument must have dimCount elements, where dimCount is specified in distgrid. It specifies the upper corner of the total memory region with respect to the upper corner of the computational region. The default is to accommodate the union of exclusive and computational region.
[indexflag]
Indicate how DE-local indices are defined. By default each DE's' exclusive region is placed to start at the local index space origin, i.e. (1, 1, ..., 1). Alternatively the DE-local index space can be aligned with the global index space, if a global index space is well defined by the associated DistGrid. See section 9.1.7 for a list of valid indexflag options.
[staggerLoc]
Stagger location is an arbitrary integer index. This information is used to correctly apply connection transformations of the corresponding DistGrid during halo operations.
[vectorDim]
If the data stored in this Array object is a component of a vector field then the vectorDim argument may be used to identify the dimension along which the vector component is aligned. This information is used to correctly apply the signChangeVector defined in the connection transformations of the corresponding DistGrid during halo operations.
[undistLBound]
Lower bounds for the array dimensions that are not distributed.
[undistUBound]
Upper bounds for the array dimensions that are not distributed.
[name]
Name of the Array object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.4 ESMF_ArrayCreate - Create Array object as copy of existing Array object


INTERFACE:

   ! Private name; call using ESMF_ArrayCreate()
   function ESMF_ArrayCreateCopy(array, rc)
ARGUMENTS:
        type(ESMF_Array), intent(in) :: array
        integer, intent(out), optional :: rc
RETURN VALUE:
     type(ESMF_Array) :: ESMF_ArrayCreateCopy
DESCRIPTION:

Create an ESMF_Array object as the copy of an existing Array.

The return value is the newly created ESMF_Array object.

The arguments are:

array
ESMF_Array object to be copied.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.5 ESMF_ArrayDestroy - Destroy Array object


INTERFACE:

   subroutine ESMF_ArrayDestroy(array, rc)
ARGUMENTS:
     type(ESMF_Array), intent(inout) :: array
     integer, intent(out), optional :: rc
DESCRIPTION:

Destroy an ESMF_Array object.

The arguments are:

array
ESMF_Array object to be destroyed.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.6 ESMF_ArrayGather - Gather a Fortran90 array from an ESMF_Array


INTERFACE:

   subroutine ESMF_ArrayGather<rank><type><kind>(array, farray, patch, & 
   rootPet, vm, rc)
ARGUMENTS:
   type(ESMF_Array), intent(inout) :: array 
   mtype (ESMF_KIND_mtypekind),dimension(mdim),intent(in),target :: farray 
   integer, intent(in), optional :: patch 
   integer, intent(in) :: rootPet 
   type(ESMF_VM), intent(in), optional :: vm 
   integer, intent(out), optional :: rc
DESCRIPTION:

Gather the data of an ESMF_Array object into the farray located on rootPET. A single DistGrid patch of array must be gathered into farray. The optional patch argument allows selection of the patch. For Arrays defined on a single patch DistGrid the default selection (patch 1) will be correct. The shape of farray must match the shape of the patch in Array.

If the Array contains replicating DistGrid dimensions data will be gathered from the numerically higher DEs. Replicated data elements in numericaly lower DEs will be ignored.

This version of the interface implements the PET-based blocking paradigm: Each PET of the VM must issue this call exactly once for all of its DEs. The call will block until all PET-local data objects are accessible.

The arguments are:

array
The ESMF_Array object from which data will be gathered.
[farray]
The Fortran90 array into which to gather data. Only root must provide a valid farray.
[patch]
The DistGrid patch in array from which to gather farray. By default farray will be gathered from patch 1.
rootPet
PET that holds the valid destination array, i.e. farray.
[vm]
Optional ESMF_VM object of the current context. Providing the VM of the current context will lower the method's overhead.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.7 ESMF_ArrayGet - Get Array internals


INTERFACE:

   ! Private name; call using ESMF_ArrayGet()
   subroutine ESMF_ArrayGetDefault(array, typekind, rank, larrayList, &
     indexflag, distgridToArrayMap, arrayToDistGridMap, undistLBound, &
     undistUBound, exclusiveLBound, exclusiveUBound, &
     computationalLBound, computationalUBound, totalLBound, totalUBound, &
     computationalLWidth, computationalUWidth, totalLWidth, totalUWidth, &
     name, distgrid, dimCount, patchCount, minIndexPDimPPatch, &
     maxIndexPDimPPatch, patchListPDe, indexCountPDimPDe, delayout, deCount, &
     localDeCount, localDeList, rc)
ARGUMENTS:
     type(ESMF_Array), intent(in) :: array
     type(ESMF_TypeKind), intent(out), optional :: typekind
     integer, intent(out), optional :: rank
     type(ESMF_LocalArray), target, intent(out), optional :: larrayList(:)
     type(ESMF_IndexFlag), intent(out), optional :: indexflag
     integer, intent(out), optional :: distgridToArrayMap(:)
     integer, intent(out), optional :: arrayToDistGridMap(:)
     integer, intent(out), optional :: undistLBound(:)
     integer, intent(out), optional :: undistUBound(:)
     integer, intent(out), optional :: exclusiveLBound(:,:)
     integer, intent(out), optional :: exclusiveUBound(:,:)
     integer, intent(out), optional :: computationalLBound(:,:)
     integer, intent(out), optional :: computationalUBound(:,:)
     integer, intent(out), optional :: totalLBound(:,:)
     integer, intent(out), optional :: totalUBound(:,:)
     integer, intent(out), optional :: computationalLWidth(:,:)
     integer, intent(out), optional :: computationalUWidth(:,:)
     integer, intent(out), optional :: totalLWidth(:,:)
     integer, intent(out), optional :: totalUWidth(:,:)
     character(len=*), intent(out), optional :: name
     type(ESMF_DistGrid), intent(out), optional :: distgrid
     integer, intent(out), optional :: dimCount
     integer, intent(out), optional :: patchCount
     integer, intent(out), optional :: minIndexPDimPPatch(:,:)
     integer, intent(out), optional :: maxIndexPDimPPatch(:,:)
     integer, intent(out), optional :: patchListPDe(:)
     integer, intent(out), optional :: indexCountPDimPDe(:,:)
     type(ESMF_DELayout), intent(out), optional :: delayout
     integer, intent(out), optional :: deCount
     integer, intent(out), optional :: localDeCount
     integer, intent(out), optional :: localDeList(:)
     integer, intent(out), optional :: rc
DESCRIPTION:

Get internal information.

This interface works for any number of DEs per PET.

The arguments are:

array
Queried ESMF_Array object.
[typekind]
TypeKind of the Array object.
[rank]
Rank of the Array object.
[larrayList]
Upon return this holds a list of the associated ESMC_LocalArray objects. larrayList must be allocated to be of size localDeCount, i.e. the number of DEs associated with the calling PET.
[indexflag]
Upon return this flag indicates how the DE-local indices are defined. See section 9.1.7 for a list of possible return values.
[distgridToArrayMap]
Upon return this list holds the Array dimensions against which the DistGrid dimensions are mapped. distgridToArrayMap must be allocated to be of size dimCount. An entry of zero indicates that the respective DistGrid dimension is replicating the Array across the DEs along this direction.
[arrayToDistGridMap]
Upon return this list holds the DistGrid dimensions against which the Array dimensions are mapped. arrayToDistGridMap must be allocated to be of size rank. An entry of zero indicates that the respective Array dimension is not decomposed, rendering it a tensor dimension.
[undistLBound]
Upon return this array holds the lower bounds of the undistributed dimensions of the Array. UndistLBound must be allocated to be of size rank-dimCount.
[undistUBound]
Upon return this array holds the upper bounds of the undistributed dimensions of the Array. UndistUBound must be allocated to be of size rank-dimCount.
[exclusiveLBound]
Upon return this holds the lower bounds of the exclusive regions for all PET-local DEs. exclusiveLBound must be allocated to be of size (dimCount, localDeCount).
[exclusiveUBound]
Upon return this holds the upper bounds of the exclusive regions for all PET-local DEs. exclusiveUBound must be allocated to be of size (dimCount, localDeCount).
[computationalLBound]
Upon return this holds the lower bounds of the computational regions for all PET-local DEs. computationalLBound must be allocated to be of size (dimCount, localDeCount).
[computationalUBound]
Upon return this holds the upper bounds of the computational regions for all PET-local DEs. computationalUBound must be allocated to be of size (dimCount, localDeCount).
[totalLBound]
Upon return this holds the lower bounds of the total regions for all PET-local DEs. totalLBound must be allocated to be of size (dimCount, localDeCount).
[totalUBound]
Upon return this holds the upper bounds of the total regions for all PET-local DEs. totalUBound must be allocated to be of size (dimCount, localDeCount).
[computationalLWidth]
Upon return this holds the lower width of the computational regions for all PET-local DEs. computationalLWidth must be allocated to be of size (dimCount, localDeCount).
[computationalUWidth]
Upon return this holds the upper width of the computational regions for all PET-local DEs. computationalUWidth must be allocated to be of size (dimCount, localDeCount).
[totalLWidth]
Upon return this holds the lower width of the total memory regions for all PET-local DEs. computationalUWidth must be allocated to be of size (dimCount, localDeCount).
[totalUWidth]
Upon return this holds the upper width of the total memory regions for all PET-local DEs. totalUWidth must be allocated to be of size (dimCount, localDeCount).
[name]
Name of the Array object.
[distgrid]
Upon return this holds the associated ESMF_DistGrid object.
[dimCount]
Number of dimensions (rank) of distgrid.
[patchCount]
Number of patches in distgrid.
[minIndexPDimPPatch]
Lower index space corner per dim, per patch, with size(minIndexPDimPPatch) == (/dimCount, patchCount/).
[maxIndexPDimPPatch]
Upper index space corner per dim, per patch, with size(minIndexPDimPPatch) == (/dimCount, patchCount/).
[patchListPDe]
List of patch id numbers, one for each DE, with size(patchListPDe) == (/deCount/)
[indexCountPDimPDe]
Array of extents per dim, per de, with size(indexCountPDimPDe) == (/dimCount, deCount/).
[delayout]
Upon return this holds the associated ESMF_DELayout object.
[deCount]
Upon return this holds the total number of DEs defined in the DELayout associated with the Array object.
[localDeCount]
Upon return this holds the number of PET-local DEs defined in the DELayout associated with the Array object.
[localDeList]
Upon return this holds the list of DE ids for the PET-local DEs defined in the DELayout associated with the Array object. The provided argument must be of size localDeCount.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.8 ESMF_ArrayGet - Get Array internals per dim per local DE


INTERFACE:

   ! Private name; call using ESMF_ArrayGet()
   subroutine ESMF_ArrayGetPLocalDePDim(array, localDe, dim, indexCount, indexList, rc)
ARGUMENTS:
     type(ESMF_Array), intent(in) :: array
     integer, intent(in) :: localDe
     integer, intent(in) :: dim
     integer, intent(out), optional :: indexCount
     integer, intent(out), optional :: indexList(:)
     integer, intent(out), optional :: rc
DESCRIPTION:

Get internal information per local DE, per dim.

This interface works for any number of DEs per PET.

The arguments are:

array
Queried ESMF_Array object.
localDe
Local DE for which information is requested. [0,..,localDeCount-1]
dim
Dimension for which information is requested. [1,..,dimCount]
[indexCount]
DistGrid indexCount associated with localDe, dim.
[indexList]
List of DistGrid patch-local indices for localDe along dimension dim.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.9 ESMF_ArrayGet - Get access to PET-local Array patch via Fortran90 array pointer


INTERFACE:

   ! Private name; call using ESMF_ArrayGet() 
   subroutine ESMF_ArrayGetFPtr<rank><type><kind>(array, farrayPtr, rc)
ARGUMENTS:
   type(ESMF_Array), intent(in) :: array 
   <type> (ESMF_KIND_<kind>),dimension(<rank>),pointer :: farrayPtr 
   integer, intent(out), optional :: rc
DESCRIPTION:

Get Fortran90 pointer to DE-local memory regions in Array object.

This interface requires that exactly 1 DE is associated with the calling PET. An error will be returned if this condition is not met.

The arguments are:

array
Queried ESMF_Array object.
farrayPtr
Upon return farrayPtr points to the DE-local data allocation of array.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.10 ESMF_ArrayGet - Get access to PET-local Array patch via LocalArray object.


INTERFACE:

   ! Private name; call using ESMF_ArrayGet()
   subroutine ESMF_ArrayGetLarray(array, larray, rc)
ARGUMENTS:
     type(ESMF_Array), intent(in) :: array
     type(ESMF_LocalArray), intent(inout) :: larray
     integer, intent(out), optional :: rc
DESCRIPTION:

Get internal information.

This interface requires that exactly 1 DE is associated with the calling PET. An error will be returned if this condition is not met.

The arguments are:

array
Queried ESMF_Array object.
larray
Upon return larray refers to the DE-local data allocation of array.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.11 ESMF_ArrayScatter - Scatter a Fortran90 array across the ESMF_Array


INTERFACE:

   subroutine ESMF_ArrayScatter<rank><type><kind>(array, farray, patch, & 
   rootPet, vm, rc)
ARGUMENTS:
   type(ESMF_Array), intent(inout) :: array 
   mtype (ESMF_KIND_mtypekind),dimension(mdim),intent(in),target :: farray 
   integer, intent(in), optional :: patch 
   integer, intent(in) :: rootPet 
   type(ESMF_VM), intent(in), optional :: vm 
   integer, intent(out), optional :: rc
DESCRIPTION:

Scatter the data of farray located on rootPET across an ESMF_Array object. A single farray must be scattered across a single DistGrid patch in Array. The optional patch argument allows selection of the patch. For Arrays defined on a single patch DistGrid the default selection (patch 1) will be correct. The shape of farray must match the shape of the patch in Array.

If the Array contains replicating DistGrid dimensions data will be scattered across all of the replicated pieces.

This version of the interface implements the PET-based blocking paradigm: Each PET of the VM must issue this call exactly once for all of its DEs. The call will block until all PET-local data objects are accessible.

The arguments are:

array
The ESMF_Array object across which data will be scattered.
[farray]
The Fortran90 array that is to be scattered. Only root must provide a valid farray.
[patch]
The DistGrid patch in array into which to scatter farray. By default farray will be scattered into patch 1.
rootPet
PET that holds the valid data in farray.
[vm]
Optional ESMF_VM object of the current context. Providing the VM of the current context will lower the method's overhead.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.12 ESMF_ArrayPrint - Print Array internals


INTERFACE:

   subroutine ESMF_ArrayPrint(array, options, rc)
ARGUMENTS:
     type(ESMF_Array), intent(in)              :: array
     character(len=*), intent(in),   optional  :: options
     integer,          intent(out),  optional  :: rc
DESCRIPTION:

Print internal information of the specified ESMF_Array object.

The arguments are:

array
ESMF_Array object.
[options]
Print options are not yet supported.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.13 ESMF_ArrayRedistStore - Precompute Array redistribution


INTERFACE:

   ! Private name; call using ESMF_ArrayRedistStore()
   subroutine ESMF_ArrayRedistStore<type><kind>(srcArray, dstArray, routehandle, &
     factor, srcToDstTransposeMap, rc)
ARGUMENTS:
     type(ESMF_Array),           intent(in)              :: srcArray
     type(ESMF_Array),           intent(inout)           :: dstArray
     type(ESMF_RouteHandle),     intent(inout)           :: routehandle
     <type>(ESMF_KIND_<kind>),   intent(in)              :: factor
     integer,                    intent(in),   optional  :: srcToDstTransposeMap(:)
     integer,                    intent(out),  optional  :: rc
DESCRIPTION:

Store an Array redistribution operation from srcArray to dstArray. PETs that specify a factor argument must use the <type><kind> overloaded interface. Other PETs call into the interface without factor argument. If multiple PETs specify the factor argument its type and kind as well as its value must match across all PETs. If none of the PETs specifies a factor argument the default will be a factor of 1.

Both srcArray and dstArray are interpreted as sequentialized vectors. The sequence is defined by the order of DistGrid dimensions and the order of patches within the DistGrid or by user-supplied arbitrary sequence indices. See section 19.2.15 for details on the definition of sequence indices. Redistribution corresponds to an identity mapping of the source Array vector to the destination Array vector.

Source and destination Arrays may be of different <type><kind>. Further source and destination Arrays may differ in shape, however, the number of elements must match.

It is erroneous to specify the identical Array object for srcArray and dstArray arguments.

The routine returns an ESMF_RouteHandle that can be used to call ESMF_ArrayRedist() on any pair of Arrays that are congruent and typekind conform with the srcArray, dstArray pair. Congruent Arrays possess matching DistGrids and the shape of the local array tiles matches between the Arrays for every DE.

This call is collective across the current VM.

srcArray
ESMF_Array with source data.
dstArray
ESMF_Array with destination data.
routehandle
Handle to the precomputed Route.
[factor]
Factor by which to multipy source data. Default is 1.
[srcToDstTransposeMap]
List with as many entries as there are dimensions in srcArray. Each entry maps the corresponding srcArray dimension against the specified dstArray dimension. Mixing of distributed and undistributed dimensions is supported.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.14 ESMF_ArrayRedistStore - Precompute Array redistribution


INTERFACE:

   ! Private name; call using ESMF_ArrayRedistStore()
   subroutine ESMF_ArrayRedistStoreNF(srcArray, dstArray, routehandle, &
     srcToDstTransposeMap, rc)
ARGUMENTS:
     type(ESMF_Array),           intent(in)              :: srcArray
     type(ESMF_Array),           intent(inout)           :: dstArray
     type(ESMF_RouteHandle),     intent(inout)           :: routehandle
     integer,                    intent(in),   optional  :: srcToDstTransposeMap(:)
     integer,                    intent(out),  optional  :: rc
DESCRIPTION:

Store an Array redistribution operation from srcArray to dstArray. PETs that specify a factor argument must use the <type><kind> overloaded interface. Other PETs call into the interface without factor argument. If multiple PETs specify the factor argument its type and kind as well as its value must match across all PETs. If none of the PETs specifies a factor argument the default will be a factor of 1.

Both srcArray and dstArray are interpreted as sequentialized vectors. The sequence is defined by the order of DistGrid dimensions and the order of patches within the DistGrid or by user-supplied arbitrary sequence indices. See section 19.2.15 for details on the definition of sequence indices. Redistribution corresponds to an identity mapping of the source Array vector to the destination Array vector.

Source and destination Arrays may be of different <type><kind>. Further source and destination Arrays may differ in shape, however, the number of elements must match.

It is erroneous to specify the identical Array object for srcArray and dstArray arguments.

The routine returns an ESMF_RouteHandle that can be used to call ESMF_ArrayRedist() on any pair of Arrays that are congruent and typekind conform with the srcArray, dstArray pair. Congruent Arrays possess matching DistGrids and the shape of the local array tiles matches between the Arrays for every DE.

This call is collective across the current VM.

srcArray
ESMF_Array with source data.
dstArray
ESMF_Array with destination data.
routehandle
Handle to the precomputed Route.
[srcToDstTransposeMap]
List with as many entries as there are dimensions in srcArray. Each entry maps the corresponding srcArray dimension against the specified dstArray dimension. Mixing of distributed and undistributed dimensions is supported.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.15 ESMF_ArrayRedist - Execute an Array redistribution


INTERFACE:

   subroutine ESMF_ArrayRedist(srcArray, dstArray, routehandle, checkflag, rc)
ARGUMENTS:
     type(ESMF_Array),       intent(in),   optional  :: srcArray
     type(ESMF_Array),       intent(inout),optional  :: dstArray
     type(ESMF_RouteHandle), intent(inout)           :: routehandle
     type(ESMF_Logical),     intent(in),   optional  :: checkflag
     integer,                intent(out),  optional  :: rc
DESCRIPTION:

Execute a precomputed Array redistribution from srcArray to dstArray. Both srcArray and dstArray must be congruent and typekind conform with the respective Arrays used during ESMF_ArrayRedistStore(). Congruent Arrays possess matching DistGrids and the shape of the local array tiles matches between the Arrays for every DE.

It is erroneous to specify the identical Array object for srcArray and dstArray arguments.

See ESMF_ArrayRedistStore() on how to precompute routehandle.

This call is collective across the current VM.

[srcArray]
ESMF_Array with source data.
[dstArray]
ESMF_Array with destination data.
routehandle
Handle to the precomputed Route.
[checkflag]
If set to ESMF_TRUE the input Array pair will be checked for consistency with the precomputed operation provided by routehandle. If set to ESMF_FALSE (default) only a very basic input check will be performed, leaving many inconsistencies undetected. Set checkflag to ESMF_FALSE to achieve highest performance.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.16 ESMF_ArraySet - Set Array properties


INTERFACE:

   subroutine ESMF_ArraySet(array, name, staggerLoc, vectorDim, &
     computationalLWidth, computationalUWidth, rc)
ARGUMENTS:
     type(ESMF_Array),   intent(inout)           :: array
     character(len = *), intent(in),   optional  :: name
     integer,            intent(in),   optional  :: staggerLoc
     integer,            intent(in),   optional  :: vectorDim
     integer,            intent(in),   optional  :: computationalLWidth(:,:)
     integer,            intent(in),   optional  :: computationalUWidth(:,:)
     integer,            intent(out),  optional  :: rc
DESCRIPTION:

Sets adjustable settings in an ESMF_Array object. Arrays with tensor dimensions will set values for all tensor components.

The arguments are:

array
ESMF_Array object for which to set properties.
[name]
The Array name.
[staggerLoc]
User-defined stagger location.
[vectorDim]
User-defined vector dimension.
[computationalLWidth]
This argument must have of size (dimCount, localDeCount). computationalLWidth specifies the lower corner of the computational region with respect to the lower corner of the exclusive region for all local DEs.
[computationalUWidth]
This argument must have of size (dimCount, localDeCount). computationalUWidth specifies the upper corner of the computational region with respect to the upper corner of the exclusive region for all local DEs.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.17 ESMF_ArraySet - Set Array internals for specific tensor component


INTERFACE:

   ! Private name; call using ESMF_ArraySet()
   subroutine ESMF_ArraySetTensor(array, tensorIndex, staggerLoc, vectorDim, rc)
ARGUMENTS:
     type(ESMF_Array), intent(in)              :: array
     integer,          intent(in)              :: tensorIndex(:)
     integer,          intent(in),   optional  :: staggerLoc
     integer,          intent(in),   optional  :: vectorDim
     integer,          intent(out),  optional  :: rc
DESCRIPTION:

Sets adjustable settings in an ESMF_Array object for a specific tensor component.

The arguments are:

array
ESMF_Array object for which to set properties.
tensorIndex
Specifies the tensor component within the not distributed array dimensions for which properties are to be set.
[staggerLoc]
Stagger location of this tensor element.
[vectorDim]
Dimension along this vector component of this tensor element is aligned.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.18 ESMF_ArraySparseMatMulStore - Precompute Array sparse matrix multiplication with local factors


INTERFACE:

   ! Private name; call using ESMF_ArraySparseMatMulStore()
   subroutine ESMF_ArraySparseMatMulStore<type><kind>(srcArray, dstArray, &
     routehandle, factorList, factorIndexList, rc)
ARGUMENTS:
     type(ESMF_Array),           intent(in)              :: srcArray
     type(ESMF_Array),           intent(inout)           :: dstArray
     type(ESMF_RouteHandle),     intent(inout)           :: routehandle
     <type>(ESMF_KIND_<kind>), target, intent(in)        :: factorList(:)
     integer,                    intent(in)              :: factorIndexList(:,:)
     integer,                    intent(out),  optional  :: rc
DESCRIPTION:

Store an Array sparse matrix multiplication operation from srcArray to dstArray. PETs that specify non-zero matrix coefficients must use the <type><kind> overloaded interface and provide the factorList and factorIndexList arguments. Providing factorList and factorIndexList arguments with size(factorList) = (/0/) and size(factorIndexList) = (/2,0/) or (/4,0/) indicates that a PET does not provide matrix elements. Alternatively, PETs that do not provide matrix elements may also call into the overloaded interface without factorList and factorIndexList arguments.

Both srcArray and dstArray are interpreted as sequentialized vectors. The sequence is defined by the order of DistGrid dimensions and the order of patches within the DistGrid or by user-supplied arbitrary sequence indices. See section 19.2.15 for details on the definition of sequence indices.

Source and destination Arrays, as well as the supplied factorList argument, may be of different <type><kind>. Further source and destination Arrays may differ in shape and number of elements.

It is erroneous to specify the identical Array object for srcArray and dstArray arguments.

The routine returns an ESMF_RouteHandle that can be used to call ESMF_ArraySparseMatMul() on any pair of Arrays that are congruent and typekind conform with the srcArray, dstArray pair. Congruent Arrays possess matching DistGrids and the shape of the local array tiles matches between the Arrays for every DE.

This method is overloaded for:
ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8,
ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.

This call is collective across the current VM.

srcArray
ESMF_Array with source data.
dstArray
ESMF_Array with destination data.
routehandle
Handle to the precomputed Route.
factorList
List of non-zero coefficients.
factorIndexList
Pairs of sequence indices for the factors stored in factorList.

The second dimension of factorIndexList steps through the list of pairs, i.e. size(factorIndexList,2) == size(factorList). The first dimension of factorIndexList is either of size 2 or size 4.

In the size 2 format factorIndexList(1,:) specifies the sequence index of the source element in the srcArray while factorIndexList(2,:) specifies the sequence index of the destination element in dstArray. For this format to be a valid option source and destination Arrays must have matching number of tensor elements (the product of the sizes of all Array tensor dimensions). Under this condition an identiy matrix can be applied within the space of tensor elements for each sparse matrix factor.

The size 4 format is more general and does not require a matching tensor element count. Here the factorIndexList(1,:) specifies the sequence index while factorIndexList(2,:) specifies the tensor sequence index of the source element in the srcArray. Further factorIndexList(3,:) specifies the sequence index and factorIndexList(4,:) specifies the tensor sequence index of the destination element in the dstArray.

See section 19.2.15 for details on the definition of Array sequence indices and tensor sequence indices.

[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.19 ESMF_ArraySparseMatMulStore - Precompute Array sparse matrix multiplication without local factors


INTERFACE:

   ! Private name; call using ESMF_ArraySparseMatMulStore()
   subroutine ESMF_ArraySparseMatMulStoreNF(srcArray, dstArray, routehandle, &
     rc)
ARGUMENTS:
     type(ESMF_Array),           intent(in)              :: srcArray
     type(ESMF_Array),           intent(inout)           :: dstArray
     type(ESMF_RouteHandle),     intent(inout)           :: routehandle
     integer,                    intent(out),  optional  :: rc
DESCRIPTION:

Store an Array sparse matrix multiplication operation from srcArray to dstArray. PETs that specify non-zero matrix coefficients must use the <type><kind> overloaded interface and provide the factorList and factorIndexList arguments. Providing factorList and factorIndexList arguments with size(factorList) = (/0/) and size(factorIndexList) = (/2,0/) or (/4,0/) indicates that a PET does not provide matrix elements. Alternatively, PETs that do not provide matrix elements may also call into the overloaded interface without factorList and factorIndexList arguments.

Both srcArray and dstArray are interpreted as sequentialized vectors. The sequence is defined by the order of DistGrid dimensions and the order of patches within the DistGrid or by user-supplied arbitrary sequence indices. See section 19.2.15 for details on the definition of sequence indices.

Source and destination Arrays, as well as the supplied factorList argument, may be of different <type><kind>. Further source and destination Arrays may differ in shape and number of elements.

It is erroneous to specify the identical Array object for srcArray and dstArray arguments.

The routine returns an ESMF_RouteHandle that can be used to call ESMF_ArraySparseMatMul() on any pair of Arrays that are congruent and typekind conform with the srcArray, dstArray pair. Congruent Arrays possess matching DistGrids and the shape of the local array tiles matches between the Arrays for every DE.

This method is overloaded for:
ESMF_TYPEKIND_I4, ESMF_TYPEKIND_I8,
ESMF_TYPEKIND_R4, ESMF_TYPEKIND_R8.

This call is collective across the current VM.

srcArray
ESMF_Array with source data.
dstArray
ESMF_Array with destination data.
routehandle
Handle to the precomputed Route.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.20 ESMF_ArraySparseMatMul - Execute an Array sparse matrix multiplication


INTERFACE:

   subroutine ESMF_ArraySparseMatMul(srcArray, dstArray, routehandle, &
     zeroflag, checkflag, rc)
ARGUMENTS:
     type(ESMF_Array),       intent(in),   optional  :: srcArray
     type(ESMF_Array),       intent(inout),optional  :: dstArray
     type(ESMF_RouteHandle), intent(inout)           :: routehandle
     type(ESMF_Logical),     intent(in),   optional  :: zeroflag
     type(ESMF_Logical),     intent(in),   optional  :: checkflag
     integer,                intent(out),  optional  :: rc
DESCRIPTION:

Execute a precomputed Array sparse matrix multiplication from srcArray to dstArray. Both srcArray and dstArray must be congruent and typekind conform with the respective Arrays used during ESMF_ArraySparseMatMulStore(). Congruent Arrays possess matching DistGrids and the shape of the local array tiles matches between the Arrays for every DE.

It is erroneous to specify the identical Array object for srcArray and dstArray arguments.

See ESMF_ArraySparseMatMulStore() on how to precompute routehandle. See section 19.2.15 for details on the operation ESMF_ArraySparseMatMul() performs.

This call is collective across the current VM.

[srcArray]
ESMF_Array with source data.
[dstArray]
ESMF_Array with destination data.
routehandle
Handle to the precomputed Route.
[zeroflag]
If set to ESMF_TRUE (default) the total regions of all DEs in dstArray will be initialized to zero before updating the elements with the results of the sparse matrix multiplication. If set to ESMF_FALSE the elements in dstArray will not be modified prior to the sparse matrix multiplication and results will be added to the incoming element values.
[checkflag]
If set to ESMF_TRUE the input Array pair will be checked for consistency with the precomputed operation provided by routehandle. If set to ESMF_FALSE (default) only a very basic input check will be performed, leaving many inconsistencies undetected. Set checkflag to ESMF_FALSE to achieve highest performance.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

19.5.21 ESMF_ArrayValidate - Validate Array internals


INTERFACE:

   subroutine ESMF_ArrayValidate(array, rc)
ARGUMENTS:
     type(ESMF_Array), intent(in)              :: array
     integer,          intent(out),  optional  :: rc
DESCRIPTION:

Validates that the Array is internally consistent. The method returns an error code if problems are found.

The arguments are:

array
Specified ESMF_Array object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

20 LocalArray Class

20.1 Description

The ESMF_LocalArray class provides a language independent representation of data in array format. One of the major functions of the LocalArray class is to bridge the Fortran/C/C++ language difference that exists with respect to array representation. All ESMF Field and Array data is internally stored in ESMF LocalArray objects allowing transparent access from Fortran and C/C++.

In the ESMF Fortran API the LocalArray becomes visible in those cases where a local PET may be associated with multiple pieces of an Array, e.g. if there are multiple DEs associated with a single PET. The Fortran language standard does not provide an array of arrays construct, however arrays of derived types holding arrays are possible. ESMF calls use arguments that are of type ESMF_LocalArray with dimension attribute where necessary.

20.2 Restrictions and Future Work

20.3 Class API

20.3.1 ESMF_LocalArrayCreate - Create a LocalArray explicitly specifying TKR arguments.


INTERFACE:

   ! Private name; call using ESMF_LocalArrayCreate()
   function ESMF_LocalArrayCreateByTKR(rank, typekind, counts, lbounds, &
     ubounds, rc)
RETURN VALUE:
     type(ESMF_LocalArray) :: ESMF_LocalArrayCreateByTKR
ARGUMENTS:
     integer, intent(in) :: rank
     type(ESMF_TypeKind), intent(in) :: typekind
     integer, intent(in), optional :: counts(:)
     integer, intent(in), optional :: lbounds(:)
     integer, intent(in), optional :: ubounds(:)
     integer, intent(out), optional :: rc
DESCRIPTION:

Create a new ESMF_LocalArray and allocate data space, which remains uninitialized. The return value is a new LocalArray.

The arguments are:

rank
Array rank (dimensionality, 1D, 2D, etc). Maximum allowed is 7D.
typekind
Array typekind. See section 9.2.1 for valid values.
[counts]
The number of items in each dimension of the array. This is a 1D integer array the same length as the rank. The count argument may be omitted if both lbounds and ubounds arguments are present.
[lbounds]
An integer array of length rank, with the lower index for each dimension.
[ubounds]
An integer array of length rank, with the upper index for each dimension.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

20.3.2 ESMF_LocalArrayCreate - Create a LocalArray specifying an ArraySpec


INTERFACE:

   ! Private name; call using ESMF_LocalArrayCreate()
   function ESMF_LocalArrayCreateBySpec(arrayspec, counts, lbounds, ubounds, rc)
RETURN VALUE:
     type(ESMF_LocalArray) :: ESMF_LocalArrayCreateBySpec
ARGUMENTS:
     type(ESMF_ArraySpec), intent(inout) :: arrayspec
     integer, intent(in), optional :: counts(:)
     integer, intent(in), optional :: lbounds(:)
     integer, intent(in), optional :: ubounds(:)
     integer, intent(out), optional :: rc
DESCRIPTION:

Create a new ESMF_LocalArray and allocate data space, which remains uninitialized. The return value is a new LocalArray.

The arguments are:

arrayspec
ArraySpec object specifying typekind and rank.
[counts]
The number of items in each dimension of the array. This is a 1D integer array the same length as the rank. The count argument may be omitted if both lbounds and ubounds arguments are present.
[lbounds]
An integer array of length rank, with the lower index for each dimension.
[ubounds]
An integer array of length rank, with the upper index for each dimension.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

20.3.3 ESMF_LocalArrayCreate - Create a LocalArray from existing one


INTERFACE:

   ! Private name; call using ESMF_LocalArrayCreate()
   function ESMF_LocalArrayCreateCopy(larray, rc)
RETURN VALUE:
     type(ESMF_LocalArray) :: ESMF_LocalArrayCreateCopy
ARGUMENTS:
     type(ESMF_LocalArray), intent(in) :: larray
     integer, intent(out), optional :: rc
DESCRIPTION:

Perform a deep copy of an existing ESMF_LocalArray object. The return value is a new LocalArray.

The arguments are:

larray
Existing LocalArray to be copied.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

20.3.4 ESMF_LocalArrayCreate - Create a LocalArray from a Fortran pointer (associated or unassociated)


INTERFACE:

   ! Private name; call using ESMF_LocalArrayCreate() 
   function ESMF_LocalArrCreateByPtr<rank><type><kind>(fptr, docopy, counts, & 
   lbounds, ubounds, rc)
RETURN VALUE:
   type(ESMF_LocalArray) :: ESMF_LocalArrCreateByPtr<rank><type><kind>
ARGUMENTS:
   <type> (ESMF_KIND_<kind>), dimension(<rank>), pointer :: fptr 
   type(ESMF_CopyFlag), intent(in), optional :: docopy 
   integer, intent(in), optional :: counts(:) 
   integer, intent(in), optional :: lbounds(:) 
   integer, intent(in), optional :: ubounds(:) 
   integer, intent(out), optional :: rc
DESCRIPTION:

Creates an ESMF_LocalArray based on a Fortran array pointer. Two cases must be distinguished.

First, if fptr is associated the optional docopy argument may be used to indicate whether the associated data is to be copied or referenced. For associated fptr the optional counts, lbounds and ubounds arguments need not be specified. However, all present arguments will be checked against fptr for consistency.

Second, if fptr is unassociated the optional argument docopy must not be specified. However, in this case a complete set of counts and bounds information must be provided. Any combination of present counts lbounds and ubounds arguments that provides a complete specification is valid. All input information will be checked for consistency.

The arguments are:

fptr
A Fortran array pointer (associated or unassociated).
[docopy]
Indicate copy vs. reference behavior in case of associated fptr. This argument must not be present for unassociated fptr. Default to ESMF_DATA_REF, makes the ESMF_LocalArray reference the associated data array. If set to ESMF_DATA_COPY this routine allocates new memory and copies the data from the pointer into the new LocalArray allocation.
[counts]
The number of items in each dimension of the array. This is a 1D integer array the same length as the rank. The count argument may be omitted if both lbounds and ubounds arguments are present.
[lbounds]
An integer array of lower index values. Must be the same length as the rank.
[ubounds]
An integer array of upper index values. Must be the same length as the rank.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

20.3.5 ESMF_LocalArrayDestroy - Destroy a LocalArray object


INTERFACE:

   subroutine ESMF_LocalArrayDestroy(larray, rc)
ARGUMENTS:
     type(ESMF_LocalArray), intent(inout) :: larray
     integer, intent(out), optional :: rc
DESCRIPTION:

Releases all resources associated with this ESMF_LocalArray object.

The arguments are:

larray
Destroy contents of this ESMF_LocalArray.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

20.3.6 ESMF_LocalArrayGet - Return LocalArray information.


INTERFACE:

   ! Private name; call using ESMF_LocalArrayGet()
   subroutine ESMF_LocalArrayGetDefault(larray, rank, typekind, counts, lbounds, &
     ubounds, base, name, rc)
ARGUMENTS:
     type(ESMF_LocalArray), intent(in) :: larray
     integer, intent(out), optional :: rank
     type(ESMF_TypeKind), intent(out), optional :: typekind
     integer, intent(out), optional :: counts(:)
     integer, intent(out), optional :: lbounds(:)
     integer, intent(out), optional :: ubounds(:)
     type(ESMF_Pointer), intent(out), optional :: base
     character(len=ESMF_MAXSTR), intent(out), optional :: name
     integer, intent(out), optional :: rc
DESCRIPTION:

Returns information about the ESMF_LocalArray.

The arguments are:

larray
Queried ESMF_LocalArray object.
[rank]
Rank of the LocalArray object.
[typekind]
TypeKind of the LocalArray object.
[counts]
Count per dimension.
[lbounds]
Lower bound per dimension.
[ubounds]
Upper bound per dimension.
[base]
Base class object.
[name]
Name of the LocalArray object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

20.3.7 ESMF_LocalArrayGet - Get access to data in LocalArray object


INTERFACE:

   ! Private name; call using ESMF_LocalArrayGet() 
   subroutine ESMF_LocalArrayGetData<rank><type><kind>(larray, fptr, docopy, rc)
ARGUMENTS:
   type(ESMF_LocalArray) :: larray 
   <type> (ESMF_KIND_<kind>), dimension(<rank>), pointer :: fptr 
   type(ESMF_CopyFlag), intent(in), optional :: docopy 
   integer, intent(out), optional :: rc
DESCRIPTION:

Return a Fortran pointer to the data buffer, or return a Fortran pointer to a new copy of the data.

The arguments are:

larray
The ESMF_LocalArray to get the value from.
fptr
An unassociated or associated Fortran pointer correctly allocated.
[docopy]
An optional copy flag which can be specified. Can either make a new copy of the data or reference existing data. See section 9.1.4 for a list of possible values.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

21 ArraySpec Class

21.1 Description

An ArraySpec is a very simple class that contains type, kind, and rank information about an array. This information is stored in two parameters. TypeKind describes the data type of the elements in the array and their precision. Rank is the number of dimensions in the array.

The only methods that are associated with the ArraySpec class are those that allow you to set and retrieve this information.

21.2 Use and Examples

The ArraySpec is passed in as an argument at Field and Bundle creation in order to describe an Array that will be allocated or attached at a later time. There are any number of situations in which this approach is useful. One common example is a case in which the user wants to create a very flexible export State with many diagnostic variables predefined, but only a subset desired and consequently allocated for a particular run.

! !PROGRAM: ESMF_ArraySpecEx - ArraySpec manipulation examples
!
! !DESCRIPTION:
!
! This program shows examples of ArraySpec set and get usage
!-----------------------------------------------------------------------------

      ! ESMF Framework module
      use ESMF_Mod
      implicit none

      ! local variables 
      type(ESMF_ArraySpec) :: arrayDS
      integer :: myrank
      type(ESMF_TypeKind) :: mytypekind


      ! return code
      integer:: rc

      ! initialize ESMF framework
      call ESMF_Initialize(rc=rc)

21.2.1 Setting ArraySpec Values

This example shows how to set values in an ESMF_ArraySpec.

      call ESMF_ArraySpecSet(arrayDS, rank=2, &
                             typekind=ESMF_TYPEKIND_R8, rc=rc)

21.2.2 Getting ArraySpec Values

This example shows how to query an ESMF_ArraySpec.

      call ESMF_ArraySpecGet(arrayDS, myrank, mytypekind, rc)
      print *, "Returned values from ArraySpec:"
      print *, "rank =", myrank

      ! finalize ESMF framework
      call ESMF_Finalize(rc=rc)

      end program ESMF_ArraySpecEx

21.3 Restrictions and Future Work

  1. Limit on rank. The values for type, kind and rank passed into the ArraySpec class are subject to the same limitations as Arrays. The maximum array rank is 7, which is the highest rank supported by Fortran.

21.4 Design and Implementation Notes

The information contained in an ESMF_ArraySpec is used to create ESMF_Array objects.

ESMF_ArraySpec is a shallow class, and only set and get methods are needed. They do not need to be created or destroyed.

21.5 Class API

21.5.1 ESMF_ArraySpecGet - Get values from an ArraySpec


INTERFACE:

   subroutine ESMF_ArraySpecGet(arrayspec, rank, typekind, rc)
ARGUMENTS:
     type(ESMF_ArraySpec), intent(inout)         :: arrayspec
     integer,              intent(out), optional :: rank
     type(ESMF_TypeKind),  intent(out), optional :: typekind
     integer,              intent(out), optional :: rc
DESCRIPTION:

Returns information about the contents of an ESMF_ArraySpec.

The arguments are:

arrayspec
The ESMF_ArraySpec to query.
rank
Array rank (dimensionality - 1D, 2D, etc). Maximum possible is 7D.
typekind
Array typekind. See section 9.2.1 for valid values.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

21.5.2 ESMF_ArraySpecSet - Set values for an ArraySpec


INTERFACE:

   subroutine ESMF_ArraySpecSet(arrayspec, rank, typekind, rc)
ARGUMENTS:
     type(ESMF_ArraySpec), intent(inout)         :: arrayspec
     integer,              intent(in)            :: rank
     type(ESMF_TypeKind),  intent(in)            :: typekind
     integer,              intent(out), optional :: rc
DESCRIPTION:

Creates a description of the data - the typekind, the rank, and the dimensionality.

The arguments are:

arrayspec
The ESMF_ArraySpec to set.
rank
Array rank (dimensionality - 1D, 2D, etc). Maximum allowed is 7D.
typekind
Array typekind. See section 9.2.1 for valid values.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

21.5.3 ESMF_ArraySpecValidate - Validate ArraySpec internals


INTERFACE:

   subroutine ESMF_ArraySpecValidate(arrayspec, rc)
ARGUMENTS:
     type(ESMF_ArraySpec), intent(inout)              :: arrayspec
     integer,              intent(out),  optional  :: rc
DESCRIPTION:

Validates that the arrayspec is internally consistent. The method returns an error code if problems are found.

The arguments are:

arrayspec
Specified ESMF_ArraySpec object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

21.5.4 ESMF_ArraySpecPrint - Print information of ArraySpec


INTERFACE:

   subroutine ESMF_ArraySpecPrint(arrayspec, rc)
ARGUMENTS:
     type(ESMF_ArraySpec), intent(in)              :: arrayspec
     integer, intent(out), optional                :: rc
DESCRIPTION:

Print ArraySpec internals.

The arguments are:

arrayspec
Specified ESMF_ArraySpec object.

22 Grid Class

22.1 Description

The ESMF Grid class is used to describe the geometry and discretization of logically rectangular physical grids. It also contains the description of the grid's underlying topology and the decomposition of the physical grid across the available computational resources. The most frequent use of the Grid class is to describe physical grids in user code so that sufficient information is available to perform ESMF methods such as regridding.

In the current release (v3.1.0) the functionality in this class is partially implemented. Multi-tile grids are not supported, and edge connectivities are not implemented and default to aperiodic. Both regular and irregular distributions can be defined, but arbitrary distributions have not yet been implemented. Other constraints of the current implementation are noted in the usage section and in the API descriptions.


Key Features
Representation of grids formed by logically rectangular regions, including uniform and rectilinear grids (e.g. lat-lon grids), curvilinear grids (e.g. displaced pole grids), and grids formed by connected logically rectangular regions (e.g. cubed sphere grids) [CONNECTED REGIONS ARE NOT YET SUPPORTED].
Support for 1D, 2D, 3D, and higher dimension grids.
Distribution of grids across computational resources for parallel operations - users set which grid dimensions are distributed.
Grids can be created already distributed, so that no single resource needs global information during the creation process.
Options to define periodicity and other edge connectivities either explicitly or implicitly via shape shortcuts [EDGE CONNECTIVITIES CURRENTLY DEFAULT TO APERIODIC BOUNDS].
Options for users to define grid coordinates themselves or call prefabricated coordinate generation routines for standard grids [NO GENERATION ROUTINES YET].
Options for incremental construction of grids.
Options for using a set of pre-defined stagger locations or for setting custom stagger locations.

22.1.1 Grid Representation in ESMF

ESMF Grids are based on the concepts described in A Standard Description of Grids Used in Earth System Models [Balaji 2006]. In this document Balaji introduces the mosaic concept as a means of describing a wide variety of Earth system model grids. A mosaic is composed of grid tiles connected at their edges. Mosaic grids includes simple, single tile grids as a special case.

The ESMF Grid class is a representation of a mosaic grid. Each ESMF Grid is constructed of one or more logically rectangular Tiles. A Tile will usually have some physical significance (e.g. the region of the world covered by one face of a cubed sphere grid).

The piece of a Tile that resides on one DE (for simple cases, a DE can be thought of as a processor - see section on the DELayout) is called a LocalTile. For example, the six faces of a cubed sphere grid are each Tiles, and each Tile can be divided into many LocalTiles.

Every ESMF Grid contains a DistGrid object, which defines the Grid's index space, topology, distribution, and connectivities. It enables the user to define the complex edge relationships of tripole and other grids. The DistGrid can be created explicitly and passed into a Grid creation routine, or it can be created implicitly if the user takes a Grid creation shortcut. Options for grid creation are described in more detail in section 22.1.8.

22.1.2 Supported Grids

The range of supported grids in ESMF can be defined by:


22.1.3 Grid Topologies and Periodicity

ESMF has shortcuts for the creation of standard Grid topologies or shapes up to 3D. In many cases, these enable the user to bypass the step of creating a DistGrid before creating the Grid. The basic call is ESMF_GridCreateShapeTile(). With this call, the user can specify for each dimension whether there is no connection, it is periodic, it is a pole, or it is a bipole. The assumed connectivities for poles and bipoles are described in section 22.5.1. Connectivities are specified using the ESMF_GridConn parameter, which has values such as ESMF_GRIDCONN_PERIODIC.

The table below shows the ESMF_GridConn settings used to create standard shapes in 2D using the ESMF_GridCreateShapeTile() call. Two values are specified for each dimension, one for the low end and one for the high end of the dimension's index values. Note that connectivities have not been implemented as of v3.1.0 and default to aperiodic bounds.


2D Shape connDim1(1) connDim1(2) connDim2(1) connDim2(2)
Rectangle NONE NONE NONE NONE
Bipole Sphere POLE POLE PERIODIC PERIODIC
Tripole Sphere POLE BIPOLE PERIODIC PERIODIC
Cylinder NONE NONE PERIODIC PERIODIC
Torus PERIODIC PERIODIC PERIODIC PERIODIC


If the user's grid shape is too complex for an ESMF shortcut routine, or involves more than three dimensions, a DistGrid can be created to specify the shape in detail. This DistGrid is then passed into a Grid create call.


22.1.4 Grid Distribution

ESMF Grids have several options for data distribution (also referred to as decomposition). The user specifies which dimensions are to be distributed through a coordinate dependency (coordDep) argument.

The main distribution options are regular, irregular, and arbitrary. A regular distribution is one in which the same number of contiguous grid points are assigned to each DE in the distributed dimension. A irregular distribution is one in which unequal numbers of contiguous gridpoints are assigned to each DE in the distributed dimension. An arbitrary distribution is one in which any gridpoint can be assigned to any DE. Any of these distribution options can be applied to any of the grid shapes (i.e., rectangle) or types (i.e., rectilinear). Arbitrary distributions have not been implemented as of v3.1.0.

Figure 11 illustrates options for distribution.

Figure 11: Examples of regular and irregular decomposition of a grid a that is 6x6, and an arbitrary decomposition of a grid b that is 6x3.
\scalebox{0.9}{\includegraphics{GridDecomps}}

A distribution can also be specified using the DistGrid, by passing object into a Grid create call.


22.1.5 Grid Coordinates

Grid Tiles can have uniform, rectilinear, or curvilinear coordinates. The coordinates of uniform grids are equally spaced along their axes, and can be fully specified by the coordinates of the two opposing points that define the grid's physical span. The coordinates of rectilinear grids are unequally spaced along their axes, and can be fully specified by giving the spacing of grid points along each axis. The coordinates of curvilinear grids must be specified by giving the explicit set of coordinates for each grid point. Curvilinear grids are often uniform or rectilinear grids that have been warped; for example, to place a pole over a land mass so that it does not affect the computations performed on an ocean model grid. Figure 12 shows examples of each type of grid.

Any of these logically rectangular grid types can be combined through edge connections to form a mosaic. Cubed sphere and yin-yang grids are examples of mosaic grids. Note that as of v3.1.0 multi-tile grids have not yet been implemented.

Figure 12: Types of logically rectangular grid tiles. Red circles show the values needed to specify grid coordinates for each type.
\scalebox{0.9}{\includegraphics{LogRectGrids}}

Each of these coordinate types can be set for each of the standard grid shapes described in section 22.1.3.

The table below shows how examples of common single Tile grids fall into this shape and coordinate taxonomy. Note that any of the grids in the table can have a regular or arbitrary distribution.


  Uniform Rectilinear Curvilinear
Sphere Global uniform lat-lon grid Gaussian grid Displaced pole grid
Rectangle Regional uniform lat-lon grid Gaussian grid section Polar stereographic grid section

22.1.6 Coordinate Specification and Generation

There are two ways of specifying coordinates in ESMF. The first way is for the user to set the coordinates. The second way is to take a shortcut and have the framework generate the coordinates.

No ESMF generation routines are currently available.

See Section 22.2.6 for more description and examples of setting coordinates.

22.1.7 Staggering

Staggering is a finite difference technique in which the values of different physical quantities are placed at different locations within a grid cell.

The ESMF Grid class supports a variety of stagger locations, including cell centers, corners, and edge centers. Combinations of these are sufficient to specify any of the Arakawa staggers. ESMF also supports staggering in 3D and higher dimensions. There are shortcuts for standard staggers, and interfaces through which users can create custom staggers.

As a default the ESMF Grid class provides symmetric staggering, so that cell centers are enclosed by cell perimeter (e.g. corner) stagger locations. This means the coordinate arrays for stagger locations other than the center will have an additional element of padding in order to enclose the cell center locations. However, to achieve other types of staggering, the user may alter or eliminate this padding by using the appropriate options when adding coordinates to a Grid.

For examples and a full description of the stagger interface see Section 22.2.6.


22.1.8 Options for Building Grids

ESMF Grid objects must represent a wide range of grid types and use cases, some of them quite complex. As a result, multiple ways to build Grid objects are required. This section describes the stages to building Grids, the options for each stage, and typical calling sequences.

In ESMF there are two main stages to building Grids. The ESMF_GridStatus value stored within the Grid object reflects the stage the Grid has attained (see Section 22.5.2). These stages are:

  1. Create the Grid topology or shape. At the completion of this stage, the Grid has a specific topology and distribution, but empty coordinate arrays. The Grid can be used as the basis for allocating a Field. Its ESMF_GridStatus parameter has a value of ESMF_GRIDSTATUS_SHAPE_READY.

    The options for specifying the Grid shape are:

  2. Specify the Grid coordinates and any other information required for regridding (this can vary depending on the particular regridding method). At the completion of this stage, the Grid can be used in a regridding operation (once Grid is connected to regrid; as of v3.1.0, it is not). Its ESMF_GridStatus has a value of ESMF_GRIDSTATUS_REGRID_READY.

When creating the Grid shape and specifying the Grid coordinates, the user can either specify all required information at once, or can provide information incrementally. The call ESMF_GridCreateEmpty() builds a Grid object container that can be filled in with subsequent calls to ESMF_GridSet() methods. A Grid that is empty has the ESMF_GridStatus value ESMF_GRIDSTATUS_NOT_READY.

The following table summarizes possible call sequences for building Grids.

Create Shape
From shape shortcut
grid = ESMF_GridCreateShapeTile(...)
Using DistGrid with general create interface
distgrid = ESMF_DistGridCreate(...)
grid = ESMF_GridCreate(distgrid, ...)
Incremental
grid = ESMF_GridCreateEmpty(...)
call ESMF_GridSetCommitShapeTile(grid, ...)
Set Coordinates
Set coordinates by copy or reference
call ESMF_GridSetCoord(grid, ...)
Retrieve ESMF Array of coordinates from Grid and set values
call ESMF_GridGetCoord(grid, esmfArray, ...), set values
Retrieve local bounds and native array from Grid and set values
call ESMF_GridGetCoord(grid, lbound, ubound, array), set values

22.2 Use and Examples

This section describes the use of the ESMF Grid class. It first discusses the more user friendly shape specific interface to the Grid. During this discussion it covers creation and options, adding stagger locations, coordinate data access, and other grid functionality. After this initial phase the document discusses the more advanced options which the user can employ should they need more customized interaction with the Grid class.

22.2.1 Shortcut Creation Method for Single-Tile Grids

The method ESMF_GridCreateShapeTile() is a shortcut for building single tile logically rectangular Grids up to three dimensions. It is partially implemented. The user can specify Grid size, rank and distribution, but cannot specify tile edge connectivities yet. The default is that Grid edges are not connected. Once completed, this method will enable users to create many common grid shapes, including rectangle, bipole sphere, and tripole sphere.

The ESMF_GridCreateShapeTile() method will eventually support the three types of distributions described in Section 22.1.4. It currently supports two of these types: regular and irregular.

To create a Grid with a regular distribution the user specifies the global maximum and minimum ranges of the Grid cell index space (maxIndex and minIndex), and the number of pieces in which to partition each dimension (via a regDecomp argument). ESMF then divides the index space as evenly as possible into the specified number of pieces. If there are cells left over then they are distributed one per DE starting from the first DE until they are gone.

If minIndex is not specified, then the bottom of the Grid cell index range is assumed to be (1,1,...,1). If regDecomp is not specified, then by default ESMF creates a distribution that partitions the grid cells in the first dimension (e.g. NPx1x1...1) as evenly as possible by the number of processors NP. The remaining dimensions are not partitioned. The rank of the Grid is the size of maxIndex. To create an undistributed dimension set that entry in regDecomp to 1, and set the corresponding entry in distDim to .false.. The following is an example of creating a 10x20x30 3D grid where the first dimensions is broken into 2 pieces, the second is broken into 4 pieces, and the third is undistributed.

  grid3D=ESMF_GridCreateShapeTile(regDecomp=(/2,4,1/), maxIndex=(/10,20,30/), &
           distDim=(/.true.,.true.,.false./), rc=rc)

Irregular distribution requires the user to specify the exact number of Grid cells per DE in each dimension. In the ESMF_GridCreateShapeTile() call the countsPerDEDim1, countsPerDim2, and countsPerDim3 arguments are used to specify a rectangular distribution containing size(countsPerDEDim1) by size(countsPerDEDim2) by size(countsPerDEDim3) DEs. The entries in each of these arrays specify the number of grid cells per DE in that dimension. The rank of the grid is determined by the presence of countsPerDEDim3. If it's present the Grid will be 3D. If just countsPerDEDim1 and countsPerDEDim2 are specified the Grid will be 2D.

The following call illustrates the creation of a 10x20 two dimensional rectangular Grid distributed across six DEs that are arranged 2x3. In the first dimension there are 3 grid cells on the first DE and 7 cells on the second DE. The second dimension has 3 DEs with 11,2, and 7 cells, respectively.

   grid2D=ESMF_GridCreateShapeTile(countsPerDEDim1=(/3,7/), &
          countsPerDEDim2=(/11,2,7/), rc=rc)

To add a distributed third dimension of size 30, broken up into two groups of 15, the above call would be altered as follows.

   grid3d=ESMF_GridCreateShapeTile(countsPerDEDim1=(/3,7/), &
          countsPerDEDim2=(/11,2,7/), countsPerDEDim3=(/15,15/), rc=rc)

Alternatively, if the third dimension were to be undistributed, then countsPerDEDim3 in the call would have only a single term.

   grid3D=ESMF_GridCreateShapeTile(countsPerDEDim1=(/3,7/), &
          countsPerDEDim2=(/11,2,7/), countsPerDEDim3=(/30/), rc=rc)

The petMap parameter may be used to specify on to which specific PETs the DEs in the Grid are assigned. Note that this parameter is only available for the regular and irregular distribution types. The petMap array is a 3D array, for a 3D Grid each of its dimensions correspond to a Grid dimension. If the Grid is 2D, then the first two dimensions correspond to Grid dimensions and the last dimension should be of size 1. The size of each petMap dimension is the number of DE's along that dimension in the Grid. For a regular Grid, the size is equal to the number in regDecomp (i.e. size(petMap,d)=regDecomp(d) for all dimensions d in the Grid). For an irregular Grid the size is equal to the number of items in the corresponding countsPerDEDim variable (i.e. size(petMap,d)=size(countsPerDEDimd) for all dimensions d in the Grid).

Each entry in petMap specifies to which PET the corresponding DE should be assigned. For example, petMap(3,2)=4 tells the Grid create call to put the DE located at column 3 row 2 on PET 4.

The following example demonstrates how to specify the PET to DE association for an ESMF_GridCreateShapeTile() call.

   ! allocate memory for petMap
   allocate( petMap(2,2,1) )

   ! Set petMap
   petMap(:,1,1) = (/3,2/) ! DE (1,1,1) on PET 3 and DE (2,1,1) on PET 2
   petMap(:,2,1) = (/1,0/) ! DE (1,2,1) on PET 1 and DE (2,2,1) on PET 0


   ! Let the 3D grid be be distributed only in the first two dimensions.
   grid2D=ESMF_GridCreateShapeTile(countsPerDEDim1=(/3,7/), &
           countsPerDEDim2=(/7,6/), petMap=petMap, rc=rc)

Arbitrary distribution has not yet been implemented. The design is that the user specifies the global minimum and maximum ranges of the index space with the arguments minIndex and maxIndex, and through a localIndices argument specifies the set of index space locations residing on the local DE. Again, if minIndex is not specified, then the bottom of the index range is assumed to be (1,1,...). The rank of the Grid is equal to the size of maxIndex.

The following example creates a 2D Grid of dimensions 5x5, and places the diagonal elements (i.e. indices (i,i) where i goes from 1 to 5) on the local DE. The remaining DEs would individually declare the remainder of the Grid locations.

   ! allocate memory for local
   allocate( localIndices(2,5) )
   ! Set local indices
   localIndices(:,1)=(/1,1/)
   localIndices(:,2)=(/2,2/)
   localIndices(:,3)=(/3,3/)
   localIndices(:,4)=(/4,4/)
   localIndices(:,5)=(/5,5/)

   ! Create Grid
!  grid2D=ESMF_GridCreateShapeTile(maxIndex=(/5,5/), &
!         localIndices=localIndices, rc=rc)


22.2.2 Creating a 2D Irregularly Distributed Rectilinear Grid With Uniformly Spaced Coordinates

The following is an example of creating a simple rectilinear grid and loading in a set of coordinates. It illustrates a straightforward use of the ESMF_GridCreateShapeTile() call described in the previous section. This code creates a 10x20 2D grid with uniformly spaced coordinates varying from (10,10) to (100,200). The grid is partitioned using an irregular distribution. The first dimension it is divided into two pieces, the first with 3 grid cells per DE and the second with 7 grid cells per DE. In the second dimension, the Grid is divided into 3 pieces, with 5, 9, and 6 cells per DE respectively. The Grid is created with global indices. After grid creation the local bounds and native Fortran arrays are retrieved and the coordinates are set by the user.

   !-------------------------------------------------------------------
   ! Create the Grid:  Allocate space for the Grid object, define the
   ! topology and distribution of the grid, and specify that it 
   ! will have global coordinates.  Note that aperiodic bounds are
   ! specified by default - if periodic bounds were desired they
   ! would need to be specified using an additional gridConn argument
   ! (which isn't implemented yet).
   !-------------------------------------------------------------------
   grid2D=ESMF_GridCreateShapeTile(          &
            ! Define an irregular distribution
            countsPerDEDim1=(/3,7/),     &
            countsPerDEDim2=(/11,2,7/),   &
            ! Specify mapping of coords dim to Grid dim
            coordDep1=(/1/), &
            coordDep2=(/2/), &
            indexflag=ESMF_INDEX_GLOBAL, & ! Use global indices
            rc=rc)

   !-------------------------------------------------------------------
   ! Allocate coordinate storage and associate it with the center
   ! stagger location.  Since no coordinate values are specified in
   ! this call no coordinate values are set yet.
   !-------------------------------------------------------------------
   call ESMF_GridAllocCoord(grid2D,  & 
          staggerloc=ESMF_STAGGERLOC_CENTER, rc=rc)

   !-------------------------------------------------------------------
   ! Get the pointer to the first coordinate array and the bounds
   ! of its global indices on the local DE.   
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid2D, coordDim=1, &
          staggerloc=ESMF_STAGGERLOC_CENTER, &
          computationalLBound=lbnd, computationalUBound=ubnd, fptr=coordX, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the first dimension [10-100].
   !-------------------------------------------------------------------
   do i=lbnd(1),ubnd(1)
        coordX(i) = i*10.0
   enddo

   !-------------------------------------------------------------------
   ! Get the pointer to the second coordinate array and the bounds of
   ! its global indices on the local DE.
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid2D, coordDim=2, &
          staggerloc=ESMF_STAGGERLOC_CENTER, &
          computationalLBound=lbnd, computationalUBound=ubnd, fptr=coordY, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the second dimension [10-200]
   !-------------------------------------------------------------------
   do j=lbnd(1),ubnd(1)
        coordY(j) = j*10.0
   enddo


22.2.3 Creating a 2D Irregularly Distributed Grid With Curvilinear Coordinates

The following is an example of creating a simple curvilinear grid and loading in a set of coordinates. It creates a 10x20 2D grid where the coordinates vary along every dimension. The grid is partitioned using an irregular distribution. The first dimension is divided into two pieces, the first with 3 grid cells per DE and the second with 7 grid cells per DE. In the second dimension, the Grid is divided into 3 pieces, with 5, 9, and 6 cells per DE respectively. The Grid is created with global indices. After grid creation the local bounds and native Fortran arrays are retrieved and the coordinates are set by the user.

   !-------------------------------------------------------------------
   ! Create the Grid:  Allocate space for the Grid object, define the
   ! distribution of the grid, and specify that it 
   ! will have global coordinates.  Note that aperiodic bounds are
   ! specified by default - if periodic bounds were desired they
   ! would need to be specified using an additional gridConn argument
   ! (which isn't implemented yet).
   !-------------------------------------------------------------------
   grid2D=ESMF_GridCreateShapeTile(          &
            ! Define an irregular distribution
            countsPerDEDim1=(/3,7/),     &
            countsPerDEDim2=(/11,2,7/),   &
            indexflag=ESMF_INDEX_GLOBAL, & ! Use global indices
            rc=rc)

   !-------------------------------------------------------------------
   ! Allocate coordinate storage and associate it with the center
   ! stagger location.  Since no coordinate values are specified in
   ! this call no coordinate values are set yet.
   !-------------------------------------------------------------------
   call ESMF_GridAllocCoord(grid2D,  & 
          staggerloc=ESMF_STAGGERLOC_CENTER, rc=rc)

   !-------------------------------------------------------------------
   ! Get the pointer to the first coordinate array and the bounds
   ! of its global indices on the local DE.
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid2D, coordDim=1, &
          staggerloc=ESMF_STAGGERLOC_CENTER, &
          computationalLBound=lbnd, computationalUBound=ubnd, fptr=coordX2D, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the first dimension [10-100].
   !-------------------------------------------------------------------
   do j=lbnd(2),ubnd(2)
   do i=lbnd(1),ubnd(1)
        coordX2D(i,j) = i+j
   enddo
   enddo

   !-------------------------------------------------------------------
   ! Get the pointer to the second coordinate array and the bounds of 
   ! its global indices on the local DE.
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid2D, coordDim=2, &
          staggerloc=ESMF_STAGGERLOC_CENTER, &
          computationalLBound=lbnd, computationalUBound=ubnd, fptr=coordY2D, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the second dimension [10-200]
   !-------------------------------------------------------------------
   do j=lbnd(2),ubnd(2)
   do i=lbnd(1),ubnd(1)
        coordY2D(i,j) = j-i/100.0
   enddo
   enddo


22.2.4 Creating an Irregularly Distributed Rectilinear Grid with an Undistributed Vertical Dimension

This example demonstrates how a user can build a rectilinear horizontal grid with an undistributed vertical dimension. The Grid contains both the center and corner stagger locations (i.e. Arakawa B-Grid).

   !-------------------------------------------------------------------
   ! Create the Grid:  Allocate space for the Grid object.  The
   ! grid is defined to be 180 elements in Dim1 (longitude), 90 in
   ! Dim2 (longitude), and 40 in Dim3 (depth).  The first dimension is
   ! decomposed over 4 DEs, the second over 3 DEs, and the third is 
   ! undistributed.  The connectivities in each dimension default 
   ! to aperiodic since they are not yet implemented.  (Once connectivities
   ! are implemented, the longitude dimension will be periodic, the 
   ! poles will be defined at each end of the latitude dimension, 
   ! and the depth dimension will remain aperiodic.
   !-------------------------------------------------------------------
   grid3D=ESMF_GridCreateShapeTile(               &
              countsPerDEDim1=(/45,75,40,20/),    &
              countsPerDEDim2=(/30,40,20/),       &
              countsPerDEDim3=(/40/),             &
              coordDep1=(/1/),                    &
              coordDep2=(/2/),                    &
              coordDep3=(/3/),                    &
              distDim=(/.true.,.true.,.false./),  & 
              indexflag=ESMF_INDEX_GLOBAL,        & ! Use global indices
              rc=rc)

   !-------------------------------------------------------------------
   ! Allocate coordinate storage for both center and corner stagger
   ! locations.  Since no coordinate values are specified in this
   ! call no coordinate values are set yet.
   !-------------------------------------------------------------------
   call ESMF_GridAllocCoord(grid3D, &
          staggerloc=ESMF_STAGGERLOC_CENTER_VCENTER, rc=rc)
   call ESMF_GridAllocCoord(grid3D, &
          staggerloc=ESMF_STAGGERLOC_CORNER_VCENTER, rc=rc)

!----------------------------------------------------------------------
! Fill in the coordinates for the corner stagger location first.
!----------------------------------------------------------------------
   !-------------------------------------------------------------------
   ! Get the local bounds of the global indexing for the first
   ! coordinate array on the local DE. If the number of processors
   ! is less than the total number of DEs then the rest of this
   ! example would be in a loop over the local DEs.  Also get the
   ! pointer to the first coordinate array. 
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid3D, coordDim=1,   &
          staggerLoc=ESMF_STAGGERLOC_CORNER_VCENTER, &
          computationalLBound=lbnd_corner,                 &
          computationalUBound=ubnd_corner,                 &
          fptr=cornerX, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the first dimension.
   !-------------------------------------------------------------------
    do i=lbnd_corner(1),ubnd_corner(1)
        cornerX(i) = (i-1)*(360.0/180.0)
   enddo


   !-------------------------------------------------------------------
   ! Get the local bounds of the global indexing for the second
   ! coordinate array on the local DE.  Also get the pointer to the
   ! second coordinate array.
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid3D, coordDim=2,     &
          staggerLoc=ESMF_STAGGERLOC_CORNER_VCENTER,   &
          computationalLBound=lbnd_corner,                   &
          computationalUBound=ubnd_corner,                   &
          fptr=cornerY, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the second dimension.
   !-------------------------------------------------------------------
   do j=lbnd_corner(1),ubnd_corner(1)
        cornerY(j) = (j-1)*(180.0/90.0)
   enddo


!----------------------------------------------------------------------
! Now fill the coordinates for the center stagger location with
! the average of the corner coordinate location values.
!----------------------------------------------------------------------
   !-------------------------------------------------------------------
   ! Get the local bounds of the global indexing for the first 
   ! coordinate array on the local DE, and the pointer to the array.
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid3D, coordDim=1,   &
          staggerloc=ESMF_STAGGERLOC_CENTER_VCENTER, &
          computationalLBound=lbnd, computationalUBound=ubnd, fptr=centerX, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the first dimension.
   !-------------------------------------------------------------------
   do i=lbnd(1),ubnd(1)
        centerX(i) = 0.5*(i-1 + i)*(360.0/180.0) 
   enddo

   !-------------------------------------------------------------------
   ! Get the local bounds of the global indexing for the second
   ! coordinate array on the local DE, and the pointer to the array.
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid3D, coordDim=2,   &
          staggerloc=ESMF_STAGGERLOC_CENTER_VCENTER, &
          computationalLBound=lbnd, computationalUBound=ubnd, fptr=centerY, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set coordinates in the second dimension.
   !-------------------------------------------------------------------
   do j=lbnd(1),ubnd(1)
        centerY(j) = 0.5*(j-1 + j)*(180.0/90.0) 
   enddo


   !-------------------------------------------------------------------
   ! Get the local bounds of the global indexing for the third
   ! coordinate array on the local DE, and the pointer to the array.
   !-------------------------------------------------------------------
   call ESMF_GridGetCoord(grid3D, coordDim=3,   &
          staggerloc=ESMF_STAGGERLOC_CENTER_VCENTER, &
          computationalLBound=lbnd, computationalUBound=ubnd, fptr=centerZ, rc=rc)

   !-------------------------------------------------------------------
   ! Calculate and set the vertical coordinates
   ! Note that the centerZ array needs to be 3D because currently
   ! all coordinate arrays must each have the same rank as the grid, but 
   ! because the coordinate is rectilinear we only need to store a 1D array.
   !-------------------------------------------------------------------
   do k=lbnd(1),ubnd(1)
        centerZ(k) = 4000.0*( (1./39.)*(k-1)  )**2
   enddo


22.2.5 Creating an Empty Grid in a Parent Component for Completion in a Child Component

ESMF Grids can be created using an incremental paradigm. To do this, the user first calls ESMF_GridCreateEmpty to allocate the shell of a Grid. Next, a series of ESMF_GridSet() calls are used to fill in the details of the grid. Here we use a convenient ESMF_GridSetCommitShapeTile() call that fills in the Grid via an interface much like the ESMF_GridCreateShapeTile() call. When using ESMF_GridSet the user must explicity call ESMF_GridCommit afterwards to make the Grid usable. ESMF_GridSetCommitShapeTile() contains this commit internally, so it doesn't need to done separately. For consistency's sake the initial ESMF_GridCreateEmpty call must occur on the same or a superset of the processors as the ESMF_GridSet() calls. The following example uses the incremental technique to create a rectangular 10x20 grid with coordinates at the center and corner stagger locations.

!---------------------------------------------------------------------------
! IN THE PARENT COMPONENT:
! Create an empty grid in the parent component for use in a child component.
! The parent may be defined on more PETs than the child component.  
! The child's [vm or pet list] is passed into the create call so that
! the Grid is defined on the appropriate subset of the parent's PETs. 
!---------------------------------------------------------------------------
   grid2D=ESMF_GridCreateEmpty(rc=rc)

!---------------------------------------------------------------------------
! IN THE CHILD COMPONENT:
! Set the grid topology.  Here we define an irregularly distributed 
! rectangular Grid.
!---------------------------------------------------------------------------

   call ESMF_GridSetCommitShapeTile(grid2D,             &
                          countsPerDEDim1=(/6,4/),      &
                          countsPerDEDim2=(/10,3,7/), rc=rc)

!---------------------------------------------------------------------------
! Set Grid coordinates at the cell center location.
!---------------------------------------------------------------------------
   call ESMF_GridAllocCoord(grid2D, staggerLoc=ESMF_STAGGERLOC_CENTER, rc=rc)

!---------------------------------------------------------------------------
! Set Grid coordinates at the corner stagger location.
!---------------------------------------------------------------------------
   call ESMF_GridAllocCoord(grid2D, staggerLoc=ESMF_STAGGERLOC_CORNER, rc=rc)


22.2.6 Associating Coordinates with Stagger Locations

A useful finite difference technique is to place different physical quantities at different locations within a grid cell. This staggering of the physical variables on the mesh is introduced so that the difference of a field is naturally defined at the location of another variable. This method was first formalized by Mesinger and Arakawa (1976).

To support the staggering of variables, the Grid provides the idea of stagger locations. Stagger locations refer to the places in a Grid cell that contain coordinates and, once a Grid is associated with a Field object, field data. Typically data can be located at the cell center, at the cell corners, or at the cell faces, in 2D, 3D, and higher dimensions. (Note that any Arakawa stagger can be constructed of a set of Grid stagger locations.) Users can put coordinates, which are necessary for operations such as regrid, at multiple stagger locations in a Grid. In addition, the user can put Field data at any of the stagger locations in a Grid.

By default the coordinate array at the center stagger location starts at the bottom index of the Grid (default (1,1..,1)) and extends up to the maximum cell index in the Grid (e.g. given by the maxIndex argument). Other stagger locations also start at the bottom index of the Grid, however, they can extend to +1 element beyond the center in some dimensions to allow for the extra space to surround the center elements. See Section 22.2.15 for a description of this extra space and how to adjust if it necessary. The subroutine ESMF_GridGetCoord can be used to retrieve the stagger bounds for the piece of a coordinate array on a particular DE.

The user can allocate coordinate arrays without setting coordinates using the ESMF_AllocCoord() call, or allocate and set coordinates in a single call with ESMF_SetCoord(). When adding or accessing coordinate data, the stagger location is specified to tell the Grid method where in the cell to get the data. There are predefined stagger locations (see Section 22.5.3), or, should the user wish to specify their own, there is also a set of methods for generating custom locations (See Section 22.2.15).

The following example adds coordinate storage to the corner stagger location in a grid using one of the predefined stagger locations.

   call ESMF_GridAllocCoord(grid2D, staggerLoc=ESMF_STAGGERLOC_CORNER, rc=rc)

22.2.7 Specifying the Relationship of Coordinate Arrays to Index Space Dimensions

To specify how the coordinate arrays are mapped to the index dimensions the arguments coordDep1, coordDep2, and coordDep3 are used, each of which is a Fortran array. The values of the elements in a coordDep array specify which index dimension the corresponding coordinate dimension maps to. For example, coordDep1=(/1,2/) means that the first dimension of coordinate 1 maps to index dimension 1 and the second maps to index dimension 2. If the coordDep arrays are not specified, then coordDep1 defaults to /1,2..,gridrank/. This default thus specifies a curvilinear grid.

The following call demonstrates the creation of a 10x20 2D rectilinear grid where the first coordinate component is mapped to the second index dimension (i.e. is of size 20) and the second coordinate component is mapped to the first index dimension (i.e. is of size 10).

   grid2D=ESMF_GridCreateShapeTile(countsPerDEDim1=(/5,5/), &
          countsPerDEDim2=(/7,7,6/),                    &
          coordDep1=(/2/),                              &
          coordDep2=(/1/), rc=rc)

The following call demonstrates the creation of a 10x20x30 2D plus 1 curvilinear grid where coordinate component 1 and 2 are still 10x20, but coordinate component 3 is mapped just to the third index dimension.

   grid2D=ESMF_GridCreateShapeTile(countsPerDEDim1=(/6,4/), &
          countsPerDEDim2=(/10,7,3/), countsPerDEDim3=(/30/), &
          coordDep1=(/1,2/), coordDep2=(/1,2/), &
          coordDep3=(/3/), rc=rc)

By default the local piece of the array on each processor starts at (1,1,..), however, the indexing for each grid coordinate array on each DE may be shifted to the global indices by using the indexflag. For example, the following call switches the grid to use global indices.

   grid2D=ESMF_GridCreateShapeTile(countsPerDEDim1=(/6,4/), &
           countsPerDEDim2=(/10,7,3/), indexflag=ESMF_INDEX_GLOBAL, rc=rc)

22.2.8 Accessing Grid Coordinates

Once a Grid has been created, the user has several options to access the Grid coordinate data. The first of these, ESMF_GridSetCoord(), enables the user to set data for one stagger location across the whole Grid, using ESMF Arrays. For example, the following sets the coordinates in the first dimension (e.g. x) for the center stagger location to those in the ESMF Array arrayCoordX.

   call ESMF_GridSetCoord(grid2D, &
          staggerLoc=ESMF_STAGGERLOC_CORNER, &
          coordDim=1, array=arrayCoordX, rc=rc)

The method ESMF_GridGetCoord() allows the user to access the Array, as a direct reference, which contains the coordinate data for a stagger location on a Grid. The user can then employ any of the standard ESMF_Array tools to operate on the data. The following copies the coordinates from the second component of the corner and puts it into the ESMF Array arrayCoordY.

   call ESMF_GridGetCoord(grid2D,               &
          staggerLoc=ESMF_STAGGERLOC_CORNER,    &
          coordDim=2,                           &
          array=arrayCoordY, rc=rc)

Alternatively, the call ESMF_GridGetCoord() gets a Fortran pointer to the coordinate data. The user can then operate on this array in the usual manner. The following call gets a reference to the Fortran array which holds the data for the second coordinate (e.g. y).

   call ESMF_GridGetCoord(grid2D, coordDim=2, &
          staggerloc=ESMF_STAGGERLOC_CORNER, fptr=coordY2D, rc=rc)


22.2.9 Grid Regions and Bounds

The index space of the Grid contains three regions with associated bounds. This section describes these regions and bounds in general. The next couple of sections describe getting the bound information for specific types of Grid information.

The exclusive region is the index space defined by the distgrid, undistLBound, and undistUBound of the Grid. These correspond to the maximum index space usable by any stagger location in the Grid. The size of the exclusive region is the index space for the Grid cells, plus the stagger padding.

The default stagger padding depends on the topology of the Grid. For an unconnected dimension the stagger padding is a width of 1 on the upper side (i.e. gridEdgeUWidth=(1,1,1,1...)). For a periodic dimension there is no stagger padding. By adjusting gridEdgeLWidth and gridEdgeUWidth, the user can set the stagger padding for the whole Grid and thus the exclusive region can be adjusted at will around the index space corresponding to the cells. The user can also use staggerEdgeLWidth and staggerEdgeUWidth to adjust individual stagger location padding within the Grid's padding (Please see Section 22.2.16 for further discussion of customizing the stagger padding).

The Grid computational region is a subset of the the Grid exclusive region. The computational region indicates which index locations in the Grid are active for a particular stagger. The computational region is typically the region that a user would compute over (e.g. would iterate over setting values for).

The total region is the outermost boundary of the memory allocated on each DE to hold the data for the Grid on that DE. This region can be as small as the computational region, but may be larger to include space for halos, memory padding, etc. The total region is what is enlarged to include space for halos, and the total region must be large enough to contain the maximum halo operation on the Grid. The total region is a property of an underlying Array and so information about it is only retrievable when an Array has been set or allocated.

The user can retrieve a set of bounds for each index space region described above: exclusive bounds, computational bounds, and total bounds. Note that although some of these are similar to bounds provided by ESMF_Array subroutines (see Section 19.2.6) the format here is different. The Array bounds are only for distributed dimensions and are ordered to correspond to the dimension order in the associated DistGrid. The bounds provided by the Grid are for both distributed and undistributed dimensions and are ordered according to the order of dimensions of the data in question. This means that the bounds provided should be usable "as is" to access the data.

Each of the three types of bounds refers to the maximum and minimum per dimension of the index ranges of a particular region. The paramters referring to the maximums contain a 'U' for upper. The parameters referring to the minimums contain an 'L' for lower. The bounds and associated quantities are almost always given on a per DE basis. The three types of bounds exclusiveBounds, computationalBounds, and totalBounds refer to the ranges of the exlusive region, the computational region, and the total region. Each of these bounds also has a corresponding count parameter which gives the number of items across that region (on a DE) in each dimension. (e.g. totalCount(d)=totallUBound(i)-totalLBound(i)+1). Width parameters give the spacing between two different types of region. The computationalWidth argument gives the spacing between the exclusive region and the computational region. The totalWidth argument gives the spacing between the total region and the computational region. Like the other bound information these are typically on a per DE basis, for example specifying totalLWidth=(1,1) makes the bottom of the total region one lower in each dimension than the computational region on each DE. The exceptions to the per DE rule are computationalEdgeWidth, staggerEdgeWidth, and gridEdgeWidth which give the spacing only on the DEs along the boundary of the Grid.

22.2.10 Getting Grid Coordinate Bounds

When operating on coordinates the user may often wish to retrieve the bounds of the piece of coordinate data on a particular local DE. This is useful for iterating through the data to set coordinates, retrieve coordinates, or do calculations. The method ESMF_GridGetCoord allows the user to retrieve bound information for a particular coordinate array.

As described in the previous section there are three types of bounds the user can get: exclusive bounds, computational bounds, and total bounds. The exclusive and computational bounds may be retrieved from an unallocated stagger location, but the total bounds may only be retrieved from a stagger location which contains a valid coordinate Array. The bounds provided by ESMF_GridGetCoord are for both distributed and undistributed dimensions and are ordered according to the order of dimensions in the coordinate. This means that the bounds provided should be usable "as is" to access data in the coordinate array. In the case of factorized coordinate Arrays where a coordinate may have a smaller dimension than its associated Grid, then the dimension of the coordinate's bounds are the dimension of the coordinate, not the Grid.

The following is an example of retrieving the bounds for the first coordinate array from the corner stagger location.

   call ESMF_GridGetCoord(grid2D, localDE=0, coordDim=1,        &
          staggerLoc=ESMF_STAGGERLOC_CORNER,                    &
          exclusiveLBound=elbnd, exclusiveUBound=eubnd,         &
          computationalLBound=clbnd, computationalUBound=cubnd, &
          totalLBound=tlbnd, totalUBound=tubnd, rc=rc)

22.2.11 Getting Grid Stagger Location Bounds

When operating on data stored at a particular stagger in a Grid the user may find it useful to be able to retrieve the bounds of the data on a particular local DE. This is useful for iterating through the data for computations or allocating arrays to hold the data. The method ESMF_GridGet allows the user to retrieve bound information for a particular stagger location.

As described in Section 22.2.9 there are three types of bounds the user can typically get, however, the Grid doesn't hold data at a stagger location (that is the job of the Field), and so no Array is contained there and so no total region exists, so the user may only retrieve exclusive and computational bounds from a stagger location. The bounds provided by ESMF_GridGet are for both distributed and undistributed dimensions and are ordered according to the order of dimensions in the Grid.

The following is an example of retrieving the bounds for localDE 0 from the corner stagger location.

   call ESMF_GridGet(grid2D, localDE=0,                         &
          staggerLoc=ESMF_STAGGERLOC_CORNER,                    &
          exclusiveLBound=elbnd, exclusiveUBound=eubnd,         &
          computationalLBound=clbnd, computationalUBound=cubnd, rc=rc)

22.2.12 Getting Grid Stagger Location Information

In addition to the per DE information that can be accessed about a stagger location there is a set of global information that can accessed by using ESMF_GridGet without specifying a localDE. One of the main uses of this information is to create an ESMF Array to hold data for a stagger location.

There are several types of information currently available from a stagger location. The first set is computationalEdgeLWidth and computationalEdgeUWidth these give the difference between the lower and upper boundary of the exclusive region and the computational region. This information is just for the distributed dimensions and so is the same size as the distgrid dimension and is arranged to correspond to the distgrid dimensions.

The second set is undistLBound and undistUBound these are the bounds of the undistributed dimensions of the stagger locations. These will be of the same size as the undistributed dimensions of the Grid. The values of these bounds are the undistributed bounds of the Grid modified by the padding for this stagger location.

The following is an example of retrieving information from the corner stagger location.

    ! Get info about staggerloc
    call ESMF_GridGet(grid3D, staggerLoc=ESMF_STAGGERLOC_CORNER, &
           computationalEdgeLWidth=celwdth, computationalEdgeUWidth=ceuwdth, &
           undistLBound=lbnd, undistUBound=ubnd, rc=rc)

22.2.13 Creating an Array at a Stagger Location

In order to create an Array to correspond to a Grid stagger location several pieces of information need to be obtained from both the Grid and the stagger location in the Grid.

The information that needs to be obtained from the Grid is the distgrid and distgridToGridMap to ensure that the new Array has the correct size and distribution and that its dimensions are mapped correctly to the Grid. These are obtained using the ESMF_GridGet method.

The information that needs to be obtained from the stagger location are the distributed and undistributed sizes. The distributed sizes are give as offsets from the edges of the exclusive region of the distgrid. These may be obtained from ESMF_GridGet by passing in the stagger location and the arguments computationalEdgeLWidth and computationalEdgeUWidth. The undistributed sizes may may be obtained from the same call using the undistLBound and undistUBound arguments. Note that if the Grid doesn't contain undistributed dimensions, then this second set of bounds shouldn't be used.

The following is an example of using information from the Grid to create an Array corresponding to a stagger location. The Grid is 3D and contains both distributed and undistributed dimensions.

    ! Get info from Grid
    call ESMF_GridGet(grid3D, distgrid=distgrid, distgridToGridMap=distgridToGridMap, rc=rc)

    ! Get info about staggerloc
    call ESMF_GridGet(grid3D, staggerLoc=ESMF_STAGGERLOC_CORNER, &
           computationalEdgeLWidth=celwdth, computationalEdgeUWidth=ceuwdth, &
           undistLBound=lbnd1D, undistUBound=ubnd1D, rc=rc)

    ! construct ArraySpec
    call ESMF_ArraySpecSet(arrayspec, rank=3, typekind=ESMF_TYPEKIND_R8, rc=rc)

    ! Create an Array based on the presence of distributed dimensions
    array=ESMF_ArrayCreate(arrayspec=arrayspec, &
            distgrid=distgrid, distgridToArrayMap=distgridToGridMap, &
            computationalEdgeLWidth=celwdth, &
            computationalEdgeUWidth=ceuwdth, &
            undistLBound=lbnd1D, undistUBound=ubnd1D, rc=rc)


22.2.14 Creating More Complex Grids Using DistGrid

Besides the shortcut methods for creating a Grid object such as ESMF_GridCreateShapeTile(), there is a set of methods which give the user more control over the specifics of the grid. The following describes the more general interface, using DistGrid. The basic idea is to first create an ESMF DistGrid object describing the distribution and shape of the Grid, and then to employ that to either directly create the Grid or first create Arrays and then create the Grid from those. This method gives the user maximum control over the topology and distribution of the Grid. See the DistGrid documentation in Section 23.1 for an in-depth description of its interface and use.

A DistGrid describes only the distributed dimensions of the index space, so when creating a Grid from a DistGrid some arguments are needed to describe the undistributed part, To add undistributed dimensions to the Grid, the arguments undistLBound and undistUBound are used. The undistLBound argument contains the lower bounds of the undistributed dimensions and undistUBound contains the upper bounds. As an example, the following call constructs a 10x20x30 Grid with a lower bound of (1,2,3), with the third dimension undistributed.

   ! Create DistGrid
   distgrid2D = ESMF_DistGridCreate(minIndex=(/1,2/), maxIndex=(/11,22/), rc=rc)  

   ! Create Grid
   grid3D=ESMF_GridCreate(distGrid=distgrid2D,        & 
                       undistLBound=(/3/), undistUBound=(/33/), & 
                       rc=rc)

To alter which dimensions are distributed, the distgridToGridMap argument can be used. The distgridToGridMap is used to set which dimensions of the Grid are mapped to the dimensions described by maxIndex. In other words, it describes how the dimensions of the underlying default DistGrid are mapped to the Grid. Each entry in distgridToGridMap contains the Grid dimension to which the cooresponding DistGrid dimension should be mapped. The following example illustrates the creation of a Grid where the undistributed dimension is first. To accomplish this the two distributed dimensions are mapped to the last two Grid dimensions (i.e. 2 and 3).

   ! Create DistGrid
   distgrid2D = ESMF_DistGridCreate(minIndex=(/1,2/), maxIndex=(/11,22/), rc=rc)  

   ! Create Grid
   grid3D=ESMF_GridCreate(distGrid=distgrid2D, undistLBound=(/3/), undistUBound=(/33/), & 
          distgridToGridMap=(/2,3/), rc=rc)


22.2.15 Specifying Custom Stagger Locations

Although ESMF provides a set of predefined stagger locations (See Section 22.5.3), the user may need one outside this set. This section describes the construction of custom stagger locations.

To completely specify stagger for an arbitrary number of dimensions, we define the stagger location in terms of a set of cartesian coordinates. The cell is represented by a n-dimensional cube with sides of length 2, and the coordinate origin located at the center of the cell. The geometry of the cell is for reference purposes only, and does not literally represent the actual shape of the cell. Think of this method instead as an easy way to specify a part (e.g. center, corner, face) of a higher dimensional cell which is extensible to any number of dimensions.

To illustrate this approach, consider a 2D cell. In 2 dimensions the cell is represented by a square. An xy axis is placed at its center, with the positive x-axis oriented East and the positive y-axis oriented North. The resulting coordinate for the lower left corner is at $(-1,-1)$, and upper right corner at $(1,1)$. However, because our staggers are symmetric they don't need to distinguish between the $-1$, and the $1$, so we only need concern ourselves with the first quadrant of this cell. We only need to use the $1$, and the $0$, and many of the cell locations collapse together (e.g. we only need to represent one corner).

                                  (0,1)-EDGE2     (1,1)-CORNER
    1  *-------*-------*         1  *---------------* 
       |               |                            |
       |               |                            | 
       |       |       |                            | 
    0  *       +-      *                            |  
       |               |                            | 
       |               |            |               |  EDGE1
       |               |            |               |   |
   -1  *-------*-------*         0  *----           * (1,0)
      -1       0       1            0               1
  
          Full Cell               Just The 1st Quadrant

The cell center is represented by the coordinate pair $(0,0)$ indicating the origin. The cell corner is $+1$ in each direction, giving a coordinate pair of $(1,1)$. The edges are each $+1$ in one dimension and $0$ in the other indicating that they're even with the center in one dimension and offset in the other.

For three dimensions, the vertical component of the stagger location can be added by simply adding an additional coordinate. The three dimensional generalization of the cell center becomes $(0,0,0)$ and the cell corner becomes $(1,1,1)$. The rest of the 3D stagger locations are combinations of $+1$ offsets from the center.

To generalize this to $d$ dimensions, to represent a $d$ dimensional stagger location. A set of $d$ $0$ and $1$ is used to specify for each dimension whether a stagger location is aligned with the cell center in that dimension ($0$), or offset by $+1$ in that dimension ($1$). Using this scheme we can represent any symmetric stagger location.

To construct a custom stagger location in ESMF the subroutine ESMF_StaggerLocSet() is used to specify, for each dimension, whether the stagger is located at the interior (0) or on the boundary (1) of the cell. This method allows users to construct stagger locations for which there is no predefined value. In this example, it's used to set the 4D center and 4D corner locations.

   ! Set Center
   call ESMF_StaggerLocSet(staggerLoc,loc=(/0,0,0,0/),rc=rc)
   call ESMF_GridAllocCoord(grid4D, staggerLoc=staggerLoc, rc=rc)

   ! Set Corner
   call ESMF_StaggerLocSet(staggerLoc,loc=(/1,1,1,1/),rc=rc)
   call ESMF_GridAllocCoord(grid4D, staggerLoc=staggerLoc, rc=rc)


22.2.16 Specifying Custom Stagger Padding

There is an added complication with the data (e.g. coordinates) stored at stagger locations in that they can require different amounts of storage depending on the underlying Grid type.

  
  
    *-------*-------*-------*
    |       |       |       |
    |   +   |   +   |   +   |
    |       |       |       |
    *-------*-------*-------*
    |       |       |       |
    |   +   |   +   |   +   |
    |       |       |       |
    *-------*-------*-------*
  
          Example Grid

Consider the preceeding 2D grid, where the ``*'' represents the cell corners and the ``+'' represents the cell centers. For the corners to completely enclose the cell centers (symmetric stagger), the number of corners in each dimension needs to be one greater then the number of cell centers. In the above figure, there are two rows and three columns of cell centers. To enclose the cell centers, there must be three rows and four columns of cell corners. This is true in general for Grids without periodicity or other connections. In fact, for a symmetric stagger, given that the center location requires n x m storage, the corresponding corner location requires n+1 x m+1, and the edges, depending on the side, require n+1 x m or m+1 x n. In order to add the extra storage, but also to allow the the different stagger location arrays to remain on the same DistGrid, the capability of the ESMF Array class to have computational bounds different from exclusive bounds is used. By default, when the coordinate arrays are created, one extra layer of padding is added to the arrays to create symmetric staggers (i.e. the center location is surrounded). The default is to add this padding on the positive side, and to only add this padding where needed (e.g. no padding for the center, padding on both dimensions for the corner, in only one dimension for the edge in 2D.) There are two ways for the user to change these defaults.

One way is to use the GridEdgeWidth or GridAlign arguments when creating a Grid. These arguments can be used to change the padding around the Grid cell index space. This extra padding is the extra space used by all the stagger locations, and no stagger location can extend outside of it.

The gridEdgeLWidth and gridEdgeUWidth arguments are both 1D arrays of the same size as the Grid rank. The entries in the arrays give the extra offset from the outer boundary of the grid cell index space to the exclusive region of the Grid. The following example shows the creation of a Grid with all the extra space to hold stagger padding on the negative side of a Grid. This is the reverse of the default behavior. The resulting Grid will have an exclusive region which extends from $(-1,-1)$ to $(10,10)$, however, the cell center stagger location will still extend from $(1,1)$ to $(10,10)$.

   grid2D=ESMF_GridCreateShapeTile(minIndex=(/1,1/),maxIndex=(/10,10/), &
            gridEdgeLWidth=(/1,1/), gridEdgeUWidth=(/0,0/), rc=rc)

To indicate how the data in a Grid's stagger locations are aligned with the cell centers, the optional gridAlign parameter may be used. This parameter indicates which stagger elements in a cell share the same index values as the cell center. For example, in a 2D cell, it would indicate which of the four corners has the same index value as the center. To set gridAlign, the values -1,+1 are used to indicate the alignment in each dimension. This parameter is mostly informational, however, if the gridEdgeWidth parameters are not set then its value determines where the default padding is placed. If not specified, then the default is to align all staggers to the most negative, so the padding is on the positive side. The following code illustrates creating a Grid aligned to the reverse of default (with everything to the positive side). This creates a Grid identical to that created in the previous example.

   grid2D=ESMF_GridCreateShapeTile(minIndex=(/1,1/),maxIndex=(/10,10/), &
            gridAlign=(/1,1/), rc=rc)

The gridEdgeWidth and gridAlign arguments both allow the user to set the extra padding available to be used by stagger locations in a Grid. By default, stagger locations allocated in a Grid set their stagger padding based on these values. A stagger location's padding in each dimension is equal to the value of gridEdgeWidth (or the value implied by gridAlign), unless the stagger location is centered in a dimension in which case the stagger padding is 0. For example, the cell center stagger location has 0 stagger padding in all dimensions, whereas the edge stagger location lower padding is equal to gridEdgeLWidth and the upper padding is equal to gridEdgeUWidth in one dimension, but both are 0 in the other, centered, dimension. If the user wishes to set the stagger padding individually for each stagger location they may use the staggerEdgeWidth and staggerAlign arguments, however, the padding set this way must be within that specified by the gridEdgeWidth and gridAlign used when the Grid was created (or the defaults if none were used).

The staggerEdgeLWidth and staggerEdgeUWidth arguments are both 1D arrays of the same size as the Grid rank. The entries in the arrays give the extra offset from the Grid cell index space for a stagger location. The following example shows the addition of two stagger locations. The corner location has no extra boundary and the center has a single layer of extra padding on the negative side and none on the positive. This is the reverse of the default behavior.

   grid2D=ESMF_GridCreate(distgrid=distgrid2D, &
            gridEdgeLWidth=(/1,1/), gridEdgeUWidth=(/0,0/), rc=rc)

   call ESMF_GridAllocCoord(grid2D, &
          staggerLoc=ESMF_STAGGERLOC_CORNER, &
          staggerEdgeLWidth=(/0,0/), staggerEdgeUWidth=(/0,0/), rc=rc)

   call ESMF_GridAllocCoord(grid2D, &
          staggerLoc=ESMF_STAGGERLOC_CENTER, &
          staggerEdgeLWidth=(/1,1/), staggerEdgeUWidth=(/0,0/), rc=rc)

To indicate how the data at a particular stagger location is aligned with the cell center, the optional staggerAlign parameter may be used. This parameter indicates which stagger elements in a cell share the same index values as the cell center. For example, in a 2D cell, it would indicate which of the four corners has the same index value as the center. To set staggerAlign, the values -1,+1 are used to indicate the alignment in each dimension. If a stagger location is centered in a dimension (e.g. an edge in 2D), then that dimension is ignored in the alignment. This parameter is mostly informational, however, if the staggerEdgeWidth parameters are not set then its value determines where the default padding is placed. If not specified, then the default is to align all staggers to the most negative, so the padding is on the positive side. The following code illustrates aligning the positive (northeast in 2D) corner with the center.

   call ESMF_GridAllocCoord(grid2D, &
          staggerLoc=ESMF_STAGGERLOC_CORNER, staggerAlign=(/1,1/), rc=rc)

22.3 Restrictions and Future Work

22.4 Design and Implementation Notes

22.4.1 Grid Topology

The ESMF_Grid class depends upon the ESMF_DistGrid class for the specification of its topology. That is, when creating a Grid, first an ESMF_DistGrid is created to describe the appropriate index space topology. This decision was made because it seemed redundant to have a system for doing this in both classes. It also seems most appropriate for the machinary for topology creation to be located at the lowest level possible so that it can be used by other classes (e.g. the ESMF_Array class). Because of this, however, the authors recommend that as a natural part of the implementation of subroutines to generate standard grid shapes (e.g. ESMF_GridGenSphere) a set of standard topology generation subroutines be implemented (e.g. ESMF_DistGridGenSphere) for users who want to create a standard topology, but a custom geometry.

22.4.2 Storage and Distribution of Stagger Locations in Grid

The primarily complication in the storage of multiple stagger locations in a Grid is that different variables in a symmetric stagger can require a different amount of storage depending on the underlying grid type. For example while h,u, and v on an A-grid all require n x m arrays, on a B-grid u and v require n+1 x m+1. On a C or D grid one vector component requires n+1 x m and the other n x m+1. To handle this complication the natural approach would be to define each stagger's storage to what is necessary for that grid type. This approach introduces a problem when the arrays are distributed, because they are different sizes. It is non-trivial to guarantee that the (i,j) element of all three of arrays ends up on the same processor. It is simpler to guarantee a consistent distribution of the arrays when using the same distGrid if they are the same size.

This may sound like a contradiction, but to be more precise we choose the exclusive region of each array to be the same size (say n x m), and pad the arrays that need it with additional memory from the computational region of the Array class. Recall that the exclusive region is defined as the cells for which the DE claims exclusive ownership. These are the cells updated by computations local to that DE. The exclusive region is a subset of the computation region. The computational region contains all the cells kept locally on the DE in addition to the exclusive cells. By using the computational region as padding we are able to guarantee a consistent distribution of the arrays and at the same time impose a symmetric stagger. This approach extends naturally to the connected/periodic cases because the padding can be used to hold the values across the branch cut.

The biased configuration (where each stagger location has the same number of elements) falls out trivially by setting an optional padding argument (staggerWidth) to zero. This argument can also be used to adjust where the stagger padding is located or to add extra for halos.

22.5 Grid Options


22.5.1 ESMF_GridConn

DESCRIPTION:
The ESMF_GridCreateShapeTile command has three specific arguments connDim1, connDim2, and connDim3. These can be used to setup different types of connections at the ends of each dimension of a Tile. Each of these parameters is a two element array. The first element is the connection type at the minimum end of the dimension and the second is the connection type at the maximum end. The default value for all the connections is ESMF_GRIDCONN_NONE, specifying no connection.


ESMF_GRIDCONN_NONE
No connection.

ESMF_GRIDCONN_PERIODIC
Periodic connection.

ESMF_GRIDCONN_POLE
This edge is connected to itself. Given that the edge is n elements long, then element i is connected to element i+n/2.

ESMF_GRIDCONN_BIPOLE
This edge is connected to itself. Given that the edge is n elements long, element i is connected to element n-i-1.


22.5.2 ESMF_GridStatus

DESCRIPTION:
The ESMF Grid class can exist in three states. These states are present so that the library code can detect if a Grid has been appropriately setup for the task at hand. The following are the valid values of ESMF_GRIDSTATUS.


ESMF_GRIDSTATUS_NOT_READY:
Status after a Grid has been created with ESMF_GridCreateEmpty. A Grid object container is allocated but space for internal objects is not. Topology information and coordinate information is incomplete. This object can be used in ESMF_GridSet() methods in which additional information is added to the Grid.
ESMF_GRIDSTATUS_SHAPE_READY:
The Grid has a specific topology and distribution, but incomplete coordinate arrays. The Grid can be used as the basis for allocating a Field.
ESMF_GRIDSTATUS_REGRID_READY:
The grid contains valid coordinate values and is ready to be used in regrid.


22.5.3 ESMF_StaggerLoc

DESCRIPTION:
In the ESMF Grid class, data can be located at different positions in a Grid cell. When setting or retrieving coordinate data the stagger location is specified to tell the Grid method from where in the cell to get the data. Although the user may define their own custom stagger locations, ESMF provides a set of predefined locations for ease of use. The following are the valid predefined stagger locations.


    
                 2----4----2
                 |         |
                 |         |
                 3    1    3
                 |         |
                 |         |
                 2----4----2
 
      Diagram Illustrating 2D Stagger Locations
   (Numbers correspond to bracketed numbers in list.)

The 2D predefined stagger locations are:

ESMF_STAGGERLOC_CENTER:
The center of the cell [1].
ESMF_STAGGERLOC_CORNER:
The corners of the cell [2].
ESMF_STAGGERLOC_EDGE1:
The edges offset from the center in the 1st dimension [3].
ESMF_STAGGERLOC_EDGE2:
The edges offset from the center in the 2nd dimension [4].


    
      5----7----5        2----4----2         5----7----5
      |         |        |         |         |         |
      |         |        |         |         |         | 
      6    8    6        3    1    3         6    8    6
      |         |        |         |         |         |
      |         |        |         |         |         |
      5----7----5        2----4----2         5----7----5

       Cell Top          Cell Middle         Cell Bottom
         

           Diagram Illustrating 3D Stagger Locations
       (Numbers correspond to bracketed numbers in list.)

The 3D predefined stagger locations are:

ESMF_STAGGERLOC_CENTER_VCENTER:
The center of the 3D cell [1].
ESMF_STAGGERLOC_CORNER_VCENTER:
Half way up the vertical edges of the cell [2].
ESMF_STAGGERLOC_EDGE1_VCENTER:
The center of the face bounded by edge 1 and the vertical dimension [3].
ESMF_STAGGERLOC_EDGE2_VCENTER:
The center of the face bounded by edge 2 and the vertical dimension [4].
ESMF_STAGGERLOC_CORNER_VFACE:
The corners of the 3D cell [5].
ESMF_STAGGERLOC_EDGE1_VFACE:
The center of the edges of the 3D cell parallel offset from the center in the 1st dimension [6].
ESMF_STAGGERLOC_EDGE2_VFACE:
The center of the edges of the 3D cell parallel offset from the center in the 2nd dimension [7].
ESMF_STAGGERLOC_CENTER_VFACE:
The center of the top and bottom face. The face bounded by the 1st and 2nd dimensions [8].

22.6 Class API: General Grid Methods

22.6.1 ESMF_GridAllocCoord - Allocate coordinate arrays but don't set their values


INTERFACE:

   ! Private name; call using ESMF_GridAllocCoord()
      subroutine ESMF_GridAllocCoordNoValues(grid, staggerloc,  &
                 staggerEdgeLWidth, staggerEdgeUWidth, staggerAlign, &
                 totalLWidth, totalUWidth,rc)
ARGUMENTS:
       type(ESMF_Grid),        intent(in)              :: grid 
       type (ESMF_StaggerLoc), intent(in),optional     :: staggerloc
       integer,                intent(in),optional     :: staggerEdgeLWidth(:)
       integer,                intent(in),optional     :: staggerEdgeUWidth(:)
       integer,                intent(in),optional     :: staggerAlign(:)
       integer,                intent(out), optional   :: totalLWidth(:)         ! N. IMP
       integer,                intent(out), optional   :: totalUWidth(:)         ! N. IMP
       integer,                intent(out),optional    :: rc
DESCRIPTION:

When a Grid is created all of its potential stagger locations can hold coordinate data, but none of them have storage allocated. This call allocates coordinate storage (creates internal ESMF_Arrays and associated memory) for a particular stagger location. Note that this call doesn't assign any values to the storage, it only allocates it. The remaining options staggerEdgeLWidth, etc. allow the user to adjust the padding on the coordinate arrays.

The arguments are:

grid
Grid to allocate coordinate storage in.
[staggerloc]
The stagger location to add. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER.
[staggerEdgeLWidth]
This array should be the same rank as the grid. It specifies the lower corner of the stagger region with respect to the lower corner of the exclusive region.
[staggerEdgeUWidth]
This array should be the same rank as the grid. It specifies the upper corner of the stagger region with respect to the upper corner of the exclusive region.
[staggerAlign]
This array is of size grid rank. For this stagger location, it specifies which element has the same index value as the center. For example, for a 2D cell with corner stagger it specifies which of the 4 corners has the same index as the center. If this is set and either staggerEdgeUWidth or staggerEdgeLWidth is not, this determines the default array padding for a stagger. If not set, then this defaults to all negative. (e.g. The most negative part of the stagger in a cell is aligned with the center and the padding is all on the postive side.)
[totalLWidth]
The lower boundary of the computatational region in reference to the computational region. Note, the computational region includes the extra padding specified by ccordLWidth. [CURRENTLY NOT IMPLEMENTED]
[totalUWidth]
The lower boundary of the computatational region in reference to the computational region. Note, the computational region includes the extra padding specified by staggerEdgeLWidth. [CURRENTLY NOT IMPLEMENTED]
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.2 ESMF_GridCommit - Commit a Grid to a specified completion level


INTERFACE:

       subroutine ESMF_GridCommit(grid, status, defaultflag, rc)
ARGUMENTS:
       type(ESMF_Grid), intent(inout)     :: grid
       type(ESMF_GridStatus),optional     :: status      ! NOT IMPLEMENTED
       type(ESMF_DefaultFlag), optional   :: defaultflag ! NOT IMPLEMENTED
       integer, intent(out), optional     :: rc
DESCRIPTION:

This call is used to complete the grid so that it is usable at the level indicated by the status flag. For example, once committed with a status value of ESMF_GRIDSTATUS_SHAPE_READY, the grid will have sufficient size, rank, and distribution information to be used as the basis for allocating Field data. (The integration of Field and Grid classes has't yet happened, so you can't currently allocate Fields based on Grids no matter what the status.)

It is necessary to call the ESMF_GridCommit() method after creating a Grid object using the ESMF_GridCreateEmpty() method and incrementally filling it in with ESMF_GridSet() calls. The EMF_GridCommit() call is a signal to the Grid that it can combine the pieces of information that it's received and finish building any necessary internal structures. For example, an ESMF_GridCommit() call with the status flag set to ESMF_GRIDSTATUS_SHAPE_READY will trigger the grid to build an internal DistGrid object that contains topology and distribution information.

It's possible using the ESMF_GridCreateEmpty()/ESMF_GridSet() approach that not all information is present when the ESMF_GridCommit call is made. If this is the case and the defaultflag is set to ESMF_USE_DEFAULTS the Grid will attempt to build any internal objects necessary to get to the desired status by using reasonable defaults. If the defaultflag is set to ESMF_NO_DEFAULTS and any information is missing, the ESMF_GridCommit call will fail. If the defaultflag argument is not passed in, no defaults are used.

The arguments are:

grid
Grid object to commit.
status
Grid status to commit to. For valid values see section 22.5.2. [CURRENTLY NOT IMPLEMENTED]
[defaultFlag]
Indicates whether to use default values to achieve the desired grid status. The default value is ESMF_NO_DEFAULTS. [CURRENTLY NOT IMPLEMENTED]
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.3 ESMF_GridCreate - Create a Grid from a DistGrid


INTERFACE:

   ! Private name; call using ESMF_GridCreate()
       function ESMF_GridCreateFromDistGrid(name,coordTypeKind,distgrid, &
                          distgridToGridMap, undistLBound, undistUBound, coordRank, coordDimMap, &
                          gridEdgeLWidth, gridEdgeUWidth, gridAlign, indexflag, rc)
RETURN VALUE:
       type(ESMF_Grid) :: ESMF_GridCreateFromDistGrid
ARGUMENTS:
        character (len=*), intent(in), optional :: name
        type(ESMF_TypeKind),  intent(in),   optional  :: coordTypeKind
        type(ESMF_DistGrid),   intent(in)              :: distgrid
        integer,               intent(in),   optional  :: distgridToGridMap(:)
        integer,               intent(in),   optional  :: undistLBound(:)
        integer,               intent(in),   optional  :: undistUBound(:)
        integer,               intent(in),   optional  :: coordRank(:)
        integer,               intent(in),   optional  :: coordDimMap(:,:)
        integer,               intent(in),   optional  :: gridEdgeLWidth(:)
        integer,               intent(in),   optional  :: gridEdgeUWidth(:)
        integer,               intent(in),   optional  :: gridAlign(:)
        type(ESMF_IndexFlag),  intent(in),   optional  :: indexflag
        integer,               intent(out),  optional  :: rc
DESCRIPTION:

This is the most general form of creation for an ESMF_Grid object. It allows the user to fully specify the topology and index space (of the distributed dimensions) using the DistGrid methods and then build a grid out of the resulting distgrid. Optional lbound and ubound arguments can be used to specify extra undistributed dimensions. The distgridToGridMap argument specifies how the distributed (from distgrid) and undistributed (from bounds) dimensions are intermixed. The coordRank and coordDimMap arguments allow the user to specify how the coordinate arrays should map to the grid dimensions. (Note, though, that creating a grid does not allocate coordinate storage. A method such as ESMF_GridAllocCoord() must be called before adding coordinate values.)

The arguments are:

[name]
ESMF_Grid name.
[coordTypeKind]
The type/kind of the grid coordinate data. If not specified then the type/kind will be 8 byte reals.
distgrid
ESMF_DistGrid object that describes how the array is decomposed and distributed over DEs. The dimCount of distgrid must be smaller or equal to the grid rank, otherwise a runtime ESMF error will be raised.
[distgridToGridMap]
List that has as many elements as indicated by distgrid's dimCount value. The elements map each dimension of distgrid to a dimension in the grid. (i.e. the values should range from 1 to gridrank). If not specified, the default is to map all of distgrid's dimensions against the lower dimensions of the grid in sequence.
[undistLBound]
Lower bounds for undistributed array dimensions. Must be the same size as undistUBound.
[undistUBound]
Upper bounds for undistributed array dimensions. Must be the same size as undistLBound.
[coordRank]
List that has as many elements as the grid rank . Gives the dimension of each component (e.g. x) array. This is to allow factorization of the coordinate arrays. If not specified all arrays are the same size as the grid. [NOTE FACTORIZATION HAS NOT CURRENTLY BEEN IMPLEMENTED].
[coordDimMap]
2D list of size grid rank x grid rank. This array describes the map of each component array's dimensions onto the grids dimensions. Each entry coordDimMap(i,j) tells which grid dimension component i's, jth dimension maps to. Note that if j is bigger than coordRank(i) than its ignored.
[gridEdgeLWidth]
The padding around the lower edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridEdgeUWidth]
The padding around the upper edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridAlign]
Specification of how the stagger locations should align with the cell index space (can be overridden by the individual staggerAligns). If the gridEdgeWidths are not specified than this parameter implies the EdgeWidths.
[indexflag]
Indicates whether the indices in the grid are to be interpreted to form a flat pseudo global index space (ESMF_INDEX_GLOBAL), or are to be taken as patch local (ESMF_INDEX_DELOCAL), which is the default.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.4 ESMF_GridCreateEmpty - Create a Grid that has no contents


INTERFACE:

      function ESMF_GridCreateEmpty(rc)
RETURN VALUE:
      type(ESMF_Grid) :: ESMF_GridCreateEmpty
ARGUMENTS:
        integer,               intent(out),  optional  :: rc
DESCRIPTION:

Partially create an ESMF_Grid object. This function allocates an ESMF_Grid object, but doesn't allocate any coordinate storage or other internal structures. The ESMF_GridSet calls can be used to set the values in the grid object. Before using the grid, ESMF_GridCommit needs to be called to validate the internal state and construct internal structures.

The arguments are:

[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.5 ESMF_GridCreateShapeTile - Create a Grid with an irregular distribution


INTERFACE:

   ! Private name; call using ESMF_GridCreateShapeTile()
       function ESMF_GridCreateShapeTileIrreg(name,coordTypeKind, minIndex,  &
                         countsPerDEDim1,countsPerDeDim2, countsPerDEDim3, &
                         connDim1, connDim2, connDim3, &
                         poleStaggerLoc1, poleStaggerLoc2, poleStaggerLoc3, &
                         bipolePos1, bipolePos2, bipolePos3, &
                         coordDep1, coordDep2, coordDep3, &
                         gridEdgeLWidth, gridEdgeUWidth, gridAlign, &
                         indexflag, distDim, petMap, rc)
RETURN VALUE:
       type(ESMF_Grid) :: ESMF_GridCreateShapeTileIrreg
ARGUMENTS:
       character (len=*), intent(in), optional :: name 
        type(ESMF_TypeKind),  intent(in),    optional  :: coordTypeKind
        integer,               intent(in),   optional  :: minIndex(:)
        integer,               intent(in)              :: countsPerDEDim1(:)
        integer,               intent(in)              :: countsPerDEDim2(:)
        integer,               intent(in),   optional  :: countsPerDEDim3(:)
        type(ESMF_GridConn),   intent(in),   optional  :: connDim1(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim2(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim3(:)        ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc1(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc2(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc3(2) ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos1(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos2(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos3(2)      ! N. IMP.
        integer,               intent(in),   optional  :: coordDep1(:)
        integer,               intent(in),   optional  :: coordDep2(:)
        integer,               intent(in),   optional  :: coordDep3(:)
        integer,               intent(in),   optional  :: gridEdgeLWidth(:)
        integer,               intent(in),   optional  :: gridEdgeUWidth(:)
        integer,               intent(in),   optional  :: gridAlign(:)
        type(ESMF_IndexFlag),  intent(in),   optional  :: indexflag
        logical,               intent(in),   optional  :: distDim(:)
        integer,               intent(in),   optional  :: petMap(:,:,:)
        integer,               intent(out),  optional  :: rc
DESCRIPTION:

This method creates a single tile, irregularly distributed grid (see Figure 11). To specify the irregular distribution, the user passes in an array for each grid dimension, where the length of the array is the number of DEs in the dimension. Up to three dimensions can be specified, using the countsPerDEDim1, countsPerDEDim2, countsPerDEDim3 arguments. The index of each array element corresponds to a DE number. The array value at the index is the number of grid cells on the DE in that dimension. The rank of the grid is equal to the number of countsPerDEDim<> arrays that are specified.

To specify an undistributed dimension, the array in that dimension should have only one element and the corresponding entry in distDim should be false.

Section 22.2.2 shows an example of using this method to create a 2D Grid with uniformly spaced coordinates. This creation method can also be used as the basis for grids with rectilinear coordinates or curvilinear coordinates.

The arguments are:

[name]
ESMF_Grid name.
[coordTypeKind]
The type/kind of the grid coordinate data. If not specified then the type/kind will be 8 byte reals.
[minIndex]
Tuple to start the index ranges at. If not present, defaults to /1,1,1,.../.
countsPerDEDim1
This arrays specifies the number of cells per DE for index dimension 1 for the exclusive region (the center stagger location). If the array has only one entry, then the dimension is undistributed.
countsPerDEDim2
This array specifies the number of cells per DE for index dimension 2 for the exclusive region (center stagger location). If the array has only one entry, then the dimension is undistributed.
[countsPerDEDim3]
This array specifies the number of cells per DE for index dimension 3 for the exclusive region (center stagger location). If not specified then grid is 2D. Also, If the array has only one entry, then the dimension is undistributed.
[connDim1]
Fortran array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim2]
Fortran array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim3]
Fortran array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[bipolePos1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[coordDep1]
This array specifies the dependence of the first coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the first coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep2]
This array specifies the dependence of the second coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the second coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep3]
This array specifies the dependence of the third coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the third coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[gridEdgeLWidth]
The padding around the lower edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridEdgeUWidth]
The padding around the upper edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridAlign]
Specification of how the stagger locations should align with the cell index space (can be overridden by the individual staggerAligns). If the gridEdgeWidths are not specified than this parameter implies the EdgeWidths.
[indexflag]
Flag that indicates how the DE-local indices are to be defined.
[distDim]
Array of the same rank as the Grid. It specifies if each dimensions should be distributed. If not specified, defaults to all true. Only dimensions with size(countsPerDeDim)=1 may be made undistributed.
[petMap]
Sets the mapping of pets to the created DEs. This 3D should be of size size(countsPerDEDim1) x size(countsPerDEDim2) x size(countsPerDEDim3). If countsPerDEDim3 isn't present, then the last dimension is of size 1.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.6 ESMF_GridCreateShapeTile - Create a Grid with a regular distribution


INTERFACE:

   ! Private name; call using ESMF_GridCreateShapeTile()
       function ESMF_GridCreateShapeTileReg(name, coordTypeKind, &
                         regDecomp, decompFlag, minIndex, maxIndex, &
                         connDim1, connDim2, connDim3, &
                         poleStaggerLoc1, poleStaggerLoc2, poleStaggerLoc3, &
                         bipolePos1, bipolePos2, bipolePos3, &
                         coordDep1, coordDep2, coordDep3, &
                         gridEdgeLWidth, gridEdgeUWidth, gridAlign, &
                         indexflag, distDim, petMap, rc)
RETURN VALUE:
       type(ESMF_Grid) :: ESMF_GridCreateShapeTileReg
ARGUMENTS:
        character (len=*), intent(in), optional :: name 
        type(ESMF_TypeKind),  intent(in),    optional  :: coordTypeKind
        integer,               intent(in),   optional  :: regDecomp(:)
        type(ESMF_DecompFlag), intent(in),   optional  :: decompflag(:)
        integer,               intent(in),   optional  :: minIndex(:)
        integer,               intent(in)              :: maxIndex(:)
        type(ESMF_GridConn),   intent(in),   optional  :: connDim1(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim2(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim3(:)        ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc1(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc2(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc3(2) ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos1(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos2(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos3(2)      ! N. IMP.
        integer,               intent(in),   optional  :: coordDep1(:)
        integer,               intent(in),   optional  :: coordDep2(:)
        integer,               intent(in),   optional  :: coordDep3(:)
        integer,               intent(in),   optional  :: gridEdgeLWidth(:)
        integer,               intent(in),   optional  :: gridEdgeUWidth(:)
        integer,               intent(in),   optional  :: gridAlign(:)
        type(ESMF_IndexFlag),  intent(in),   optional  :: indexflag
        logical,               intent(in),   optional  :: distDim(:)
        integer,               intent(in),   optional  :: petMap(:,:,:)
        integer,               intent(out),  optional  :: rc
DESCRIPTION:

This method creates a single tile, regularly distributed grid (see Figure 11). To specify the distribution, the user passes in an array (regDecomp) specifying the number of DEs to divide each dimension into. If the number of DEs is 1 than the dimension is undistributed. The array decompFlag indicates how the division into DEs is to occur. The default is to divide the range as evenly as possible.

The arguments are:

[name]
ESMF_Grid name.
[coordTypeKind]
The type/kind of the grid coordinate data. If not specified then the type/kind will be 8 byte reals.
[regDecomp]
List that has the same number of elements as maxIndex. Each entry is the number of decounts for that dimension. If not specified, the default decomposition will be petCountx1x1..x1.
[decompflag]
List of decomposition flags indicating how each dimension of the patch is to be divided between the DEs. The default setting is ESMF_DECOMP_HOMOGEN in all dimensions. Please see Section 9.1.6 for a full description of the possible options.
[minIndex]
The bottom extent of the grid array. If not given then the value defaults to /1,1,1,.../.
maxIndex
The upper extent of the grid array.
[connDim1]
Fortran array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim2]
Fortran array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim3]
Fortran array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[bipolePos1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[coordDep1]
This array specifies the dependence of the first coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the first coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep2]
This array specifies the dependence of the second coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the second coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep3]
This array specifies the dependence of the third coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the third coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[gridEdgeLWidth]
The padding around the lower edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridEdgeUWidth]
The padding around the upper edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridAlign]
Specification of how the stagger locations should align with the cell index space (can be overridden by the individual staggerAligns). If the gridEdgeWidths are not specified than this parameter implies the EdgeWidths.
[indexflag]
Flag that indicates how the DE-local indices are to be defined.
[distDim]
Array of the same rank as the Grid. It specifies if each dimensions should be distributed. If not specified, defaults to all true. Only dimensions with regDecomp()=1 may be made undistributed.
[petMap]
Sets the mapping of pets to the created DEs. This 3D should be of size regDecomp(1) x regDecomp(2) x regDecomp(3) If the Grid is 2D, then the last dimension is of size 1. If the Grid contains undistributed dimensions then these should also be of size 1.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.7 ESMF_GridDestroy - Free all resources associated with a Grid


INTERFACE:

       subroutine ESMF_GridDestroy(grid, rc)
ARGUMENTS:
       type(ESMF_Grid) :: grid
       integer, intent(out), optional :: rc
DESCRIPTION:

Destroys an ESMF_Grid object and related internal structures. This call does not destroy the internal coordinate Arrays, or the internally generated DistGrid.

The arguments are:

grid
ESMF_Grid to be destroyed.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.8 ESMF_GridGet - Get information about a Grid


INTERFACE:

       subroutine ESMF_GridGet(grid, name, coordTypeKind, &
           rank, distRank, undistRank,  &
           tileCount, staggerlocsCount, localDECount, distgrid, &
           distgridToGridMap, undistLBound, undistUBound, coordRank, coordDimMap, &
           gridEdgeLWidth, gridEdgeUWidth, gridAlign,  &
           indexFlag, rc)
ARGUMENTS:
       type(ESMF_Grid),       intent(in)            :: grid
       character (len=*),     intent(out), optional :: name
       type(ESMF_TypeKind),   intent(out), optional :: coordTypeKind
       integer,               intent(out), optional :: rank
       integer,               intent(out), optional :: distRank
       integer,               intent(out), optional :: undistRank
       integer,               intent(out), optional :: tileCount
       integer,               intent(out), optional :: staggerlocsCount
       integer,               intent(out), optional :: localDECount
       type(ESMF_DistGrid),   intent(out), optional :: distgrid
       integer,               intent(out), optional :: distgridToGridMap(:)
       integer,               intent(out), optional :: undistLBound(:)
       integer,               intent(out), optional :: undistUBound(:)
       integer,               intent(out), optional :: coordRank(:)
       integer,               intent(out), optional :: coordDimMap(:,:)
       integer,               intent(out), optional :: gridEdgeLWidth(:)
       integer,               intent(out), optional :: gridEdgeUWidth(:)
       integer,               intent(out), optional :: gridAlign(:)
       type(ESMF_IndexFlag),  intent(out), optional :: indexflag
       integer,               intent(out), optional :: rc
DESCRIPTION:

Gets various types of information about a grid.

The arguments are:

grid
Grid to get the information from.
[name]
ESMF_Grid name.
[coordTypeKind]
The type/kind of the grid coordinate data. If not specified then the type/kind will be 8 byte reals.
[rank]
Rank of the Grid object.
[distRank]
The rank of the distributed part of the grid. Should be equal to the distgrid's dimCount.
[undistRank]
The rank of the undistributed part of the grid.
[tileCount]
The number of logically rectangular tiles in the grid.
[staggerlocsCount]
The number of stagger locations.
[localDECount]
The number of DEs in this grid on this PET.
[distgrid]
The structure describing the distribution of the grid.
[distgridToGridMap]
List that has as many elements as the distgrid rank. This array describes mapping between the grids dimensions and the distgrid.
[undistLBound]
Lower bounds for undistributed array dimensions.
[undistUBound]
Upper bounds for undistributed array dimensions.
[coordRank]
List that has as many elements as the grid rank (from arrayspec). Gives the dimension of each component (e.g. x) array. This is to allow factorization of the coordinate arrays. If not specified all arrays are the same size as the grid.
[coordDimMap]
2D list of size grid rank x grid rank. This array describes the map of each component array's dimensions onto the grids dimensions.
[gridEdgeLWidth]
The padding around the lower edges of the grid. The array should be of size greater or equal to the Grid rank.
[gridEdgeUWidth]
The padding around the upper edges of the grid. The array should be of size greater or equal to the Grid rank.
[gridAlign]
Specification of how the stagger locations should align with the cell index space. The array should be of size greater or equal to the Grid rank.
[indexflag]
Flag that indicates how the DE-local indices are to be defined.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.9 ESMF_GridGet - Get information about a particular DE in a stagger location in a Grid


INTERFACE:

   ! Private name; call using ESMF_GridGet()
       subroutine ESMF_GridGetPLocalDePSloc(grid, localDe, staggerloc, &
           exclusiveLBound, exclusiveUBound, exclusiveCount,  &
           computationalLBound, computationalUBound, computationalCount, rc)
ARGUMENTS:
       type(ESMF_Grid),        intent(in)            :: grid
       integer,                intent(in)            :: localDe
       type (ESMF_StaggerLoc), intent(in)            :: staggerloc
       integer,                intent(out), optional :: exclusiveLBound(:)
       integer,                intent(out), optional :: exclusiveUBound(:)
       integer,                intent(out), optional :: exclusiveCount(:)
       integer,                intent(out), optional :: computationalLBound(:)
       integer,                intent(out), optional :: computationalUBound(:)
       integer,                intent(out), optional :: computationalCount(:)
       integer,                intent(out), optional :: rc
DESCRIPTION:

This method gets information about the range of index space which a particular stagger location occupies. This call differs from the coordinate bound calls (e.g. ESMF_GridGetCoord) in that a given coordinate array may only occupy a subset of the Grid's dimensions, and so these calls may not give all the bounds of the stagger location. The bounds from this call are the full bounds, and so for example, give the appropriate bounds for allocating a F90 array to hold data residing on the stagger location. Note that unlike the output from the Array, these values also include the undistributed dimensions and are ordered to reflect the order of the indices in the Grid. This call will still give correct values even if the stagger location does not contain coordinate arrays (e.g. if ESMF_GridAllocCoord hasn't yet been called on the stagger location).

The arguments are:

grid
Grid to get the information from.
[localDe]
The local DE from which to get the information.
staggerloc
The stagger location to get the information for. Please see Section 22.5.3 for a list of predefined stagger locations.
[exclusiveLBound]
Upon return this holds the lower bounds of the exclusive region. exclusiveLBound must be allocated to be of size equal to the Grid rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[exclusiveUBound]
Upon return this holds the upper bounds of the exclusive region. exclusiveUBound must be allocated to be of size equal to the Grid rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[exclusiveCount]
Upon return this holds the number of items in the exclusive region per dimension (i.e. exclusiveUBound-exclusiveLBound+1). exclusiveCount must be allocated to be of size equal to the Grid rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalLBound]
Upon return this holds the lower bounds of the computational region. computationalLBound must be allocated to be of size equal to the Grid rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalUBound]
Upon return this holds the upper bounds of the computational region. computationalUBound must be allocated to be of size equal to the Grid rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalCount]
Upon return this holds the number of items in the computational region per dimension. (i.e. computationalUBound-computationalLBound+1). computationalCount must be allocated to be of size equal to the Grid rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.10 ESMF_GridGet - Get information about a particular stagger location in a Grid


INTERFACE:

   ! Private name; call using ESMF_GridGet()
       subroutine ESMF_GridGetPSloc(grid, staggerloc, &
           computationalEdgeLWidth, computationalEdgeUWidth, &
           undistLBound,undistUBound, rc)
ARGUMENTS:
       type(ESMF_Grid),        intent(in)            :: grid
       type (ESMF_StaggerLoc), intent(in)            :: staggerloc
       integer,                intent(out), optional :: computationalEdgeLWidth(:)
       integer,                intent(out), optional :: computationalEdgeUWidth(:)
       integer,                intent(out), optional :: undistLBound(:)
       integer,                intent(out), optional :: undistUBound(:)
       integer,                intent(out), optional :: rc
DESCRIPTION:

This method gets information about a particular stagger location. This information is useful for creating an ESMF Array to hold the data at the stagger location.

The arguments are:

grid
Grid to get the information from.
staggerloc
The stagger location to get the information for. Please see Section 22.5.3 for a list of predefined stagger locations.
[computationalEdgeLWidth]
Upon return this holds the global lower width of the stagger region. The width returned is only for the distGrid dimensions and is mapped to correspond to those dimensions. computationalEdgeLWidth must be allocated to be of size equal to the grid distRank (i.e. the grid's distgrid's dimCount).
[computationalEdgeUWidth]
Upon return this holds the global upper width of the stagger region. The width returned is only for the distGrid dimensions and is mapped to correspond to those dimensions. computationalEdgeUWidth must be allocated to be of size equal to the grid distRank (i.e. the grid's distgrid's dimCount).
[undistLBound]
Upon return this holds the lower bound of the stagger region. This bound is the lower bound used to create the grid modified by the appropriate staggerEdgeLWidths. undistLBound must be allocated to be of size equal to the grid undistRank.
[undistUBound]
Upon return this holds the upper bound of the stagger region. This bound is the upper bound used to create the grid modified by the appropriate staggerEdgeUWidths. undistUBound must be allocated to be of size equal to the grid undistRank.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.11 ESMF_GridGetCoord - Get Grid coordinate bounds and an F90 pointer to coordinate data


INTERFACE:

        subroutine ESMF_GridGetCoord(grid, localDE, coordDim, staggerloc, &
           exclusiveLBound, exclusiveUBound, exclusiveCount,              &
           computationalLBound, computationalUBound, computationalCount,  &
           totalLBound, totalUBound, totalCount,                          &
           <pointer argument>, doCopy, rc)
ARGUMENTS:
       type(ESMF_Grid),        intent(in) :: grid
       integer,                intent(in), optional :: localDE
       integer,                intent(in) :: coordDim
       type (ESMF_StaggerLoc), intent(in), optional :: staggerloc
       integer,                intent(out), optional :: exclusiveLBound(:)
       integer,                intent(out), optional :: exclusiveUBound(:)
       integer,                intent(out), optional :: exclusiveCount(:)
       integer,                intent(out), optional :: computationalLBound(:)
       integer,                intent(out), optional :: computationalUBound(:)
       integer,                intent(out), optional :: computationalCount(:)
       integer,                intent(out), optional :: totalLBound(:)
       integer,                intent(out), optional :: totalUBound(:)
       integer,                intent(out), optional :: totalCount(:)
       <pointer argument>, see below for supported values
       type(ESMF_CopyFlag),    intent(in), optional :: docopy
       integer,                intent(out), optional :: rc
DESCRIPTION:

This method gets a Fortran pointer to the piece of memory which holds the coordinate data on the local DE for the given coordinate dimension and stagger locations. This is useful, for example, for setting the coordinate values in a Grid, or for reading the coordinate values. Currently this method supports up to three coordinate dimensions, of either R4 or R8 datatype. See below for specific supported values. If the coordinates that you are trying to retrieve are of higher dimension, use the ESMF_GetCoord() interface that returns coordinate values in an ESMF_Array instead. That interface supports the retrieval of coordinates up to 7D.

Supported values for the <pointer argument> are:

real(ESMF_KIND_R4), pointer :: fptr(:)
real(ESMF_KIND_R4), pointer :: fptr(:,:)
real(ESMF_KIND_R4), pointer :: fptr(:,:,:)
real(ESMF_KIND_R8), pointer :: fptr(:)
real(ESMF_KIND_R8), pointer :: fptr(:,:)
real(ESMF_KIND_R8), pointer :: fptr(:,:,:)

The arguments are:

grid
Grid to get the information from.
[localDE]
The local DE to get the information for. If not set, defaults to the first DE on this processor. (localDE starts at 0)
coordDim
The coordinate dimension to get the data from (e.g. 1=x).
staggerloc
The stagger location to get the information for. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER.
[exclusiveLBound]
Upon return this holds the lower bounds of the exclusive region. exclusiveLBound must be allocated to be of size equal to the coord rank.
[exclusiveUBound]
Upon return this holds the upper bounds of the exclusive region. exclusiveUBound must be allocated to be of size equal to the coord rank.
[exclusiveCount]
Upon return this holds the number of items in the exclusive region per dimension (i.e. exclusiveUBound-exclusiveLBound+1). exclusiveCount must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalLBound]
Upon return this holds the lower bounds of the stagger region. computationalLBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalUBound]
Upon return this holds the upper bounds of the stagger region. exclusiveUBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalCount]
Upon return this holds the number of items in the computational region per dimension (i.e. computationalUBound-computationalLBound+1). computationalCount must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[totalLBound]
Upon return this holds the lower bounds of the total region. totalLBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[totalUBound]
Upon return this holds the upper bounds of the total region. totalUBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[totalCount]
Upon return this holds the number of items in the total region per dimension (i.e. totalUBound-totalLBound+1). totalCount must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
fptr
The pointer to the coordinate data.
[doCopy]
If not specified, default to ESMF_DATA_REF, in this case fptr is a reference to the data in the Grid coordinate arrays. Please see Section 9.1.4 for further description and a list of valid values.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.12 ESMF_GridGetCoord - Get Grid coordinate bounds


INTERFACE:

   ! Private name; call using ESMF_GridGetCoord()
       subroutine ESMF_GridGetCoordBounds(grid, localDE, coordDim, staggerloc, &
           exclusiveLBound, exclusiveUBound, exclusiveCount,                   &
           computationalLBound, computationalUBound, computationalCount,       &
           totalLBound, totalUBound, totalCount, rc)
ARGUMENTS:
       type(ESMF_Grid),        intent(in)            :: grid
       integer,                intent(in),  optional :: localDE
       integer,                intent(in)            :: coordDim
       type (ESMF_StaggerLoc), intent(in),  optional :: staggerloc
       integer,                intent(out), optional :: exclusiveLBound(:)
       integer,                intent(out), optional :: exclusiveUBound(:)
       integer,                intent(out), optional :: exclusiveCount(:)
       integer,                intent(out), optional :: computationalLBound(:)
       integer,                intent(out), optional :: computationalUBound(:)
       integer,                intent(out), optional :: computationalCount(:)
       integer,                intent(out), optional :: totalLBound(:)
       integer,                intent(out), optional :: totalUBound(:)
       integer,                intent(out), optional :: totalCount(:)
       integer,                intent(out), optional :: rc
DESCRIPTION:

This method gets information about the range of index space which a particular piece of coordinate data occupies. In other words, this method returns the bounds of the coordinate arrays. Note that unlike the output from the Array, these values also include the undistributed dimensions and are ordered to reflect the order of the indices in the coordinate. So, for example, totalLBound and totalUBound should match the bounds of the Fortran array retrieved by ESMF_GridGetCoord.

The arguments are:

grid
Grid to get the information from.
[localDE]
The local DE from which to get the information. If not set, defaults to the first DE on this processor. (localDE starts at 0)
coordDim
The coordinate dimension to get the information for (e.g. 1=x).
staggerloc
The stagger location to get the information for. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER.
[exclusiveLBound]
Upon return this holds the lower bounds of the exclusive region. exclusiveLBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[exclusiveUBound]
Upon return this holds the upper bounds of the exclusive region. exclusiveUBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[exclusiveCount]
Upon return this holds the number of items in the exclusive region per dimension (i.e. exclusiveUBound-exclusiveLBound+1). exclusiveCount must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalLBound]
Upon return this holds the lower bounds of the stagger region. computationalLBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalUBound]
Upon return this holds the upper bounds of the stagger region. computationalUBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[computationalCount]
Upon return this holds the number of items in the computational region per dimension (i.e. computationalUBound-computationalLBound+1). computationalCount must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[totalLBound]
Upon return this holds the lower bounds of the total region. totalLBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[totalUBound]
Upon return this holds the upper bounds of the total region. totalUBound must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[totalCount]
Upon return this holds the number of items in the total region per dimension (i.e. totalUBound-totalLBound+1). totalCount must be allocated to be of size equal to the coord rank. Please see Section 22.2.9 for a description of the regions and their associated bounds and counts.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.13 ESMF_GridGetCoord - Get coordinates and put in an ESMF Array


INTERFACE:

   ! Private name; call using ESMF_GridGetCoord()
       subroutine ESMF_GridGetCoordIntoArray(grid, staggerloc,coordDim, array, &
                             docopy, rc)
ARGUMENTS:
       type(ESMF_Grid), intent(in) :: grid
       type (ESMF_StaggerLoc), intent(in),optional  :: staggerloc
       integer, intent(in)  :: coordDim
       type(ESMF_Array), intent(out) :: array
       type(ESMF_CopyFlag), intent(in), optional :: docopy ! NOT IMPLEMENTED
       integer, intent(out), optional :: rc
DESCRIPTION:

This method allows the user to get access to the ESMF Array holding coordinate data at a particular stagger location. This is useful, for example, to set the coordinate values. To have an Array to access, the coordinate Arrays must have already been allocated, for example by ESMF_GridAllocCoord or ESMF_GridSetCoord.

The arguments are:

staggerloc
The stagger location from which to get the arrays. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER.
coordDim
The coordinate dimension to get the data from (e.g. 1=x).
array
An array into which to put the coordinate infomation.
[doCopy]
If not specified, default to ESMF_DATA_REF, in this case array will contain a reference to the Grid coordinate Arrays. Please see Section 9.1.4 for further description and a list of valid values. [THE ESMF_DATA_COPY OPTION IS CURRENTLY NOT IMPLEMENTED]
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.14 ESMF_GridSet - Set the values in a Grid which has been created with CreateEmpty


INTERFACE:

   ! Private name; call using ESMF_GridSet()
     subroutine ESMF_GridSetFromDistGrid(grid, name, coordTypeKind, distgrid, & 
                  distgridToGridMap, undistLBound, undistUBound, coordRank, coordDimMap,           &
                  gridEdgeLWidth, gridEdgeUWidth, gridAlign,                  &
                  indexflag, rc)
RETURN VALUE:
ARGUMENTS:
        type(ESMF_Grid),       intent(inout)           :: grid
        character (len=*),     intent(in),   optional  :: name
        type(ESMF_TypeKind),   intent(in),   optional  :: coordTypeKind
        type(ESMF_DistGrid),   intent(in),   optional  :: distgrid
        integer,               intent(in),   optional  :: distgridToGridMap(:)
        integer,               intent(in),   optional  :: undistLBound(:)
        integer,               intent(in),   optional  :: undistUBound(:)
        integer,               intent(in),   optional  :: coordRank(:)
        integer,               intent(in),   optional  :: coordDimMap(:,:)
        integer,               intent(in),   optional  :: gridEdgeLWidth(:)
        integer,               intent(in),   optional  :: gridEdgeUWidth(:)
        integer,               intent(in),   optional  :: gridAlign(:)
        type(ESMF_IndexFlag),  intent(in),   optional  :: indexflag
        integer,               intent(out),  optional  :: rc
DESCRIPTION:

Set values in a grid in preparation for committing and creating a grid. This method is called between ESMF_GridCreateEmpty and ESMF_GridCommit. Note that once a grid is committed and created it's an error to try to set values in it. Note also that new values overwrite old values if previously set.

The arguments are:

grid
Partially created Grid to set information into.
[name]
ESMF_Grid name.
[coordTypeKind]
The type/kind of the grid coordinate data. If not specified then the type/kind will be 8 byte reals.
distgrid
ESMF_DistGrid object that describes how the array is decomposed and distributed over DEs. The dimCount of distgrid must be smaller or equal to the grid rank, otherwise a runtime ESMF error will be raised.
[distgridToGridMap]
List that has as many elements as indicated by distgrid's dimCount value. The elements map each dimension of distgrid to a dimension in the grid. (i.e. the values should range from 1 to gridrank). If not specified, the default is to map all of distgrid's dimensions against the lower dimensions of the grid in sequence.
[undistLBound]
Lower bounds for undistributed array dimensions.
[undistUBound]
Upper bounds for undistributed array dimensions.
[gridEdgeLWidth]
The padding around the lower edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridEdgeUWidth]
The padding around the upper edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridAlign]
Specification of how the stagger locations should align with the cell index space (can be overridden by the individual staggerAligns). If the gridEdgeWidths are not specified than this parameter implies the EdgeWidths.
[indexflag]
Flag that indicates how the DE-local indices are to be defined.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.15 ESMF_GridSetCoord - Set coordinates using ESMF Arrays


INTERFACE:

       subroutine ESMF_GridSetCoordFromArray(grid, staggerloc, coordDim, &
                             array, doCopy, rc)
ARGUMENTS:
       type(ESMF_Grid),        intent(in)            :: grid
       type (ESMF_StaggerLoc), intent(in), optional  :: staggerloc
       integer,                intent(in)            :: coordDim
       type(ESMF_Array),       intent(in)            :: array
       type(ESMF_CopyFlag),    intent(in), optional  :: docopy ! NOT IMPLEMENTED
       integer,                intent(out), optional :: rc
DESCRIPTION:

This method sets the passed in Array as the holder of the coordinate data for stagger location staggerloc and coordinate coord. If the location already contains an Array, then this one overwrites it.

The arguments are:

staggerloc
The stagger location into which to copy the arrays. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER.
coordDim
The coordinate dimension to put the data in (e.g. 1=x).
array
An array to set the grid coordinate information from.
[doCopy]
If not specified, default to ESMF_DATA_REF, in this case the Grid coordinate Array will be set to a reference to array. Please see Section 9.1.4 for further description and a list of valid values. [THE ESMF_DATA_COPY OPTION IS CURRENTLY NOT IMPLEMENTED]
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.16 ESMF_GridSetCommitShapeTile - Create a Grid with an irregular distribution


INTERFACE:

   ! Private name; call using ESMF_GridSetCommitShapeTile()
      subroutine ESMF_GridSetCmmitShapeTileIrreg(grid, name,coordTypeKind, minIndex,  &
                         countsPerDEDim1,countsPerDeDim2, countsPerDEDim3, &
                         connDim1, connDim2, connDim3, &
                         poleStaggerLoc1, poleStaggerLoc2, poleStaggerLoc3, &
                         bipolePos1, bipolePos2, bipolePos3, &
                         coordDep1, coordDep2, coordDep3, &
                         gridEdgeLWidth, gridEdgeUWidth, gridAlign, &
                         indexflag, distDim, petMap, rc)
ARGUMENTS:
 	type (ESMF_Grid) :: grid
       character (len=*), intent(in), optional :: name 
        type(ESMF_TypeKind),  intent(in),    optional  :: coordTypeKind
        integer,               intent(in),   optional  :: minIndex(:)
        integer,               intent(in)              :: countsPerDEDim1(:)
        integer,               intent(in)              :: countsPerDEDim2(:)
        integer,               intent(in),   optional  :: countsPerDEDim3(:)
        type(ESMF_GridConn),   intent(in),   optional  :: connDim1(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim2(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim3(:)        ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc1(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc2(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc3(2) ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos1(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos2(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos3(2)      ! N. IMP.
        integer,               intent(in),   optional  :: coordDep1(:)
        integer,               intent(in),   optional  :: coordDep2(:)
        integer,               intent(in),   optional  :: coordDep3(:)
        integer,               intent(in),   optional  :: gridEdgeLWidth(:)
        integer,               intent(in),   optional  :: gridEdgeUWidth(:)
        integer,               intent(in),   optional  :: gridAlign(:)
        type(ESMF_IndexFlag),  intent(in),   optional  :: indexflag
        logical,               intent(in),   optional  :: distDim(:)
        integer,               intent(in),   optional  :: petMap(:,:,:)
        integer,               intent(out),  optional  :: rc
DESCRIPTION:

This method sets information into an empty Grid and then commits it to create a single tile, irregularly distributed grid (see Figure 11). To specify the irregular distribution, the user passes in an array for each grid dimension, where the length of the array is the number of DEs in the dimension. Up to three dimensions can be specified, using the countsPerDEDim1, countsPerDEDim2, countsPerDEDim3 arguments. The index of each array element corresponds to a DE number. The array value at the index is the number of grid cells on the DE in that dimension. The rank of the grid is equal to the number of countsPerDEDim<> arrays that are specified.

To specify an undistributed dimension, the array in that dimension should have only one element and the corresponding entry in distDim should be false.

Section 22.2.2 shows an example of using this method to create a 2D Grid with uniformly spaced coordinates. This creation method can also be used as the basis for grids with rectilinear coordinates or curvilinear coordinates.

The arguments are:

grid
ESMF_Grid to set information into and then commit.
[name]
ESMF_Grid name.
[coordTypeKind]
The type/kind of the grid coordinate data. If not specified then the type/kind will be 8 byte reals.
[minIndex]
Tuple to start the index ranges at. If not present, defaults to /1,1,1,.../.
countsPerDEDim1
This arrays specifies the number of cells per DE for index dimension 1 for the exclusive region (the center stagger location). If the array has only one entry, then the dimension is undistributed.
countsPerDEDim2
This array specifies the number of cells per DE for index dimension 2 for the exclusive region (center stagger location). If the array has only one entry, then the dimension is undistributed.
[countsPerDEDim3]
This array specifies the number of cells per DE for index dimension 3 for the exclusive region (center stagger location). If not specified then grid is 2D. Also, If the array has only one entry, then the dimension is undistributed.
[connDim1]
Fortran array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim2]
Fortran array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim3]
Fortran array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3 If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a pole, this describes which staggerlocation is at the pole at each end. If not present, the default is the edge. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[bipolePos1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[coordDep1]
This array specifies the dependence of the first coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the first coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep2]
This array specifies the dependence of the second coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the second coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep3]
This array specifies the dependence of the third coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the third coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[gridEdgeLWidth]
The padding around the lower edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridEdgeUWidth]
The padding around the upper edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridAlign]
Specification of how the stagger locations should align with the cell index space (can be overridden by the individual staggerAligns). If the gridEdgeWidths are not specified than this parameter implies the EdgeWidths.
[indexflag]
Flag that indicates how the DE-local indices are to be defined.
[distDim]
Array of the same rank as the Grid. It specifies if each dimensions should be distributed. If not specified, defaults to all true. Only dimensions with size(countsPerDeDim)=1 may be made undistributed.
[petMap]
Sets the mapping of pets to the created DEs. This 3D should be of size size(countsPerDEDim1) x size(countsPerDEDim2) x size(countsPerDEDim3). If countsPerDEDim3 isn't present, then the last dimension is of size 1.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.17 ESMF_GridSetCommitShapeTile - Set a Grid with a regular distribution


INTERFACE:

   ! Private name; call using ESMF_GridSetCommitShapeTile()
       subroutine ESMF_GridSetCmmitShapeTileReg(grid, name, coordTypeKind, &
                         regDecomp, decompFlag, minIndex, maxIndex, &
                         connDim1, connDim2, connDim3, &
                         poleStaggerLoc1, poleStaggerLoc2, poleStaggerLoc3, &
                         bipolePos1, bipolePos2, bipolePos3, &
                         coordDep1, coordDep2, coordDep3, &
                         gridEdgeLWidth, gridEdgeUWidth, gridAlign, &
                         indexflag, distDim, petMap, rc)
ARGUMENTS:
        type(ESMF_Grid),       intent(inout)              :: grid
        character (len=*),     intent(in),   optional  :: name 
        type(ESMF_TypeKind),   intent(in),   optional  :: coordTypeKind
        integer,               intent(in),   optional  :: regDecomp(:)
        type(ESMF_DecompFlag), intent(in),   optional  :: decompflag(:)
        integer,               intent(in),   optional  :: minIndex(:)
        integer,               intent(in)              :: maxIndex(:)
        type(ESMF_GridConn),   intent(in),   optional  :: connDim1(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim2(:)        ! N. IMP.
        type(ESMF_GridConn),   intent(in),   optional  :: connDim3(:)        ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc1(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc2(2) ! N. IMP.
        type(ESMF_StaggerLoc), intent(in),   optional  :: poleStaggerLoc3(2) ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos1(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos2(2)      ! N. IMP.
        integer,               intent(in),   optional  :: bipolePos3(2)      ! N. IMP.
        integer,               intent(in),   optional  :: coordDep1(:)
        integer,               intent(in),   optional  :: coordDep2(:)
        integer,               intent(in),   optional  :: coordDep3(:)
        integer,               intent(in),   optional  :: gridEdgeLWidth(:)
        integer,               intent(in),   optional  :: gridEdgeUWidth(:)
        integer,               intent(in),   optional  :: gridAlign(:)
        type(ESMF_IndexFlag),  intent(in),   optional  :: indexflag
        logical,               intent(in),   optional  :: distDim(:)
        integer,               intent(in),   optional  :: petMap(:,:,:)
        integer,               intent(out),  optional  :: rc
DESCRIPTION:

This method sets information into an empty Grid and then commits it to create a single tile, regularly distributed grid (see Figure 11). To specify the distribution, the user passes in an array (regDecomp) specifying the number of DEs to divide each dimension into. If the number of DEs is 1 than the dimension is undistributed. The array decompFlag indicates how the division into DEs is to occur. The default is to divide the range as evenly as possible.

The arguments are:

grid
ESMF_Grid to set information into in preparation for commit.
[name]
ESMF_Grid name.
[coordTypeKind]
The type/kind of the grid coordinate data. If not specified then the type/kind will be 8 byte reals.
[regDecomp]
List that has the same number of elements as maxIndex. Each entry is the number of decounts for that dimension. If not specified, the default decomposition will be petCountx1x1..x1.
[decompflag]
List of decomposition flags indicating how each dimension of the patch is to be divided between the DEs. The default setting is ESMF_DECOMP_HOMOGEN in all dimensions. Please see Section 9.1.6 for a full description of the possible options.
[minIndex]
The bottom extent of the grid array. If not given then the value defaults to /1,1,1,.../.
maxIndex
The upper extent of the grid array.
[connDim1]
Fortran array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim2]
Fortran array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[connDim3]
Fortran array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If array is only one element long, then that element is used for both the minimum and maximum end. Please see Section 22.5.1 for a list of valid options. If not present, defaults to ESMF_GRIDCONN_NONE. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[poleStaggerLoc3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a pole, this describes which staggerlocation is at the pole at each end. Please see Section 22.5.3 for a list of predefined stagger locations. If not present, defaults to ESMF_STAGGERLOC_CENTER. [CURRENTLY NOT IMPLEMENTED]
[bipolePos1]
Two element array describing the index dimension 1 connections. The first element represents the minimum end of dimension 1. The second element represents the maximum end of dimension 1. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos2]
Two element array describing the index dimension 2 connections. The first element represents the minimum end of dimension 2. The second element represents the maximum end of dimension 2. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[bipolePos3]
Two element array describing the index dimension 3 connections. The first element represents the minimum end of dimension 3. The second element represents the maximum end of dimension 3. If a bipole, this gives the index position of one of the poles. The other is half way around. If not present, the default is 1. [CURRENTLY NOT IMPLEMENTED]
[coordDep1]
This array specifies the dependence of the first coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the first coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep2]
This array specifies the dependence of the second coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the second coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[coordDep3]
This array specifies the dependence of the third coordinate component on the three index dimensions described by coordsPerDEDim1,2,3. The size of the array specifies the number of dimensions of the third coordinate component array. The values specify which of the index dimensions the corresponding coordinate arrays map to. If not present the default is /1,2,3/.
[gridEdgeLWidth]
The padding around the lower edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridEdgeUWidth]
The padding around the upper edges of the grid. This padding is between the index space corresponding to the cells and the boundary of the the exclusive region. This extra space is to contain the extra padding for non-center stagger locations, and should be big enough to hold any stagger in the grid.
[gridAlign]
Specification of how the stagger locations should align with the cell index space (can be overridden by the individual staggerAligns). If the gridEdgeWidths are not specified than this parameter implies the EdgeWidths.
[indexflag]
Flag that indicates how the DE-local indices are to be defined.
[distDim]
Array of the same rank as the Grid. It specifies if each dimensions should be distributed. If not specified, defaults to all true. Only dimensions with regDecomp()=1 may be made undistributed.
[petMap]
Sets the mapping of pets to the created DEs. This 3D should be of size regDecomp(1) x regDecomp(2) x regDecomp(3) If the Grid is 2D, then the last dimension is of size 1. If the Grid contains undistributed dimensions then these should also be of size 1.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.6.18 ESMF_GridValidate - Validate Grid internals


INTERFACE:

   subroutine ESMF_GridValidate(grid, rc)
ARGUMENTS:
     type(ESMF_Grid), intent(in)              :: grid
     integer,         intent(out),  optional  :: rc
DESCRIPTION:

Validates that the Grid is internally consistent. Note that one of the checks that the Grid validate does is the Grid status. Currently, the validate will return an error if the grid is not at least ESMF_GRIDSTATUS_SHAPE_READY. This means if a Grid was created with ESMF_GridCreateEmpty it must also have been commited with ESMF_GridCommit to be valid. If a Grid was created with another create call it should automatically have the correct status level to pass the status part of the validate. The Grid validate at this time doesn't check for the presence or consistency of the Grid coordinates. The method returns an error code if problems are found.

The arguments are:

grid
Specified ESMF_Grid object.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.7 Class API: StaggerLoc Methods

 

22.7.1 ESMF_StaggerLocSet - Set a StaggerLoc to a particular position in the cell


INTERFACE:

   ! Private name; call using ESMF_StaggerLocSet() 
      subroutine ESMF_StaggerLocSetAllDim(staggerloc,loc,rc)
ARGUMENTS:
       type (ESMF_StaggerLoc), intent(inout) :: staggerloc
       integer, intent(in) :: loc(:)
       integer, optional :: rc
DESCRIPTION:

Sets a custom staggerloc to a position in a cell by using the array loc. The values in the array should only be 0,1. If loc(i) is 0 it means the position should be in the center in that dimension. If loc(i) is 1 then for dimension i, the position should be on the side of the cell. Please see Section 22.2.15 for diagrams and further discussion of custom stagger locations.

The arguments are:

staggerloc
Grid location to be initialized
loc
Array holding position data. Each entry in loc should only be 0 or 1. note that dimensions beyond those specified are set to 0.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.7.2 ESMF_StaggerLocSet - Set one dimension of a StaggerLoc to a particular position


INTERFACE:

   ! Private name; call using ESMF_StaggerLocSet() 
       subroutine ESMF_StaggerLocSetDim(staggerloc,dim,loc,rc)
ARGUMENTS:
       type (ESMF_StaggerLoc), intent(inout) :: staggerloc
       integer, intent(in) :: dim,loc
       integer, optional :: rc
DESCRIPTION:

Sets a particular dimension of a custom staggerloc to a position in a cell by using the variable loc. The variable loc should only be 0,1. If loc is 0 it means the position should be in the center in that dimension. If loc is +1 then for the dimension, the position should be on the positive side of the cell. Please see Section 22.2.15 for diagrams and further discussion of custom stagger locations.

The arguments are:

staggerloc
Stagger location to be initialized
dim
Dimension to be changed (1-7).
loc
Position data should be either 0,1.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.7.3 ESMF_StaggerLocString - Return a StaggerLoc as a string


INTERFACE:

       subroutine ESMF_StaggerLocString(staggerloc, string, rc)
ARGUMENTS:
       type(ESMF_StaggerLoc), intent(in) :: staggerloc
       character (len = *), intent(out) :: string
       integer, intent(out), optional :: rc
DESCRIPTION:

Return an ESMF_StaggerLoc as a printable string.

The arguments are:

staggerloc
The ESMF_StaggerLoc to be turned into a string.
string
Return string.
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

22.7.4 ESMF_StaggerLocPrint - Print information of a ESMF_StaggerLoc object


INTERFACE:

       subroutine ESMF_StaggerLocPrint(staggerloc, rc)
ARGUMENTS:
       type (ESMF_StaggerLoc), intent(in) :: staggerloc
       integer, intent(out), optional     :: rc
DESCRIPTION:

Print the internal data members of a ESMF_StaggerLoc object

The arguments are:

staggerloc
ESMF_StaggerLoc object as the method input
[rc]
Return code; equals ESMF_SUCCESS if there are no errors.

23 DistGrid Class

23.1 Description

The ESMF_DistGrid class sits on top of the DELayout class and holds domain information in index space. A DistGrid object captures the index space topology and describes its decomposition in terms of DEs. Combined with DELayout and VM the DistGrid defines the data distribution of a domain decomposition across the computational resources of an ESMF component.

The global domain is defined as the union or ``patchwork'' of logically rectangular (LR) sub-domains or patches. The DistGrid create methods allow the specification of such a patchwork global domain and its decomposition into exclusive, DE-local LR regions according to various degrees of user specified constraints. Complex index space topologies can be constructed by specifying connection relationships between patches during creation.

The DistGrid class holds domain information for all DEs. Each DE is associated with a local LR region. No overlap of the regions is allowed. The DistGrid offers query methods that allow DE-local topology information to be extracted, e.g. for the construction of halos by higher classes.

A DistGrid object only contains decomposable dimensions. The minimum rank for a DistGrid object is 1. A maximum rank does not exist for DistGrid objects, however, ranks greater than 7 may lead to difficulties with respect to the Fortran API of higher classes based on DistGrid. The rank of a DELayout object contained within a DistGrid object must be equal to the DistGrid rank. Higher class objects that use the DistGrid, such as an Array object, may be of different rank than the associated DistGrid object. The higher class object will hold the mapping information between its dimensions and the DistGrid dimensions.

23.2 Use and Examples

The following examples demonstrate how to create, use and destroy DistGrid objects. In order to produce complete and valid DistGrid objects all of the ESMF_DistGridCreate() calls require to be called in unison i.e. on all PETs of a component with a complete set of valid arguments.

23.2.1 Single patch DistGrid with regular decomposition

The minimum information required to create an ESMF_DistGrid object for a single patch with default decomposition are the corners of the patch in index space. The following call will create a 1D DistGrid for a 1D index space patch with elements from 1 through 1000.

  distgrid = ESMF_DistGridCreate(minIndex=(/1/), maxIndex=(/1000/), rc=rc)

A default DELayout with 1 DE per PET will be created during ESMF_DistGridCreate(). The 1000 elements of the specified 1D patch will then be block decomposed across the available DEs, i.e. across all PETs. Hence, for 4 PETs the (min) $\sim$ (max) corners of the DE-local LR regions will be:

     DE 0 - (1) ~ (250)
     DE 1 - (251) ~ (500)
     DE 2 - (501) ~ (750)
     DE 3 - (751) ~ (1000)

DistGrids with rank > 1 can also be created with default decompositions, specifying only the corners of the patch. The following will create a 2D DistGrid for a 5x5 patch with default decomposition.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), rc=rc)

The default decomposition for a DistGrid of rank $N$ will be $ (nDEs \times 1
\times ... \times 1) $, where $nDEs$ is the number of DEs in the DELayout and there are $N-1$ factors of $1$. For the 2D example above this means a $4 \times 1$ regular decomposition if executed on 4 PETs and will result in the following DE-local LR regions:

     DE 0 - (1,1) ~ (2,5)
     DE 1 - (3,1) ~ (3,5)
     DE 2 - (4,1) ~ (4,5)
     DE 3 - (5,1) ~ (5,5)

In many cases the default decomposition will not suffice for higher rank DistGrids (rank > 1). For this reason a decomposition descriptor regDecomp argument is available during ESMF_DistGridCreate(). The following call creates a DistGrid on the same 2D patch as before, but now with a user specified regular decomposition of $2 \times 3 = 6 $ DEs.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), rc=rc)

The default DE labeling sequence follows column major order for the regDecomp argument:

     -----------> 2nd dimension
     |  0  2  4
     |  1  3  5
     v
    1st dimension

By default grid points along all dimensions are homogeneously divided between the DEs. The maximum element count difference between DEs along any dimension is 1. The (min) $\sim$ (max) corners of the DE-local LR domains of the above example are as follows:

     DE 0 - (1,1) ~ (3,2)
     DE 1 - (4,1) ~ (5,2)
     DE 2 - (1,3) ~ (3,4)
     DE 3 - (4,3) ~ (5,4)
     DE 4 - (1,5) ~ (3,5)
     DE 5 - (4,5) ~ (5,5)

The specifics of the patch decomposition into DE-local LR domains can be modified by the optional decompflag argument. The following line shows how this argument is used to keep ESMF's default decomposition in the first dimension but move extra grid points of the second dimension to the last DEs in that direction. Extra elements occur if the number of DEs for a certain dimension does not evenly divide its extent. In this example there are 2 extra grid points for the second dimension because its extent is 5 but there are 3 DEs along this index space axis.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), decompflag=(/ESMF_DECOMP_DEFAULT,ESMF_DECOMP_RESTLAST/),&
    rc=rc)

Now DE 4 and DE 5 will hold the extra elements along the 2nd dimension.

     DE 0 - (1,1) ~ (3,1)
     DE 1 - (4,1) ~ (5,1)
     DE 2 - (1,2) ~ (3,2)
     DE 3 - (4,2) ~ (5,2)
     DE 4 - (1,3) ~ (3,5)
     DE 5 - (4,3) ~ (5,5)

An alternative way of indicating the DE-local LR regions is to list the index space coordinate as given by the associated DistGrid patch for each dimension. For this 2D example there are two lists (dim 1) / (dim 2) for each DE:

     DE 0 - (1,2,3) / (1)
     DE 1 - (4,5)   / (1)
     DE 2 - (1,2,3) / (2)
     DE 3 - (4,5)   / (2)
     DE 4 - (1,2,3) / (3,4,5)
     DE 5 - (4,5)   / (3,4,5)

Information about DE-local LR regions in the latter format can be obtained from the DistGrid object by use of ESMF_DistGridGet() methods:

  allocate(dimExtent(2, 0:5)) ! (dimCount, deCount)
  call ESMF_DistGridGet(distgrid, delayout=delayout, &
    indexCountPDimPDe=dimExtent, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)
  call ESMF_DELayoutGet(delayout, localDeCount=localDeCount, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)
  allocate(localDeList(0:localDeCount-1))
  call ESMF_DELayoutGet(delayout, localDeList=localDeList, rc=rc)
  if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)
  do localDe=0, localDeCount-1
    de = localDeList(localDe)
    do dim=1, 2
      allocate(localIndexList(dimExtent(dim, de))) ! allocate list to hold indices
      call ESMF_DistGridGet(distgrid, localDe=localDe, dim=dim, &
        indexList=localIndexList, rc=rc)
      if (rc /= ESMF_SUCCESS) call ESMF_Finalize(terminationflag=ESMF_ABORT)
      print *, "local DE ", localDe," - DE ",de," localIndexList along dim=", &
        dim," :: ", localIndexList
      deallocate(localIndexList)
    enddo
  enddo
  deallocate(localDeList)
  deallocate(dimExtent)

The advantage of the localIndexList format over the min-/max-corner format is that it can be used directly for DE-local to patch index dereferencing. Furthermore the localIndexList allows to express very general decompositions such as the cyclic decompositions in the first dimension generated by the following call:

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), decompflag=(/ESMF_DECOMP_CYCLIC,ESMF_DECOMP_RESTLAST/),&
    rc=rc)

with decomposition:

     DE 0 - (1,3,5) / (1)
     DE 1 - (2,4)   / (1)
     DE 2 - (1,3,5) / (2)
     DE 3 - (2,4)   / (2)
     DE 4 - (1,3,5) / (3,4,5)
     DE 5 - (2,4)   / (3,4,5)

Finally, a DistGrid object is destroyed by calling

  call ESMF_DistGridDestroy(distgrid, rc=rc)

23.2.2 DistGrid and DELayout

The examples of this section use the 2D DistGrid of the previous section to show the interplay between DistGrid and DELayout. By default, i.e. without specifying the delayout argument, a DELayout will be created during DistGrid creation that provides as many DEs as the DistGrid object requires. The implicit call to ESMF_DELayoutCreate() is issued with a fixed number of DEs and default settings in all other aspects. The resulting DE to PET mapping depends on the number of PETs of the current VM context. Assuming 6 PETs in the VM

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), rc=rc)

will result in the following domain decomposition in terms of DEs

     0  2  4
     1  3  5
and their layout or distribution over the available PETs:
     DE 0  -> PET 0
     DE 1  -> PET 1
     DE 2  -> PET 2
     DE 3  -> PET 3
     DE 4  -> PET 4
     DE 5  -> PET 5

Running the same example on a 4 PET VM will not change the domain decomposition into 6 DEs as specified by

     0  2  4
     1  3  5
but the layout across PETs will now contain multiple DE-to-PET mapping with default cyclic distribution:
     DE 0  -> PET 0
     DE 1  -> PET 1
     DE 2  -> PET 2
     DE 3  -> PET 3
     DE 4  -> PET 0
     DE 5  -> PET 1

Sometimes it may be desirable for performance tuning to construct a DELayout with specific characteristics. For instance, if the 6 PETs of the above example are running on 3 nodes of a dual-SMP node cluster and there is a higher communication load along the first dimension of the model than along the second dimension it would be sensible to place DEs according to this knowledge.

The following example first creates a DELayout with 6 DEs where groups of 2 DEs are to be in fast connection. This DELayout is then used to create a DistGrid.

  delayout = ESMF_DELayoutCreate(deCount=6, deGrouping=(/(i/2,i=0,5)/), rc=rc)

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), delayout=delayout, rc=rc)

This will ensure a distribution of DEs across the cluster resource in the following way:

     0   2   4
     1   3   5
    SMP SMP SMP

The interplay between DistGrid and DELayout may at first seem complicated. The simple but important rule to understand is that DistGrid describes a domain decomposition and each domain is labeled with a DE number. The DELayout describes how these DEs are laid out over the compute resources of the VM, i.e. PETs. The DEs are purely logical elements of decomposition and may be relabeled to fit the algorithm or legacy code better. The following example demonstrates this by describing the exact same distribution of the domain data across the fictitious cluster of SMP-nodes with a different choice of DE labeling:

  delayout = ESMF_DELayoutCreate(deCount=6, deGrouping=(/(mod(i,3),i=0,5)/), &
    rc=rc)

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), deLabelList=(/0,3,1,4,2,5/), delayout=delayout, rc=rc)

Here the deLabelList argument changes the default DE label sequence from column major to row major. The DELayout compensates for this change in DE labeling by changing the deGrouping argument to map the first dimension to SMP nodes as before. The decomposition and layout now looks as follows:

     0   1   2
     3   4   5
    SMP SMP SMP

Finally, in order to achieve a completely user-defined distribution of the domain data across the PETs of the VM a DELayout may be created from a petMap before using it in the creation of a DistGrid. If for instance the desired distribution of a 2 x 3 decomposition puts the DEs of the first row onto 3 separate PETs (PET 0, 1, 2) and groups the DEs of the second row onto PET 3 a petMap must first be setup that takes the DE labeling of the DistGrid into account.The following lines of code result in the desired distribution using column major DE labeling by first create a DELayout and then using it in the DistGrid creation.

  delayout = ESMF_DELayoutCreate(petMap=(/0,3,1,3,2,3/), rc=rc)

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    regDecomp=(/2,3/), delayout=delayout, rc=rc)

This decomposes the global domain into

     0   2   4
     1   3   5
and associates the DEs to the following PETs:
     DE 0  -> PET 0
     DE 1  -> PET 3
     DE 2  -> PET 1
     DE 3  -> PET 3
     DE 4  -> PET 2
     DE 5  -> PET 3

23.2.3 Single patch DistGrid with decomposition by DE blocks

The examples of the previous sections showed how DistGrid objects with regular decompositions are created. However, in some cases a regular decomposition may not be specific enough. The following example shows how the deBlockList argument is used to create a DistGrid object with completely user-defined decomposition.

A single 5x5 LR domain is to be decomposed into 6 DEs. To this end a list is constructed that holds the min and max corners of all six DE LR blocks. The DE-local LR blocks are arranged as to cover the whole patch domain without overlap.

  allocate(deBlockList(2, 2, 6))  ! (dimCount, 2, deCount)
  deBlockList(:,1,1) = (/1,1/)  ! minIndex  1st deBlock
  deBlockList(:,2,1) = (/3,2/)  ! maxIndex  1st deBlock
  deBlockList(:,1,2) = (/4,1/)  ! minIndex  2nd deBlock
  deBlockList(:,2,2) = (/5,2/)  ! maxIndex  2nd deBlock
  deBlockList(:,1,3) = (/1,3/)
  deBlockList(:,2,3) = (/2,4/)
  deBlockList(:,1,4) = (/3,3/)
  deBlockList(:,2,4) = (/5,4/)
  deBlockList(:,1,5) = (/1,5/)
  deBlockList(:,2,5) = (/3,5/)
  deBlockList(:,1,6) = (/4,5/)  ! minIndex  6th deBlock
  deBlockList(:,2,6) = (/5,5/)  ! maxInbex  6th deBlock

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    deBlockList=deBlockList, rc=rc)

23.2.4 Single patch DistGrid with periodic boundaries

By default the edges of all patches have solid wall boundary conditions. Periodic boundary conditions can be imposed by specifying connections between patches. For the single LR domain of the last section periodic boundaries along the first dimension are imposed by adding a connectionList argument with only one element to the create call.

Each connectionList element is a vector of (3 * dimCount + 2) integer numbers:

  allocate(connectionList(3*2+2, 1))  ! (3*dimCount+2, number of connections)

and has the following format:

(/patchIndex_A, patchIndex_B, positionVector, orientationVector, repetitionVector/).

The following constructor call can be used to construct a suitable connectionList element.

  call ESMF_DistGridConnection(connection=connectionList(:,1), &
     patchIndexA=1, patchIndexB=1, &
     positionVector=(/5, 0/), &
     orientationVector=(/1, 2/), &
     repetitionVector=(/1, 0/), rc=rc)

The patchIndexA and patchIndexB arguments specify that this is a connection within patch 1. The positionVector indicates that there is no offset between patchB and patchA along the second dimension, but there is an offset of 5 along the first dimension (which in this case is the length of dimension 1). This aligns patchB (which is patch 1) right next to patchA (which is also patch 1).

The orientationVector fixes the orientation of the patchB index space to be the same as the orientation of patchA (it maps index 1 of patchA to index 1 of patchB and the same for index 2). The orientationVector could have been omitted in this case which corresponds to the default orientation.

Finally, the repetitionVector idicates that this connetion element will be periodically repeated along dimension 1.

The connectionList can now be used to create a DistGrid object with the desired boundary conditions.

  distgrid = ESMF_DistGridCreate(minIndex=(/1,1/), maxIndex=(/5,5/), &
    deBlockList=deBlockList, connectionList=connectionList, rc=rc)

  deallocate(connectionList)

This closes the patch along the first dimension on itself, thus imposing periodic boundaries along this direction.

23.2.5 2D patchwork DistGrid with regular decomposition

Creating a DistGrid from a list of LR domains is a straight forward extension of the case with a single LR domain. The first four arguments of ESMF_DistGridCreate() are promoted to rank 2, the second dimension being the patch count index.

The following 2D patchwork domain consisting of 3 LR patches will be used in the examples of this section:

     ----------------------------------------> 2nd dim
     |
     |                   (1,11)-----(1,20)
     |                   |               | 
     |                   |               | 
     |                   |               | 
     |                   |               | 
     |                   |               | 
     |                   (10,11)---(10,20)
     |  (11,1)----(11,10)(11,11)---(11,20)
     |  |               ||               |
     |  |               ||               |
     |  |               ||               |
     |  |               ||               |
     |  |               ||               |
     |  (20,1)----(20,10)(20,11)---(20,20)
     |
     |
     v
    1st dim

The first step in creating a patchwork global domain is to construct the minIndex and maxIndex arrays.

  allocate(minIndex(2,3))    ! (dimCount, number of patches)
  allocate(maxIndex(2,3))    ! (dimCount, number of patches)
  minIndex(:,1) = (/11,1/)
  maxIndex(:,1) = (/20,10/)
  minIndex(:,2) = (/11,11/)
  maxIndex(:,2) = (/20,20/)
  minIndex(:,3) = (/1,11/)
  maxIndex(:,3) = (/10,20/)

Next the regular decomposition for each patch is set up in the regDecomp array. In this example each patch is associated with a single DE.

  allocate(regDecomp(2,3))    ! (dimCount, number of patches)
  regDecomp(:,1) = (/1,1/)    ! one DE
  regDecomp(:,2) = (/1,1/)    ! one DE
  regDecomp(:,3) = (/1,1/)    ! one DE

Finally the DistGrid can be created by calling

  distgrid = ESMF_DistGridCreate(minIndex=minIndex, maxIndex=maxIndex, &
    regDecomp=regDecomp, rc=rc)

The default DE labeling sequence is identical to the patch labeling sequence and follows the sequence in which the patches are defined during the create call. However, DE labels start at 0 whereas patch labels start at 1. In this case the DE labels look as:

           2
       0   1

Each patch can be decomposed differently into DEs. The default DE labeling follows the column major order for each patch. This is demonstrated in the following case where the patchwork global domain is decomposed into 9 DEs,

  regDecomp(:,1) = (/2,2/)    ! 4 DEs
  regDecomp(:,2) = (/1,3/)    ! 3 DEs
  regDecomp(:,3) = (/2,1/)    ! 2 DEs
  
  distgrid = ESMF_DistGridCreate(minIndex=minIndex, maxIndex=maxIndex, &
    regDecomp=regDecomp, rc=rc)

resulting in the following decomposition:

             +-------+
             |   7   |
             |       |
             |   8   |
     +-------+-------+
     | 0   2 |       |
     |       | 4 5 6 |
     | 1   3 |       |
     +-------+-------+

     DE 0 - (11,1)  ~ (15,5)
     DE 1 - (16,1)  ~ (20,5)
     DE 2 - (11,6)  ~ (15,10)
     DE 3 - (16,6)  ~ (20,10)
     DE 4 - (11,11) ~ (20,14)
     DE 5 - (11,15) ~ (20,17)
     DE 6 - (11,18) ~ (20,20)
     DE 7 - (1,11)  ~ (5,20)
     DE 8 - (6,11)  ~ (10,20)

The decompflag and deLabelList arguments can be used much like in the single LR domain case to overwrite the default grid decomposition (per patch) and to change the overall DE labeling sequence, respectively.

23.3 Restrictions and Future Work

23.4 Design and Implementation Notes

This section will be updated as the implementation of the DistGrid class nears completion.

23.5 Class API

23.5.1 ESMF_DistGridCreate - Create DistGrid object with regular decomposition


INTERFACE:

   ! Private name; call using ESMF_DistGridCreate()
   
   function ESMF_DistGridCreateRD(minIndex, maxIndex, regDecomp, &
     decompflag, deLabelList, indexflag, connectionList, connectionTransList, &
     delayout, vm, rc)
ARGUMENTS:
     integer,                      intent(in)            :: minIndex(:)
     integer,                      intent(in)            :: maxIndex(:)
     integer, target,              intent(in), optional  :: regDecomp(:)
     type(ESMF_DecompFlag), target,intent(in), optional  :: decompflag(:)
     integer, target,              intent(in), optional  :: deLabelList(:)
     type(ESMF_IndexFlag),         intent(in), optional  :: indexflag
     integer, target,              intent(in), optional  :: connectionList(:,:)
     integer, target,              intent(in), optional  :: connectionTransList(:,:)
     type(ESMF_DELayout),          intent(in), optional  :: delayout
     type(ESMF_VM),                intent(in), optional  :: vm
     integer,                      intent(out),optional  :: rc
RETURN VALUE:
     type(ESMF_DistGrid) :: ESMF_DistGridCreateRD
DESCRIPTION:

Create an ESMF_DistGrid from a single logically rectangular (LR) patch with regular decomposition. A regular decomposition is of the same rank as the patch and decomposes each dimension into a fixed number of DEs. A regular decomposition of a single patch is expressed by a single regDecomp list of DE counts in each dimension.

The arguments are:

minIndex
Global coordinate tuple of the lower corner of the patch.
maxIndex
Global coordinate tuple of the upper corner of the patch.
[regDecomp]
List of DE counts for each dimension. The default decomposition will be deCount $ \times 1 \times ... \times 1$. The value of deCount for a default DELayout equals petCount, i.e. the default decomposition will be into as many DEs as there are PETs and the distribution will be 1 DE per PET.
[decompflag]
List of decomposition flags indicating how each dimension of the patch is to be divided between the DEs. The default setting is ESMF_DECOMP_HOMOGEN in all dimensions. See section 9.1.6 for a list of valid decomposi