module areaMod 9,14

!-----------------------------------------------------------------------
!BOP
!
! !MODULE: areaMod
!
! !DESCRIPTION:
! Area averaging routines
! Thes routines are used for area-average mapping of a field from one
! grid to another.
!
! !USES:
  use clm_varcon   , only : re
  use clm_varpar   , only : numrad
  use clm_varctl   , only : iulog
  use domainMod    , only : domain_type, domain_setptrs, latlon_type
  use shr_const_mod, only : SHR_CONST_PI
  use shr_kind_mod , only : r8 => shr_kind_r8
  use spmdMod      , only : iam,masterproc
  use nanMod      
  use abortutils   , only : endrun
!
! !PUBLIC TYPES:
  implicit none
  private

  type map_type
     private
     ! lower level in hierarchy
     character(len=32)         :: name
     character(len=16)         :: type        ! global, dst, src, etc
     integer                   :: ni_i,nj_i   ! size of src grid ni,nj
     integer                   :: ni_o,nj_o   ! size of dst grid ni,nj
     integer                   :: nwts        ! size of row, col, S (local)
     integer          ,pointer :: src(:)      ! src index (COL)
     integer          ,pointer :: dst(:)      ! dst index (ROW)
     real(r8)         ,pointer :: S(:)        ! wt of overlap input cell
     integer                   :: dstmo       ! max num of overlaps of dst cell
  end type map_type
  public map_type

  type(map_type),public        :: map1dl_a2l   ! a2l mapping 1d loc glo to gdc
  type(map_type),public        :: map1dl_l2a   ! l2a mapping 1d loc gdc to glo

  character(len=16),parameter,public :: map_typelocal  = 'local'
  character(len=16),parameter,public :: map_typeglobal = 'global'

!
! !PUBLIC MEMBER FUNCTIONS:
  public :: map_init
  public :: map_setptrs
  public :: map_setmapsFM
  public :: map_setmapsAR

  interface map_maparrayl 5
     module procedure map_maparrayl_arr
     module procedure map_maparrayl_rev
     module procedure map_maparrayl_av
  end interface
  public :: map_maparrayl
  public :: map_maparrayg
  public :: map_setgatm

  interface celledge 1
     module procedure latlon_celledge_regional
     module procedure latlon_celledge_global
  end interface
  public :: celledge
  public :: cellarea

!
! !REVISION HISTORY:
! Created by Sam Levis
! Updated to clm2.1 data structures by Mariana Vertenstein
! 2005.11.01 Updated and cleaned by T Craig
!
!
! !PRIVATE MEMBER FUNCTIONS:
!EOP
!-----------------------------------------------------------------------

contains

!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_init
!
! !INTERFACE:

  subroutine map_init(map,domain_i,domain_o,nwts,name,type) 2,1
!
! !DESCRIPTION:
! This subroutine initializes the map datatype
!
! !USES:
!
! !ARGUMENTS:
  implicit none
  type(map_type)    , intent(inout)       :: map
  type(domain_type) , intent(in),target   :: domain_i
  type(domain_type) , intent(in),target   :: domain_o
  integer           , intent(in)          :: nwts     ! number of wts
  character(len=*)  , intent(in),optional :: name
  character(len=*)  , intent(in),optional :: type
!
! !REVISION HISTORY:
! 2006.06.28  T Craig  Creation.
!
!
! !LOCAL VARIABLES:
!EOP
  integer ier    ! error flag
!------------------------------------------------------------------------------

!  map%domain_i => domain_i
!  map%domain_o => domain_o
  map%ni_i = domain_i%ni
  map%nj_i = domain_i%nj
  map%ni_o = domain_o%ni
  map%nj_o = domain_o%nj
  if (present(name)) then
    map%name = trim(name)
  else
    map%name = 'unset'
  endif
  if (present(type)) then
    map%type = trim(type)
  else
    map%type = 'unset'
  endif

  map%nwts = nwts
  allocate(map%src(nwts),map%dst(nwts),map%S(nwts),stat=ier)
  if (ier /= 0) then
     write(iulog,*) 'map_init ERROR: allocate map'
     call endrun()
  endif

  map%src = -1
  map%dst = -1
  map%S   = nan

end subroutine map_init
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setptrs
!
! !INTERFACE:

  subroutine map_setptrs(map,name,type,ni_i,nj_i,ni_o,nj_o, & 10
     nwts,src,dst,wts,dstmo)
!
! !DESCRIPTION:
! This subroutine sets external pointer arrays to arrays in map
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(map_type)   ,intent(in)        :: map
    character(len=*) ,optional          :: name     
    character(len=*) ,optional          :: type
    integer          ,optional          :: ni_i,nj_i
    integer          ,optional          :: ni_o,nj_o
    integer          ,optional          :: nwts
    integer          ,optional,pointer  :: src(:)
    integer          ,optional,pointer  :: dst(:)
    real(r8)         ,optional,pointer  :: wts(:)
    integer          ,optional          :: dstmo
!
! !REVISION HISTORY:
!   Created by T Craig
!
!
! !LOCAL VARIABLES:
!
!EOP
!------------------------------------------------------------------------------
    if (present(name)) then
      name = map%name
    endif
    if (present(type)) then
      type = map%type
    endif
    if (present(ni_i)) then
      ni_i = map%ni_i
    endif
    if (present(nj_i)) then
      nj_i = map%nj_i
    endif
    if (present(ni_o)) then
      ni_o = map%ni_o
    endif
    if (present(nj_o)) then
      nj_o = map%nj_o
    endif
    if (present(nwts)) then
      nwts = map%nwts
    endif
    if (present(src)) then
      src => map%src
    endif
    if (present(dst)) then
      dst => map%dst
    endif
    if (present(wts)) then
      wts => map%S
    endif
    if (present(dstmo)) then
      dstmo = map%dstmo
    endif

end subroutine map_setptrs
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayl_arr
!
! !INTERFACE:

  subroutine map_maparrayl_arr(begg_i, endg_i, begg_o, endg_o, nflds, & 1,2
                               fld_i, fld_o, map)
!
! !DESCRIPTION:
! This subroutine maps arrays, local 1d with 1d map type
!
! !USES:
!
! !ARGUMENTS:
  implicit none
  integer                         :: begg_i,endg_i         !beg,end of input grid
  integer                         :: begg_o,endg_o         !beg,end of output grid
  integer                         :: nflds                 !number of fields being mapped
  real(r8), intent(in)            :: fld_i(begg_i:endg_i,nflds)
  real(r8), intent(out)           :: fld_o(begg_o:endg_o,nflds)
  type(map_type), intent(in)      :: map
!
! !REVISION HISTORY:
! 2005.11.15  T Craig  Creation.
! 2006.3.30   P Worley Restructuring for improved vector performance
!

! !LOCAL VARIABLES:
!EOP
  integer :: g_o ,g_i              ! gridcell indices
  integer :: n,ifld                ! loop counters
  real(r8):: wtx                   ! wt for map

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

    if (trim(map%type) /= trim(map_typelocal)) then
       write(iulog,*) 'map_maparrayl_arr WARNING: map type not correct, ', &
                   map%name,map%type
    endif

    ! check for errors in overlap

    if (minval(map%src) < begg_i .or. maxval(map%src) > endg_i) then
       write(iulog,*) 'map_maparrayl_arr ERROR: src out of bounds:', &
                   minval(map%src),maxval(map%src),begg_i,endg_i
       call endrun()
    endif

    if (minval(map%dst) < begg_o .or. maxval(map%dst) > endg_o) then
       write(iulog,*) 'map_maparrayl_arr ERROR: dst out of bounds:', &
                   minval(map%dst),maxval(map%dst),begg_o,endg_o
       call endrun()
    endif

    ! initialize field on output grid to zero everywhere

    fld_o(:,:) = 0._r8

    ! map flds

    do ifld = 1,nflds
    do n = 1,map%nwts
       g_i = map%src(n)
       g_o = map%dst(n)
       wtx = map%S(n)
       fld_o(g_o,ifld) = fld_o(g_o,ifld) + wtx * fld_i(g_i,ifld)
    enddo
    enddo

