MAPL_XYGridFactory.F90 Source File


This file depends on

sourcefile~~mapl_xygridfactory.f90~~EfferentGraph sourcefile~mapl_xygridfactory.f90 MAPL_XYGridFactory.F90 sourcefile~base_base.f90 Base_Base.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~base_base.f90 sourcefile~constants.f90 Constants.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~constants.f90 sourcefile~mapl_abstractgridfactory.f90 MAPL_AbstractGridFactory.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~mapl_abstractgridfactory.f90 sourcefile~mapl_comms.f90 MAPL_Comms.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~mapl_comms.f90 sourcefile~mapl_config.f90 MAPL_Config.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~mapl_config.f90 sourcefile~mapl_exceptionhandling.f90 MAPL_ExceptionHandling.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~mapl_io.f90 MAPL_IO.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~mapl_io.f90 sourcefile~mapl_keywordenforcer.f90 MAPL_KeywordEnforcer.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~mapl_keywordenforcer.f90 sourcefile~mapl_obsutil.f90 MAPL_ObsUtil.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~mapl_obsutil.f90 sourcefile~pfio.f90 pFIO.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~pfio.f90 sourcefile~plain_netcdf_time.f90 Plain_netCDF_Time.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~plain_netcdf_time.f90 sourcefile~shmem.f90 Shmem.F90 sourcefile~mapl_xygridfactory.f90->sourcefile~shmem.f90

Files dependent on this one

sourcefile~~mapl_xygridfactory.f90~~AfferentGraph sourcefile~mapl_xygridfactory.f90 MAPL_XYGridFactory.F90 sourcefile~mapl_gridmanager.f90 MAPL_GridManager.F90 sourcefile~mapl_gridmanager.f90->sourcefile~mapl_xygridfactory.f90 sourcefile~base.f90 Base.F90 sourcefile~base.f90->sourcefile~mapl_gridmanager.f90 sourcefile~cfiocollection.f90 CFIOCollection.F90 sourcefile~cfiocollection.f90->sourcefile~mapl_gridmanager.f90 sourcefile~comp_testing_driver.f90 Comp_Testing_Driver.F90 sourcefile~comp_testing_driver.f90->sourcefile~mapl_gridmanager.f90 sourcefile~datacollection.f90 DataCollection.F90 sourcefile~datacollection.f90->sourcefile~mapl_gridmanager.f90 sourcefile~esmfl_mod.f90 ESMFL_Mod.F90 sourcefile~esmfl_mod.f90->sourcefile~mapl_gridmanager.f90 sourcefile~extdatagridcompmod.f90 ExtDataGridCompMod.F90 sourcefile~extdatagridcompmod.f90->sourcefile~mapl_gridmanager.f90 sourcefile~extdatagridcompng.f90 ExtDataGridCompNG.F90 sourcefile~extdatagridcompng.f90->sourcefile~mapl_gridmanager.f90 sourcefile~fieldbundleread.f90 FieldBundleRead.F90 sourcefile~fieldbundleread.f90->sourcefile~mapl_gridmanager.f90 sourcefile~filemetadatautilities.f90 FileMetadataUtilities.F90 sourcefile~filemetadatautilities.f90->sourcefile~mapl_gridmanager.f90 sourcefile~griddedio.f90 GriddedIO.F90 sourcefile~griddedio.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_bundleio_test.f90 mapl_bundleio_test.F90 sourcefile~mapl_bundleio_test.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_capgridcomp.f90 MAPL_CapGridComp.F90 sourcefile~mapl_capgridcomp.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_cfio.f90 MAPL_CFIO.F90 sourcefile~mapl_cfio.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_epochswathmod.f90 MAPL_EpochSwathMod.F90 sourcefile~mapl_epochswathmod.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_esmfregridder.f90 MAPL_EsmfRegridder.F90 sourcefile~mapl_esmfregridder.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_generic.f90 MAPL_Generic.F90 sourcefile~mapl_generic.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_historycollection.f90 MAPL_HistoryCollection.F90 sourcefile~mapl_historycollection.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_historygridcomp.f90 MAPL_HistoryGridComp.F90 sourcefile~mapl_historygridcomp.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_regriddermanager.f90 MAPL_RegridderManager.F90 sourcefile~mapl_regriddermanager.f90->sourcefile~mapl_gridmanager.f90 sourcefile~mapl_tilingregridder.f90 MAPL_TilingRegridder.F90 sourcefile~mapl_tilingregridder.f90->sourcefile~mapl_gridmanager.f90 sourcefile~newregriddermanager.f90 NewRegridderManager.F90 sourcefile~newregriddermanager.f90->sourcefile~mapl_gridmanager.f90 sourcefile~regrid_util.f90 Regrid_Util.F90 sourcefile~regrid_util.f90->sourcefile~mapl_gridmanager.f90 sourcefile~regridderspec.f90 RegridderSpec.F90 sourcefile~regridderspec.f90->sourcefile~mapl_gridmanager.f90 sourcefile~test_gridmanager.pf Test_GridManager.pf sourcefile~test_gridmanager.pf->sourcefile~mapl_gridmanager.f90

Source Code

#include "MAPL_Exceptions.h"
#include "MAPL_ErrLog.h"
#include "unused_dummy.H"

