FieldPointerUtilities.F90 Source File


This file depends on

sourcefile~~fieldpointerutilities.f90~~EfferentGraph sourcefile~fieldpointerutilities.f90 FieldPointerUtilities.F90 sourcefile~mapl_exceptionhandling.f90 MAPL_ExceptionHandling.F90 sourcefile~fieldpointerutilities.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~errorhandling.f90 ErrorHandling.F90 sourcefile~mapl_exceptionhandling.f90->sourcefile~errorhandling.f90 sourcefile~mapl_throw.f90 MAPL_Throw.F90 sourcefile~mapl_exceptionhandling.f90->sourcefile~mapl_throw.f90 sourcefile~errorhandling.f90->sourcefile~mapl_throw.f90

Files dependent on this one

sourcefile~~fieldpointerutilities.f90~~AfferentGraph sourcefile~fieldpointerutilities.f90 FieldPointerUtilities.F90 sourcefile~accumulatoraction.f90 AccumulatorAction.F90 sourcefile~accumulatoraction.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldbinaryoperations.f90 FieldBinaryOperations.F90 sourcefile~fieldbinaryoperations.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldblas.f90 FieldBLAS.F90 sourcefile~fieldblas.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldbundledelta.f90 FieldBundleDelta.F90 sourcefile~fieldbundledelta.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldcondensedarray.f90 FieldCondensedArray.F90 sourcefile~fieldcondensedarray.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fielddelta.f90 FieldDelta.F90 sourcefile~fielddelta.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldunaryfunctions.f90 FieldUnaryFunctions.F90 sourcefile~fieldunaryfunctions.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldutilities.f90 FieldUtilities.F90 sourcefile~fieldutilities.f90->sourcefile~fieldpointerutilities.f90 sourcefile~fieldutils.f90 FieldUtils.F90 sourcefile~fieldutils.f90->sourcefile~fieldpointerutilities.f90 sourcefile~grid_pfio.f90 Grid_PFIO.F90 sourcefile~grid_pfio.f90->sourcefile~fieldpointerutilities.f90 sourcefile~maxaction.f90 MaxAction.F90 sourcefile~maxaction.f90->sourcefile~fieldpointerutilities.f90 sourcefile~meanaction.f90 MeanAction.F90 sourcefile~meanaction.f90->sourcefile~fieldpointerutilities.f90 sourcefile~minaction.f90 MinAction.F90 sourcefile~minaction.f90->sourcefile~fieldpointerutilities.f90 sourcefile~test_fieldarithmetic.pf Test_FieldArithmetic.pf sourcefile~test_fieldarithmetic.pf->sourcefile~fieldpointerutilities.f90 sourcefile~test_fieldblas.pf Test_FieldBLAS.pf sourcefile~test_fieldblas.pf->sourcefile~fieldpointerutilities.f90 sourcefile~test_timeinterpolateaction.pf Test_TimeInterpolateAction.pf sourcefile~test_timeinterpolateaction.pf->sourcefile~fieldpointerutilities.f90 sourcefile~vectorbasis.f90 VectorBasis.F90 sourcefile~vectorbasis.f90->sourcefile~fieldpointerutilities.f90

Source Code

#include "MAPL_Generic.h"

module MAPL_FieldPointerUtilities
   use ESMF
   use MAPL_ExceptionHandling
   use, intrinsic :: iso_c_binding, only: c_ptr, c_f_pointer, c_loc
   implicit none
   private

   public :: FieldsHaveUndef
   public :: GetFieldsUndef
   public :: assign_fptr
   public :: FieldGetLocalElementCount
   public :: FieldGetLocalSize
   public :: FieldGetCptr
   public :: FieldClone
   public :: FieldsAreConformable
   public :: FieldsAreBroadcastConformable
   public :: FieldsAreSameTypeKind
   public :: FieldCopy
   public :: MAPL_FieldDestroy
   public :: FieldCopyBroadcast

   interface GetFieldsUndef
      module procedure GetFieldsUndef_r4
      module procedure GetFieldsUndef_r8
   end interface

   interface assign_fptr
      module procedure assign_fptr_r4_rank1
      module procedure assign_fptr_r8_rank1
      module procedure assign_fptr_r4_rank2
      module procedure assign_fptr_r8_rank2
      module procedure assign_fptr_r4_rank3
      module procedure assign_fptr_r8_rank3
      module procedure assign_fptr_i4_rank1
      module procedure assign_fptr_i8_rank1
   end interface assign_fptr

   interface FieldGetCptr
      procedure get_cptr
   end interface

   interface FieldGetLocalSize
      procedure get_local_size
   end interface FieldGetLocalSize

   interface FieldGetLocalElementCount
      procedure get_local_element_count
   end interface FieldGetLocalElementCount

   interface FieldsAreConformable
      procedure are_conformable_scalar
      procedure are_conformable_array
   end interface

   interface FieldsAreBroadCastConformable
      procedure are_broadcast_conformable
   end interface

   interface FieldClone
      module procedure clone
   end interface FieldClone

   interface FieldsAreSameTypeKind
      module procedure are_same_type_kind
   end interface FieldsAreSameTypeKind

   interface verify_typekind
      module procedure verify_typekind_scalar
      module procedure verify_typekind_array
   end interface verify_typekind

   interface FieldCOPY
      procedure copy
   end interface FieldCOPY

   interface FieldCopyBroadcast
      procedure copy_broadcast
   end interface FieldCopyBroadcast

   interface MAPL_FieldDestroy
      procedure destroy
   end interface