end subroutine map_maparrayl_arr

!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayl_rev
!
! !INTERFACE:

  subroutine map_maparrayl_rev(begg_i, endg_i, begg_o, endg_o, nflds, & 1,3
                              fld_i, fld_o, map, reverse_order)
!
! !DESCRIPTION:
! This subroutine maps arrays, local 1d with 1d map type
!
! !USES:
  use mct_mod
!
! !ARGUMENTS:
  implicit none
  integer                         :: begg_i,endg_i         !beg,end of input grid
  integer                         :: begg_o,endg_o         !beg,end of output grid
  integer                         :: nflds                 !number of fields being mapped
  real(r8), intent(in)            :: fld_i(nflds,endg_i-begg_i+1)
  real(r8), intent(out)           :: fld_o(nflds,endg_o-begg_o+1)
  type(map_type), intent(in)      :: map
  logical, intent(in)             :: reverse_order
!
! !REVISION HISTORY:
! 2005.11.15  T Craig  Creation.
! 2006.3.30   P Worley Restructuring for improved vector performance
! 2010.5.1    M Vertenstein Added new interfaces
!

! !LOCAL VARIABLES:
!EOP
  integer :: g_o ,g_i              ! gridcell indices
  integer :: n,ifld                ! loop counters
  real(r8):: wtx                   ! wt for map
!
!------------------------------------------------------------------------------

    if (trim(map%type) /= trim(map_typelocal)) then
       write(iulog,*) 'map_maparrayl_rev WARNING: map type not correct, ', &
                   map%name,map%type
    endif

    ! check for errors in overlap

    if (minval(map%src) < begg_i .or. maxval(map%src) > endg_i) then
       write(iulog,*) 'map_maparrayl_rev ERROR: src out of bounds:', &
                   minval(map%src),maxval(map%src),begg_i,endg_i
       call endrun()
    endif

    if (minval(map%dst) < begg_o .or. maxval(map%dst) > endg_o) then
       write(iulog,*) 'map_maparrayl_rev ERROR: dst out of bounds:', &
                   minval(map%dst),maxval(map%dst),begg_o,endg_o
       call endrun()
    endif

    ! initialize field on output grid to zero everywhere

    fld_o(:,:) = 0._r8

    ! map flds

    do n = 1,map%nwts
       g_i = map%src(n) - begg_i + 1
       g_o = map%dst(n) - begg_o + 1
       wtx = map%S(n)
       do ifld = 1,nflds
          fld_o(ifld,g_o) = fld_o(ifld,g_o) + wtx * fld_i(ifld,g_i)
       enddo
    enddo

end subroutine map_maparrayl_rev

!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayl_av
!
! !INTERFACE:

  subroutine map_maparrayl_av(begg_i, endg_i, begg_o, endg_o, nflds, & 1,3
                              fld_i, fld_o, map)
!
! !DESCRIPTION:
! This subroutine maps arrays, local 1d with 1d map type
!
! !USES:
  use mct_mod
!
! !ARGUMENTS:
  implicit none
  integer                         :: begg_i,endg_i         !beg,end of input grid
  integer                         :: begg_o,endg_o         !beg,end of output grid
  integer                         :: nflds                 !number of fields being mapped
  type(mct_aVect), intent(inout)  :: fld_i                 !land model import and export states
  type(mct_aVect), intent(inout)  :: fld_o                 !land model import and export states
  type(map_type), intent(in)      :: map
!
! !REVISION HISTORY:
! 2005.11.15  T Craig  Creation.
! 2006.3.30   P Worley Restructuring for improved vector performance
!

! !LOCAL VARIABLES:
!EOP
  integer :: g_o ,g_i              ! gridcell indices
  integer :: n,ifld                ! loop counters
  real(r8):: wtx                   ! wt for map
!
!------------------------------------------------------------------------------

    if (trim(map%type) /= trim(map_typelocal)) then
       write(iulog,*) 'map_maparrayl_av WARNING: map type not correct, ', &
                   map%name,map%type
    endif

    ! check for errors in overlap

    if (minval(map%src) < begg_i .or. maxval(map%src) > endg_i) then
       write(iulog,*) 'map_maparrayl_av ERROR: src out of bounds:', &
                   minval(map%src),maxval(map%src),begg_i,endg_i
       call endrun()
    endif

    if (minval(map%dst) < begg_o .or. maxval(map%dst) > endg_o) then
       write(iulog,*) 'map_maparrayl_av ERROR: dst out of bounds:', &
                   minval(map%dst),maxval(map%dst),begg_o,endg_o
       call endrun()
    endif

    ! initialize field on output grid to zero everywhere

    call mct_aVect_zero(fld_o)

    ! map flds

    do n = 1,map%nwts
       g_i = map%src(n) - begg_i + 1
       g_o = map%dst(n) - begg_o + 1
       wtx = map%S(n)
       do ifld = 1,nflds
          fld_o%rAttr(ifld,g_o) = fld_o%rAttr(ifld,g_o) + wtx * fld_i%rAttr(ifld,g_i)
       enddo
    enddo

end subroutine map_maparrayl_av

!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_maparrayg
!
! !INTERFACE:

  subroutine map_maparrayg(fld_i, fld_o, map)
!
! !DESCRIPTION:
! This subroutine maps arrays, global 1d with 1d map type
!
! !USES:
!
! !ARGUMENTS:
  implicit none
  real(r8), intent(in)            :: fld_i(:,:)
  real(r8), intent(out)           :: fld_o(:,:)
  type(map_type), intent(in)      :: map
!
! !REVISION HISTORY:
! 2005.11.15  T Craig  Creation.
! 2006.3.30   P Worley Restructuring for improved vector performance
!

! !LOCAL VARIABLES:
!EOP
  integer :: g_o ,g_i              ! gridcell indices
  integer :: n,ifld,nflds          ! loop counters
  real(r8):: wtx                   ! wt for map

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

    if (trim(map%type) /= trim(map_typeglobal)) then
       write(iulog,*) 'map_maparrayg WARNING: map type not correct, ', &
                   map%name,map%type
    endif

    nflds = size(fld_i,dim=2)
    ! initialize field on output grid to zero everywhere

    fld_o(:,:) = 0._r8

    ! map flds

    do ifld = 1,nflds
    do n = 1,map%nwts
       g_i = map%src(n)
       g_o = map%dst(n)
       wtx = map%S(n)
       fld_o(g_o,ifld) = fld_o(g_o,ifld) + wtx * fld_i(g_i,ifld)
    enddo
    enddo

end subroutine map_maparrayg

!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setgatm
!
! !INTERFACE:

  subroutine map_setgatm(gatm, alatlon, llatlon, amask, pftm) 1,6
!
! !DESCRIPTION:
! Set gatm index in ldomain.  unique for finemesh.
!
! !USES:
!
  use domainMod, only : latlon_type
!
! !ARGUMENTS:
  implicit none
  integer, pointer               :: gatm(:)
  type(latlon_type), intent(in)  :: alatlon
  type(latlon_type), intent(in)  :: llatlon
  integer          , intent(in)  :: amask(:)
  integer          , intent(in)  :: pftm(:)
!
! !REVISION HISTORY:
! 2006.06.28  T Craig  Creation.
! 2006.08.23  P Worley Performance optimizations
!
!
! !LOCAL VARIABLES:
!EOP
    integer          :: nlon_a       !input  grid: max number of longitude pts
    integer          :: nlat_a       !input  grid: number of latitude  points
    integer          :: ns_a         !input  grid: total number of cells
!    integer ,pointer :: mask_a(:)    !input grid: mask
    real(r8),pointer :: lon_a(:)     !input grid: longitude (degrees)
    real(r8),pointer :: lat_a(:)     !input grid: latitude  (degrees)
    real(r8),pointer :: lone_a(:)    !input grid: longitude, E edge (degrees)
    real(r8),pointer :: lonw_a(:)    !input grid: longitude, W edge (degrees)
    real(r8),pointer :: latn_a(:)    !input grid: latitude , N edge (degrees)
    real(r8),pointer :: lats_a(:)    !input grid: latitude , S edge (degrees)
    integer          :: nlon_l       !output grid: max number of longitude pts
    integer          :: nlat_l       !output grid: number of latitude  points
    integer          :: ns_l         !output grid: total number of cells