module MAPL_XYGridFactoryMod
   use MAPL_AbstractGridFactoryMod
   use MAPL_KeywordEnforcerMod
   use MAPL_ExceptionHandling
   use MAPL_ShmemMod
   use MAPL_Constants
   use MAPL_CommsMod
   use MAPL_BaseMod
   use ESMF
   use pFIO
   use NetCDF
   !   use Plain_netCDF_Time, only : get_ncfile_dimension
   use Plain_netCDF_Time
   use MAPL_ObsUtilMod, only : ABI_XY_2_lonlat
   use, intrinsic :: iso_fortran_env, only: REAL32
   use, intrinsic :: iso_fortran_env, only: REAL64
   implicit none
   private

   public :: XYGridFactory

   integer, parameter :: NUM_DIM = 2

   type, extends(AbstractGridFactory) :: XYGridFactory
      private
      character(len=:), allocatable :: grid_file_name
      character(len=:), allocatable :: grid_name
      ! Grid dimensions
      integer :: im_world = MAPL_UNDEFINED_INTEGER
      integer :: jm_world = MAPL_UNDEFINED_INTEGER
      integer :: lm
      ! Domain decomposition:
      integer :: nx = MAPL_UNDEFINED_INTEGER
      integer :: ny = MAPL_UNDEFINED_INTEGER
      integer, allocatable :: ims(:)
      integer, allocatable :: jms(:)
      logical :: has_corners

      logical :: initialized_from_metadata = .false.

      character(len=ESMF_MAXSTR) :: index_name_x
      character(len=ESMF_MAXSTR) :: index_name_y
      character(len=ESMF_MAXSTR) :: var_name_x
      character(len=ESMF_MAXSTR) :: var_name_y
      character(len=ESMF_MAXSTR) :: var_name_proj
      character(len=ESMF_MAXSTR) :: att_name_proj

      integer :: xdim_true
      integer :: ydim_true
      integer :: thin_factor
   contains
      procedure :: make_new_grid
      procedure :: create_basic_grid
      procedure :: add_horz_coordinates_from_file
      procedure :: add_horz_coordinates_from_ABIfile
      procedure :: init_halo
      procedure :: halo

      procedure :: initialize_from_file_metadata
      procedure :: initialize_from_config_with_prefix
      procedure :: initialize_from_esmf_distGrid

      procedure :: equals

      procedure :: check_and_fill_consistency
      procedure :: generate_grid_name
      procedure :: to_string

      procedure :: append_metadata
      procedure :: get_grid_vars
      procedure :: get_file_format_vars
      procedure :: append_variable_metadata
      procedure :: generate_file_bounds
      procedure :: generate_file_corner_bounds
      procedure :: generate_file_reference2D
      procedure :: generate_file_reference3D
      procedure :: decomps_are_equal
      procedure :: physical_params_are_equal
      procedure :: file_has_corners
      procedure :: add_mask
   end type XYGridFactory

   character(len=*), parameter :: MOD_NAME = 'MAPL_XYGridFactory::'

   interface XYGridFactory
      module procedure XYGridFactory_from_parameters
   end interface XYGridFactory

   interface set_with_default
      module procedure set_with_default_integer
      module procedure set_with_default_character
   end interface set_with_default


