#include <misc.h>
#include <preproc.h>


module surfrdMod 1,15

!-----------------------------------------------------------------------
!BOP
!
! !MODULE: surfrdMod
!
! !DESCRIPTION:
! Contains methods for reading in surface data file and determining
! two-dimensional subgrid weights as well as writing out new surface
! dataset. When reading in the surface dataset, determines array
! which sets the PFT for each of the [maxpatch] patches and
! array which sets the relative abundance of the PFT.
! Also fills in the PFTs for vegetated portion of each grid cell.
! Fractional areas for these points pertain to "vegetated"
! area not to total grid area. Need to adjust them for fraction of grid
! that is vegetated. Also fills in urban, lake, wetland, and glacier patches.
!
! !USES:
  use shr_kind_mod, only : r8 => shr_kind_r8
  use abortutils  , only : endrun
  use clm_varpar  , only : lsmlon, lsmlat
  use clm_varpar  , only : nlevsoi, numpft, &
                           maxpatch_pft, numcft, maxpatch, &
                           npatch_urban, npatch_lake, npatch_wet, npatch_glacier, &
                           maxpatch_urb
  use clm_varpar  , only : npatch_glacier_mec
  use clm_varctl  , only : create_glacier_mec_landunit
  use clm_varsur  , only : wtxy, vegxy
  use clm_varsur  , only : topoxy
  use clm_varsur  , only : pctspec
  use clm_varctl  , only : iulog
  use ncdio
  use clmtype
  use spmdMod                         
  use clm_varctl,   only : scmlat, scmlon, single_column
  use decompMod   , only : get_proc_bounds,gsMap_lnd_gdc2glo,ldecomp

!
! !PUBLIC TYPES:
  implicit none
  save
!
! !PUBLIC MEMBER FUNCTIONS:
  public :: surfrd  ! Read surface dataset and determine subgrid weights
  public :: surfrd_get_grid  ! Read surface dataset into domain
  public :: surfrd_get_latlon  ! Read surface dataset into domain
  public :: surfrd_get_frac  ! Read land fraction into domain
  public :: surfrd_get_topo  ! Read topography into domain

!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! Updated by T Craig
!
!
! !PRIVATE MEMBER FUNCTIONS:
  private :: surfrd_wtxy_special
  private :: surfrd_wtxy_veg_rank
  private :: surfrd_wtxy_veg_all
  private :: surfrd_wtxy_veg_dgvm
  private :: surfrd_mkrank
!EOP
!-----------------------------------------------------------------------

contains

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd
!
! !INTERFACE:
!  subroutine surfrd(vegxy, wtxy, lfsurdat, domain)

  subroutine surfrd(lfsurdat, domain) 1,14
!
! !DESCRIPTION:
! Read the surface dataset and create subgrid weights.
! The model's surface dataset recognizes 6 basic land cover types within a grid
! cell: lake, wetland, urban, glacier, glacier_mec and vegetated. The vegetated
! portion of the grid cell is comprised of up to [maxpatch_pft] PFTs. These
! subgrid patches are read in explicitly for each grid cell. This is in
! contrast to LSMv1, where the PFTs were built implicitly from biome types.
!    o real edges of grid
!    o integer  number of longitudes per latitude
!    o real latitude  of grid cell (degrees)
!    o real longitude of grid cell (degrees)
!    o integer surface type: 0 = ocean or 1 = land
!    o integer soil color (1 to 20) for use with soil albedos
!    o real soil texture, %sand, for thermal and hydraulic properties
!    o real soil texture, %clay, for thermal and hydraulic properties
!    o real % of cell covered by lake    for use as subgrid patch
!    o real % of cell covered by wetland for use as subgrid patch
!    o real % of cell that is urban      for use as subgrid patch
!    o real % of cell that is glacier    for use as subgrid patch
!    o real % of cell that is glacier_mec for use as subgrid patch
!    o integer PFTs
!    o real % abundance PFTs (as a percent of vegetated area)
!
! !USES:
    use clm_varctl  , only : allocate_all_vegpfts, create_crop_landunit
    use pftvarcon   , only : noveg
    use fileutils   , only : getfil
    use domainMod , only : domain_type
!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
!    integer , intent(out) :: vegxy(:,:)   ! PFT
!    real(r8), intent(out) :: wtxy(:,:)  ! subgrid weights
    character(len=*), intent(in) :: lfsurdat               ! surf filename
    type(domain_type),intent(in) :: domain ! domain associated with wtxy
!
! !CALLED FROM:
! subroutine initialize in module initializeMod
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan
!
!
! !LOCAL VARIABLES:
!EOP
    character(len=256) :: locfn                          ! local file name
    integer  :: ncid,dimid,varid                         ! netCDF id's
    integer  :: begg,endg   
    logical  :: found                                    ! temporary for error check
    integer  :: iindx, jindx                             ! temporary for error check
    integer  :: ier                                      ! error status
    character(len=32) :: subname = 'surfrd'              ! subroutine name
!-----------------------------------------------------------------------

    call get_proc_bounds(begg,endg)
    allocate(pctspec(begg:endg))

    vegxy(:,:) = noveg
    wtxy(:,:)  = 0._r8
    pctspec(:) = 0._r8
    if (allocated(topoxy)) topoxy(:,:) = 0._r8

    if (masterproc) then
       write(iulog,*) 'Attempting to read surface boundary data .....'
       if (lfsurdat == ' ') then
          write(iulog,*)'lfsurdat must be specified'; call endrun()
       endif
    endif

    ! Read surface data

    if (masterproc) then
       call getfil( lfsurdat, locfn, 0 )
       call check_ret( nf_open(locfn, 0, ncid), subname )
    end if

    ! Obtain surface dataset special landunit info

    call surfrd_wtxy_special(ncid, domain)

    ! Obtain surface dataset vegetated landunit info

#if (defined CNDV)
    if (create_crop_landunit) then ! CNDV means allocate_all_vegpfts = .true.
       call surfrd_wtxy_veg_all(ncid, domain)
    end if
    call surfrd_wtxy_veg_dgvm(domain)
#else
    if (allocate_all_vegpfts) then
       call surfrd_wtxy_veg_all(ncid, domain)
    else
       call surfrd_wtxy_veg_rank(ncid, domain)
    end if
#endif

    if ( masterproc )then
       call check_ret(nf_close(ncid), subname)
       write(iulog,*) 'Successfully read surface boundary data'
       write(iulog,*)
    end if

  end subroutine surfrd

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_get_grid
!
! !INTERFACE:

  subroutine surfrd_get_grid(domain,filename,beg,end,clmlevel) 2,19
!
! !DESCRIPTION:
! Read the surface dataset grid related information:
! o real edges of grid
! o integer  number of longitudes per latitude
! o real latitude  of grid cell (degrees)
! o real longitude of grid cell (degrees)
! If grid is read in from dataset, grid is assumed to be global but
! does not have to be regular.
! If grid is generated by model, grid does not have to be global but 
! must then define the north, east, south, and west edges:
!
! o edges(1)    = northern edge of grid (degrees): >  -90 and <= 90
! o edges(2)    = eastern edge of grid (degrees) : see following notes
! o edges(3)    = southern edge of grid (degrees): >= -90 and <  90
! o edges(4)    = western edge of grid (degrees) : see following notes
!
!   For partial grids, northern and southern edges are any latitude
!   between 90 (North Pole) and -90 (South Pole). Western and eastern
!   edges are any longitude between -180 and 180, with longitudes
!   west of Greenwich negative. That is, western edge >= -180 and < 180;
!   eastern edge > western edge and <= 180.
!
!   For global grids, northern and southern edges are 90 (North Pole)
!   and -90 (South Pole). The western and eastern edges depend on
!   whether the grid starts at Dateline or Greenwich. Regardless,
!   these edges must span 360 degrees. Examples:
!
!                              West edge    East edge
!                            --------------------------------------------------
!  (1) Dateline            :        -180 to 180       (negative W of Greenwich)
!  (2) Greenwich (centered):    0 - dx/2 to 360 - dx/2
!
!    Grid 2 is the grid for cam and ccsm mode since the NCAR CAM
!    starts at Greenwich, centered on Greenwich
!
! !USES:
    use clm_varcon, only : spval
    use domainMod , only : domain_type,domain_init
    use fileutils , only : getfil