!    integer ,pointer :: gatm_l(:)    !output grid: atm grid cell overlapping
    real(r8),pointer :: lon_l(:)     !output grid: longitude (degrees)
    real(r8),pointer :: lat_l(:)     !output grid: latitude  (degrees)
    real(r8),pointer :: lone_l(:)    !output grid: longitude, E edge (degrees)
    real(r8),pointer :: lonw_l(:)    !output grid: longitude, W edge (degrees)
    real(r8),pointer :: latn_l(:)    !output grid: latitude , N edge (degrees)
    real(r8),pointer :: lats_l(:)    !output grid: latitude , S edge (degrees)
!    integer ,pointer :: pftm_l(:)    !output grid: cell frac
    integer          :: n            !loop counters
    integer          :: ia,ja,na     !indices for atm grid
    integer          :: il,jl,nl     !indices for lnd grid
    integer          :: if,jf,nf     !found indices
    integer          :: noffset=1    !noffset
    real(r8)         :: doffset =360_r8 !offset value
    real(r8)         :: offset       !offset*n_offset
    logical          :: found        !local logical 
    logical          :: overlapgrid  !are atm and lnd grids 1:1
    logical          :: latlongrid   !are atm and lnd grids regular lat/lon
    real(r8),parameter :: relerr = 1.0e-6    ! error limit
    integer          :: cnt,cnt0,cmax  !counters
!tcx fix, lat_l_local should be removed when limit no longer needed
    real(r8)         :: lat_l_local  !local copy of lat_l(il,jl), adjusted
    real(r8),parameter:: eps = 1.0e-8  ! eps for check

    integer, pointer :: ilfound(:)     ! list over overlap i indices
    integer, pointer :: jlfound(:)     ! list over overlap j indices
    integer, pointer :: nocnt(:)      ! lnd cell count per atm cell
    integer, pointer :: nooff(:)      ! atm cell offset in nomap
    integer, pointer :: nomap(:)      ! map from atm cell to lnd cells
    integer :: noidx
!
!------------------------------------------------------------------------

    !--- set pointers into domains, initialize gridmap a2l gridmap ---

    ns_a   =  alatlon%ns
    nlon_a =  alatlon%ni
    nlat_a =  alatlon%nj
    lat_a  => alatlon%latc
    lon_a  => alatlon%lonc
    latn_a => alatlon%latn
    lats_a => alatlon%lats
    lone_a => alatlon%lone
    lonw_a => alatlon%lonw

    ns_l   =  llatlon%ns
    nlon_l =  llatlon%ni
    nlat_l =  llatlon%nj
    lat_l  => llatlon%latc
    lon_l  => llatlon%lonc
    latn_l => llatlon%latn
    lats_l => llatlon%lats
    lone_l => llatlon%lone
    lonw_l => llatlon%lonw

    allocate(gatm(ns_l))

    !--- search for the overlap, input to output, 1:1 "disaggregation" ---
    !--- this is the coarse to fine map where there should be exactly
    !--- one coarse overlap point for each fine point 
    !--- three possible search algorithms, overlapgrid, latlongrid, neither
    !--- figure out which search scheme to use

    !--- overlapgrid means both grids are identical to relerr
    overlapgrid = .false.
    if (nlon_a == nlon_l .and. nlat_a == nlat_l) then
       overlapgrid = .true.
       do jl = 1, nlat_l
          if (abs( lat_l(jl)- lat_a(jl)) > relerr .or. &
              abs(latn_l(jl)-latn_a(jl)) > relerr .or. &
              abs(lats_l(jl)-lats_a(jl)) > relerr) then
             overlapgrid = .false.
          endif
       enddo
       do il = 1, nlon_l
          if (abs( lon_l(il)- lon_a(il)) > relerr .or. &
              abs(lone_l(il)-lone_a(il)) > relerr .or. &
              abs(lonw_l(il)-lonw_a(il)) > relerr) then
             overlapgrid = .false.
          endif
       enddo
    endif

    !--- latlongrid means atm grid is regular latlon grid
    !--- always true for now, may not be in the future
    latlongrid = .true.

    if (masterproc) write(iulog,*) 'setgatm overlapgrid,latlongrid = ',overlapgrid,latlongrid

!pw major restructuring follows
    if (overlapgrid) then
       gatm = -1
       do nl = 1,ns_l
          if (pftm(nl) >= 0) then       ! only real or fake points
             if (amask(nl) /= 0) then
                gatm(nl)=nl
             endif
          endif
       enddo

    elseif (latlongrid) then
!pw Still need restructuring for vectorization.

       allocate(ilfound(nlon_l),jlfound(nlat_l))
       ilfound = 0
       jlfound = 0

       do jl = 1, nlat_l
          found  = .false.
          lat_l_local = min(max(lat_l(jl),-90.0_r8),90.0_r8)  !limit [-90,90]
          do ja = 1,nlat_a
             if ((ja == 1 .and. lat_l_local <= latn_a(ja) .and.   &
                                lat_l_local >= lats_a(ja)) .or.   &
                 (ja >  1 .and. lat_l_local <= latn_a(ja) .and.   &
                                lat_l_local >  lats_a(ja))) then
                if (found) then
                   write(iulog,*) 'map_setgatm WARNING: found > 1 pt j ', &
                      jl,ja,jlfound(jl),lat_l(jl),lat_l_local
                   call endrun()
                endif
                jlfound(jl) = ja
                found = .true.
             endif
          enddo  ! ja
       enddo !jl

       do il = 1, nlon_l
          found  = .false.
          do ia = 1,nlon_a
          do n = -noffset,noffset
             offset = n*doffset
             if ((ia == 1 .and. lon_l(il)+offset <= lone_a(ia) .and.   &
                                lon_l(il)+offset >  lonw_a(ia)) .or.   &
                 (ia >  1 .and. lon_l(il)+offset <= lone_a(ia) .and.   &
                                lon_l(il)+offset >  lonw_a(ia))) then
                if (found) then
                   write(iulog,*) 'map_setgatm WARNING: found > 1 pt i ', &
                      il,ia,ilfound(il),lon_l(il)+offset
                   call endrun()
                endif
                ilfound(il) = ia
                found = .true.
             endif
          enddo  ! n, offset
          enddo  ! ia
       enddo

       gatm = -1
       do jl = 1,nlat_l
       do il = 1,nlon_l
          nl = (jl-1)*nlon_l + il
          if (pftm(nl) >= 0) then       ! only real or fake points
             if = ilfound(il)
             jf = jlfound(jl)
             nf = (jf-1)*nlon_a + if
             if (if == 0 .or. jf == 0) then
                write(iulog,*) 'map_setgatm ERROR: pt not found, ', &
                   il,lon_l(il), '_l', &
                   minval(lon_l),maxval(lon_l),           &
                   minval(lat_l),maxval(lat_l),'_awe',    &
                   minval(lonw_a),maxval(lonw_a),         &
                   minval(lone_a),maxval(lone_a),'_asn',  &
                   minval(lats_a),maxval(lats_a),         &
                   minval(latn_a),maxval(latn_a)
                call endrun()
             endif
             if (amask(nf) /= 0) then
                gatm(nl)=nf
             endif
          endif
       enddo
       enddo

       deallocate(ilfound,jlfound)

    else
!pw Still need restructuring for vectorization

       write(iulog,*) 'map_setgatm ERROR: irregular lat lon grid not supported'
       call endrun()

    endif