contains

   function XYGridFactory_from_parameters(unusable, grid_file_name, grid_name, &
        & im_world,jm_world,lm,nx, ny, rc) result(factory)
      type (XYGridFactory) :: factory
      class (KeywordEnforcer), optional, intent(in) :: unusable

      ! grid details:
      character(len=*), intent(in) :: grid_file_name ! required
      character(len=*), optional, intent(in) :: grid_name
      integer, optional, intent(in) :: im_world
      integer, optional, intent(in) :: jm_world
      integer, optional, intent(in) :: lm

      ! decomposition:
      integer, optional, intent(in) :: nx
      integer, optional, intent(in) :: ny
      integer, optional, intent(out) :: rc

      integer :: status
      character(len=*), parameter :: Iam = MOD_NAME // 'XYGridFactory_from_parameters'

      if (present(unusable)) print*,shape(unusable)

      call set_with_default(factory%grid_name, grid_name, MAPL_GRID_NAME_DEFAULT)
      call set_with_default(factory%grid_file_name, grid_file_name, MAPL_GRID_FILE_NAME_DEFAULT)

      call set_with_default(factory%ny, nx, MAPL_UNDEFINED_INTEGER)
      call set_with_default(factory%nx, ny, MAPL_UNDEFINED_INTEGER)
      call set_with_default(factory%im_world, im_world, MAPL_UNDEFINED_INTEGER)
      call set_with_default(factory%jm_world, jm_world, MAPL_UNDEFINED_INTEGER)
      call set_with_default(factory%lm, lm, MAPL_UNDEFINED_INTEGER)

      call factory%check_and_fill_consistency(rc=status)
      _VERIFY(status)
      _RETURN(_SUCCESS)

   end function XYGridFactory_from_parameters


   function make_new_grid(this, unusable, rc) result(grid)
      type (ESMF_Grid) :: grid
      class (XYGridFactory), intent(in) :: this
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      integer :: status
      character(len=*), parameter :: Iam = MOD_NAME // 'make_geos_grid'

      _UNUSED_DUMMY(unusable)

      grid = this%create_basic_grid(_RC)
      if ( index(trim(adjustl(this%grid_name)), 'ABI') == 0 ) then
         call this%add_horz_coordinates_from_file(grid, _RC)
      else
         call this%add_horz_coordinates_from_ABIfile(grid, _RC)
      end if
      call this%add_mask(grid,_RC)

      _RETURN(_SUCCESS)

   end function make_new_grid



   function create_basic_grid(this, unusable, rc) result(grid)
      type (ESMF_Grid) :: grid
      class (XYGridFactory), intent(in) :: this
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      integer :: status
      character(len=*), parameter :: Iam = MOD_NAME // 'create_basic_grid'

      _UNUSED_DUMMY(unusable)

       grid = ESMF_GridCreateNoPeriDim( &
            name=trim(this%grid_name) ,&
            countsPerDEDim1=this%ims, &
            countsPerDEDim2=this%jms, &
            indexFlag=ESMF_INDEX_DELOCAL, &
            gridEdgeLWidth=[0,0], &
            gridEdgeUWidth=[0,1], &
            coordDep1=[1,2], &
            coordDep2=[1,2], &
            coordSys=ESMF_COORDSYS_SPH_RAD, _RC)

      ! Allocate coords at default stagger location
      call ESMF_GridAddCoord(grid, rc=status)
      _VERIFY(status)
      if (this%has_corners) then
         call ESMF_GridAddCoord(grid, staggerloc=ESMF_STAGGERLOC_CORNER, rc=status)
      end if

      _VERIFY(status)

      if (this%lm /= MAPL_UNDEFINED_INTEGER) then
         call ESMF_AttributeSet(grid, name='GRID_LM', value=this%lm, _RC)
      end if

      call ESMF_AttributeSet(grid, 'GridType', 'XY', _RC)

      _RETURN(_SUCCESS)
   end function create_basic_grid


   subroutine add_horz_coordinates_from_file(this, grid, unusable, rc)
      use MAPL_BaseMod, only: MAPL_grid_interior, MAPL_gridget
      use MAPL_CommsMod
      use MAPL_IOMod
      use MAPL_Constants
      class (XYGridFactory), intent(in) :: this
      type (ESMF_Grid), intent(inout) :: grid
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      integer :: status
      character(len=*), parameter :: Iam = MOD_NAME // 'add_horz_coordinates'

      integer :: i_1,i_n,j_1,j_n, ncid, varid
      integer :: ic_1,ic_n,jc_1,jc_n ! regional corner bounds
      real, pointer :: centers(:,:), corners(:,:)
      real(ESMF_KIND_R8), pointer :: fptr(:,:)

      integer :: IM, JM
      integer :: IM_WORLD, JM_WORLD
      integer :: COUNTS(3), DIMS(3)
      character(len=:), allocatable :: lon_center_name, lat_center_name, lon_corner_name, lat_corner_name

      _UNUSED_DUMMY(unusable)

       lon_center_name = "lons"
       lat_center_name = "lats"
       lon_corner_name = "corner_lons"
       lat_corner_name = "corner_lats"
       call MAPL_GridGet(GRID, localCellCountPerDim=COUNTS, globalCellCountPerDim=DIMS, RC=STATUS)
       _VERIFY(STATUS)
       IM = COUNTS(1)
       JM = COUNTS(2)
       IM_WORLD = DIMS(1)
       JM_WORLD = DIMS(2)
       call MAPL_Grid_Interior(grid, i_1, i_n, j_1, j_n)

       ic_1=i_1
       ic_n=i_n

       jc_1=j_1
       if (j_n == this%jm_world) then
          jc_n=j_n+1
       else
          jc_n=j_n
       end if

       if (MAPL_AmNodeRoot .or. (.not. MAPL_ShmInitialized)) then
          status = nf90_open(this%grid_file_name,NF90_NOWRITE,ncid)
          _VERIFY(status)
       end if

       call MAPL_AllocateShared(centers,[im_world,jm_world],transroot=.true.,_RC)

       call MAPL_SyncSharedMemory(_RC)

       ! do longitudes
       if (MAPL_AmNodeRoot .or. (.not. MAPL_ShmInitialized)) then
          status = nf90_inq_varid(ncid,lon_center_name,varid)
          _VERIFY(status)
          status = nf90_get_var(ncid,varid,centers)
          _VERIFY(status)
          where(centers /= MAPL_UNDEF) centers=centers*MAPL_DEGREES_TO_RADIANS_R8
       end if
       call MAPL_SyncSharedMemory(_RC)

       call ESMF_GridGetCoord(grid, coordDim=1, localDE=0, &
          staggerloc=ESMF_STAGGERLOC_CENTER, &
          farrayPtr=fptr, rc=status)
       fptr=centers(i_1:i_n,j_1:j_n)
       ! do latitudes

       call MAPL_SyncSharedMemory(_RC)
       if (MAPL_AmNodeRoot .or. (.not. MAPL_ShmInitialized)) then
          status = nf90_inq_varid(ncid,lat_center_name,varid)
          _VERIFY(status)
          status = nf90_get_var(ncid,varid,centers)
          _VERIFY(status)
          where(centers /= MAPL_UNDEF) centers=centers*MAPL_DEGREES_TO_RADIANS_R8
       end if
       call MAPL_SyncSharedMemory(_RC)

       call ESMF_GridGetCoord(grid, coordDim=2, localDE=0, &
          staggerloc=ESMF_STAGGERLOC_CENTER, &
          farrayPtr=fptr, rc=status)
       fptr=centers(i_1:i_n,j_1:j_n)

       call MAPL_SyncSharedMemory(_RC)
       if(MAPL_ShmInitialized) then
          call MAPL_DeAllocNodeArray(centers,_RC)
       else
          deallocate(centers)
       end if
       !! now repeat for corners
       if (this%has_corners) then
          call MAPL_AllocateShared(corners,[im_world+1,jm_world+1],transroot=.true.,_RC)

          ! do longitudes

          call MAPL_SyncSharedMemory(_RC)
          if (MAPL_AmNodeRoot .or. (.not. MAPL_ShmInitialized)) then
             status = nf90_inq_varid(ncid,lon_corner_name,varid)
             _VERIFY(status)
             status = nf90_get_var(ncid,varid,corners)
             _VERIFY(status)
             where(corners /= MAPL_UNDEF) corners=corners*MAPL_DEGREES_TO_RADIANS_R8
          end if
          call MAPL_SyncSharedMemory(_RC)

          call ESMF_GridGetCoord(grid, coordDim=1, localDE=0, &
             staggerloc=ESMF_STAGGERLOC_CORNER, &
             farrayPtr=fptr, _RC)
          fptr=corners(ic_1:ic_n,jc_1:jc_n)
          ! do latitudes

          call MAPL_SyncSharedMemory(_RC)
          if (MAPL_AmNodeRoot .or. (.not. MAPL_ShmInitialized)) then
             status = nf90_inq_varid(ncid,lat_corner_name,varid)
             _VERIFY(status)
             status = nf90_get_var(ncid,varid,corners)
             _VERIFY(status)
             where(corners /= MAPL_UNDEF) corners=corners*MAPL_DEGREES_TO_RADIANS_R8
          end if
          call MAPL_SyncSharedMemory(_RC)

          call ESMF_GridGetCoord(grid, coordDim=2, localDE=0, &
             staggerloc=ESMF_STAGGERLOC_CORNER, &
             farrayPtr=fptr, _RC)
          fptr=corners(ic_1:ic_n,jc_1:jc_n)

          call MAPL_SyncSharedMemory(_RC)
          if(MAPL_ShmInitialized) then
             call MAPL_DeAllocNodeArray(corners,_RC)
          else
             deallocate(corners)
          end if

      end if
      if (MAPL_AmNodeRoot .or. (.not. MAPL_ShmInitialized)) then
         status=nf90_close(ncid)
         _VERIFY(status)
      end if

      _RETURN(_SUCCESS)

   end subroutine add_horz_coordinates_from_file


   subroutine add_horz_coordinates_from_ABIfile(this, grid, unusable, rc)
      use MAPL_CommsMod
      use MAPL_IOMod
      use MAPL_Constants
      class (XYGridFactory), intent(in) :: this
      type (ESMF_Grid), intent(inout) :: grid
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc
      integer :: status

      type(ESMF_VM) :: vm
      integer :: i, j
      integer :: ix, jx
      integer :: i_1, i_n, j_1, j_n
      real(REAL64), pointer :: fptr_x(:,:)   ! lon
      real(REAL64), pointer :: fptr_y(:,:)   ! lat
      real(REAL64), pointer :: x(:)
      real(REAL64), pointer :: y(:)
      real(REAL64), pointer :: lambda0(:)
      real(REAL64) :: lambda0_deg
      real(REAL64) :: x0, y0
      real(REAL64) :: lam_sat
      character(len=ESMF_MAXSTR) :: fn, key_x, key_y, key_p, key_p_att

      _UNUSED_DUMMY(unusable)

      call MAPL_Grid_Interior (grid, i_1, i_n, j_1, j_n)
      call MAPL_AllocateShared(x,[this%Xdim_true],transroot=.true.,_RC)
      call MAPL_AllocateShared(y,[this%Ydim_true],transroot=.true.,_RC)
      call MAPL_AllocateShared(lambda0,[1],transroot=.true.,_RC)
      call MAPL_SyncSharedMemory(_RC)

      if (mapl_am_i_root()) then
         fn    = this%grid_file_name
         key_x = this%var_name_x
         key_y = this%var_name_y
         key_p = this%var_name_proj
         key_p_att = this%att_name_proj
         call get_v1d_netcdf_R8_complete (fn, key_x, x, _RC)
         call get_v1d_netcdf_R8_complete (fn, key_y, y, _RC)
         call get_att_real_netcdf (fn, key_p, key_p_att, lambda0_deg, _RC)
         lambda0 = lambda0_deg*MAPL_DEGREES_TO_RADIANS_R8
      end if
      call MAPL_SyncSharedMemory(_RC)

      call ESMF_VMGetCurrent(vm, _RC)
      call MAPL_BcastShared (vm, data=x, N=this%Xdim_true, Root=MAPL_ROOT, RootOnly=.false., _RC)
      call MAPL_BcastShared (vm, data=y, N=this%Ydim_true, Root=MAPL_ROOT, RootOnly=.false., _RC)
      call MAPL_BcastShared (vm, data=lambda0, N=1,        Root=MAPL_ROOT, RootOnly=.false., _RC)

      call ESMF_GridGetCoord(grid, coordDim=1, localDE=0, &
           staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=fptr_x, _RC)
      call ESMF_GridGetCoord(grid, coordDim=2, localDE=0, &
           staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=fptr_y, _RC)
      lam_sat = lambda0(1)
      do i = i_1, i_n
         ix = i - i_1 + 1
         do j= j_1, j_n
            jx = j - j_1 + 1
            x0 = x( i * this%thin_factor )
            y0 = y( j * this%thin_factor )
            call ABI_XY_2_lonlat (x0, y0, lam_sat, fptr_x(ix, jx), fptr_y(ix, jx) )
         end do
      end do
      call MAPL_SyncSharedMemory(_RC)

      if(MAPL_ShmInitialized) then
         call MAPL_DeAllocNodeArray(x,_RC)
         call MAPL_DeAllocNodeArray(y,_RC)
      else
         deallocate(x)
         deallocate(y)
      end if

      _RETURN(_SUCCESS)

    end subroutine add_horz_coordinates_from_ABIfile


   subroutine initialize_from_file_metadata(this, file_metadata, unusable, force_file_coordinates, rc)
      use MAPL_KeywordEnforcerMod
      use MAPL_BaseMod, only: MAPL_DecomposeDim
      class (XYGridFactory), intent(inout)  :: this
      type (FileMetadata), target, intent(in) :: file_metadata
      class (KeywordEnforcer), optional, intent(in) :: unusable
      logical, optional, intent(in) :: force_file_coordinates
      integer, optional, intent(out) :: rc

      integer :: status

      this%im_world = file_metadata%get_dimension('Xdim',_RC)
      this%jm_world = file_Metadata%get_dimension('Ydim',_RC)
      if (file_metadata%has_dimension('lev')) then
         this%lm = file_metadata%get_dimension('lev',_RC)
      end if

      this%grid_file_name=file_metadata%get_source_file()

      this%initialized_from_metadata = .true.
      call this%make_arbitrary_decomposition(this%nx, this%ny, rc=status)
      _VERIFY(status)

      ! Determine IMS and JMS with constraint for ESMF that each DE has at least an extent
      ! of 2.  Required for ESMF_FieldRegrid().
      allocate(this%ims(0:this%nx-1))
      allocate(this%jms(0:this%ny-1))
      call MAPL_DecomposeDim(this%im_world, this%ims, this%nx, min_DE_extent=2)
      call MAPL_DecomposeDim(this%jm_world, this%jms, this%ny, min_DE_extent=2)

      call this%check_and_fill_consistency(rc=status)
      _VERIFY(status)

      _UNUSED_DUMMY(this)
      _UNUSED_DUMMY(unusable)
      _UNUSED_DUMMY(rc)
      _UNUSED_DUMMY(force_file_coordinates)

   end subroutine initialize_from_file_metadata

   subroutine initialize_from_config_with_prefix(this, config, prefix, unusable, rc)
      use esmf
      class (XYGridFactory), intent(inout) :: this
      type (ESMF_Config), intent(inout) :: config
      character(len=*), intent(in) :: prefix  ! effectively optional due to overload without this argument
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      integer :: status
      character(len=*), parameter :: Iam = MOD_NAME//'make_geos_grid_from_config'
      character(len=ESMF_MAXSTR) :: tmp
      integer :: n1, n2
      integer :: arr(2)
      type(ESMF_VM) :: vm

      if (present(unusable)) print*,shape(unusable)

      call ESMF_ConfigGetAttribute(config, tmp, label=prefix//'GRIDNAME:', default=MAPL_GRID_NAME_DEFAULT, _RC)
      this%grid_name = trim(tmp)
      call ESMF_ConfigGetAttribute(config, tmp, label=prefix//'GRID_FILENAME:', default='', _RC)
      this%grid_file_name = trim(tmp)

      call ESMF_ConfigGetAttribute(config, this%nx, label=prefix//'NX:', default=MAPL_UNDEFINED_INTEGER, _RC)
      call ESMF_ConfigGetAttribute(config, this%ny, label=prefix//'NY:', default=MAPL_UNDEFINED_INTEGER, _RC)
      call ESMF_ConfigGetAttribute(config, this%lm, label=prefix//'LM:', default=MAPL_UNDEFINED_INTEGER, _RC)

      call ESMF_ConfigGetAttribute(config, this%index_name_x, label=prefix//'index_name_x:', default="x", _RC)
      call ESMF_ConfigGetAttribute(config, this%index_name_y, label=prefix//'index_name_y:', default="y", _RC)
      call ESMF_ConfigGetAttribute(config, this%var_name_x,   label=prefix//'var_name_x:',   default="x", _RC)
      call ESMF_ConfigGetAttribute(config, this%var_name_y,   label=prefix//'var_name_y:',   default="y", _RC)
      call ESMF_ConfigGetAttribute(config, this%var_name_proj,label=prefix//'var_name_proj:',default="",  _RC)
      call ESMF_ConfigGetAttribute(config, this%att_name_proj,label=prefix//'att_name_proj:',default="",  _RC)
      call ESMF_ConfigGetAttribute(config, this%thin_factor,  label=prefix//'thin_factor:',  default=1,   _RC)

      if (mapl_am_i_root()) then
         call get_ncfile_dimension(this%grid_file_name, nlon=n1, nlat=n2, &
              key_lon=this%index_name_x, key_lat=this%index_name_y, _RC)
         arr(1)=n1
         arr(2)=n2
      end if
      call ESMF_VMGetCurrent(vm,_RC)
      call ESMF_VMBroadcast (vm, arr, 2, 0, _RC)
      !
      ! use thin_factor to reduce regridding matrix size
      !
      this%xdim_true = arr(1)
      this%ydim_true = arr(2)
      this%im_world  = arr(1) / this%thin_factor
      this%jm_world  = arr(2) / this%thin_factor

      call this%check_and_fill_consistency(rc=status)

      _RETURN(_SUCCESS)

    contains

      subroutine get_multi_integer(values, label, rc)
         integer, allocatable, intent(out) :: values(:)
         character(len=*) :: label
         integer, optional, intent(out) :: rc

         integer :: i
         integer :: n
         integer :: tmp
         integer :: status
         logical :: isPresent

         call ESMF_ConfigFindLabel(config, label=prefix//label,isPresent=isPresent,rc=status)
         _VERIFY(status)
         if (.not. isPresent) then
            _RETURN(_SUCCESS)
         end if

         ! First pass:  count values
         n = 0
         do
            call ESMF_ConfigGetAttribute(config, tmp, rc=status)
            if (status /= _SUCCESS) then
               exit
            else
               n = n + 1
            end if
         end do

         ! Second pass: allocate and fill
         allocate(values(n), stat=status) ! no point in checking status
         _VERIFY(status)
         call ESMF_ConfigFindLabel(config, label=prefix//label,rc=status)
         _VERIFY(status)
         do i = 1, n
            call ESMF_ConfigGetAttribute(config, values(i), rc=status)
            _VERIFY(status)
         end do

         _RETURN(_SUCCESS)

      end subroutine get_multi_integer

   end subroutine initialize_from_config_with_prefix



   function to_string(this) result(string)
      character(len=:), allocatable :: string
      class (XYGridFactory), intent(in) :: this

      _UNUSED_DUMMY(this)
      string = 'XYGridFactory'

   end function to_string



   subroutine check_and_fill_consistency(this, unusable, rc)
      use MAPL_BaseMod, only: MAPL_DecomposeDim
      class (XYGridFactory), intent(inout) :: this
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      integer :: status
      character(len=*), parameter :: Iam = MOD_NAME // 'check_and_fill_consistency'

      _UNUSED_DUMMY(unusable)

      if (.not. allocated(this%grid_name)) then
         this%grid_name = MAPL_GRID_NAME_DEFAULT
      end if
      ! local extents
      call verify(this%nx, this%im_world, this%ims, _RC)
      call verify(this%ny, this%jm_world, this%jms, _RC)
      call this%file_has_corners(_RC)

      _RETURN(_SUCCESS)

   contains

      subroutine verify(n, m_world, ms, rc)
         integer, intent(inout) :: n
         integer, intent(inout) :: m_world
         integer, allocatable, intent(inout) :: ms(:)
         integer, optional, intent(out) :: rc

         integer :: status

         if (allocated(ms)) then
            _ASSERT(size(ms) > 0,"needs message")

            if (n == MAPL_UNDEFINED_INTEGER) then
               n = size(ms)
            else
               _ASSERT(n == size(ms),"needs message")
            end if

            if (m_world == MAPL_UNDEFINED_INTEGER) then
               m_world = sum(ms)
            else
               _ASSERT(m_world == sum(ms),"needs message")
            end if

         else
            _ASSERT(n /= MAPL_UNDEFINED_INTEGER,"needs message")
            _ASSERT(m_world /= MAPL_UNDEFINED_INTEGER,"needs message")
            allocate(ms(n), stat=status)
            _VERIFY(status)
            call MAPL_DecomposeDim(m_world, ms, n)
         end if

         _RETURN(_SUCCESS)

      end subroutine verify

   end subroutine check_and_fill_consistency


   elemental subroutine set_with_default_integer(to, from, default)
      integer, intent(out) :: to
      integer, optional, intent(in) :: from
      integer, intent(in) :: default

      if (present(from)) then
         to = from
      else
         to = default
      end if

   end subroutine set_with_default_integer


   subroutine set_with_default_character(to, from, default)
      character(len=:), allocatable, intent(out) :: to
      character(len=*), optional, intent(in) :: from
      character(len=*), intent(in) :: default

      if (present(from)) then
         to = from
      else
         to = default
      end if

   end subroutine set_with_default_character

   ! MAPL uses values in lon_array and lat_array only to determine the
   ! general positioning.  Actual coordinates are then recomputed.
   ! This helps to avoid roundoff differences from slightly different
   ! input files.
   subroutine initialize_from_esmf_distGrid(this, dist_grid, lon_array, lat_array, unusable, rc)
      use MAPL_ConfigMod
      use MAPL_Constants, only: PI => MAPL_PI_R8
      class (XYGridFactory), intent(inout)  :: this
      type (ESMF_DistGrid), intent(in) :: dist_grid
      type (ESMF_LocalArray), intent(in) :: lon_array
      type (ESMF_LocalArray), intent(in) :: lat_array
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      character(len=*), parameter :: Iam = MOD_NAME // 'initialize_from_esmf_distGrid'

      _UNUSED_DUMMY(this)
      _UNUSED_DUMMY(unusable)
      _UNUSED_DUMMY(dist_grid)
      _UNUSED_DUMMY(lon_array)
      _UNUSED_DUMMY(lat_array)


      ! not supported
      _FAIL("XY initialize from distgrid non supported")

   end subroutine initialize_from_esmf_distGrid

   function decomps_are_equal(this,a) result(equal)
      class (XYGridFactory), intent(in) :: this
      class (AbstractGridFactory), intent(in) :: a
      logical :: equal

      select type (a)
      class default
         equal = .false.
         return
      class is (XYGridFactory)
         equal = .true.

         ! same decomposition
         equal = a%nx == this%nx .and. a%ny == this%ny
         if (.not. equal) return

      end select

   end function decomps_are_equal


   function physical_params_are_equal(this, a) result(equal)
      class (XYGridFactory), intent(in) :: this
      class (AbstractGridFactory), intent(in) :: a
      logical :: equal

      select type (a)
      class default
         equal = .false.
         return
      class is (XYGridFactory)
         equal = .true.

         !equal = (a%grid_file_name == this%grid_file_name)
         !if (.not. equal) return

         equal = (a%im_world == this%im_world) .and. (a%jm_world == this%jm_world)
         if (.not. equal) return

      end select

   end function physical_params_are_equal


   logical function equals(a, b)
      class (XYGridFactory), intent(in) :: a
      class (AbstractGridFactory), intent(in) :: b

      select type (b)
      class default
         equals = .false.
         return
      class is (XYGridFactory)
         equals = .true.

         equals = (a%lm == b%lm)
         if (.not. equals) return

         equals = a%decomps_are_equal(b)
         if (.not. equals) return

         equals = a%physical_params_are_equal(b)
         if (.not. equals) return

      end select

   end function equals


   function generate_grid_name(this) result(name)
      character(len=:), allocatable :: name
      class (XYGridFactory), intent(in) :: this

      _UNUSED_DUMMY(this)

      name = ''
      ! needs to be implemented
      error stop -1

   end function generate_grid_name

   subroutine init_halo(this, unusable, rc)
      class (XYGridFactory), intent(inout) :: this
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(out) :: rc

      _RETURN(_SUCCESS)

      _UNUSED_DUMMY(this)
      _UNUSED_DUMMY(unusable)

   end subroutine init_halo


   subroutine halo(this, array, unusable, halo_width, rc)
      use MAPL_CommsMod
      class (XYGridFactory), intent(inout) :: this
      real(kind=REAL32), intent(inout) :: array(:,:)
      class (KeywordEnforcer), optional, intent(in) :: unusable
      integer, optional, intent(in) :: halo_width
      integer, optional, intent(out) :: rc

      character(len=*), parameter :: Iam = MOD_NAME // 'halo'

      _UNUSED_DUMMY(this)
      _UNUSED_DUMMY(array)
      _UNUSED_DUMMY(unusable)
      _UNUSED_DUMMY(halo_width)
      _UNUSED_DUMMY(rc)

   end subroutine halo

   subroutine append_metadata(this, metadata)
      class (XYGridFactory), intent(inout) :: this
      type (FileMetadata), intent(inout) :: metadata

      type (Variable) :: v
      real(kind=real64), allocatable :: fake_coord(:)
      integer :: i

      call metadata%add_dimension('Xdim', this%im_world)
      call metadata%add_dimension('Ydim', this%jm_world)
      if (this%has_corners) then
         call metadata%add_dimension('XCdim', this%im_world+1)
         call metadata%add_dimension('YCdim', this%jm_world+1)
      end if

      allocate(fake_coord(this%im_world))
      do i=1,this%im_world
         fake_coord(i)=dble(i)
      enddo

      ! Coordinate variables
      v = Variable(type=PFIO_REAL64, dimensions='Xdim')
      call v%add_attribute('long_name', 'Fake Longitude for GrADS Compatibility')
      call v%add_attribute('units', 'degrees_east')
      call v%add_const_value(UnlimitedEntity(fake_coord))
      call metadata%add_variable('Xdim', v)
      deallocate(fake_coord)

      allocate(fake_coord(this%jm_world))
      do i=1,this%jm_world
         fake_coord(i)=dble(i)
      enddo

      v = Variable(type=PFIO_REAL64, dimensions='Ydim')
      call v%add_attribute('long_name', 'Fake Latitude for GrADS Compatibility')
      call v%add_attribute('units', 'degrees_north')
      call v%add_const_value(UnlimitedEntity(fake_coord))
      call metadata%add_variable('Ydim', v)
      deallocate(fake_coord)

      v = Variable(type=PFIO_REAL64, dimensions='Xdim,Ydim')
      call v%add_attribute('long_name','longitude')
      call v%add_attribute('units','degrees_east')
      call metadata%add_variable('lons',v)

      v = Variable(type=PFIO_REAL64, dimensions='Xdim,Ydim')
      call v%add_attribute('long_name','latitude')
      call v%add_attribute('units','degrees_north')
      call metadata%add_variable('lats',v)

      if (this%has_corners) then
         v = Variable(type=PFIO_REAL64, dimensions='XCdim,YCdim')
         call v%add_attribute('long_name','longitude')
         call v%add_attribute('units','degrees_east')
         call metadata%add_variable('corner_lons',v)

         v = Variable(type=PFIO_REAL64, dimensions='XCdim,YCdim')
         call v%add_attribute('long_name','latitude')
         call v%add_attribute('units','degrees_north')
         call metadata%add_variable('corner_lats',v)
      end if
!
     call metadata%add_attribute('grid_type','XY')

   end subroutine append_metadata

   function get_grid_vars(this) result(vars)
      class (XYGridFactory), intent(inout) :: this

      character(len=:), allocatable :: vars
      _UNUSED_DUMMY(this)

      vars = 'Xdim,Ydim'

   end function get_grid_vars

   function get_file_format_vars(this) result(vars)
      class (XYGridFactory), intent(inout) :: this

      character(len=:), allocatable :: vars
      _UNUSED_DUMMY(this)

      !vars = 'Xdim,Ydim,lons,lats,corner_lons,corner_lats'
      vars = 'Xdim,Ydim,lons,lats'

   end function get_file_format_vars

   subroutine append_variable_metadata(this,var)
      class (XYGridFactory), intent(inout) :: this
      type(Variable), intent(inout) :: var
      _UNUSED_DUMMY(this)
      _UNUSED_DUMMY(var)
   end subroutine append_variable_metadata

   subroutine generate_file_bounds(this,grid,local_start,global_start,global_count,metadata,rc)
      use MAPL_BaseMod
      class(XYGridFactory), intent(inout) :: this
      type(ESMF_Grid),      intent(inout) :: grid
      integer, allocatable, intent(out) :: local_start(:)
      integer, allocatable, intent(out) :: global_start(:)
      integer, allocatable, intent(out) :: global_count(:)
      type(FileMetaData), intent(in), optional :: metaData
      integer, optional, intent(out) :: rc

      integer :: status
      integer :: global_dim(3), i1,j1,in,jn
      character(len=*), parameter :: Iam = MOD_NAME // 'generate_file_bounds'

      call MAPL_GridGet(grid,globalCellCountPerDim=global_dim,rc=status)
      _VERIFY(status)
      call MAPL_GridGetInterior(grid,i1,in,j1,jn)
      allocate(local_start,source=[i1,j1])
      allocate(global_start,source=[1,1])
      allocate(global_count,source=[global_dim(1),global_dim(2)])

      _UNUSED_DUMMY(this)
      _UNUSED_DUMMY(metadata)

   end subroutine generate_file_bounds

   subroutine generate_file_corner_bounds(this,grid,local_start,global_start,global_count,rc)
      use MAPL_BaseMod
      class (XYGridFactory), intent(inout) :: this
      type(ESMF_Grid), intent(inout)      :: grid
      integer, allocatable, intent(out) :: local_start(:)
      integer, allocatable, intent(out) :: global_start(:)
      integer, allocatable, intent(out) :: global_count(:)
      integer, optional, intent(out) :: rc

      character(len=*), parameter :: Iam = MOD_NAME // 'generate_file_corner_bounds'

      integer :: status
      integer :: global_dim(3), i1,j1,in,jn

      call MAPL_GridGet(grid,globalCellCountPerDim=global_dim,rc=status)
      _VERIFY(status)
      call MAPL_GridGetInterior(grid,i1,in,j1,jn)
      allocate(local_start,source=[i1,j1])
      allocate(global_start,source=[1,1])
      allocate(global_count,source=[global_dim(1)+1,global_dim(2)+1])

      _UNUSED_DUMMY(this)

   end subroutine generate_file_corner_bounds


   function generate_file_reference2D(this,fpointer) result(ref)
      use pFIO
      type(ArrayReference) :: ref
      class(XYGridFactory), intent(inout) :: this
      real, pointer, intent(in) :: fpointer(:,:)
      ref = ArrayReference(fpointer)

      _UNUSED_DUMMY(this)
   end function generate_file_reference2D

   function generate_file_reference3D(this,fpointer,metadata) result(ref)
      use pFIO
      type(ArrayReference) :: ref
      class(XYGridFactory), intent(inout) :: this
      real, pointer, intent(in) :: fpointer(:,:,:)
      type(FileMetaData), intent(in), optional :: metaData
      ref = ArrayReference(fpointer)

      _UNUSED_DUMMY(this)
      _UNUSED_DUMMY(metadata)
   end function generate_file_reference3D

   subroutine file_has_corners(this,rc)
      use MAPL_CommsMod
      class(XYGridFactory), intent(inout) :: this
      integer, intent(out), optional :: rc

      integer :: status, ncid,varid
      type(ESMF_VM) :: vm
      integer :: log_array(1)

      if (mapl_am_i_root()) then
         status = nf90_open(this%grid_file_name,NF90_NOWRITE,ncid)
         _VERIFY(status)
         status = NF90_inq_varid(ncid,"corner_lons",varid)
         if (status == 0) then
            this%has_corners = .true.
            log_array(1) = 1
         else
            this%has_corners = .false.
            log_array(1) = 0
         end if
      end if
      call ESMF_VMGetCurrent(vm,_RC)
      call ESMF_VMBroadcast(vm,log_array,1,0,_RC)
      this%has_corners = (1 == log_array(1))

      _RETURN(_SUCCESS)
   end subroutine

   subroutine add_mask(this,grid,rc)
      class(XYGridFactory), intent(in) :: this
      type(ESMF_Grid), intent(inout) :: grid
      integer, intent(out), optional :: rc

      integer(ESMF_KIND_I4), pointer :: mask(:,:)
      real(ESMF_KIND_R8), pointer :: fptr(:,:)
      integer :: status
      type(ESMF_VM) :: vm
      integer :: has_undef, local_has_undef

      call ESMF_GridGetCoord(grid, coordDim=1, localDE=0, &
         staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=fptr, _RC)
      local_has_undef = 0
      if (any(fptr == MAPL_UNDEF)) local_has_undef = 1

      call ESMF_GridGetCoord(grid, coordDim=2, localDE=0, &
         staggerloc=ESMF_STAGGERLOC_CENTER, farrayPtr=fptr, _RC)
      if (any(fptr == MAPL_UNDEF)) local_has_undef = local_has_undef + 1

      call ESMF_VMGetCurrent(vm,_RC)
      call ESMF_VMAllFullReduce(vm, [local_has_undef], has_undef, 1, ESMF_REDUCE_MAX, _RC)
      _RETURN_IF(has_undef == 0)

      call ESMF_GridAddItem(grid,staggerLoc=ESMF_STAGGERLOC_CENTER,itemflag=ESMF_GRIDITEM_MASK,_RC)
      call ESMF_GridGetItem(grid,localDE=0,staggerLoc=ESMF_STAGGERLOC_CENTER, &
          itemflag=ESMF_GRIDITEM_MASK,farrayPtr=mask,_RC)

      mask = MAPL_MASK_IN
      where(fptr==MAPL_UNDEF) mask = MAPL_MASK_OUT

      _RETURN(_SUCCESS)
    end subroutine add_mask

end module MAPL_XYGridFactoryMod