!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
    type(domain_type),intent(inout) :: domain   ! domain to init
    character(len=*) ,intent(in)    :: filename ! grid filename
    integer          ,intent(in)    :: beg      ! local beg index
    integer          ,intent(in)    :: end      ! local end index
    character(len=*) ,intent(in)    :: clmlevel ! type of grid
!
! !CALLED FROM:
! subroutine surfrd in this module
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: ni,nj               ! size of grid on file
    integer :: ncid,dimid,varid    ! netCDF id's
    integer :: ier                 ! error status
    character(len=256)  :: locfn   ! local file name
    integer :: ret
    character(len=32) :: subname = 'surfrd_get_grid'     ! subroutine name
!-----------------------------------------------------------------------

    if (masterproc) then

       if (filename == ' ') then
          write(iulog,*) trim(subname),' ERROR: filename must be specified '
          call endrun()
       endif

       call getfil( filename, locfn, 0 )
       call check_ret( nf_open(locfn, 0, ncid), subname )

       if (single_column) then
          ni = lsmlon
          nj = lsmlat
       else
          call check_ret(nf_inq_dimid (ncid, 'lsmlon', dimid), subname)
          call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname)
          call check_ret(nf_inq_dimid (ncid, 'lsmlat', dimid), subname)
          call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname)
       endif

    endif

    call mpi_bcast (ni, 1, MPI_INTEGER, 0, mpicom, ier)
    call mpi_bcast (nj, 1, MPI_INTEGER, 0, mpicom, ier)

    call domain_init(domain,ni,nj,beg,end,clmlevel)

    call ncd_iolocal(ncid, 'AREA', 'read', domain%area, clmlevel, status=ret)
    if (ret == 0) domain%areaset = .true.

    call ncd_iolocal(ncid, 'LONGXY', 'read', domain%lonc, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY NOT on file' )
    call ncd_iolocal(ncid, 'LATIXY', 'read', domain%latc, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LATIXY NOT on file' )

! set mask to 1 everywhere by default, override if LANDMASK exists
! if landmask exists, use it to set pftm (for older datasets)
! pftm should be overwritten below for newer datasets
    domain%mask = 1
    call ncd_iolocal(ncid, 'LANDMASK', 'read', domain%mask, clmlevel, status=ret)
    domain%pftm = domain%mask
    where (domain%mask <= 0)
       domain%pftm = -1
    endwhere

    call ncd_iolocal(ncid, 'PFTDATA_MASK', 'read', domain%pftm, clmlevel, status=ret)

!tcx fix, this or a test/abort should be added so overlaps can be computed
!tcx fix, this is demonstrated not bfb in cam bl311 test.
!tcx fix, see also lat_o_local in areaMod.F90
#if (defined TCX_REMOVE_SEE_NOTES_ABOVE)
       ! Check lat limited to -90,90
       if (minval(domain%latc) < -90.0_r8 .or. &
           maxval(domain%latc) >  90.0_r8) then
           write(iulog,*) trim(subname),' Limiting lat/lon to [-90/90] from ', &
              minval(domain%latc),maxval(domain%latc)
           where (domain%latc < -90.0_r8) domain%latc = -90.0_r8
           where (domain%latc >  90.0_r8) domain%latc =  90.0_r8
       endif
#endif

    if (masterproc) call check_ret(nf_close(ncid), subname)

  end subroutine surfrd_get_grid

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_get_latlon
!
! !INTERFACE:

  subroutine surfrd_get_latlon(latlon,filename,mask,mfilename,pftmflag) 2,31
!
! !DESCRIPTION:
! Read the surface dataset grid related information:
!
! !USES:
    use clm_varcon, only : spval
    use domainMod , only : latlon_type, latlon_init
    use fileutils , only : getfil
!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
    type(latlon_type)         ,intent(inout) :: latlon   ! domain to init
    character(len=*)          ,intent(in)    :: filename ! grid filename
    integer,pointer  ,optional               :: mask(:)
    character(len=*) ,optional,intent(in)    :: mfilename ! grid filename
    logical          ,optional,intent(in)    :: pftmflag   ! is mask pft mask?
!
! !CALLED FROM:
! subroutine surfrd in this module
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: ni,nj               ! size of grid on file
    integer :: n                   ! index
    integer :: ncid,dimid,varid    ! netCDF id's
    integer :: ncidm               ! mask file netCDF id's
    integer :: ier                 ! error status
    character(len=256)  :: locfn   ! local file name
    integer :: ret, time_index
    real(r8),pointer :: rdata(:,:) ! temporary data
    logical :: NSEWset             ! true if lat/lon NSEW read from grid file
    logical :: EDGEset             ! true if EDGE NSEW read from grid file
    logical :: lpftmflag           ! is mask a pft mask, local copy
    logical :: readv               ! read variable in or not
    character(len=32) :: subname = 'surfrd_get_latlon'     ! subroutine name
!-----------------------------------------------------------------------

    NSEWset = .false.
    EDGEset = .false.
    lpftmflag = .false.
    ni = 0
    nj = 0

    if (present(pftmflag)) then
       lpftmflag = pftmflag
    endif

    if (masterproc) then

       if (filename == ' ') then
          write(iulog,*) trim(subname),' ERROR: filename must be specified '
          call endrun()
       endif

       call getfil( filename, locfn, 0 )
       call check_ret( nf_open(locfn, 0, ncid), subname )

       if (single_column) then
          ni = lsmlon
          nj = lsmlat
       else
          ier = nf_inq_dimid (ncid, 'lon', dimid)
          if (ier == NF_NOERR) then
            call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname)
          endif
          ier = nf_inq_dimid (ncid, 'lat', dimid)
          if (ier == NF_NOERR) then
            call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname)
          endif
          ier = nf_inq_dimid (ncid, 'lsmlon', dimid)
          if (ier == NF_NOERR) then
            call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname)
          endif
          ier = nf_inq_dimid (ncid, 'lsmlat', dimid)
          if (ier == NF_NOERR) then
            call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname)
          endif
       endif

       if (ni == 0 .or. nj == 0) then
          write(iulog,*) trim(subname),' ERROR: ni or nj not set',ni,nj
          call endrun()
       endif

    endif

    call mpi_bcast (ni, 1, MPI_INTEGER, 0, mpicom, ier)
    call mpi_bcast (nj, 1, MPI_INTEGER, 0, mpicom, ier)

    call latlon_init(latlon,ni,nj)
    if (present(mask)) then
       allocate(mask(ni*nj))
       mask = 1
    endif

    if (masterproc) then

       allocate(rdata(ni,nj))

       call ncd_ioglobal('LONGXY',rdata,'read',ncid,readvar=readv)
       if ( .not. readv ) call endrun( trim(subname)//' ERROR: LONGXY NOT on file' )
       latlon%lonc(:) = rdata(:,1)

       call ncd_ioglobal('LATIXY',rdata,'read',ncid,readvar=readv)
       if ( .not. readv ) call endrun( trim(subname)//' ERROR: LONGXY NOT on file' )
       latlon%latc(:) = rdata(1,:)

       if (single_column) then
          EDGEset = .true.
          latlon%edges(1) = 90.0_r8
          latlon%edges(2) = latlon%lonc(1) + 180._r8
          latlon%edges(3) = -90.0_r8
          latlon%edges(4) = latlon%lonc(1) - 180._r8
       else
          latlon%edges(:) = spval
          ier = nf_inq_varid (ncid, 'EDGEN', varid)
          if (ier == NF_NOERR) then
             EDGEset = .true.
             call ncd_ioglobal('EDGEN',latlon%edges(1),'read',ncid,readvar=readv)
             call ncd_ioglobal('EDGEE',latlon%edges(2),'read',ncid,readvar=readv)
             call ncd_ioglobal('EDGES',latlon%edges(3),'read',ncid,readvar=readv)
             call ncd_ioglobal('EDGEW',latlon%edges(4),'read',ncid,readvar=readv)
             if (maxval(latlon%edges) > 1.0e35) EDGEset = .false. !read garbage
          endif
       endif

       ier = nf_inq_varid (ncid, 'LATN', varid)
       if (ier == NF_NOERR) then
          NSEWset = .true.
          call ncd_ioglobal('LATN',rdata,'read',ncid)
          latlon%latn(:) = rdata(1,:)
          call ncd_ioglobal('LONE',rdata,'read',ncid)
          latlon%lone(:) = rdata(:,1)
          call ncd_ioglobal('LATS',rdata,'read',ncid)
          latlon%lats(:) = rdata(1,:)
          call ncd_ioglobal('LONW',rdata,'read',ncid)
          latlon%lonw(:) = rdata(:,1)
       endif

       if (present(mask)) then
          if (present(mfilename)) then
             if (mfilename == ' ') then
               write(iulog,*) trim(subname),' ERROR: mfilename must be specified '
               call endrun()
             endif

             call getfil( mfilename, locfn, 0 )
             call check_ret( nf_open(locfn, 0, ncidm), subname )
          else
             ncidm = ncid
          endif

          mask = 1
          ier = nf_inq_varid(ncidm, 'LANDMASK', varid)
          if (ier == NF_NOERR) then
             call ncd_ioglobal('LANDMASK',mask,'read',ncidm)
          endif

          !--- if this is a pft mask, then modify and look for pftdata_mask array on dataset ---
          if (lpftmflag) then
             do n = 1,ni*nj
                if (mask(n) <= 0) mask(n) = -1
             enddo
             ier = nf_inq_varid (ncidm, 'PFTDATA_MASK', varid)
             if (ier == NF_NOERR) then
                call ncd_ioglobal('PFTDATA_MASK',mask,'read',ncidm)
             endif
          endif

          if (present(mfilename)) then
             call check_ret(nf_close(ncidm), subname)
          endif

       endif

       deallocate(rdata)
        
!tcx fix, this or a test/abort should be added so overlaps can be computed
!tcx fix, this is demonstrated not bfb in cam bl311 test.
!tcx fix, see also lat_o_local in areaMod.F90
#if (defined TCX_REMOVE_SEE_NOTES_ABOVE)
       ! Check lat limited to -90,90
       if (minval(latlon%latc) < -90.0_r8 .or. &
           maxval(latlon%latc) >  90.0_r8) then
           write(iulog,*) trim(subname),' Limiting lat/lon to [-90/90] from ', &
              minval(latlon%latc),maxval(latlon%latc)
           where (latlon%latc < -90.0_r8) latlon%latc = -90.0_r8
           where (latlon%latc >  90.0_r8) latlon%latc =  90.0_r8
       endif
#endif

       call check_ret(nf_close(ncid), subname)

    end if   ! end of if-masterproc block

    call mpi_bcast (latlon%latc , size(latlon%latc) , MPI_REAL8  , 0, mpicom, ier)
    call mpi_bcast (latlon%lonc , size(latlon%lonc) , MPI_REAL8  , 0, mpicom, ier)
    call mpi_bcast (latlon%lats , size(latlon%lats) , MPI_REAL8  , 0, mpicom, ier)
    call mpi_bcast (latlon%latn , size(latlon%latn) , MPI_REAL8  , 0, mpicom, ier)
    call mpi_bcast (latlon%lonw , size(latlon%lonw) , MPI_REAL8  , 0, mpicom, ier)
    call mpi_bcast (latlon%lone , size(latlon%lone) , MPI_REAL8  , 0, mpicom, ier)
    call mpi_bcast (latlon%edges, size(latlon%edges), MPI_REAL8  , 0, mpicom, ier)
    if (present(mask)) then
       call mpi_bcast(mask      , size(mask)        , MPI_INTEGER, 0, mpicom, ier)
    endif

  end subroutine surfrd_get_latlon

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_get_frac
!
! !INTERFACE:

  subroutine surfrd_get_frac(domain,filename,glcfilename) 2,26
!
! !DESCRIPTION:
! Read the landfrac dataset grid related information:
! Assume domain has already been initialized and read
!
! !USES:
    use domainMod , only : domain_type
    use fileutils , only : getfil
!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
    type(domain_type),intent(inout) :: domain   ! domain to init
    character(len=*) ,intent(in)    :: filename ! grid filename
    character(len=*) ,optional, intent(in) :: glcfilename ! glc mask filename
!
! !CALLED FROM:
! subroutine initialize
!
! !REVISION HISTORY:
! Created by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: n                   ! indices
    integer :: ni,nj,ns            ! size of grid on file
    integer :: ncid,dimid,varid    ! netCDF id's
    integer :: ncidg               ! netCDF id for glcmask
    integer :: ier                 ! error status
    real(r8):: eps = 1.0e-12_r8    ! lat/lon error tolerance
    integer :: beg,end             ! local beg,end indices
    character(len=8)    :: clmlevel   ! grid type
    real(r8),pointer    :: lonc(:),latc(:)  ! local lat/lon
    character(len=256)  :: locfn   ! local file name
    integer :: ret, time_index
    character(len=32) :: subname = 'surfrd_get_frac'     ! subroutine name
!-----------------------------------------------------------------------

    if (masterproc) then

       if (filename == ' ') then
          write(iulog,*) trim(subname),' ERROR: filename must be specified '
          call endrun()
       endif

       call getfil( filename, locfn, 0 )
       call check_ret( nf_open(locfn, 0, ncid), subname )

       if (single_column) then
          ni = lsmlon
          nj = lsmlat
       else
          call check_ret(nf_inq_dimid (ncid, 'lsmlon', dimid), subname)
          call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname)
          call check_ret(nf_inq_dimid (ncid, 'lsmlat', dimid), subname)
          call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname)
       endif

       ns = ni*nj

       if (domain%ni /= ni .or. domain%nj /= nj .or. domain%ns /= ns) then
          write(iulog,*) trim(subname),' ERROR: landfrac file mismatch ni,nj',domain%ni,ni,domain%nj,nj,domain%ns,ns
          call endrun()
       endif

    endif

    ni  = domain%ni
    nj  = domain%nj
    beg = domain%nbeg
    end = domain%nend
    clmlevel = domain%clmlevel

    allocate(latc(beg:end),lonc(beg:end))

    call ncd_iolocal(ncid, 'LONGXY', 'read', lonc, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY NOT on fracdata file' )
    call ncd_iolocal(ncid, 'LATIXY', 'read', latc, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LATIXY NOT on fracdata file' )

    do n = beg,end
       if (abs(latc(n)-domain%latc(n)) > eps .or. &
           abs(lonc(n)-domain%lonc(n)) > eps) then
          write(iulog,*) trim(subname),' ERROR: landfrac file mismatch lat,lon',latc(n),domain%latc(n),lonc(n),domain%lonc(n),eps
          call endrun()
       endif
    enddo
          
    call ncd_iolocal(ncid, 'LANDMASK', 'read', domain%mask, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LANDMASK NOT on fracdata file' )
    call ncd_iolocal(ncid, 'LANDFRAC', 'read', domain%frac, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LANDFRAC NOT on fracdata file' )

    deallocate(latc,lonc)

    if (masterproc) call check_ret(nf_close(ncid), subname)

    if (present(glcfilename)) then

       if (masterproc) then

          if (glcfilename == ' ') then
             write(iulog,*) trim(subname),' ERROR: glc filename must be specified '
             call endrun()
          endif

          call getfil( glcfilename, locfn, 0 )
          call check_ret( nf_open(locfn, 0, ncidg), subname )

       endif   ! masterproc

       domain%glcmask = 0
       call ncd_iolocal(ncid, 'GLCMASK', 'read', domain%glcmask, clmlevel, status=ret)
       if (ret /= 0) call endrun( trim(subname)//' ERROR: GLCMASK NOT in file' )

       if (masterproc) call check_ret(nf_close(ncidg), subname)

    endif   ! present(glcfilename)

  end subroutine surfrd_get_frac

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_get_topo
!
! !INTERFACE:

  subroutine surfrd_get_topo(domain,filename) 2,18
!
! !DESCRIPTION:
! Read the topo dataset grid related information:
! Assume domain has already been initialized and read
!
! !USES:
    use domainMod , only : domain_type
    use fileutils , only : getfil
!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
    type(domain_type),intent(inout) :: domain   ! domain to init
    character(len=*) ,intent(in)    :: filename ! grid filename
!
! !CALLED FROM:
! subroutine initialize
!
! !REVISION HISTORY:
! Created by T Craig
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: n                   ! indices
    integer :: ni,nj,ns            ! size of grid on file
    integer :: ncid,dimid,varid    ! netCDF id's
    integer :: ier                 ! error status
    real(r8):: eps = 1.0e-12_r8    ! lat/lon error tolerance
    integer :: beg,end             ! local beg,end indices
    character(len=8)    :: clmlevel   ! grid type
    real(r8),pointer    :: lonc(:),latc(:)  ! local lat/lon
    character(len=256)  :: locfn   ! local file name
    integer :: ret, time_index
    character(len=32) :: subname = 'surfrd_get_topo'     ! subroutine name
!-----------------------------------------------------------------------

    if (masterproc) then

       if (filename == ' ') then
          write(iulog,*) trim(subname),' ERROR: filename must be specified '
          call endrun()
       endif

       call getfil( filename, locfn, 0 )
       call check_ret( nf_open(locfn, 0, ncid), subname )

       if (single_column) then
          ni = lsmlon
          nj = lsmlat
       else
          call check_ret(nf_inq_dimid (ncid, 'lsmlon', dimid), subname)
          call check_ret(nf_inq_dimlen(ncid, dimid, ni), subname)
          call check_ret(nf_inq_dimid (ncid, 'lsmlat', dimid), subname)
          call check_ret(nf_inq_dimlen(ncid, dimid, nj), subname)
       endif

       ns = ni*nj

       if (domain%ni /= ni .or. domain%nj /= nj .or. domain%ns /= ns) then
          write(iulog,*) trim(subname),' ERROR: topo file mismatch ni,nj',domain%ni,ni,domain%nj,nj,domain%ns,ns
          call endrun()
       endif

    endif

    ni  = domain%ni
    nj  = domain%nj
    beg = domain%nbeg
    end = domain%nend
    clmlevel = domain%clmlevel

    allocate(latc(beg:end),lonc(beg:end))

    call ncd_iolocal(ncid, 'LONGXY', 'read', lonc, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY  NOT on topodata file' )
    call ncd_iolocal(ncid, 'LATIXY', 'read', latc, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY  NOT on topodata file' )

    do n = beg,end
       if (abs(latc(n)-domain%latc(n)) > eps .or. &
           abs(lonc(n)-domain%lonc(n)) > eps) then
          write(iulog,*) trim(subname),' ERROR: topo file mismatch lat,lon',latc(n),domain%latc(n),lonc(n),domain%lonc(n),eps
          call endrun()
       endif
    enddo

    call ncd_iolocal(ncid, 'TOPO', 'read', domain%topo, clmlevel, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: LONGXY  NOT on topodata file' )

    deallocate(latc,lonc)

    if (masterproc) call check_ret(nf_close(ncid), subname)

  end subroutine surfrd_get_topo

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_wtxy_special 
!
! !INTERFACE:
!  subroutine surfrd_wtxy_special(ncid, pctspec, vegxy, wtxy, domain)

  subroutine surfrd_wtxy_special(ncid, domain) 1,25
!
! !DESCRIPTION:
! Determine weight with respect to gridcell of all special "pfts" as well
! as soil color and percent sand and clay
!
! !USES:
    use pftvarcon     , only : noveg
    use UrbanInputMod , only : urbinp
    use domainMod     , only : domain_type
    use clm_varctl    , only : glc_nec, glc_topomax

!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
    integer , intent(in)    :: ncid      ! netcdf file id 
!    real(r8), intent(inout) :: pctspec(:)! percent wrt gcell special lunits
!    integer , intent(inout) :: vegxy(:,:)  ! PFT
!    real(r8), intent(inout) :: wtxy(:,:) ! subgrid weights
    type(domain_type),intent(in) :: domain ! domain associated with wtxy
!
! !CALLED FROM:
! subroutine surfrd in this module
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan
!
!
! !LOCAL VARIABLES:
!EOP
    integer  :: n,nl,ns,nurb,g             ! indices
    integer  :: begg,endg                  ! gcell beg/end
    integer  :: dimid,varid                ! netCDF id's
    integer  :: ret
    real(r8) :: nlevsoidata(nlevsoi)
    logical  :: found                      ! temporary for error check
    integer  :: nindx                      ! temporary for error check
    integer  :: ier                        ! error status
    integer  :: nlev                       ! level
    integer  :: npatch
    real(r8),pointer :: pctgla(:)      ! percent of grid cell is glacier
    real(r8),pointer :: pctlak(:)      ! percent of grid cell is lake
    real(r8),pointer :: pctwet(:)      ! percent of grid cell is wetland
    real(r8),pointer :: pcturb(:)      ! percent of grid cell is urbanized
    real(r8),pointer :: pctglc_mec(:,:)   ! percent of grid cell is glacier_mec (in each elev class)
    real(r8),pointer :: pctglc_mec_tot(:) ! percent of grid cell is glacier (sum over classes)
    real(r8),pointer :: topoglc_mec(:,:)  ! surface elevation in each elev class
    logical :: readv                      ! read variable in or not
    character(len=32) :: subname = 'surfrd_wtxy_special'  ! subroutine name
    real(r8) closelat,closelon
!!-----------------------------------------------------------------------

    ns = domain%ns
    call get_proc_bounds(begg,endg)

    allocate(pctgla(begg:endg),pctlak(begg:endg))
    allocate(pctwet(begg:endg),pcturb(begg:endg))
    if (create_glacier_mec_landunit) then
       allocate(pctglc_mec(begg:endg,glc_nec))
       allocate(pctglc_mec_tot(begg:endg))
       allocate(topoglc_mec(begg:endg,glc_nec))
    endif

    if (masterproc) then
       call check_dim(ncid, 'nlevsoi', nlevsoi)
    end if   ! end of if-masterproc

       ! Obtain non-grid surface properties of surface dataset other than percent pft

    call ncd_iolocal(ncid, 'PCT_WETLAND', 'read', pctwet, grlnd, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_WETLAND  NOT on surfdata file' )
    call ncd_iolocal(ncid, 'PCT_LAKE'   , 'read', pctlak, grlnd, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_LAKE NOT on surfdata file' )
    call ncd_iolocal(ncid, 'PCT_GLACIER', 'read', pctgla, grlnd, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_GLACIER NOT on surfdata file' )
    call ncd_iolocal(ncid, 'PCT_URBAN'  , 'read', pcturb, grlnd, status=ret)
    if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_URBAN NOT on surfdata file' )

    if (create_glacier_mec_landunit) then          ! call ncd_iolocal_gs_int2d

       call check_dim(ncid, 'nglcec',   glc_nec   )
       call check_dim(ncid, 'nglcecp1', glc_nec+1 )
       call ncd_ioglobal('GLC_MEC', glc_topomax, 'read', ncid, readvar=readv, bcast=.true.)
       if ( .not. readv) call endrun( trim(subname)//'ERROR: GLC_MEC was NOT on the input surfdata file' )
       call ncd_iolocal(ncid, 'PCT_GLC_MEC', 'read', pctglc_mec, grlnd, status=ret)
       if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_GLC_MEC NOT on surfdata file' )
       call ncd_iolocal(ncid, 'TOPO_GLC_MEC',  'read', topoglc_mec, grlnd, status=ret)
       if (ret /= 0) call endrun( trim(subname)//' ERROR: TOPO_GLC_MEC NOT on surfdata file' )

       pctglc_mec_tot(:) = 0._r8
       do n = 1, glc_nec
          do nl = begg,endg
             pctglc_mec_tot(nl) = pctglc_mec_tot(nl) + pctglc_mec(nl,n)
          enddo
       enddo

       ! Make sure sum of pctglc_mec = pctgla, then zero out pctgla
       ! (assumes glc_mec values are double precision)

       do nl = begg,endg
          if (abs(pctgla(nl) - pctglc_mec_tot(nl)) > 1.0e-11) then
             write(iulog,*) ' '
             write(iulog,*) 'surfrd error: pctgla not equal to sum of pctglc_mec for nl=', nl
             write(iulog,*) 'pctgla =', pctgla(nl)
             write(iulog,*) 'pctglc_mec_tot =', pctglc_mec_tot(nl)
             call endrun()
          endif
          pctgla(nl) = 0._r8
       enddo

       ! If pctglc_mec_tot is very close to 100%, round to 100%

       do nl = begg,endg
          if (abs(pctglc_mec_tot(nl) - 100._r8) < 1.0e-8) then
             pctglc_mec(nl,:) = pctglc_mec(nl,:) * 100._r8 / pctglc_mec_tot(nl)
             pctglc_mec_tot(nl) = 100._r8
          endif
       enddo

       pctspec = pctwet + pctlak + pcturb + pctglc_mec_tot

       if ( masterproc ) write(iulog,*) '   elevation limits = ', glc_topomax

    else

       pctspec = pctwet + pctlak + pcturb + pctgla
 
    endif

    ! Error check: glacier, lake, wetland, urban sum must be less than 100

    found = .false.
    do nl = begg,endg
       if (pctspec(nl) > 100._r8+1.e-04_r8) then
          found = .true.
          nindx = nl
          exit
       end if
       if (found) exit
    end do
    if ( found ) then
       write(iulog,*)'surfrd error: PFT cover>100 for nl=',nindx
       call endrun()
    end if

    ! Determine veg and wtxy for special landunits

    do nl = begg,endg

       vegxy(nl,npatch_lake)   = noveg
       wtxy(nl,npatch_lake)    = pctlak(nl)/100._r8

       vegxy(nl,npatch_wet)    = noveg
       wtxy(nl,npatch_wet)     = pctwet(nl)/100._r8

       vegxy(nl,npatch_glacier)= noveg
       wtxy(nl,npatch_glacier) = pctgla(nl)/100._r8

       ! Initialize urban weights

       do nurb = npatch_urban, npatch_lake-1 
          vegxy(nl,nurb) = noveg
          wtxy(nl,nurb)  = pcturb(nl) / 100._r8
       end do
       if ( pcturb(nl) > 0.0_r8 )then
          wtxy(nl,npatch_urban)   = wtxy(nl,npatch_urban)*urbinp%wtlunit_roof(nl)
          wtxy(nl,npatch_urban+1) = wtxy(nl,npatch_urban+1)*(1 - urbinp%wtlunit_roof(nl))/3
          wtxy(nl,npatch_urban+2) = wtxy(nl,npatch_urban+2)*(1 - urbinp%wtlunit_roof(nl))/3
          wtxy(nl,npatch_urban+3) = wtxy(nl,npatch_urban+3)*(1 - urbinp%wtlunit_roof(nl))/3 * (1.-urbinp%wtroad_perv(nl))
          wtxy(nl,npatch_urban+4) = wtxy(nl,npatch_urban+4)*(1 - urbinp%wtlunit_roof(nl))/3 * urbinp%wtroad_perv(nl)
       end if

    end do

    ! Check to make sure we have valid urban data for each urban patch

    found = .false.
    do nl = begg,endg
       if ( pcturb(nl) > 0.0_r8 )then
         if (urbinp%canyon_hwr(nl)            .le. 0._r8 .or. &
             urbinp%em_improad(nl)            .le. 0._r8 .or. &
             urbinp%em_perroad(nl)            .le. 0._r8 .or. &
             urbinp%em_roof(nl)               .le. 0._r8 .or. &
             urbinp%em_wall(nl)               .le. 0._r8 .or. &
             urbinp%ht_roof(nl)               .le. 0._r8 .or. &
             urbinp%thick_roof(nl)            .le. 0._r8 .or. &
             urbinp%thick_wall(nl)            .le. 0._r8 .or. &
             urbinp%t_building_max(nl)        .le. 0._r8 .or. &
             urbinp%t_building_min(nl)        .le. 0._r8 .or. &
             urbinp%wind_hgt_canyon(nl)       .le. 0._r8 .or. &
             urbinp%wtlunit_roof(nl)          .le. 0._r8 .or. &
             urbinp%wtroad_perv(nl)           .le. 0._r8 .or. &
             any(urbinp%alb_improad_dir(nl,:) .le. 0._r8) .or. &
             any(urbinp%alb_improad_dif(nl,:) .le. 0._r8) .or. &
             any(urbinp%alb_perroad_dir(nl,:) .le. 0._r8) .or. &
             any(urbinp%alb_perroad_dif(nl,:) .le. 0._r8) .or. &
             any(urbinp%alb_roof_dir(nl,:)    .le. 0._r8) .or. &
             any(urbinp%alb_roof_dif(nl,:)    .le. 0._r8) .or. &
             any(urbinp%alb_wall_dir(nl,:)    .le. 0._r8) .or. &
             any(urbinp%alb_wall_dif(nl,:)    .le. 0._r8) .or. &
             any(urbinp%tk_roof(nl,:)         .le. 0._r8) .or. &
             any(urbinp%tk_wall(nl,:)         .le. 0._r8) .or. &
             any(urbinp%cv_roof(nl,:)         .le. 0._r8) .or. &
             any(urbinp%cv_wall(nl,:)         .le. 0._r8)) then
            found = .true.
            nindx = nl
            exit
         else
            if (urbinp%nlev_improad(nl) .gt. 0) then
               nlev = urbinp%nlev_improad(nl)
               if (any(urbinp%tk_improad(nl,1:nlev) .le. 0._r8) .or. &
                   any(urbinp%cv_improad(nl,1:nlev) .le. 0._r8)) then
                  found = .true.
                  nindx = nl
                  exit
               end if
            end if
         end if
         if (found) exit
       end if
    end do
    if ( found ) then
       write(iulog,*)'surfrd error: no valid urban data for nl=',nindx
       write(iulog,*)'canyon_hwr: ',urbinp%canyon_hwr(nindx)
       write(iulog,*)'em_improad: ',urbinp%em_improad(nindx)
       write(iulog,*)'em_perroad: ',urbinp%em_perroad(nindx)
       write(iulog,*)'em_roof: ',urbinp%em_roof(nindx)
       write(iulog,*)'em_wall: ',urbinp%em_wall(nindx)
       write(iulog,*)'ht_roof: ',urbinp%ht_roof(nindx)
       write(iulog,*)'thick_roof: ',urbinp%thick_roof(nindx)
       write(iulog,*)'thick_wall: ',urbinp%thick_wall(nindx)
       write(iulog,*)'t_building_max: ',urbinp%t_building_max(nindx)
       write(iulog,*)'t_building_min: ',urbinp%t_building_min(nindx)
       write(iulog,*)'wind_hgt_canyon: ',urbinp%wind_hgt_canyon(nindx)
       write(iulog,*)'wtlunit_roof: ',urbinp%wtlunit_roof(nindx)
       write(iulog,*)'wtroad_perv: ',urbinp%wtroad_perv(nindx)
       write(iulog,*)'alb_improad_dir: ',urbinp%alb_improad_dir(nindx,:)
       write(iulog,*)'alb_improad_dif: ',urbinp%alb_improad_dif(nindx,:)
       write(iulog,*)'alb_perroad_dir: ',urbinp%alb_perroad_dir(nindx,:)
       write(iulog,*)'alb_perroad_dif: ',urbinp%alb_perroad_dif(nindx,:)
       write(iulog,*)'alb_roof_dir: ',urbinp%alb_roof_dir(nindx,:)
       write(iulog,*)'alb_roof_dif: ',urbinp%alb_roof_dif(nindx,:)
       write(iulog,*)'alb_wall_dir: ',urbinp%alb_wall_dir(nindx,:)
       write(iulog,*)'alb_wall_dif: ',urbinp%alb_wall_dif(nindx,:)
       write(iulog,*)'tk_roof: ',urbinp%tk_roof(nindx,:)
       write(iulog,*)'tk_wall: ',urbinp%tk_wall(nindx,:)
       write(iulog,*)'cv_roof: ',urbinp%cv_roof(nindx,:)
       write(iulog,*)'cv_wall: ',urbinp%cv_wall(nindx,:)
       if (urbinp%nlev_improad(nindx) .gt. 0) then
          nlev = urbinp%nlev_improad(nindx)
          write(iulog,*)'tk_improad: ',urbinp%tk_improad(nindx,1:nlev)
          write(iulog,*)'cv_improad: ',urbinp%cv_improad(nindx,1:nlev)
       end if
       call endrun()
    end if

    ! Initialize glacier_mec weights

    if (create_glacier_mec_landunit) then

       do n = 1, glc_nec
          npatch = npatch_glacier_mec - glc_nec + n

          do nl = begg, endg
             vegxy (nl,npatch) = noveg
             wtxy  (nl,npatch) = pctglc_mec(nl,n)/100._r8
             topoxy(nl,npatch) = topoglc_mec(nl,n)

          enddo   ! nl
       enddo      ! glc_nec

       deallocate(pctglc_mec, pctglc_mec_tot, topoglc_mec)

   endif    ! create_glacier_mec_landunit

   deallocate(pctgla,pctlak,pctwet,pcturb)

  end subroutine surfrd_wtxy_special

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_wtxy_veg_rank
!
! !INTERFACE:
!  subroutine surfrd_wtxy_veg_rank(ncid, pctspec, vegxy, wtxy, domain)

  subroutine surfrd_wtxy_veg_rank(ncid, domain) 1,16
!
! !DESCRIPTION:
! Determine wtxy and veg arrays for non-dynamic landuse mode
!
! !USES:
    use clm_varctl, only : create_crop_landunit
    use pftvarcon , only : crop, noveg
    use domainMod , only : domain_type
!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
    integer , intent(in)    :: ncid        ! netcdf file id 
!    real(r8), intent(in)    :: pctspec(:)  ! percent wrt gcell of spec lunits
!    integer , intent(inout) :: vegxy(:,:)    ! PFT
!    real(r8), intent(inout) :: wtxy(:,:)   ! subgrid weights
    type(domain_type),intent(in) :: domain ! domain associated with wtxy
!
! !CALLED FROM:
! subroutine surfrd in this module
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan
!
!
! !LOCAL VARIABLES:
!EOP
    integer  :: k,m,k1,k2,n,nl,ns               ! indices
    integer  :: begg,endg                       ! beg/end gcell index
    integer  :: dimid,varid                     ! netCDF id's
    integer  :: start(3),count(3)               ! netCDF start/count arrays
    integer  :: cropcount                       ! temporary counter
    real(r8),allocatable :: sumvec(:)           ! temporary vector sum
    logical  :: found                           ! temporary for error check
    integer  :: nindx                           ! temporary for error check
    integer  :: miss = 99999                    ! missing data indicator
    real(r8) :: wst(0:numpft)                   ! as pft at specific i, j
    integer ,allocatable :: wsti(:)             ! ranked indices largest wst values
    real(r8) :: wst_sum                         ! sum of %pft
    real(r8) :: sumpct                          ! sum of %pft over maxpatch_pft
    real(r8) :: diff                            ! the difference (wst_sum - sumpct)
    real(r8) :: rmax                            ! maximum patch cover
    integer ,allocatable :: pft(:,:)            ! PFT
    integer ,allocatable :: cft(:,:)            ! CFT
    real(r8),allocatable :: pctcft_lunit(:,:)   ! % of crop lunit area for CFTs
    real(r8),allocatable :: pctpft_lunit(:,:)   ! % of vegetated lunit area PFTs
    integer  :: ier                             ! error status
    real(r8),allocatable :: pctpft(:,:)         ! percent of vegetated gridcell area for PFTs
    real(r8),pointer :: arrayl(:)               ! local array
    integer ,pointer :: irrayg(:)               ! global array
    integer  :: ret
    real(r8),allocatable :: rmaxpatchdata(:)
    integer ,allocatable :: imaxpatchdata(:)
    real(r8) :: numpftp1data(0:numpft)         
    character(len=32) :: subname = 'surfrd_wtxy_veg_rank'  ! subroutine name
!-----------------------------------------------------------------------

    ns = domain%ns
    call get_proc_bounds(begg,endg)

    allocate(sumvec(begg:endg))
    allocate(cft(begg:endg,numcft))
    allocate(pft(begg:endg,maxpatch_pft))
    allocate(pctcft_lunit(begg:endg,numcft))
    allocate(pctpft_lunit(begg:endg,maxpatch_pft))
    allocate(pctpft(begg:endg,0:numpft))
    allocate(wsti(maxpatch_pft))

    if (masterproc) then
       call check_dim(ncid, 'lsmpft', numpft+1)
    end if
    allocate(arrayl(begg:endg))
    do n = 0,numpft
       start(1) = 1
       count(1) = domain%ni
       start(2) = 1
       count(2) = domain%nj
       start(3) = n+1	 ! dataset is 1:numpft+1, not 0:numpft
       count(3) = 1
       call ncd_iolocal(ncid, 'PCT_PFT', 'read', arrayl, grlnd, start, count, status=ret)
       if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_PFT NOT on surfdata file' )
       pctpft(begg:endg,n) = arrayl(begg:endg)
    enddo
    deallocate(arrayl)

    ! 1. pctpft must go back to %vegetated landunit instead of %gridcell
    ! 2. pctpft bare = 100 when landmask = 1 and 100% special landunit
    ! NB: (1) and (2) do not apply to crops.
    ! For now keep all cfts instead of most dominant cfts

    do nl = begg,endg

       cft(nl,:) = 0
       pctcft_lunit(nl,:) = 0._r8
       cropcount = 0

       if (pctspec(nl) < 100._r8) then

          do m = 0, numpft
             if (create_crop_landunit) then
                ! Separate crop landunit is to be created

                if (crop(m) == 1._r8 .and. pctpft(nl,m) > 0._r8) then
                   cropcount = cropcount + 1
                   if (cropcount > numcft) then
                      write(iulog,*) 'ERROR surfrdMod: cropcount>numcft'
                      call endrun()
                   end if
                   cft(nl,cropcount) = m
                   pctcft_lunit(nl,cropcount) = pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl))
                   pctpft(nl,m) = 0.0_r8
                else if (crop(m) == 0._r8) then
                   pctpft(nl,m) = pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl))
                end if

             else
                ! Separate crop landunit is not created

                pctpft(nl,m) = pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl))
             end if
          end do


       else if (pctspec(nl) == 100._r8) then

          pctpft(nl,0)        = 100._r8
          pctpft(nl,1:numpft) =   0._r8

       else

          write(iulog,*)subname, 'error: pcturb+pctgla+pctlak+pctwet = ',pctspec(nl), &
               ' must be less than or equal to 100'
          call endrun()

       end if
    end do

    ! Find pft and pct arrays 
    ! Save percent cover by PFT [wst] and total percent cover [wst_sum]

    do nl = begg,endg

       wst_sum = 0._r8
       sumpct = 0
       do m = 0, numpft
          wst(m) = pctpft(nl,m)
          wst_sum = wst_sum + pctpft(nl,m)
       end do

       if (domain%pftm(nl) >= 0) then

          ! Rank [wst] in ascendg order to obtain the top [maxpatch_pft] PFTs

          call surfrd_mkrank (numpft, wst, miss, wsti, maxpatch_pft)

          ! Fill in [pft] and [pctpft] with data for top [maxpatch_pft] PFTs.
          ! If land model grid cell is ocean, set to no PFTs.
          ! If land model grid cell is land then:
          !  1. If [pctlnd_o] = 0, there is no PFT data from the input grid.
          !     Since need land data, use bare ground.
          !  2. If [pctlnd_o] > 0, there is PFT data from the input grid but:
          !     a. use the chosen PFT so long as it is not a missing value
          !     b. missing value means no more PFTs with cover > 0
                   
          do m = 1, maxpatch_pft
             if (wsti(m) /=  miss) then
                pft(nl,m) = wsti(m)
                pctpft_lunit(nl,m) = wst(wsti(m))
             else
                pft(nl,m) = noveg
                pctpft_lunit(nl,m) = 0._r8
             end if
             sumpct = sumpct + pctpft_lunit(nl,m)
          end do

       else                               ! model grid wants ocean

          do m = 1, maxpatch_pft
             pft(nl,m) = 0
             pctpft_lunit(nl,m) = 0._r8
          end do

       end if

       ! Correct for the case of more than [maxpatch_pft] PFTs present
                
       if (sumpct < wst_sum) then
          diff  = wst_sum - sumpct
          sumpct = 0._r8
          do m = 1, maxpatch_pft
             pctpft_lunit(nl,m) = pctpft_lunit(nl,m) + diff/maxpatch_pft
             sumpct = sumpct + pctpft_lunit(nl,m)
          end do
       end if

       ! Error check: make sure have a valid PFT

       do m = 1,maxpatch_pft
          if (pft(nl,m) < 0 .or. pft(nl,m) > numpft) then
             write(iulog,*)'surfrd error: invalid PFT at gridcell nl=',nl,pft(nl,m)
             call endrun()
          end if
       end do

       ! As done in mksrfdatMod.F90 for other percentages, truncate pctpft to
       ! ensure that weight relative to landunit is not nonzero
       ! (i.e. a very small number such as 1e-16) where it really should be zero
       ! The following if-block is here to preserve roundoff level differences
       ! between the call to surfrd_wtxy_veg_all and surfrd_wtxy_veg_rank

       if (maxpatch_pft < numpft+1) then
          do m=1,maxpatch_pft
             pctpft_lunit(nl,m) = float(nint(pctpft_lunit(nl,m)))
          end do
          do m=1,numcft
             pctcft_lunit(nl,m) = float(nint(pctcft_lunit(nl,m)))
          end do
       end if
                   
       ! Make sure sum of PFT cover == 100 for land points. If not,
       ! subtract excess from most dominant PFT.

       rmax = -9999._r8
       k1 = -9999
       k2 = -9999
       sumpct = 0._r8
       do m = 1, maxpatch_pft
          sumpct = sumpct + pctpft_lunit(nl,m)
          if (pctpft_lunit(nl,m) > rmax) then
             k1 = m
             rmax = pctpft_lunit(nl,m)
          end if
       end do
       do m = 1, numcft
          sumpct = sumpct + pctcft_lunit(nl,m)
          if (pctcft_lunit(nl,m) > rmax) then
             k2 = m
             rmax = pctcft_lunit(nl,m)
          end if
       end do
       if (k1 == -9999 .and. k2 == -9999) then
          write(iulog,*)'surfrd error: largest PFT patch not found'
          call endrun()
       else if (domain%pftm(nl) >= 0) then
          if (sumpct < 95 .or. sumpct > 105._r8) then
             write(iulog,*)'surfrd error: sum of PFT cover =',sumpct,' at nl=',nl
             call endrun()
          else if (sumpct /= 100._r8 .and. k2 /= -9999) then
             pctcft_lunit(nl,k2) = pctcft_lunit(nl,k2) - (sumpct-100._r8)
          else if (sumpct /= 100._r8) then
             pctpft_lunit(nl,k1) = pctpft_lunit(nl,k1) - (sumpct-100._r8)
          end if
       end if

       ! Error check: make sure PFTs sum to 100% cover

       sumpct = 0._r8
       do m = 1, maxpatch_pft
          sumpct = sumpct + pctpft_lunit(nl,m)
       end do
       do m = 1, numcft
          sumpct = sumpct + pctcft_lunit(nl,m)
       end do
       if (domain%pftm(nl) >= 0) then
          if (abs(sumpct - 100._r8) > 0.000001_r8) then
             write(iulog,*)'surfrdMod error: sum(pct) over maxpatch_pft is not = 100.'
             write(iulog,*)sumpct, nl
             call endrun()
          end if
          if (sumpct < -0.000001_r8) then
             write(iulog,*)'surfrdMod error: sum(pct) over maxpatch_pft is < 0.'
             write(iulog,*)sumpct, nl
             call endrun()
          end if
       end if

    end do   ! end of latitude loop

    ! Determine array [veg], which sets the PFT type for each of the [maxpatch]
    ! patches and array [wtxy], which sets the relative abundance of the PFT.
    ! Fill in PFTs for vegetated portion of grid cell. Fractional areas for
    ! these points [pctpft] pertain to "vegetated" area not to total grid area.
    ! So need to adjust them for fraction of grid that is vegetated.
    ! Next, fill in urban, lake, wetland, and glacier patches.

    do nl = begg,endg
       if (domain%pftm(nl) >= 0) then

          ! Naturally vegetated landunit

          do m = 1, maxpatch_pft
             vegxy(nl,m) = pft(nl,m)
             wtxy(nl,m) = pctpft_lunit(nl,m) * (100._r8-pctspec(nl))/10000._r8
          end do

          ! Crop landunit

          if (create_crop_landunit) then
             do m = 1,numcft
                vegxy(nl,npatch_glacier_mec+m) = cft(nl,m)
                wtxy(nl,npatch_glacier_mec+m) = pctcft_lunit(nl,m) * (100._r8-pctspec(nl))/10000._r8
            end do
          end if

       end if
    end do

    ! Error check

    found = .false.
    sumvec(:) = abs(sum(wtxy,dim=2)-1._r8)
    do nl = begg,endg
       if (sumvec(nl) > 1.e-06_r8 .and. domain%pftm(nl)>=0) then
          found = .true.
          nindx = nl
          exit
       endif
    end do
    if ( found ) then
       write(iulog,*)'surfrd error: WTXY > 1 occurs at nl= ',nindx; call endrun()
    end if

    deallocate(sumvec,cft,pft)
    deallocate(pctcft_lunit,pctpft_lunit,pctpft)
    deallocate(wsti)

  end subroutine surfrd_wtxy_veg_rank

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_wtxy_veg_all
!
! !INTERFACE:
!  subroutine surfrd_wtxy_veg_all(ncid, pctspec, vegxy, wtxy, domain)

  subroutine surfrd_wtxy_veg_all(ncid, domain) 2,7
!
! !DESCRIPTION:
! Determine wtxy and veg arrays for non-dynamic landuse mode
!
! !USES:
    use domainMod   , only : domain_type
!
! !ARGUMENTS:
    implicit none
    include 'netcdf.inc'
    integer , intent(in)    :: ncid       ! netcdf file id 
!    real(r8), intent(in)    :: pctspec(:) ! percent wrt gcell of spec lunits
!    integer , intent(inout) :: vegxy(:,:)   ! PFT
!    real(r8), intent(inout) :: wtxy(:,:)  ! subgrid weights
    type(domain_type),intent(in) :: domain ! domain associated with wtxy
!
! !CALLED FROM:
! subroutine surfrd in this module
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein, Sam Levis and Gordon Bonan
!
!
! !LOCAL VARIABLES:
!EOP
    integer  :: m,mp7,mp8,mp11,n,nl,ns         ! indices
    integer  :: begg,endg                      ! beg/end gcell index
    integer  :: dimid,varid                    ! netCDF id's
    integer  :: start(3),count(3)              ! netcdf start/count arrays
    integer  :: ier                            ! error status	
    real(r8) :: sumpct                         ! sum of %pft over maxpatch_pft
    real(r8),allocatable :: pctpft(:,:)        ! percent of vegetated gridcell area for PFTs
    real(r8),pointer :: arrayl(:)              ! local array
    integer  :: ret
    real(r8) :: numpftp1data(0:numpft)         
    character(len=32) :: subname = 'surfrd_wtxy_veg_all'  ! subroutine name
!-----------------------------------------------------------------------

    ns = domain%ns
    call get_proc_bounds(begg,endg)
    allocate(pctpft(begg:endg,0:numpft))

    if (masterproc) then
       call check_dim(ncid, 'lsmpft', numpft+1)
    endif

    allocate(arrayl(begg:endg))
    do n = 0,numpft
       start(1) = 1
       count(1) = domain%ni
       start(2) = 1
       count(2) = domain%nj
       start(3) = n+1	 ! dataset is 1:numpft+1, not 0:numpft
       count(3) = 1
       call ncd_iolocal(ncid, 'PCT_PFT', 'read', arrayl, grlnd, start, count, status=ret)
       if (ret /= 0) call endrun( trim(subname)//' ERROR: PCT_PFT NOT on surfdata file' )
       pctpft(begg:endg,n) = arrayl(begg:endg)
    enddo
    deallocate(arrayl)

    do nl = begg,endg
       if (domain%pftm(nl) >= 0) then

          ! Error check: make sure PFTs sum to 100% cover for vegetated landunit 
          ! (convert pctpft from percent with respect to gridcel to percent with 
          ! respect to vegetated landunit)

          if (pctspec(nl) < 100._r8) then
             sumpct = 0._r8
             do m = 0,numpft
                sumpct = sumpct + pctpft(nl,m) * 100._r8/(100._r8-pctspec(nl))
             end do
             if (abs(sumpct - 100._r8) > 0.1e-4_r8) then
                write(iulog,*)'surfrdMod error: sum(pct) over numpft+1 is not = 100.'
                write(iulog,*) sumpct, sumpct-100._r8, nl
                call endrun()
             end if
             if (sumpct < -0.000001_r8) then
                write(iulog,*)'surfrdMod error: sum(pct) over numpft+1 is < 0.'
                write(iulog,*) sumpct, nl
                call endrun()
             end if
          end if

          ! Set weight of each pft wrt gridcell (note that maxpatch_pft = numpft+1 here)

          do m = 1,numpft+1
             vegxy(nl,m)  = m - 1 ! 0 (bare ground) to numpft
             wtxy(nl,m) = pctpft(nl,m-1) / 100._r8
          end do

       end if
    end do

    deallocate(pctpft)

  end subroutine surfrd_wtxy_veg_all

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: surfrd_wtxy_veg_dgvm
!
! !INTERFACE:

  subroutine surfrd_wtxy_veg_dgvm(domain) 1,5
!
! !DESCRIPTION:
! Determine wtxy and vegxy for CNDV mode.
!
! !USES:
    use domainMod, only : domain_type
    use pftvarcon, only : noveg, crop
    use clm_varctl, only : create_crop_landunit
!
! !ARGUMENTS:
    implicit none
    type(domain_type),intent(in) :: domain ! domain associated with wtxy
!
! !CALLED FROM:
! subroutine surfrd in this module
!
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein 12/04
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: m,nl         ! indices
    integer  :: begg,endg   ! beg/end gcell index
!-----------------------------------------------------------------------

    call get_proc_bounds(begg,endg)
    do nl = begg,endg
       do m = 1, maxpatch_pft ! CNDV means allocate_all_vegpfts = .true.
          if (create_crop_landunit) then ! been through surfrd_wtxy_veg_all
             if (crop(m-1) == 0) then    ! so update natural vegetation only
                wtxy(nl,m) = 0._r8       ! crops should have values >= 0.
             end if
          else                   ! not been through surfrd_wtxy_veg_all
             wtxy(nl,m) = 0._r8  ! so update all vegetation
             vegxy(nl,m) = m - 1 ! 0 (bare ground) to maxpatch_pft-1 (= 16)
          end if
       end do
       ! bare ground weights
       wtxy(nl,noveg+1) = max(0._r8, 1._r8 - sum(wtxy(nl,:)))
       if (abs(sum(wtxy(nl,:)) - 1._r8) > 1.e-5_r8) then
          write(iulog,*) 'all wtxy =', wtxy(nl,:)
          call endrun()
       end if ! error check
    end do

  end subroutine surfrd_wtxy_veg_dgvm
   
!-----------------------------------------------------------------------
!BOP
!
! !ROUTINE: surfrd_mkrank
!
! !INTERFACE:

  subroutine surfrd_mkrank (n, a, miss, iv, num) 1,3
!
! !DESCRIPTION:
! Return indices of largest [num] values in array [a]
!
! !USES:
    use shr_kind_mod, only: r8 => shr_kind_r8
    use abortutils, only : endrun
!
! !ARGUMENTS:
    implicit none
    integer , intent(in) :: n        ! array length
    real(r8), intent(in) :: a(0:n)   ! array to be ranked
    integer , intent(in) :: miss     ! missing data value
    integer , intent(in) :: num      ! number of largest values requested
    integer , intent(out):: iv(num)  ! index to [num] largest values in array [a]
!
! !CALLED FROM:
! ! subroutine surfrd_wtxy_veg_rank in this module
!
! !REVISION HISTORY:
! Author: Gordon Bonan
!
!
! !LOCAL VARIABLES:
!EOP
    real(r8) :: a_max       ! maximum value in array
    integer  :: i           ! array index
    real(r8) :: delmax      ! tolerance for finding if larger value
    integer  :: m           ! do loop index
    integer  :: k           ! do loop index
    logical  :: exclude     ! true if data value has already been chosen
!-----------------------------------------------------------------------

    delmax = 1.e-06_r8

    ! Find index of largest non-zero number
    
    iv(1) = miss
    a_max = -9999._r8

    do i = 0, n
       if (a(i)>0._r8 .and. (a(i)-a_max)>delmax) then
          a_max = a(i)
          iv(1)  = i
       end if
    end do

    ! iv(1) = miss indicates no values > 0. this is an error

    if (iv(1) == miss) then
       write(iulog,*) 'surfrd_mkrank error: iv(1) = missing'
       call endrun
    end if

    ! Find indices of the next [num]-1 largest non-zero number.
    ! iv(m) = miss if there are no more values > 0

    do m = 2, num
       iv(m) = miss
       a_max = -9999._r8
       do i = 0, n

          ! exclude if data value has already been chosen

          exclude = .false.
          do k = 1, m-1
             if (i == iv(k)) exclude = .true.
          end do

          ! if not already chosen, see if it is the largest of
          ! the remaining values

          if (.not. exclude) then
             if (a(i)>0._r8 .and. (a(i)-a_max)>delmax) then
                a_max = a(i)
                iv(m)  = i
             end if
          end if
       end do
    end do

  end subroutine surfrd_mkrank

end module surfrdMod