!pw major restructuring ends

    !--- remove fake land if there is at least one real land overlap point ---
    allocate(nocnt(ns_a),nooff(ns_a),nomap(ns_l))

    nocnt = 0
    do nl = 1,ns_l
       na = gatm(nl)
       if (na > 0) then
          nocnt(na) = nocnt(na) + 1
       endif
    enddo

    nooff(1) = 1
    do na = 2,ns_a
       nooff(na) = nooff(na-1) + nocnt(na-1)
    enddo

    nocnt = 0
    nomap = -1
    do nl = 1,ns_l
       na = gatm(nl)
       if (na > 0) then
         nomap(nooff(na)+nocnt(na)) = nl
         nocnt(na) = nocnt(na) + 1
       endif
    enddo

    do na = 1,ns_a
       found = .false.        ! check if any points are real land
       do noidx = 0,nocnt(na)-1
          nl = nomap(nooff(na)+noidx)
          if (pftm(nl) > 0 ) then
             found = .true.
          endif
       enddo
       if (found) then        ! if so, keep only real land points
          do noidx = 0,nocnt(na)-1
             nl = nomap(nooff(na)+noidx)
             if (pftm(nl) <= 0 ) then
                gatm(nl) = -1
             endif
       enddo
       endif
    enddo

    !--- check that valid fine grid points have coarse mapping gridpoints
    if (masterproc) then
       nocnt = 0
       do nl = 1,ns_l
          na = gatm(nl)
          if (na > 0) then
             nocnt(na) = nocnt(na) + 1
          endif
       enddo

       found = .true.
       do na = 1,ns_a
          if ((amask(na) /= 0) .and. (nocnt(na) == 0)) then
             found = .false.
          endif
       enddo
       if (.not. found) then
          do na = 1,ns_a
             if ((amask(na) /= 0) .and. (nocnt(na) == 0)) then
                write(iulog,*) 'map_setgatm ERROR: invalid f->c index ', &
                   na,amask(na)
                call endrun()
             endif
          enddo
       endif

    endif

    deallocate(nocnt,nooff,nomap)

end subroutine map_setgatm
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setmapsFM
!
! !INTERFACE:

  subroutine map_setmapsFM(domain_a, domain_l, gatm_l, map1dl_a2l, map1dl_l2a, name) 1,31
!
! !DESCRIPTION:
! Set course to fine mesh maps and reverse.  domain_a should be coarse
! (atm) mesh, domain_l is fine (land) mesh.
! Simple overlap algorithm
!   - Find every fine gridcell within coarse gridcell
!   - Keep "real" cells unless there are none
!   - Weights based on areas of cells used, sum(weights)==1
!   - Use a2l mapping to set l2a mapping
!
! !USES:
  use decompMod, only : ldecomp, adecomp
  use decompMod, only : get_proc_bounds, get_proc_bounds_atm
  use clm_varsur, only : wtxy
!
! !ARGUMENTS:
  implicit none
  type(domain_type),intent(in)    :: domain_a
  type(domain_type),intent(in)    :: domain_l
  integer          ,intent(in)    :: gatm_l(:)
  type(map_type)   ,intent(inout) :: map1dl_a2l
  type(map_type)   ,intent(inout) :: map1dl_l2a
  character(len=*) ,optional,intent(in) :: name
!
! !REVISION HISTORY:
! 2005.12.01  T Craig  Creation.
!
!
! !LOCAL VARIABLES:
!EOP
    integer           :: ns_a
    integer           :: ns_l
    integer           :: na,nag
    integer           :: nl,nlg
    real(r8),pointer :: area_a(:)    !input grid: cell area
    real(r8),pointer :: topo_a(:)    !input grid: cell topo/elevation
    real(r8),pointer :: frac_a(:)    !input grid: cell frac
    integer ,pointer :: mask_l(:)    !output grid: cell mask
    real(r8),pointer :: area_l(:)    !output grid: cell area
    real(r8),pointer :: nara_l(:)    !output grid: cell equiv upscale area
    real(r8),pointer :: topo_l(:)    !output grid: cell topo/elevation
    real(r8),pointer :: ntop_l(:)    !output grid: cell equiv downscale topo
    real(r8),pointer :: frac_l(:)    !output grid: cell frac

    integer          :: n_a2l       !a2l nwts
    integer          :: mo_a2l      !a2l dstmo
    integer ,pointer :: src_a2l(:)  !a2l src indices
    integer ,pointer :: dst_a2l(:)  !a2l dst indices
    real(r8),pointer :: wts_a2l(:)  !a2l wts indices
    integer          :: n_l2a       !l2a nwts
    integer          :: mo_l2a      !l2a dstmo
    integer ,pointer :: src_l2a(:)  !l2a src indices
    integer ,pointer :: dst_l2a(:)  !l2a dst indices
    real(r8),pointer :: wts_l2a(:)  !l2a wts indices

    integer          :: na2l,nl2a
    integer          :: begg,endg
    integer          :: abegg,aendg
    integer ,pointer :: ncnta(:)    !number of overlap points in l2a
    integer ,pointer :: cnta(:)     !number of overlap points in l2a
    real(r8),pointer :: asum(:)     !number of overlap points in l2a
    real(r8),pointer :: tsum(:)     !number of overlap points in l2a
    real(r8),parameter:: eps = 1.0e-8  ! eps for check