contains

   subroutine assign_fptr_r4_rank1(x, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      real(kind=ESMF_KIND_R4), pointer, intent(out) :: fptr(:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer(ESMF_KIND_I8), allocatable :: fp_shape(:)
      integer(ESMF_KIND_I8) :: local_size
      integer :: status

      local_size = FieldGetLocalSize(x, _RC)
      fp_shape = [ local_size ]
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_r4_rank1

   subroutine assign_fptr_r8_rank1(x, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      real(kind=ESMF_KIND_R8), pointer, intent(out) :: fptr(:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer(ESMF_KIND_I8), allocatable :: fp_shape(:)
      integer(ESMF_KIND_I8) :: local_size
      integer :: status

      local_size = FieldGetLocalSize(x, _RC)
      fp_shape = [ local_size ]
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_r8_rank1

   subroutine assign_fptr_r4_rank2(x, fp_shape, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      integer(ESMF_KIND_I8), intent(in) :: fp_shape(:)
      real(kind=ESMF_KIND_R4), pointer, intent(out) :: fptr(:,:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer :: status

      _ASSERT(size(fp_shape) == rank(fptr), 'Shape size must match pointer rank.')
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_r4_rank2

   subroutine assign_fptr_r8_rank2(x, fp_shape, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      integer(ESMF_KIND_I8), intent(in) :: fp_shape(:)
      real(kind=ESMF_KIND_R8), pointer, intent(out) :: fptr(:,:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer :: status

      _ASSERT(size(fp_shape) == rank(fptr), 'Shape size must match pointer rank.')
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_r8_rank2

   subroutine assign_fptr_r4_rank3(x, fp_shape, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      integer(ESMF_KIND_I8), intent(in) :: fp_shape(:)
      real(kind=ESMF_KIND_R4), pointer, intent(out) :: fptr(:,:,:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer :: status

      _ASSERT(size(fp_shape) == rank(fptr), 'Shape size must match pointer rank.')
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_r4_rank3

   subroutine assign_fptr_r8_rank3(x, fp_shape, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      integer(ESMF_KIND_I8), intent(in) :: fp_shape(:)
      real(kind=ESMF_KIND_R8), pointer, intent(out) :: fptr(:,:,:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer :: status

      _ASSERT(size(fp_shape) == rank(fptr), 'Shape size must match pointer rank.')
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_r8_rank3

   subroutine get_cptr(x, cptr, rc)
      type(ESMF_Field), intent(inout) :: x
      type(c_ptr), intent(out) :: cptr
      integer, optional, intent(out) :: rc

      integer :: status
      type(ESMF_TypeKind_Flag) :: tk_x

      call ESMF_FieldGet(x, typekind=tk_x, _RC)

      if (tk_x == ESMF_TYPEKIND_R4) then
         call get_cptr_r4(x, cptr, _RC)
      elseif (tk_x == ESMF_TYPEKIND_R8) then
         call get_cptr_r8(x, cptr, _RC)
      elseif (tk_x == ESMF_TYPEKIND_I4) then
         call get_cptr_i4(x, cptr, _RC)
      elseif (tk_x == ESMF_TYPEKIND_I8) then
         call get_cptr_i8(x, cptr, _RC)
      else
         _FAIL('Unsupported typekind in FieldGetCptr().')
      end if

      _RETURN(_SUCCESS)
   end subroutine get_cptr

   subroutine get_cptr_r4(x, cptr, rc)
      type(ESMF_Field), intent(inout) :: x
      type(c_ptr), intent(out) :: cptr
      integer, optional, intent(out) :: rc

      integer :: status
      integer :: rank
      real(kind=ESMF_KIND_R4), pointer :: x_1d(:)
      real(kind=ESMF_KIND_R4), pointer :: x_2d(:,:)
      real(kind=ESMF_KIND_R4), pointer :: x_3d(:,:,:)
      real(kind=ESMF_KIND_R4), pointer :: x_4d(:,:,:,:)
      real(kind=ESMF_KIND_R4), pointer :: x_5d(:,:,:,:,:)

      call ESMF_FieldGet(x, rank=rank, _RC)

      select case (rank)
      case (1)
         call ESMF_FieldGet(x, farrayPtr = x_1d, _RC)
         cptr = c_loc(x_1d)
      case (2)
         call ESMF_FieldGet(x, farrayPtr = x_2d, _RC)
         cptr = c_loc(x_2d)
      case (3)
         call ESMF_FieldGet(x, farrayPtr = x_3d, _RC)
         cptr = c_loc(x_3d)
      case (4)
         call ESMF_FieldGet(x, farrayPtr = x_4d, _RC)
         cptr = c_loc(x_4d)
      case (5)
         call ESMF_FieldGet(x, farrayPtr = x_5d, _RC)
         cptr = c_loc(x_5d)
      case default
         _FAIL('Unsupported rank in FieldGetCptr().')
      end select

      _RETURN(_SUCCESS)
   end subroutine get_cptr_r4

   subroutine get_cptr_r8(x, cptr, rc)
      type(ESMF_Field), intent(inout) :: x
      type(c_ptr), intent(out) :: cptr
      integer, optional, intent(out) :: rc

      integer :: status
      integer :: rank
      real(kind=ESMF_KIND_R8), pointer :: x_1d(:)
      real(kind=ESMF_KIND_R8), pointer :: x_2d(:,:)
      real(kind=ESMF_KIND_R8), pointer :: x_3d(:,:,:)
      real(kind=ESMF_KIND_R8), pointer :: x_4d(:,:,:,:)
      real(kind=ESMF_KIND_R8), pointer :: x_5d(:,:,:,:,:)

      call ESMF_FieldGet(x, rank=rank, _RC)

      select case (rank)
      case (1)
         call ESMF_FieldGet(x, farrayPtr = x_1d, _RC)
         cptr = c_loc(x_1d)
      case (2)
         call ESMF_FieldGet(x, farrayPtr = x_2d, _RC)
         cptr = c_loc(x_2d)
      case (3)
         call ESMF_FieldGet(x, farrayPtr = x_3d, _RC)
         cptr = c_loc(x_3d)
      case (4)
         call ESMF_FieldGet(x, farrayPtr = x_4d, _RC)
         cptr = c_loc(x_4d)
      case (5)
         call ESMF_FieldGet(x, farrayPtr = x_5d, _RC)
         cptr = c_loc(x_5d)
      case default
         _FAIL('Unsupported rank in FieldGetCptr().')
      end select

      _RETURN(_SUCCESS)
   end subroutine get_cptr_r8

   subroutine get_cptr_i4(x, cptr, rc)
      type(ESMF_Field), intent(inout) :: x
      type(c_ptr), intent(out) :: cptr
      integer, optional, intent(out) :: rc

      integer :: status
      integer :: rank
      integer(kind=ESMF_KIND_I4), pointer :: x_1d(:)
      integer(kind=ESMF_KIND_I4), pointer :: x_2d(:,:)
      integer(kind=ESMF_KIND_I4), pointer :: x_3d(:,:,:)
      integer(kind=ESMF_KIND_I4), pointer :: x_4d(:,:,:,:)
      integer(kind=ESMF_KIND_I4), pointer :: x_5d(:,:,:,:,:)

      call ESMF_FieldGet(x, rank=rank, _RC)

      select case (rank)
      case (1)
         call ESMF_FieldGet(x, farrayPtr = x_1d, _RC)
         cptr = c_loc(x_1d)
      case (2)
         call ESMF_FieldGet(x, farrayPtr = x_2d, _RC)
         cptr = c_loc(x_2d)
      case (3)
         call ESMF_FieldGet(x, farrayPtr = x_3d, _RC)
         cptr = c_loc(x_3d)
      case (4)
         call ESMF_FieldGet(x, farrayPtr = x_4d, _RC)
         cptr = c_loc(x_4d)
      case (5)
         call ESMF_FieldGet(x, farrayPtr = x_5d, _RC)
         cptr = c_loc(x_5d)
      case default
         _FAIL('Unsupported rank in FieldGetCptr().')
      end select

      _RETURN(_SUCCESS)
   end subroutine get_cptr_i4

   subroutine get_cptr_i8(x, cptr, rc)
      type(ESMF_Field), intent(inout) :: x
      type(c_ptr), intent(out) :: cptr
      integer, optional, intent(out) :: rc

      integer :: status
      integer :: rank
      integer(kind=ESMF_KIND_I8), pointer :: x_1d(:)
      integer(kind=ESMF_KIND_I8), pointer :: x_2d(:,:)
      integer(kind=ESMF_KIND_I8), pointer :: x_3d(:,:,:)
      integer(kind=ESMF_KIND_I8), pointer :: x_4d(:,:,:,:)
      integer(kind=ESMF_KIND_I8), pointer :: x_5d(:,:,:,:,:)

      call ESMF_FieldGet(x, rank=rank, _RC)

      select case (rank)
      case (1)
         call ESMF_FieldGet(x, farrayPtr = x_1d, _RC)
         cptr = c_loc(x_1d)
      case (2)
         call ESMF_FieldGet(x, farrayPtr = x_2d, _RC)
         cptr = c_loc(x_2d)
      case (3)
         call ESMF_FieldGet(x, farrayPtr = x_3d, _RC)
         cptr = c_loc(x_3d)
      case (4)
         call ESMF_FieldGet(x, farrayPtr = x_4d, _RC)
         cptr = c_loc(x_4d)
      case (5)
         call ESMF_FieldGet(x, farrayPtr = x_5d, _RC)
         cptr = c_loc(x_5d)
      case default
         _FAIL('Unsupported rank in FieldGetCptr().')
      end select

      _RETURN(_SUCCESS)
   end subroutine get_cptr_i8

   function get_local_element_count(x, rc) result(element_count)
      type(ESMF_Field), intent(inout) :: x
      integer, optional, intent(out) :: rc
      integer, allocatable :: element_count(:)

      integer :: status
      integer :: rank

      call ESMF_FieldGet(x, rank=rank, _RC)
      allocate(element_count(rank))
      ! ESMF has a big fat bug with multi tile grids and loal element count
      !call ESMF_FieldGet(x, localElementCount=element_count, _RC)
      ! until it is fixed we must kluge :(
      call MAPL_FieldGetLocalElementCount(x, element_count, _RC)

      _RETURN(_SUCCESS)
   end function get_local_element_count

   function get_local_size(x, rc) result(sz)
      integer(kind=ESMF_KIND_I8) :: sz
      type(ESMF_Field), intent(inout) :: x
      integer, optional, intent(out) :: rc

      integer :: status
      integer, allocatable :: element_count(:)

      sz = 0
      element_count = FieldGetLocalElementCount(x, _RC)
      sz = int(product(element_count), kind=ESMF_KIND_I8)

      _RETURN(_SUCCESS)
   end function get_local_size

   subroutine clone(x, y, rc)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_Field), intent(inout) :: y
      integer, optional, intent(out) :: rc

      character(len=*), parameter :: CLONE_TAG = '_clone'
      !type(ESMF_ArraySpec) :: arrayspec
      type(ESMF_Grid) :: grid
      type(ESMF_StaggerLoc) :: staggerloc
      integer, allocatable :: gridToFieldMap(:)
      integer, allocatable :: ungriddedLBound(:)
      integer, allocatable :: ungriddedUBound(:)
      type(ESMF_TypeKind_Flag) :: tk
      character(len=ESMF_MAXSTR) :: name
      integer :: status
      integer :: field_rank, grid_rank,ungrid_size
      type(ESMF_Index_Flag) :: index_flag
      real(kind=ESMF_KIND_R4), pointer      :: VR4_1D(:), VR4_2D(:,:), VR4_3D(:,:,:), VR4_4D(:,:,:,:)
      real(kind=ESMF_KIND_R8), pointer      :: VR8_1D(:), VR8_2D(:,:), VR8_3D(:,:,:), VR8_4D(:,:,:,:)
      integer, allocatable :: lc(:)

      call ESMF_FieldGet(x,grid=grid,rank=field_rank,_RC)
      lc = get_local_element_count(x,_RC)
      call ESMF_GridGet(grid,dimCount=grid_rank,indexFlag=index_flag,_RC)
      ungrid_size = field_rank-grid_rank
      allocate(gridToFieldMap(grid_rank))
      allocate(ungriddedLBound(ungrid_size),ungriddedUBound(ungrid_size))
      call ESMF_FieldGet(x, typekind=tk, name = name, &
         staggerloc=staggerloc, gridToFieldMap=gridToFieldMap, &
         ungriddedLBound=ungriddedLBound, ungriddedUBound=ungriddedUBound,  _RC)

      name = trim(name) // CLONE_TAG

      if (index_flag == ESMF_INDEX_USER) then
         if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 1) then
            allocate(VR4_1d(lc(1)),_STAT)
            y = ESMF_FieldCreate(grid,VR4_1d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 1) then
            allocate(VR8_1d(lc(1)),_STAT)
            y = ESMF_FieldCreate(grid,VR8_1d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 2) then
            allocate(VR4_2d(lc(1),lc(2)),_STAT)
            y = ESMF_FieldCreate(grid,VR4_2d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 2) then
            allocate(VR8_2d(lc(1),lc(2)),_STAT)
            y = ESMF_FieldCreate(grid,VR8_2d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 3) then
            allocate(VR4_3d(lc(1),lc(2),lc(3)),_STAT)
            y = ESMF_FieldCreate(grid,VR4_3d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 3) then
            allocate(VR8_3d(lc(1),lc(2),lc(3)),_STAT)
            y = ESMF_FieldCreate(grid,VR8_3d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else if (tk == ESMF_TYPEKIND_R4 .and. field_rank == 4) then
            allocate(VR4_4d(lc(1),lc(2),lc(3),lc(4)),_STAT)
            y = ESMF_FieldCreate(grid,VR4_4d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else if (tk == ESMF_TYPEKIND_R8 .and. field_rank == 4) then
            allocate(VR8_4d(lc(1),lc(2),lc(3),lc(4)),_STAT)
            y = ESMF_FieldCreate(grid,VR8_4d,gridToFieldMap=gridToFieldMap,name=name,_RC)
         else
            _FAIL( 'unsupported typekind+field_rank')
         end if
      else
         y = ESMF_FieldCreate(grid, tk, staggerloc=staggerloc, &
            gridToFieldMap=gridToFieldMap, ungriddedLBound=ungriddedLBound, &
            ungriddedUBound=ungriddedUBound, name=name, _RC)
      end if

      _RETURN(_SUCCESS)
   end subroutine clone

   logical function are_conformable_scalar(x, y, rc) result(conformable)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_Field), intent(inout) :: y
      integer, optional, intent(out) :: rc
      integer :: rank_x, rank_y
      integer, dimension(:), allocatable :: count_x, count_y
      integer :: status

      conformable = .false.

      call ESMF_FieldGet(x, rank=rank_x, _RC)
      call ESMF_FieldGet(y, rank=rank_y, _RC)

      if(rank_x == rank_y) then
         count_x = FieldGetLocalElementCount(x, _RC)
         count_y = FieldGetLocalElementCount(y, _RC)
         conformable = all(count_x == count_y)
      end if

      _RETURN(_SUCCESS)
   end function are_conformable_scalar

   logical function are_conformable_array(x, y, rc) result(conformable)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_Field), intent(inout) :: y(:)
      integer, optional, intent(out) :: rc

      integer :: status
      integer :: j
      logical :: element_not_conformable

      conformable = .false.
      element_not_conformable = .false.

      do j = 1, size(y)
         element_not_conformable = .not. FieldsAreConformable(x, y(j), _RC)
         if(element_not_conformable) return
      end do

      conformable = .true.

      _RETURN(_SUCCESS)
   end function are_conformable_array

   logical function are_broadcast_conformable(x, y, rc) result(conformable)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_Field), intent(inout) :: y
      integer, optional, intent(out) :: rc
      integer :: rank_x, rank_y
      integer, dimension(:), allocatable :: count_x, count_y
      integer :: status
      logical :: normal_conformable

      conformable = .false.
      ! this should really used the geom and ungridded dims
      ! for now we will do this until we have a geom agnostic stuff worked out...
      ! the ideal algorithm would be if geom == geom and input does not have ungridded
      ! and thing we are copying to does, then we are "conformable"
      normal_conformable = FIeldsAreConformable(x,y,_RC)

      if (normal_conformable) then
         conformable = .true.
         _RETURN(_SUCCESS)
      end if

      call ESMF_FieldGet(x, rank=rank_x, _RC)
      call ESMF_FieldGet(y, rank=rank_y, _RC)

      if( (rank_x+1) == rank_y) then
         count_x = FieldGetLocalElementCount(x, _RC)
         count_y = FieldGetLocalElementCount(y, _RC)
         conformable = all(count_x == count_y(:rank_y-1))
      end if

      _RETURN(_SUCCESS)
   end function are_broadcast_conformable

   logical function are_same_type_kind(x, y, rc) result(same_tk)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_Field), intent(inout) :: y
      integer, optional, intent(out) :: rc

      integer :: status
      type(ESMF_TypeKind_Flag) :: tk_x, tk_y

      same_tk = .false.
      call ESMF_FieldGet(x, typekind=tk_x, _RC)
      call ESMF_FieldGet(y, typekind=tk_y, _RC)

      same_tk = (tk_x == tk_y)

      _RETURN(_SUCCESS)
   end function are_same_type_kind

   subroutine verify_typekind_scalar(x, expected_tk, rc)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_TypeKind_Flag), intent(in) :: expected_tk
      integer, optional, intent(out) :: rc

      integer :: status

      type(ESMF_TypeKind_Flag) :: found_tk

      call ESMF_FieldGet(x, typekind=found_tk, _RC)

      _ASSERT((found_tk == expected_tk), 'Found incorrect typekind.')
      _RETURN(_SUCCESS)
   end subroutine verify_typekind_scalar

   subroutine verify_typekind_array(x, expected_tk, rc)
      type(ESMF_Field), intent(inout) :: x(:)
      type(ESMF_TypeKind_Flag), intent(in) :: expected_tk
      integer, optional, intent(out) :: rc

      integer :: status
      integer :: i

      do i = 1, size(x)
         call verify_typekind(x(i), expected_tk, _RC)
      end do
      _RETURN(_SUCCESS)
   end subroutine verify_typekind_array

   function is_valid_typekind(actual_tk, valid_tks) result(is_valid)
      type(ESMF_TypeKind_Flag), intent(in) :: actual_tk
      type(ESMF_TypeKind_Flag), intent(in) :: valid_tks(:)
      logical :: is_valid
      integer :: i

      is_valid = .FALSE.
      do i = 1, size(valid_tks)
         is_valid = (actual_tk == valid_tks(i))
         if(is_valid) return
      end do

   end function is_valid_typekind

   subroutine copy_broadcast(x, y, rc)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_Field), intent(inout) :: y
      integer, optional, intent(out) :: rc

      type(ESMF_TypeKind_Flag) :: tk_x, tk_y
      type(c_ptr) :: cptr_x, cptr_y
      integer(kind=ESMF_KIND_I8) :: n_input,n_extra
      integer :: status
      logical :: conformable, broadcast
      integer, allocatable :: x_shape(:), y_shape(:)
      logical :: x_is_double
      logical :: y_is_double
      character(len=*), parameter :: UNSUPPORTED_TK = &
         'Unsupported typekind in FieldCOPY() for '

      conformable = FieldsAreConformable(x, y)
      if (conformable) then
         call copy(x,y,_RC)
         _RETURN(_SUCCESS)
      end if
      broadcast = FieldsAreBroadcastConformable(x,y)
      _ASSERT(broadcast, 'FieldCopy() - field can not be broadcast.')

      call MAPL_FieldGetLocalElementCount(x,x_shape,_RC)
      call MAPL_FieldGetLocalElementCount(y,y_shape,_RC)
      call FieldGetCptr(x, cptr_x, _RC)
      call ESMF_FieldGet(x, typekind = tk_x, _RC)

      n_input = product(x_shape)
      n_extra = y_shape(size(y_shape))

      call FieldGetCptr(y, cptr_y, _RC)
      call ESMF_FieldGet(y, typekind = tk_y, _RC)

      y_is_double = (tk_y == ESMF_TYPEKIND_R8)
      _ASSERT(y_is_double .or. (tk_y == ESMF_TYPEKIND_R4), UNSUPPORTED_TK//'y.')

      x_is_double = (tk_x == ESMF_TYPEKIND_R8)
      _ASSERT(x_is_double .or. (tk_x == ESMF_TYPEKIND_R4), UNSUPPORTED_TK//'x.')

      if (y_is_double) then
         if (x_is_double) then
            call copy_bcast_r8_r8(cptr_x, cptr_y, n_input,n_extra)
         else
            call copy_bcast_r4_r8(cptr_x, cptr_y, n_input,n_extra)
         end if
      else
         if (x_is_double) then
            call copy_bcast_r8_r4(cptr_x, cptr_y, n_input,n_extra)
         else
            call copy_bcast_r4_r4(cptr_x, cptr_y, n_input,n_extra)
         end if
      end if

      _RETURN(_SUCCESS)
   end subroutine copy_broadcast

   subroutine copy_bcast_r4_r4(cptr_x, cptr_y, n1,n2)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n1,n2

      integer :: i

      real(kind=ESMF_KIND_R4), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R4), pointer :: y_ptr(:,:)

      call c_f_pointer(cptr_x, x_ptr, [n1])
      call c_f_pointer(cptr_y, y_ptr, [n1,n2])

      do i=1,n2
         y_ptr(:,i) = x_ptr
      enddo
   end subroutine copy_bcast_r4_r4

   subroutine copy_bcast_r4_r8(cptr_x, cptr_y, n1,n2)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n1,n2

      integer :: i

      real(kind=ESMF_KIND_R4), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R8), pointer :: y_ptr(:,:)

      call c_f_pointer(cptr_x, x_ptr, [n1])
      call c_f_pointer(cptr_y, y_ptr, [n1,n2])

      do i=1,n2
         y_ptr(:,i) = x_ptr
      enddo
   end subroutine copy_bcast_r4_r8

   subroutine copy_bcast_r8_r4(cptr_x, cptr_y, n1,n2)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n1,n2

      integer :: i

      real(kind=ESMF_KIND_R8), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R4), pointer :: y_ptr(:,:)

      call c_f_pointer(cptr_x, x_ptr, [n1])
      call c_f_pointer(cptr_y, y_ptr, [n1,n2])

      do i=1,n2
         y_ptr(:,i) = x_ptr
      enddo
   end subroutine copy_bcast_r8_r4

   subroutine copy_bcast_r8_r8(cptr_x, cptr_y, n1,n2)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n1,n2

      integer :: i

      real(kind=ESMF_KIND_R8), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R8), pointer :: y_ptr(:,:)

      call c_f_pointer(cptr_x, x_ptr, [n1])
      call c_f_pointer(cptr_y, y_ptr, [n1,n2])

      do i=1,n2
         y_ptr(:,i) = x_ptr
      enddo
   end subroutine copy_bcast_r8_r8

   subroutine copy(x, y, rc)
      type(ESMF_Field), intent(inout) :: x
      type(ESMF_Field), intent(inout) :: y
      integer, optional, intent(out) :: rc

      type(ESMF_TypeKind_Flag) :: tk_x, tk_y
      type(c_ptr) :: cptr_x, cptr_y
      integer(kind=ESMF_KIND_I8) :: n
      integer :: status
      logical :: conformable
      logical :: x_is_double
      logical :: y_is_double
      character(len=*), parameter :: UNSUPPORTED_TK = &
         'Unsupported typekind in FieldCOPY() for '

      conformable = FieldsAreConformable(x, y)
      !wdb fixme need to pass RC
      _ASSERT(conformable, 'FieldCopy() - fields not conformable.')
      call FieldGetCptr(x, cptr_x, _RC)
      call ESMF_FieldGet(x, typekind = tk_x, _RC)

      n  = FieldGetLocalSize(x, _RC)

      call FieldGetCptr(y, cptr_y, _RC)
      call ESMF_FieldGet(y, typekind = tk_y, _RC)

      !wdb  fixme convert between precisions ? get rid of extra cases
      y_is_double = (tk_y == ESMF_TYPEKIND_R8)
      _ASSERT(y_is_double .or. (tk_y == ESMF_TYPEKIND_R4), UNSUPPORTED_TK//'y.')

      x_is_double = (tk_x == ESMF_TYPEKIND_R8)
      _ASSERT(x_is_double .or. (tk_x == ESMF_TYPEKIND_R4), UNSUPPORTED_TK//'x.')

      if (y_is_double) then
         if (x_is_double) then
            call copy_r8_r8(cptr_x, cptr_y, n)
         else
            call copy_r4_r8(cptr_x, cptr_y, n)
         end if
      else
         if (x_is_double) then
            call copy_r8_r4(cptr_x, cptr_y, n)
         else
            call copy_r4_r4(cptr_x, cptr_y, n)
         end if
      end if

      _RETURN(_SUCCESS)
   end subroutine copy

   subroutine copy_r4_r4(cptr_x, cptr_y, n)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n

      real(kind=ESMF_KIND_R4), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R4), pointer :: y_ptr(:)

      call c_f_pointer(cptr_x, x_ptr, [n])
      call c_f_pointer(cptr_y, y_ptr, [n])

      y_ptr=x_ptr
   end subroutine copy_r4_r4

   subroutine copy_r4_r8(cptr_x, cptr_y, n)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n

      real(kind=ESMF_KIND_R4), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R8), pointer :: y_ptr(:)

      call c_f_pointer(cptr_x, x_ptr, [n])
      call c_f_pointer(cptr_y, y_ptr, [n])

      y_ptr=x_ptr
   end subroutine copy_r4_r8

   subroutine copy_r8_r4(cptr_x, cptr_y, n)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n

      real(kind=ESMF_KIND_R8), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R4), pointer :: y_ptr(:)

      call c_f_pointer(cptr_x, x_ptr, [n])
      call c_f_pointer(cptr_y, y_ptr, [n])

      y_ptr=x_ptr
   end subroutine copy_r8_r4

   subroutine copy_r8_r8(cptr_x, cptr_y, n)
      type(c_ptr), intent(in) :: cptr_x, cptr_y
      integer(ESMF_KIND_I8), intent(in) :: n

      real(kind=ESMF_KIND_R8), pointer :: x_ptr(:)
      real(kind=ESMF_KIND_R8), pointer :: y_ptr(:)

      call c_f_pointer(cptr_x, x_ptr, [n])
      call c_f_pointer(cptr_y, y_ptr, [n])

      y_ptr=x_ptr
   end subroutine copy_r8_r8

   ! this procedure must go away as soon as ESMF Fixes their bug

   subroutine MAPL_FieldGetLocalElementCount(field,local_count,rc)
      type(ESMF_Field), intent(inout) :: field
      integer, allocatable, intent(out) :: local_count(:)
      integer, optional, intent(out) :: rc

      integer :: status, rank
      type(ESMF_TypeKind_Flag) :: tk

      real(kind=ESMF_KIND_R4), pointer :: r4_1d(:),r4_2d(:,:),r4_3d(:,:,:),r4_4d(:,:,:,:)
      real(kind=ESMF_KIND_R8), pointer :: r8_1d(:),r8_2d(:,:),r8_3d(:,:,:),r8_4d(:,:,:,:)
      integer(kind=ESMF_KIND_I4), pointer :: i4_1d(:),i4_2d(:,:),i4_3d(:,:,:),i4_4d(:,:,:,:)
      integer(kind=ESMF_KIND_I8), pointer :: i8_1d(:),i8_2d(:,:),i8_3d(:,:,:),i8_4d(:,:,:,:)

      call ESMF_FieldGet(field,rank=rank,typekind=tk,_RC)

      if (tk == ESMF_TypeKind_R4) then
         select case(rank)
         case(1)
            call ESMF_FieldGet(field,0,farrayptr=r4_1d,_RC)
            local_count = shape(r4_1d)
         case(2)
            call ESMF_FieldGet(field,0,farrayptr=r4_2d,_RC)
            local_count = shape(r4_2d)
         case(3)
            call ESMF_FieldGet(field,0,farrayptr=r4_3d,_RC)
            local_count = shape(r4_3d)
         case(4)
            call ESMF_FieldGet(field,0,farrayptr=r4_4d,_RC)
            local_count = shape(r4_4d)
         case default
            _FAIL("Unsupported rank")
         end select
         _RETURN(_SUCCESS)
      end if
      
      if (tk == ESMF_TypeKind_R8) then
         select case(rank)
         case(1)
            call ESMF_FieldGet(field,0,farrayptr=r8_1d,_RC)
            local_count = shape(r8_1d)
         case(2)
            call ESMF_FieldGet(field,0,farrayptr=r8_2d,_RC)
            local_count = shape(r8_2d)
         case(3)
            call ESMF_FieldGet(field,0,farrayptr=r8_3d,_RC)
            local_count = shape(r8_3d)
         case(4)
            call ESMF_FieldGet(field,0,farrayptr=r8_4d,_RC)
            local_count = shape(r8_4d)
         case default
            _FAIL("Unsupported rank")
         end select
         _RETURN(_SUCCESS)
      end if

      if (tk == ESMF_TypeKind_I4) then
         select case(rank)
         case(1)
            call ESMF_FieldGet(field,0,farrayptr=i4_1d,_RC)
            local_count = shape(i4_1d)
         case(2)
            call ESMF_FieldGet(field,0,farrayptr=i4_2d,_RC)
            local_count = shape(i4_2d)
         case(3)
            call ESMF_FieldGet(field,0,farrayptr=i4_3d,_RC)
            local_count = shape(i4_3d)
         case(4)
            call ESMF_FieldGet(field,0,farrayptr=i4_4d,_RC)
            local_count = shape(i4_4d)
         case default
            _FAIL("Unsupported rank")
         end select
         _RETURN(_SUCCESS)
      end if

      if (tk == ESMF_TypeKind_I8) then
         select case(rank)
         case(1)
            call ESMF_FieldGet(field,0,farrayptr=i8_1d,_RC)
            local_count = shape(i8_1d)
         case(2)
            call ESMF_FieldGet(field,0,farrayptr=i8_2d,_RC)
            local_count = shape(i8_2d)
         case(3)
            call ESMF_FieldGet(field,0,farrayptr=i8_3d,_RC)
            local_count = shape(i8_3d)
         case(4)
            call ESMF_FieldGet(field,0,farrayptr=i8_4d,_RC)
            local_count = shape(i8_4d)
         case default
            _FAIL("Unsupported rank")
         end select
      end if

      ! If you made it this far, you had an unsupported type.
      _FAIL("Unsupported type")

      _RETURN(_SUCCESS)

   end subroutine MAPL_FieldGetLocalElementCount

   function FieldsHaveUndef(fields,rc) result(all_have_undef)
      logical :: all_have_undef
      type(ESMF_Field), intent(inout) :: fields(:)
      integer, optional, intent(out) :: rc

      integer :: status, i
      logical :: isPresent
      type(ESMF_Info) :: infoh

      all_have_undef = .true.
      do i =1,size(fields)
         call ESMF_InfoGetFromHost(fields(i),infoh,_RC)
         isPresent = ESMF_InfoIsPresent(infoh,"missing_value",_RC)
         all_have_undef = (all_have_undef .and. isPresent)
      enddo
      _RETURN(_SUCCESS)
   end function

   subroutine GetFieldsUndef_r4(fields,undef_values,rc)
      type(ESMF_Field), intent(inout) :: fields(:)
      real(kind=ESMF_KIND_R4), allocatable,intent(inout) :: undef_values(:)
      integer, optional, intent(out) :: rc

      integer :: status, i
      logical :: isPresent
      type(ESMF_Info) :: infoh

      allocate(undef_values(size(fields)))
      do i =1,size(fields)
         call ESMF_InfoGetFromHost(fields(i),infoh,_RC)
         isPresent = ESMF_InfoIsPresent(infoh,"missing_value",_RC)
         _ASSERT(isPresent,"missing undef value")
         call ESMF_InfoGet(infoh,value=undef_values(i),key="missing_value",_RC)
      enddo
      _RETURN(_SUCCESS)
   end subroutine GetFieldsUndef_r4

   subroutine GetFieldsUndef_r8(fields,undef_values,rc)
      type(ESMF_Field), intent(inout) :: fields(:)
      real(kind=ESMF_KIND_R8), allocatable,intent(inout) :: undef_values(:)
      integer, optional, intent(out) :: rc

      integer :: status, i
      logical :: isPresent
      type(ESMF_Info) :: infoh

      allocate(undef_values(size(fields)))
      do i =1,size(fields)
         call ESMF_InfoGetFromHost(fields(i),infoh,_RC)
         isPresent = ESMF_InfoIsPresent(infoh,"missing_value",_RC)
         _ASSERT(isPresent,"missing undef value")
         call ESMF_InfoGet(infoh,value=undef_values(i),key="missing_value",_RC)
      enddo
      _RETURN(_SUCCESS)
   end subroutine GetFieldsUndef_r8

   subroutine Destroy(Field,RC)
      type(ESMF_Field),          intent(INOUT) :: Field
      integer, optional,         intent(OUT  ) :: RC

      integer                               :: STATUS

      real(kind=ESMF_KIND_R4), pointer      :: VR4_1D(:), VR4_2D(:,:), VR4_3D(:,:,:), VR4_4D(:,:,:,:)
      real(kind=ESMF_KIND_R8), pointer      :: VR8_1D(:), VR8_2D(:,:), VR8_3D(:,:,:), VR8_4D(:,:,:,:)
      integer                      :: rank
      type(ESMF_TypeKind_Flag)     :: tk
      logical :: esmf_allocated

      call ESMF_FieldGet(Field,typekind=tk,dimCount=rank,isESMFAllocated=esmf_allocated,_RC)
      if (.not. esmf_allocated) then
         if (tk == ESMF_TYPEKIND_R4 .and. rank == 1) then
            call ESMF_FieldGet(Field,0,VR4_1d,_RC)
            deallocate(VR4_1d,_STAT)
         else if (tk == ESMF_TYPEKIND_R8 .and. rank == 1) then
            call ESMF_FieldGet(Field,0,VR8_1d,_RC)
            deallocate(VR8_1d,_STAT)
         else if (tk == ESMF_TYPEKIND_R4 .and. rank == 2) then
            call ESMF_FieldGet(Field,0,VR4_2d,_RC)
            deallocate(VR4_2d,_STAT)
         else if (tk == ESMF_TYPEKIND_R8 .and. rank == 2) then
            call ESMF_FieldGet(Field,0,VR8_2d,_RC)
            deallocate(VR8_2d,_STAT)
         else if (tk == ESMF_TYPEKIND_R4 .and. rank == 3) then
            call ESMF_FieldGet(Field,0,VR4_3D,_RC)
            deallocate(VR4_3d,_STAT)
         else if (tk == ESMF_TYPEKIND_R8 .and. rank == 3) then
            call ESMF_FieldGet(Field,0,VR8_3D,_RC)
            deallocate(VR8_3d,_STAT)
         else if (tk == ESMF_TYPEKIND_R4 .and. rank == 4) then
            call ESMF_FieldGet(Field,0,VR4_4D,_RC)
            deallocate(VR4_3d,_STAT)
         else if (tk == ESMF_TYPEKIND_R8 .and. rank == 4) then
            call ESMF_FieldGet(Field,0,VR8_4D,_RC)
            deallocate(VR8_3d,_STAT)
         else
            _FAIL( 'unsupported typekind+rank')
         end if
      end if
      call ESMF_FieldDestroy(Field,noGarbage = .true., rc=status)
      _VERIFY(STATUS)
      _RETURN(ESMF_SUCCESS)

   end subroutine Destroy

   subroutine assign_fptr_i4_rank1(x, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      integer(kind=ESMF_KIND_I4), pointer, intent(out) :: fptr(:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer(ESMF_KIND_I8), allocatable :: fp_shape(:)
      integer(ESMF_KIND_I8) :: local_size
      integer :: status

      local_size = FieldGetLocalSize(x, _RC)
      fp_shape = [ local_size ]
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_i4_rank1

   subroutine assign_fptr_i8_rank1(x, fptr, rc)
      type(ESMF_Field), intent(inout) :: x
      integer(kind=ESMF_KIND_I8), pointer, intent(out) :: fptr(:)
      integer, optional, intent(out) :: rc

      ! local declarations
      type(c_ptr) :: cptr
      integer(ESMF_KIND_I8), allocatable :: fp_shape(:)
      integer(ESMF_KIND_I8) :: local_size
      integer :: status

      local_size = FieldGetLocalSize(x, _RC)
      fp_shape = [ local_size ]
      call FieldGetCptr(x, cptr, _RC)
      call c_f_pointer(cptr, fptr, fp_shape)

      _RETURN(_SUCCESS)
   end subroutine assign_fptr_i8_rank1

end module MAPL_FieldPointerUtilities