!
!------------------------------------------------------------------------

    !--- get local beg/end

    call get_proc_bounds    ( begg,  endg)
    call get_proc_bounds_atm(abegg, aendg)

    !--- set pointers into domains, initialize gridmap a2l gridmap ---

    call domain_setptrs(domain_a,ns=ns_a,area=area_a, &
       frac=frac_a, topo=topo_a)
    call domain_setptrs(domain_l,ns=ns_l, &
       area=area_l, mask=mask_l, frac=frac_l, &
       nara=nara_l,topo=topo_l,ntop=ntop_l)

    !--- allocate temporaries

    allocate(ncnta(abegg:aendg),asum(abegg:aendg),tsum(abegg:aendg),cnta(abegg:aendg))

    !--- count local number of wts needed, na2l, nl2a
    !--- also set global arrays ncnta and asum for later computations

    na2l = 0
    nl2a = 0
    ncnta = 0
    asum = 0.0_r8
    do nl = begg,endg
       nlg = ldecomp%gdc2glo(nl)
       nag = gatm_l(nlg)
       if (nag <= 0) then
          write(iulog,*) 'map_setmapsFM ERROR nag0 <= 0',nl,nlg,nag
          call endrun()
       endif
       na  = adecomp%glo2gdc(nag)
       if (nlg < 1 .or. nlg > ns_l .or. &
           nag < 1 .or. nag > ns_a .or. &
           na  < abegg .or. na > aendg) then
          write(iulog,*) 'map_setmapsFM ERROR in index0 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
          call endrun()
       endif
       ncnta(na) = ncnta(na) + 1
       asum(na) = asum(na) + area_l(nl)
       na2l = na2l + 1
       nl2a = nl2a + 1
    enddo

    !--- initialize and allocate maps
    call map_init(map1dl_a2l,domain_a,domain_l,na2l,name='setmapsFM_a2l', &
                  type=map_typelocal)
    call map_init(map1dl_l2a,domain_l,domain_a,nl2a,name='setmapsFM_l2a', &
                  type=map_typelocal)

    !--- set pointers to the maps

    call map_setptrs(map1dl_a2l,src=src_a2l,dst=dst_a2l,wts=wts_a2l, &
                     nwts=n_a2l,dstmo=mo_a2l)
    call map_setptrs(map1dl_l2a,src=src_l2a,dst=dst_l2a,wts=wts_l2a, &
                     nwts=n_l2a,dstmo=mo_l2a)

    !--- set dstmo in maps

    map1dl_a2l%dstmo = 1
    map1dl_l2a%dstmo = maxval(ncnta)

    !--- set src,dst,wts in maps

    na2l = 0
    nl2a = 0
    cnta = 0
    do nl = begg,endg
       nlg = ldecomp%gdc2glo(nl)
       nag = gatm_l(nlg)
       if (nag <= 0) then
          write(iulog,*) 'map_setmapsFM ERROR nag1 <= 0',nl,nlg,nag
          call endrun()
       endif
       na  = adecomp%glo2gdc(nag)
       if (nlg < 1 .or. nlg > ns_l .or. &
           nag < 1 .or. nag > ns_a .or. &
           na  < abegg .or. na > aendg) then
          write(iulog,*) 'map_setmapsFM ERROR in index1 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
          call endrun()
       endif

       na2l = na2l + 1
       if (na2l > n_a2l) then
          write(iulog,*) 'map_setmapsFM ERROR na2l > n_a2l ',na2l,n_a2l
          call endrun()
       endif
       src_a2l(na2l) = na
       dst_a2l(na2l) = nl
       wts_a2l(na2l) = 1.0_r8

       nl2a = nl2a + 1
       cnta(na) = cnta(na) + 1
       if (nl2a > n_l2a .or. cnta(na) > ncnta(na)) then
          write(iulog,*) 'map_setmapsFM ERROR nl2a > n_l2a ',nl2a,n_l2a,cnta(na),ncnta(na)
          call endrun()
       endif
       src_l2a(nl2a) = nl
       dst_l2a(nl2a) = na
       if (ncnta(na) == 1) then
          wts_l2a(nl2a) = 1.0_r8
       else
          if (asum(na) <= 0.0_r8) then
             write(iulog,*) 'map_setmapsFM ERROR asum <= 0 ',nlg,nag,asum(na)
             call endrun()
          endif
          wts_l2a(nl2a) = (area_l(nl)/asum(na))
       endif
    enddo

    !--- update ldomain arrays based on upscale/downscale stuff

    tsum = 0.0_r8
    do nl = begg,endg
       nlg = ldecomp%gdc2glo(nl)
       nag = gatm_l(nlg)
       if (nag <= 0) then
          write(iulog,*) 'map_setmapsFM ERROR nag2 <= 0',nl,nlg,nag
          call endrun()
       endif
       na  = adecomp%glo2gdc(nag)
       if (nlg < 1 .or. nlg > ns_l .or. &
           nag < 1 .or. nag > ns_a .or. &
           na  < abegg .or. na > aendg) then
          write(iulog,*) 'map_setmapsFM ERROR in index2 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
          call endrun()
       endif
       if (frac_l(nl) > 0.0_r8) then
          ntop_l(nl) = topo_l(nl)                      ! set topo ovr lnd
       else
          ntop_l(nl) = max(0.0_r8,topo_l(nl))          ! set topo ovr ocn 
       endif
       tsum(na) = tsum(na) + ntop_l(nl)*area_l(nl)   ! area wt topo avg
    enddo

    do nl = begg,endg
       nlg = ldecomp%gdc2glo(nl)
       nag = gatm_l(nlg)
       if (nag <= 0) then
          write(iulog,*) 'map_setmapsFM ERROR nag3 <= 0',nl,nlg,nag
          call endrun()
       endif
       na  = adecomp%glo2gdc(nag)
       if (nlg < 1 .or. nlg > ns_l .or. &
           nag < 1 .or. nag > ns_a .or. &
           na  < abegg .or. na > aendg) then
          write(iulog,*) 'map_setmapsFM ERROR in index3 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
          call endrun()
       endif
       if (ncnta(na) == 1) then
          nara_l(nl) = area_a(na)
          ntop_l(nl) = topo_a(na)
       else
          if (asum(na) <= 0.0_r8) then
             write(iulog,*) 'map_setmapsFM ERROR2 asum <= 0 ',nl,na,asum(na)
             call endrun()
          endif
          if (tsum(na) <  0.0_r8) then
             write(iulog,*) 'map_setmapsFM ERROR2 tsum < 0 ',nl,na,tsum(na)
             call endrun()
          endif
          nara_l(nl)   = (area_l(nl)/asum(na))*area_a(na)
! DOWNSCALING
!-v-v-v-v-v- land topo elevation adjustment for downscaling -v-v-v-v-
!----------- want avg land topo to be equal to atm topo and want the
!----------- variability in finemesh land topo to be preserved
          if (tsum(na) == 0.) then
             ntop_l(nl)   = ntop_l(nl)+topo_a(na)
          elseif (topo_a(na) > 0.) then
             ntop_l(nl)   = (ntop_l(nl)/(tsum(na)/asum(na)))*topo_a(na)
          else
             ntop_l(nl)   = (ntop_l(nl)-(tsum(na)/asum(na)))+topo_a(na)
          endif
!-^-^-^-^-^- land topo elevation adjustment for downscaling -^-^-^-^-
       endif
    enddo

    !--- check that areas and topos match up

    asum = 0.0_r8
    tsum = 0.0_r8
    do nl = begg,endg
       nlg = ldecomp%gdc2glo(nl)
       nag = gatm_l(nlg)
       if (nag <= 0) then
          write(iulog,*) 'map_setmapsFM ERROR nag4 <= 0',nl,nlg,nag
          call endrun()
       endif
       na  = adecomp%glo2gdc(nag)
       if (nlg < 1 .or. nlg > ns_l .or. &
           nag < 1 .or. nag > ns_a .or. &
           na  < abegg .or. na > aendg) then
          write(iulog,*) 'map_setmapsFM ERROR in index4 ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
          call endrun()
       endif
       asum(na) = asum(na) + nara_l(nl)
       tsum(na) = tsum(na) + nara_l(nl)*ntop_l(nl)
    enddo

    do na = abegg, aendg
       if (asum(na) > 0.0_r8) then
          if (abs(asum(na)-area_a(na)) > eps .or. &
              abs(tsum(na)/area_a(na) - topo_a(na)) > eps) then
                 write(iulog,*) ' map_setmapsFM ERROR: ERROR in nara,ntop, ',asum(na),area_a(na),tsum(na),topo_a(na),eps
                 call endrun()
          endif
       endif
    enddo

    !--- clean up
    deallocate(ncnta,cnta,asum,tsum)

    call map_checkmap(map1dl_a2l)
    call map_checkmap(map1dl_l2a)

    ! Set ldomain mask and frac based on adomain and mapping.
    ! Want ldomain%frac to match adomain%frac but scale by effective area.
    ! so the implied area of an ldomain cell is the actual area *
    ! scaled frac which aggregated over all land cells under an atm cell,
    ! will match the area associated with the atm cell.

    do nl = begg,endg
       nlg = ldecomp%gdc2glo(nl)
       nag = gatm_l(nlg)
       if (nag <= 0) then
          write(iulog,*) 'initialize2 nag <= 0 ERROR ',nl,nlg,nag
          call endrun()
       endif
       na = adecomp%glo2gdc(nag)
       if (nlg < 1 .or. nlg > ns_l .or. &
           nag < 1 .or. nag > ns_a .or. &
           na  < abegg .or. na > aendg) then
          write(iulog,*) 'initialize2 index ERROR ',nl,nlg,nag,na,ns_l,ns_a,abegg,aendg
          call endrun()
       endif
       mask_l(nl) = 1
       frac_l(nl) = frac_a(na)* (nara_l(nl)/area_l(nl))
    enddo

end subroutine map_setmapsFM

!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_setmapsAR
!
! !INTERFACE:

  subroutine map_setmapsAR (latlon_i, latlon_o, sMat, & 1,2
                      fracin, fracout)
!
! !DESCRIPTION:
! area averaging initialization
! This subroutine is used for area-average mapping of a field from one
! grid to another.
!
! !USES:
    use clm_mct_mod
!
! !ARGUMENTS:
    implicit none
    type(latlon_type) ,intent(in)   :: latlon_i   ! input domain
    type(latlon_type) ,intent(in)   :: latlon_o   ! output domain
    type(mct_sMat)    ,intent(inout)     :: sMat       ! mct sparse matrix plux
    real(r8), intent(in),target :: fracin(:)
    real(r8), intent(in),target :: fracout(:)
!
! !REVISION HISTORY:
! Created by Gordon Bonan
! 2005.11.20 Updated by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
    integer          :: nlon_i       !input  grid: max number of longitude pts
    integer          :: nlat_i       !input  grid: number of latitude  points
    real(r8),pointer :: dx_i(:)      !input grid: dx length
    real(r8),pointer :: dy_i(:)      !input grid: dy length
    real(r8),pointer :: fland_i(:)   !input grid: cell frac
    real(r8),pointer :: lone_i(:)    !input grid: longitude, E edge (degrees)
    real(r8),pointer :: lonw_i(:)    !input grid: longitude, W edge (degrees)
    real(r8),pointer :: latn_i(:)    !input grid: latitude, N edge (degrees)
    real(r8),pointer :: lats_i(:)    !input grid: latitude, S edge (degrees)
    integer          :: nlon_o       !output grid: max number of longitude pts
    integer          :: nlat_o       !output grid: number of latitude  points
    real(r8),pointer :: dx_o(:)      !output grid: dx length
    real(r8),pointer :: dy_o(:)      !output grid: dy length
    real(r8),pointer :: fland_o(:)   !output grid: cell frac
    real(r8),pointer :: lone_o(:)    !output grid: longitude, E edge  (degrees)
    real(r8),pointer :: lonw_o(:)    !output grid: longitude, W edge  (degrees)
    real(r8),pointer :: latn_o(:)    !output grid: latitude, N edge (degrees)
    real(r8),pointer :: lats_o(:)    !output grid: latitude, S edge (degrees
    integer          :: nwts         !local num of weights
    integer          :: n,ns,nw,k    !loop counters
    integer nb,na          !grid sizes
    integer i,j            !loop indices
    integer io,jo,no       !output grid loop index
    integer ii,ji,ni       !input  grid loop index
    integer nji, njilap    !counter and number of j overlaps
    integer,pointer  :: jilap(:) ! j overlap indices
    integer,pointer  :: iilaps(:),iilape(:)  ! i start/end overlap indices
    real(r8) lonw          !west longitudes of overlap
    real(r8) lone          !east longitudes of overlap
    real(r8) dx            !difference in longitudes
    real(r8) lats          !south latitudes of overlap
    real(r8) latn          !north latitudes of overlap
    real(r8) dy            !difference in latitudes
    real(r8) deg2rad       !pi/180
    real(r8) a_ovr         !area of overlap
    integer  noffsetl      !local, number of offsets to test, 0=none, default=1
    real(r8) offset        !value of offset used to shift x-grid 360 degrees
    real(r8) :: sum        !local sum of wts
    integer  :: igrow,igcol,iwgt   ! mct smat field indices
    integer  :: nr         !mct field index
    real(r8) :: wt         !mct weight

    real(r8),pointer :: fld_i(:), fld_o(:)    !dummy fields for testing
    real(r8) :: sum_fldi               !global sum of dummy input field
    real(r8) :: sum_fldo               !global sum of dummy output field
    real(r8) :: sum_areo               !global sum of dummy output field
    real(r8) :: sum_arei               !global sum of dummy input field
    real(r8) :: relerr = 0.001_r8      !relative error for error checks
    real(r8) :: sdx_i                   !input grid  longitudinal range
    real(r8) :: sdy_i                   !input grid  latitudinal  range
    real(r8) :: sdx_o                   !output grid longitudinal range
    real(r8) :: sdy_o                   !output grid latitudinal  range
    integer  :: ier                    !error status
!------------------------------------------------------------------------

    nlon_i =  latlon_i%ni
    nlat_i =  latlon_i%nj
    latn_i => latlon_i%latn
    lats_i => latlon_i%lats
    lonw_i => latlon_i%lonw
    lone_i => latlon_i%lone
    fland_i => fracin

    nlon_o =  latlon_o%ni
    nlat_o =  latlon_o%nj
    latn_o => latlon_o%latn
    lats_o => latlon_o%lats
    lonw_o => latlon_o%lonw
    lone_o => latlon_o%lone
    fland_o => fracout

    ! Dynamically allocate memory

    na = nlon_i*nlat_i
    nb = nlon_o*nlat_o
    noffsetl = 1

    ! Get indices and weights for mapping from input grid to output grid

    allocate(jilap(nlat_i))
    allocate(iilaps(nlon_o),iilape(nlon_o))

    ! Find start/end indices for i overlap to save time later, set default never
    iilaps = nlon_i
    iilape = 1
    do io = 1, nlon_o
       !------ offset -------
       do n = 0,noffsetl   ! loop through offsets
          if (lonw_i(1) < lonw_o(1)) then
             offset = (n*360)
          else
             offset = -(n*360)
          end if

          do ii = 1, nlon_i
             !--- lons overlap ---
             if (lonw_i(ii)+offset < lone_o(io) .and. &
                 lone_i(ii)+offset > lonw_o(io)) then
                 if (ii < iilaps(io)) iilaps(io) = ii
                 if (ii > iilape(io)) iilape(io) = ii
             endif
          enddo
       enddo
    enddo

    do k = 1,2    ! k = 1 compute num of wts, k = 2 set wts
       if (k == 2) then
          call mct_sMat_init(sMat, nb, na, nwts)
          igrow = mct_sMat_indexIA(sMat,'grow')
          igcol = mct_sMat_indexIA(sMat,'gcol')
          iwgt  = mct_sMat_indexRA(sMat,'weight')
       endif
       nw = 0
       deg2rad = SHR_CONST_PI / 180._r8

       !------ output grid -------
       do jo = 1, nlat_o
          njilap = 0
          do ji = 1, nlat_i
             !--- lats overlap ---
             if ( lats_i(ji)<latn_o(jo) .and. &
                  latn_i(ji)>lats_o(jo)) then
                njilap = njilap + 1
                jilap(njilap) = ji
             endif
          enddo

       do io = 1, nlon_o
          ns = nw + 1

          !------ input grid -------
          sum = 0._r8
          do nji = 1, njilap
             ji = jilap(nji)

             !------ offset -------
             do n = 0,noffsetl   ! loop through offsets
                if (lonw_i(1) < lonw_o(1)) then
                   offset = (n*360)
                else
                   offset = -(n*360)
                end if

!             do ii = 1, nlon_i
              do ii = iilaps(io),iilape(io)
                ni = (ji-1)*nlon_i + ii
                no = (jo-1)*nlon_o + io
                !--- lons overlap ---
                if (k == 1) then
                   if (lonw_i(ii)+offset < lone_o(io) .and. &
                       lone_i(ii)+offset > lonw_o(io)) then
                       
                      !------- found overlap ------
                      if (fland_i(ni) > 0._r8 .and. fland_o(no) > 0._r8 ) then
                         nw = nw + 1
                      endif
                   endif
                elseif (k == 2) then
                   if (lonw_i(ii)+offset < lone_o(io) .and. &
                       lone_i(ii)+offset > lonw_o(io)) then

                      ! determine area of overlap
                      lone = min(lone_o(io),lone_i(ii)+offset)*deg2rad 
                      lonw = max(lonw_o(io),lonw_i(ii)+offset)*deg2rad 
                      dx = max(0.0_r8,(lone-lonw))
                      latn = min(latn_o(jo),latn_i(ji))*deg2rad 
                      lats = max(lats_o(jo),lats_i(ji))*deg2rad 
                      dy = max(0.0_r8,(sin(latn)-sin(lats)))
                      a_ovr = dx*dy*re*re

                      sum = sum + a_ovr

                      !------- found overlap ------
                      if (fland_i(ni) > 0._r8 .and. fland_o(no) > 0._r8 ) then
                         nw = nw + 1
                         ! make sure nw <= nwts
                         if (nw > nwts) then
                            write(iulog,*) 'AREAOVR error: nw= ', &
                               nw,' exceeded nwts ceiling = ', &
                               nwts,' for output lon,lat = ',io,jo
                            call endrun
                         end if

                         ! save cell indices, area
                         sMat%data%iAttr(igrow,nw) = no
                         sMat%data%iAttr(igcol,nw) = ni
                         sMat%data%rAttr(iwgt ,nw) = a_ovr
                      endif
                   endif
                end if   ! found overlap lon
             end do   ! ii
             enddo    ! offset loop
          end do   ! ji

          !--- normalize ---
          if (k == 2) then
             do n = ns,nw
                if (sum > 0._r8) then
                   sMat%data%rAttr(iwgt,n) = sMat%data%rAttr(iwgt,n) / sum
                else 
                   sMat%data%rAttr(iwgt,n) = 0._r8
                endif
             enddo
           endif

       end do  ! io
       end do  ! jo

       nwts = nw

    enddo   ! k loop

    deallocate(jilap)
    deallocate(iilaps,iilape)


    ! Error check: global sum fld_o = global sum fld_i.
    ! This true only if both grids span the same domain.

    sdx_i = lone_i(nlon_i) - lonw_i(1)
    sdx_o = lone_o(nlon_o) - lonw_o(1)

    sdy_i = max(abs(latn_i(nlat_i)-lats_i(1)),abs(lats_i(nlat_i)-latn_i(1)))
    sdy_o = max(abs(latn_o(nlat_o)-lats_o(1)),abs(lats_o(nlat_o)-latn_o(1)))

    if (abs(sdx_i-sdx_o)>relerr .or. abs(sdy_i-sdy_o)>relerr) then
       if (masterproc) then
          write(iulog,*) 'MAP_SETMAPSAR warning: lats/lons not overlapping'
          write(iulog,*) '   input  grid of ',nlon_i,' x ',nlat_i,' dx,dy= ',sdx_i,sdy_i
          write(iulog,*) '   output grid of ',nlon_o,' x ',nlat_o,' dx,dy= ',sdx_o,sdy_o
       endif
       return
    end if


    ! Compute dx,dy for checking areas later

    allocate(dx_i(nlon_i),dy_i(nlat_i),dx_o(nlon_o),dy_o(nlat_o))

    do i = 1,nlon_i
       dx_i(i) = (lone_i(i) - lonw_i(i))*deg2rad
    enddo
    do j = 1,nlat_i
       dy_i(j) = sin(latn_i(j)*deg2rad) - sin(lats_i(j)*deg2rad)
    enddo

    do i = 1,nlon_o
       dx_o(i) = (lone_o(i) - lonw_o(i))*deg2rad
    enddo
    do j = 1,nlat_o
       dy_o(j) = sin(latn_o(j)*deg2rad) - sin(lats_o(j)*deg2rad)
    enddo

    ! check for conservation

    allocate(fld_i(na),fld_o(nb))

    sum_fldi = 0._r8
    sum_arei = 0._r8
    do j = 1,nlat_i
    do i = 1,nlon_i
       ni = (j-1)*nlon_i + i
       fld_i(ni) = ni
       sum_fldi = sum_fldi + fld_i(ni)*dx_i(i)*dy_i(j)*fland_i(ni)
       sum_arei = sum_arei + dx_i(i)*dy_i(j)*fland_i(ni)
    end do
    end do

    fld_o = 0._r8
    do n = 1,mct_sMat_lsize(sMat)
       no = sMat%data%iAttr(igrow,n)
       ni = sMat%data%iAttr(igcol,n)
       wt = sMat%data%rAttr(iwgt ,n)
       fld_o(no) = fld_o(no) + wt*fld_i(ni)
    enddo

    sum_fldo = 0._r8
    sum_areo = 0._r8
    do j = 1,nlat_o
    do i = 1,nlon_o
       no = (j-1)*nlon_o + i
       sum_fldo = sum_fldo + dx_o(i)*dy_o(j)*fld_o(no)
       sum_areo = sum_areo + dx_o(i)*dy_o(j)*fland_o(no)
    end do
    end do

    if ( abs(sum_fldo/sum_fldi-1._r8) > relerr ) then
       if ( abs(sum_arei-sum_areo)/(sum_arei+sum_areo) > relerr ) then
          if (masterproc) then
             write(iulog,*) 'MAP_SETMAPSAR: no conservation check done, mask incompatable'
             write(iulog,'(a30,e20.10)') 'global sum input  field = ',sum_arei
             write(iulog,'(a30,e20.10)') 'global sum output field = ',sum_areo
          endif
       else
          if (masterproc) then
             write(iulog,*) 'MAP_SETMAPSAR error: conservation check fail'
             write(iulog,'(a30,e20.10)') 'global sum input  field = ',sum_fldi
             write(iulog,'(a30,e20.10)') 'global sum output field = ',sum_fldo
           endif
       endif
    else
       if (masterproc) then
          write(iulog,*) 'MAP_SETMAPSAR: conservation check passed'
          write(iulog,'(a30,e20.10)') 'global sum input  field = ',sum_fldi
          write(iulog,'(a30,e20.10)') 'global sum output field = ',sum_fldo
       endif
    endif

    deallocate(dx_i,dy_i,dx_o,dy_o)
    deallocate(fld_i,fld_o)

  end subroutine map_setmapsAR

!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: map_checkmap
!
! !INTERFACE:

  subroutine map_checkmap(map) 2,5
!
! !DESCRIPTION:
! Checks the map for consistency
!
! !USES:
  use spmdMod
  use decompMod, only : get_proc_bounds, get_proc_bounds_atm
!
! !ARGUMENTS:
  implicit none
  type(map_type),intent(in) :: map
!
! !REVISION HISTORY:
! 2005.12.01  T Craig  Creation.
!
!
! !LOCAL VARIABLES:
!EOP
    integer          :: nlon_i       !input  grid: max number of longitude pts
    integer          :: nlat_i       !input  grid: number of latitude  points
    integer          :: nlon_o       !output grid: max number of longitude pts
    integer          :: nlat_o       !output grid: number of latitude  points
    integer          :: nwts         !local num of weights
    integer          :: dstmo        !max num of overlapping cells
    integer ,pointer :: src(:)       !src index
    integer ,pointer :: dst(:)       !dst index
    real(r8),pointer :: wts(:)       !weight
    integer          :: n            !loop counters
    real(r8),pointer :: rsum(:)      !local array for deriving values
    real(r8)         :: rmin,rmax    !local min/max values
    real(r8)         :: smin,smax    !local min/max values
    integer          :: imin,imax    !local min/max values
    integer          :: nmin,nmax,nsum  !local min/max/sum values
    integer          :: ier          ! error flag
!
!------------------------------------------------------------------------

    !--- get general info ---
    call map_setptrs(map,ni_i=nlon_i,nj_i=nlat_i, &
                         ni_o=nlon_o,nj_o=nlat_o)
    call map_setptrs(map,nwts=nwts,src=src,dst=dst,wts=wts,dstmo=dstmo)

    if (masterproc) then
       write(iulog,*) ' '
       write(iulog,*) 'map_checkmap name          = ',trim(map%name)
       write(iulog,*) 'map_checkmap type          = ',trim(map%type)
       write(iulog,*) 'map_checkmap src grid      = ',nlon_i,nlat_i
       write(iulog,*) 'map_checkmap dst grid      = ',nlon_o,nlat_o
       write(iulog,*) 'map_checkmap dstmo         = ',dstmo
    endif

    call mpi_reduce(nwts,nmin,1,MPI_INTEGER,MPI_MIN,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce nwts error: ',ier
    endif
    call mpi_reduce(nwts,nmax,1,MPI_INTEGER,MPI_MAX,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce nwts error: ',ier
    endif
    call mpi_reduce(nwts,nsum,1,MPI_INTEGER,MPI_SUM,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce nwts error: ',ier
    endif
    if (masterproc) then
       write(iulog,*) 'map_checkmap nwts gmin/max = ',nmin,nmax
       write(iulog,*) 'map_checkmap nwts gsum     = ',nsum
    endif

    imin = minval(src)
    imax = maxval(src)
    call mpi_reduce(imin,nmin,1,MPI_INTEGER,MPI_MIN,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce src min error: ',ier
    endif
    call mpi_reduce(imax,nmax,1,MPI_INTEGER,MPI_MAX,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce src max error: ',ier
    endif
    if (masterproc) then
       write(iulog,*) 'map_checkmap src gmin/max  = ',nmin,nmax
    endif

    imin = minval(dst)
    imax = maxval(dst)
    call mpi_reduce(imin,nmin,1,MPI_INTEGER,MPI_MIN,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce dst min error: ',ier
    endif
    call mpi_reduce(imax,nmax,1,MPI_INTEGER,MPI_MAX,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce dst max error: ',ier
    endif
    if (masterproc) then
       write(iulog,*) 'map_checkmap dst gmin/max  = ',nmin,nmax
    endif

    rmin = minval(wts)
    rmax = maxval(wts)
    call mpi_reduce(rmin,smin,1,MPI_REAL8,MPI_MIN,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce wts min error: ',ier
    endif
    call mpi_reduce(rmax,smax,1,MPI_REAL8,MPI_MAX,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce wts max error: ',ier
    endif
    if (masterproc) then
       write(iulog,*) 'map_checkmap wts gmin/max  = ',smin,smax
    endif

    imin = minval(dst)
    imax = maxval(dst)
    allocate(rsum(imin:imax))
    rsum = 0.0_r8
    do n = 1,nwts
       if (dst(n) < imin .or. dst(n) > imax) then
          write(iulog,*) 'map_checkmap dst index error ',n,dst(n),imin,imax
          call endrun()
       endif
       rsum(dst(n)) = rsum(dst(n)) + wts(n)
    enddo
    rmin = minval(rsum)
    rmax = maxval(rsum)
    deallocate(rsum)
    call mpi_reduce(rmin,smin,1,MPI_REAL8,MPI_MIN,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce swts min error: ',ier
    endif
    call mpi_reduce(rmax,smax,1,MPI_REAL8,MPI_MAX,0,mpicom,ier)
    if (ier /= 0) then
       write(iulog,*)'mpi_reduce swts max error: ',ier
    endif
    if (masterproc) then
       write(iulog,*) 'map_checkmap swts gmin/max  = ',smin,smax
    endif

end subroutine map_checkmap

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: cellarea
!
! !INTERFACE:

  real(r8) function cellarea(latlon,i,j) 2
!
! !DESCRIPTION:
! Comute area of grid cells (square kilometers)
! Verify total area from grid cells is same as area of grid
! as defined by its edges
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(latlon_type), intent(in   ) :: latlon    ! latlon datatype
    integer          , intent(in)    :: i,j       ! latlon index to compute
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
!
!
! !LOCAL VARIABLES:
!EOP
    integer  :: nbeg
    integer  :: nend
    integer  :: ni
    integer  :: nj

    real(r8) deg2rad            !pi/180
    real(r8) dx                 !cell width: E-W
    real(r8) dy                 !cell width: N-S
!------------------------------------------------------------------------

    deg2rad = SHR_CONST_PI / 180._r8

    dx = (latlon%lone(i) - latlon%lonw(i)) * deg2rad
    dy = sin(latlon%latn(j)*deg2rad) - sin(latlon%lats(j)*deg2rad)

    cellarea = dx*dy*re*re

    return

  end function cellarea

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: latlon_celledge_regional
!
! !INTERFACE:

  subroutine latlon_celledge_regional (latlon, edgen, edgee, edges, edgew) 1
!
! !DESCRIPTION:
! Southern and western edges of grid cells - regional grid
! (can become global as special case)
! Latitudes -- southern/northern edges for each latitude strip.
! For grids oriented South to North, the southern
! and northern edges of latitude strip [j] are:
!        southern = lats(j  )
!        northern = lats(j+1)
! For grids oriented North to South: the southern
! and northern edges of latitude strip [j] are:
!        northern = lats(j  )
!        southern = lats(j+1)
! In both cases, [lats] must be dimensioned lats(lat+1)
! Longitudes -- western edges. Longitudes for the western edge of the
! cells must increase continuously and span 360 degrees. Assume that
! grid starts at Dateline with western edge on Dateline Western edges
! correspond to [lonc] (longitude at center of cell) and range from
! -180 to 180 with negative longitudes west of Greenwich.
! Partial grids that do not span 360 degrees are allowed so long as they
! have the convention of Grid 1 with
!      western edge of grid: >= -180 and < 180
!      eastern edge of grid: > western edge  and <= 180
! [lonw] must be dimensioned lonw(lon+1,lat) because each latitude
! strip can have variable longitudinal resolution
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(latlon_type),intent(inout) :: latlon
    real(r8), intent(in) :: edgen             !northern edge of grid (degrees)
    real(r8), intent(in) :: edgee             !eastern edge of grid (degrees)
    real(r8), intent(in) :: edges             !southern edge of grid (degrees)
    real(r8), intent(in) :: edgew             !western edge of grid (degrees)

!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! 2005.11.20 Updated to latlon datatype by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
    integer  :: nlon              
    integer  :: nlat              
    real(r8),pointer :: lonc(:) 
    real(r8),pointer :: latc(:) 
    real(r8),pointer :: lats(:)   
    real(r8),pointer :: latn(:)   
    real(r8),pointer :: lonw(:)   
    real(r8),pointer :: lone(:)   
    integer i,j             !indices
    real(r8) dx             !cell width
!------------------------------------------------------------------------

    nlon = latlon%ni
    nlat = latlon%nj
    lonc => latlon%lonc
    latc => latlon%latc
    lats => latlon%lats
    latn => latlon%latn
    lonw => latlon%lonw
    lone => latlon%lone

    ! Latitudes
    ! Assumes lats are constant on an i line

    if (nlat == 1) then                      ! single latitude
       lats(:)    = edges
       latn(:)    = edgen
    elseif (latc(2) > latc(1)) then  ! South to North grid
       lats(:) = edges
       latn(:) = edgen
       do j = 2, nlat
          lats(j) = (latc(j-1) + latc(j)) / 2._r8
          latn(j-1) = lats(j)
       end do
    else                                     ! North to South grid
       lats(:) = edges
       latn(:) = edgen
       do j = 2, nlat
          latn(j)    = (latc(j-1) + latc(j)) / 2._r8
          lats(j-1) = latn(j)
       end do
    end if

    ! Longitudes
    ! Western edge of first grid cell -- since grid starts with western
    ! edge on Dateline, lonw(1,j)=-180. This is the same as [edgew].

    lonw(:) = edgew
    lone(:) = edgee
    dx = (edgee - edgew) / nlon
    do i = 2, nlon
       lonw(i)    = lonw(i) + (i-1)*dx
       lone(i-1) = lonw(i)
    end do

    latlon%regional = .true.
    latlon%edges(1) = edgen
    latlon%edges(2) = edgee
    latlon%edges(3) = edges
    latlon%edges(4) = edgew

    return

  end subroutine latlon_celledge_regional

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: latlon_celledge_global
!
! !INTERFACE:

  subroutine latlon_celledge_global (latlon) 1,1
!
! !DESCRIPTION:
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(latlon_type),intent(inout) :: latlon

!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! 2005.11.20 Updated to latlon datatype by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
    integer  :: nlon              
    integer  :: nlat              
    real(r8),pointer :: lonc(:) 
    real(r8),pointer :: latc(:) 
    real(r8),pointer :: lats(:)   
    real(r8),pointer :: latn(:)   
    real(r8),pointer :: lonw(:)   
    real(r8),pointer :: lone(:)   
    integer i,j             !indices
    real(r8) dx             !cell width
!------------------------------------------------------------------------

    nlon = latlon%ni
    nlat = latlon%nj
    lonc => latlon%lonc
    latc => latlon%latc
    lats => latlon%lats
    latn => latlon%latn
    lonw => latlon%lonw
    lone => latlon%lone

    ! Latitudes
    lats(:) = -90._r8
    latn(:) =  90._r8
    do j = 2, nlat   
       lats(j) = (latc(j-1) + latc(j)) / 2._r8
       latn(j-1) = lats(j)
    end do

    ! Longitudes

    if (lonc(1) >= 0._r8) then
       dx = 360._r8/(nlon)
       lonw(:) = -dx/2._r8
       lone(:) = -dx/2._r8 + (nlon)*dx
       do i = 2, nlon
          lonw(i)    = -dx/2._r8 + (i-1)*dx
          lone(i-1) = lonw(i)
       end do
    else
       write(iulog,*)'global non-regional grids currently only supported ', &
            'for grids starting at greenwich and centered on Greenwich'
       call endrun
    endif

    return
  end subroutine latlon_celledge_global

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

end module areaMod