module ncdio_pio

!-----------------------------------------------------------------------
!BOP
!
! !MODULE: ncdio_pioMod
!
! !DESCRIPTION:
! Generic interfaces to write fields to netcdf files for CLM
!
! !USES:
  use shr_kind_mod   , only : r8 => shr_kind_r8, i8=>shr_kind_i8, shr_kind_cl
  use spmdMod        , only : masterproc, mpicom, iam, npes,  &
                              MPI_REAL8, MPI_INTEGER, MPI_LOGICAL
  use clmtype        , only : grlnd, nameg, namel, namec, namep
  use clm_varcon     , only : spval,ispval
  use clm_varctl     , only : single_column, iulog
  use shr_sys_mod    , only : shr_sys_flush
  use shr_file_mod   , only : shr_file_getunit, shr_file_freeunit
  use shr_string_mod , only : shr_string_toUpper
  use abortutils     , only : endrun
  use decompMod      , only : get_clmlevel_gsize,get_clmlevel_gsmap
  use perf_mod       , only : t_startf, t_stopf
  use fileutils      , only : getavu, relavu
  use nanMod         , only : nan
  use mct_mod        , only : mct_gsmap, mct_gsmap_lsize, mct_gsmap_gsize, &
                              mct_gsmap_OP
  use pio
!
! !PUBLIC TYPES:
  implicit none
  private
  save
!
! !PUBLIC MEMBER FUNCTIONS:
!
  public :: check_var          ! determine if variable is on netcdf file
  public :: check_dim          ! validity check on dimension
  public :: ncd_pio_openfile   ! open a file
  public :: ncd_pio_createfile ! create a new file
  public :: ncd_pio_closefile  ! close a file
  public :: ncd_pio_init       ! called from clm_comp
  public :: ncd_enddef         ! end define mode
  public :: ncd_putatt         ! put attribute
  public :: ncd_defdim         ! define dimension
  public :: ncd_inqdid         ! inquire dimension id
  public :: ncd_inqdname       ! inquire dimension name
  public :: ncd_inqdlen        ! inquire dimension length
  public :: ncd_inqfdims       ! inquire file dimnesions 
  public :: ncd_defvar         ! define variables
  public :: ncd_inqvid         ! inquire variable id
  public :: ncd_inqvname       ! inquire variable name
  public :: ncd_inqvdims       ! inquire variable ndims
  public :: ncd_inqvdids       ! inquire variable dimids
  public :: ncd_io             ! write local data

  integer,parameter,public :: ncd_int       = pio_int
  integer,parameter,public :: ncd_log       =-pio_int
  integer,parameter,public :: ncd_float     = pio_real
  integer,parameter,public :: ncd_double    = pio_double
  integer,parameter,public :: ncd_char      = pio_char
  integer,parameter,public :: ncd_global    = pio_global
  integer,parameter,public :: ncd_write     = pio_write
  integer,parameter,public :: ncd_nowrite   = pio_nowrite
  integer,parameter,public :: ncd_clobber   = pio_clobber
  integer,parameter,public :: ncd_noclobber = pio_noclobber
  integer,parameter,public :: ncd_nofill    = pio_nofill
  integer,parameter,public :: ncd_unlimited = pio_unlimited

  ! PIO types needed for ncdio_pio interface calls
  public file_desc_t
  public var_desc_t

!
! !REVISION HISTORY:
!
!
! !PRIVATE MEMBER FUNCTIONS:
!

  interface ncd_putatt
     module procedure ncd_putatt_int
     module procedure ncd_putatt_real
     module procedure ncd_putatt_char
  end interface

  interface ncd_defvar
     module procedure ncd_defvar_bynf
     module procedure ncd_defvar_bygrid
  end interface

  interface ncd_io 
     module procedure ncd_io_log_var0_nf
     module procedure ncd_io_int_var0_nf
     module procedure ncd_io_real_var0_nf
     module procedure ncd_io_int_var1_nf
     module procedure ncd_io_log_var1_nf
     module procedure ncd_io_real_var1_nf
     module procedure ncd_io_char_var1_nf
     module procedure ncd_io_int_var2_nf
     module procedure ncd_io_real_var2_nf
     module procedure ncd_io_char_var2_nf
     module procedure ncd_io_char_var3_nf
     module procedure ncd_io_char_varn_strt_nf
     module procedure ncd_io_int_var1
     module procedure ncd_io_log_var1
     module procedure ncd_io_real_var1
     module procedure ncd_io_int_var2
     module procedure ncd_io_real_var2
     module procedure ncd_io_int_var3
     module procedure ncd_io_real_var3
     module procedure ncd_io_real_var3_nf
  end interface

  private :: ncd_getiodesc      ! obtain iodesc
  private :: scam_field_offsets ! get offset to proper lat/lon gridcell for SCAM

  integer,parameter,private :: debug = 0             ! local debug level

  integer , parameter  , public  :: max_string_len = 256     ! length of strings
  real(r8), parameter  , public  :: fillvalue = 1.e36_r8     ! fill value for netcdf fields

  integer, public :: io_type

  type(iosystem_desc_t), pointer, public  :: pio_subsystem

  type iodesc_plus_type
     character(len=64) :: name
     type(IO_desc_t)   :: iodesc
     integer           :: type
     integer           :: ndims
     integer           :: dims(4)
     integer           :: dimids(4) 
  end type iodesc_plus_type
  integer,parameter      ,private :: max_iodesc = 100
  integer                ,private :: num_iodesc = 0
  type(iodesc_plus_type) ,private, target :: iodesc_list(max_iodesc)

!EOP
!-----------------------------------------------------------------------

contains

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_pio_init
!
! !INTERFACE:
  subroutine ncd_pio_init()
!
! !DESCRIPTION:
! Initial PIO
!
! !USES:
    use shr_pio_mod     , only : shr_pio_getiosys, shr_pio_getiotype
    use clm_varctl      , only : inst_name
! !ARGUMENTS:
    implicit none
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
    character(len=*),parameter :: subname='ncd_pio_init' ! subroutine name
!-----------------------------------------------------------------------
!EOP
    PIO_subsystem => shr_pio_getiosys(inst_name)
    io_type       =  shr_pio_getiotype(inst_name)

  end subroutine ncd_pio_init

  !=======================================================================

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_pio_openfile
!
! !INTERFACE:
  subroutine ncd_pio_openfile(file, fname, mode)
!
! !DESCRIPTION:
! Open a NetCDF PIO file
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: file   ! Output PIO file handle
    character(len=*) , intent(in)    :: fname  ! Input filename to open
    integer          , intent(in)    :: mode   ! file mode
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
    integer :: ierr
    character(len=*),parameter :: subname='ncd_pio_openfile' ! subroutine name
!-----------------------------------------------------------------------
!EOP
    ierr = pio_openfile(pio_subsystem, file, io_type, fname, mode)

    if(ierr/= PIO_NOERR) then
       call endrun(subname//'ERROR: Failed to open file')
    else if(pio_subsystem%io_rank==0) then
       write(iulog,*) 'Opened existing file ', trim(fname), file%fh
    end if

  end subroutine ncd_pio_openfile

  !=======================================================================

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_pio_closefile
!
! !INTERFACE:
  subroutine ncd_pio_closefile(file)
!
! !DESCRIPTION:
! Close a NetCDF PIO file
!
! !ARGUMENTS:
    type(file_desc_t), intent(inout) :: file   ! PIO file handle to close
!
! !REVISION HISTORY:
! Created by Erik Kluzek
!
!
! !LOCAL VARIABLES:
!-----------------------------------------------------------------------
!EOP

    call pio_closefile(file)

  end subroutine ncd_pio_closefile

  !=======================================================================

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_pio_createfile
!
! !INTERFACE:
  subroutine ncd_pio_createfile(file, fname)
!
! !DESCRIPTION:
! Create a new NetCDF file with PIO
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: file    ! PIO file descriptor
    character(len=*),  intent(in)    :: fname   ! File name to create
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
    integer :: ierr
    character(len=*),parameter :: subname='ncd_pio_createfile' ! subroutine name
!-----------------------------------------------------------------------
!EOP
    ierr = pio_createfile(pio_subsystem, file, io_type, fname, ior(PIO_CLOBBER,PIO_64BIT_OFFSET))

    if(ierr/= PIO_NOERR) then
       call endrun( subname//' ERROR: Failed to open file to write: '//trim(fname))
    else if(pio_subsystem%io_rank==0) then
       write(iulog,*) 'Opened file ', trim(fname),  ' to write', file%fh
    end if

  end subroutine ncd_pio_createfile

  !=======================================================================

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: check_var
!
! !INTERFACE:
  subroutine check_var(ncid, varname, vardesc, readvar, print_err )
!
! !DESCRIPTION:
! Check if variable is on netcdf file
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout)  :: ncid      ! PIO file descriptor
    character(len=*) , intent(in)     :: varname   ! Varible name to check
    type(Var_desc_t) , intent(out)    :: vardesc   ! Output variable descriptor
    logical          , intent(out)    :: readvar   ! If variable exists or not
    logical, optional, intent(in)     :: print_err ! If should print about error
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: ret     ! return value
    logical :: log_err ! if should log error
    character(len=*),parameter :: subname='check_var' ! subroutine name
!-----------------------------------------------------------------------


    if ( present(print_err) )then
       log_err = print_err
    else
       log_err = .true.
    end if
    readvar = .true.
    call pio_seterrorhandling(ncid, PIO_BCAST_ERROR)
    ret = PIO_inq_varid (ncid, varname, vardesc)
    if (ret /= PIO_noerr) then
       readvar = .false.
       if (masterproc .and. log_err) &
           write(iulog,*) subname//': variable ',trim(varname),' is not on dataset'
    end if
    call pio_seterrorhandling(ncid, PIO_INTERNAL_ERROR)
    
  end subroutine check_var

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: check_dim
!
! !INTERFACE:
  subroutine check_dim(ncid, dimname, value)
!
! !DESCRIPTION:
! Validity check on dimension
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(in) :: ncid      ! PIO file handle
    character(len=*), intent(in) :: dimname   ! Dimension name
    integer, intent(in)          :: value     ! Expected dimension size
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: dimid, dimlen    ! temporaries
    integer :: status           ! error code      
    character(len=*),parameter :: subname='check_dim' ! subroutine name
!-----------------------------------------------------------------------

    status = pio_inq_dimid (ncid, trim(dimname), dimid)
    status = pio_inq_dimlen (ncid, dimid, dimlen)
    if (dimlen /= value) then
       write(iulog,*) subname//' ERROR: mismatch of input dimension ',dimlen, &
            ' with expected value ',value,' for variable ',trim(dimname)
       call endrun()
    end if

  end subroutine check_dim
!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_enddef
!
! !INTERFACE:
  subroutine ncd_enddef(ncid)
!
! !DESCRIPTION:
! enddef netcdf file
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid      ! netcdf file id
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status   ! error status
    character(len=*),parameter :: subname='ncd_enddef' ! subroutine name
!-----------------------------------------------------------------------

    status = PIO_enddef(ncid)

  end subroutine ncd_enddef

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqdid
!
! !INTERFACE:
  subroutine ncd_inqdid(ncid,name,dimid,dimexist)
!
! !DESCRIPTION:
! inquire on a dimension id
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid   ! netcdf file id
    character(len=*), intent(in) :: name      ! dimension name
    integer         , intent(out):: dimid     ! dimension id
    logical,optional, intent(out):: dimexist  ! if this dimension exists or not
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    if ( present(dimexist) )then
       call pio_seterrorhandling(ncid, PIO_BCAST_ERROR)
    end if
    status = PIO_inq_dimid(ncid,name,dimid)
    if ( present(dimexist) )then
       if ( status == PIO_NOERR)then
          dimexist = .true.
       else
          dimexist = .false.
       end if
       call pio_seterrorhandling(ncid, PIO_INTERNAL_ERROR)
    end if

  end subroutine ncd_inqdid

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqdlen
!
! !INTERFACE:
  subroutine ncd_inqdlen(ncid,dimid,len,name)
!
! !DESCRIPTION:
! enddef netcdf file
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid       ! netcdf file id
    integer          , intent(inout) :: dimid      ! dimension id
    integer          , intent(out)   :: len        ! dimension len
    character(len=*), optional, intent(in) :: name ! dimension name
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    if ( present(name) )then
       call ncd_inqdid(ncid,name,dimid)
    end if
    len = -1
    status = PIO_inq_dimlen(ncid,dimid,len)

  end subroutine ncd_inqdlen

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqdname
!
! !INTERFACE:
  subroutine ncd_inqdname(ncid,dimid,dname)
!
! !DESCRIPTION:
! inquire dim name
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(in) :: ncid      ! netcdf file id
    integer          , intent(in) :: dimid     ! dimension id
    character(len=*) , intent(out):: dname     ! dimension name
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    status = PIO_inq_dimname(ncid,dimid,dname)

  end subroutine ncd_inqdname

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqfdims
!
! !INTERFACE:
  subroutine ncd_inqfdims(ncid, isgrid2d, ni, nj, ns)

!
! !ARGUMENTS:
    type(file_desc_t), intent(inout):: ncid
    logical          , intent(out)  :: isgrid2d
    integer          , intent(out)  :: ni
    integer          , intent(out)  :: nj
    integer          , intent(out)  :: ns
! !LOCAL VARIABLES:
!EOP
    integer  :: dimid                                ! netCDF id
    integer  :: ier                                  ! error status 
    character(len=32) :: subname = 'surfrd_filedims' ! subroutine name
!-----------------------------------------------------------------------

    if (single_column) then
       ni = 1
       nj = 1
       ns = 1
       isgrid2d = .true.
       RETURN
    end if

    ni = 0
    nj = 0

    call pio_seterrorhandling(ncid, PIO_BCAST_ERROR)
    ier = pio_inq_dimid (ncid, 'lon', dimid)
    if (ier == PIO_NOERR) ier = pio_inq_dimlen(ncid, dimid, ni)
    ier = pio_inq_dimid (ncid, 'lat', dimid)
    if (ier == PIO_NOERR) ier = pio_inq_dimlen(ncid, dimid, nj)

    ier = pio_inq_dimid (ncid, 'lsmlon', dimid)
    if (ier == PIO_NOERR) ier = pio_inq_dimlen(ncid, dimid, ni)
    ier = pio_inq_dimid (ncid, 'lsmlat', dimid)
    if (ier == PIO_NOERR) ier = pio_inq_dimlen(ncid, dimid, nj)

    ier = pio_inq_dimid (ncid, 'ni', dimid)
    if (ier == PIO_NOERR) ier = pio_inq_dimlen(ncid, dimid, ni)
    ier = pio_inq_dimid (ncid, 'nj', dimid)
    if (ier == PIO_NOERR) ier = pio_inq_dimlen(ncid, dimid, nj)

    ier = pio_inq_dimid (ncid, 'gridcell', dimid)
    if (ier == PIO_NOERR) then
       ier = pio_inq_dimlen(ncid, dimid, ni)
       if (ier == PIO_NOERR) nj = 1
    end if

    call pio_seterrorhandling(ncid, PIO_INTERNAL_ERROR)

    if (ni == 0 .or. nj == 0) then
       write(iulog,*) trim(subname),' ERROR: ni,nj = ',ni,nj,' cannot be zero '
       call endrun()
    end if

    if (nj == 1) then
       isgrid2d = .false.
    else
       isgrid2d = .true.
    end if

    ns = ni*nj

  end subroutine ncd_inqfdims

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqvid
!
! !INTERFACE:
  subroutine ncd_inqvid(ncid,name,varid,vardesc,readvar)
!
! !DESCRIPTION:
! Inquire on a variable ID
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid      ! netcdf file id
    character(len=*) , intent(in)    :: name      ! variable name
    integer          , intent(out)   :: varid     ! variable id
    type(Var_desc_t) , intent(out)   :: vardesc   ! variable descriptor
    logical, optional, intent(out)   :: readvar   ! does variable exist
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: ret               ! return code
    character(len=*),parameter :: subname='ncd_inqvid' ! subroutine name
!-----------------------------------------------------------------------

    if (present(readvar)) then
       readvar = .false.
       call pio_seterrorhandling(ncid, PIO_BCAST_ERROR)
       ret = PIO_inq_varid(ncid,name,vardesc)
       if (ret /= PIO_noerr) then
          if (masterproc) write(iulog,*) subname//': variable ',trim(name),' is not on dataset'
          readvar = .false.
       else
          readvar = .true.
       end if
       call pio_seterrorhandling(ncid, PIO_INTERNAL_ERROR)
    else
       ret = PIO_inq_varid(ncid,name,vardesc)
    endif
    varid = vardesc%varid
 
  end subroutine ncd_inqvid

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqvdims
!
! !INTERFACE:
  subroutine ncd_inqvdims(ncid,ndims,vardesc)
!
! !DESCRIPTION:
! inquire variable dimensions
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(in)   :: ncid      ! netcdf file id
    integer          , intent(out)  :: ndims     ! variable ndims
    type(Var_desc_t) , intent(inout):: vardesc   ! variable descriptor
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    ndims = -1
    status = PIO_inq_varndims(ncid,vardesc,ndims)

  end subroutine ncd_inqvdims

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqvname
!
! !INTERFACE:
  subroutine ncd_inqvname(ncid,varid,vname,vardesc)
!
! !DESCRIPTION:
! inquire variable name
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(in)   :: ncid      ! netcdf file id
    integer          , intent(in)   :: varid     ! variable id
    character(len=*) , intent(out)  :: vname     ! variable vname
    type(Var_desc_t) , intent(inout):: vardesc   ! variable descriptor
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    vname = ''
    status = PIO_inq_varname(ncid,vardesc,vname)

  end subroutine ncd_inqvname

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_inqvdids
!
! !INTERFACE:
  subroutine ncd_inqvdids(ncid,dids,vardesc)
!
! !DESCRIPTION:
! inquire variable dimension ids
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(in)  :: ncid      ! netcdf file id
    integer         ,intent(out)  :: dids(:)   ! variable dids
    type(Var_desc_t),intent(inout):: vardesc   ! variable descriptor
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    dids = -1
    status = PIO_inq_vardimid(ncid,vardesc,dids)

  end subroutine ncd_inqvdids

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_putatt_int
!
! !INTERFACE:
  subroutine ncd_putatt_int(ncid,varid,attrib,value,xtype)
!
! !DESCRIPTION:
! put integer attributes
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid      ! netcdf file id
    integer          ,intent(in)    :: varid     ! netcdf var id
    character(len=*) ,intent(in)    :: attrib    ! netcdf attrib
    integer          ,intent(in)    :: value     ! netcdf attrib value
    integer,optional ,intent(in)    :: xtype     ! netcdf data type
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    status = PIO_put_att(ncid,varid,trim(attrib),value)

  end subroutine ncd_putatt_int

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_putatt_char
!
! !INTERFACE:
  subroutine ncd_putatt_char(ncid,varid,attrib,value,xtype)
!
! !DESCRIPTION:
! put character attributes
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid      ! netcdf file id
    integer          ,intent(in)    :: varid     ! netcdf var id
    character(len=*) ,intent(in)    :: attrib    ! netcdf attrib
    character(len=*) ,intent(in)    :: value     ! netcdf attrib value
    integer,optional ,intent(in)    :: xtype     ! netcdf data type
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    status = PIO_put_att(ncid,varid,trim(attrib),value)

  end subroutine ncd_putatt_char

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_putatt_real
!
! !INTERFACE:
  subroutine ncd_putatt_real(ncid,varid,attrib,value,xtype)
!
! !DESCRIPTION:
! put real attributes
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid      ! netcdf file id
    integer          ,intent(in)    :: varid     ! netcdf var id
    character(len=*) ,intent(in)    :: attrib    ! netcdf attrib
    real(r8)         ,intent(in)    :: value     ! netcdf attrib value
    integer          ,intent(in)    :: xtype     ! netcdf data type
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
    real*4  :: value4
!-----------------------------------------------------------------------

    value4 = value

    if (xtype == pio_double) then
       status = PIO_put_att(ncid,varid,trim(attrib),value)
    else
       status = PIO_put_att(ncid,varid,trim(attrib),value4)
    endif

  end subroutine ncd_putatt_real

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_defdim
!
! !INTERFACE:
  subroutine ncd_defdim(ncid,attrib,value,dimid)
!
! !DESCRIPTION:
! define dimension
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(in) :: ncid      ! netcdf file id
    character(len=*) , intent(in) :: attrib    ! netcdf attrib
    integer          , intent(in) :: value     ! netcdf attrib value
    integer          , intent(out):: dimid     ! netcdf dimension id
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status
!-----------------------------------------------------------------------

    status = pio_def_dim(ncid,attrib,value,dimid)

  end subroutine ncd_defdim

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_defvar_bynf
!
! !INTERFACE:
  subroutine ncd_defvar_bynf(ncid, varname, xtype, ndims, dimid, varid, &
                             long_name, units, cell_method, missing_value, fill_value, &
                             imissing_value, ifill_value, comment, flag_meanings, &
                             flag_values, nvalid_range )
!
! !DESCRIPTION:
!  Define a netcdf variable
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid                  ! netcdf file id
    character(len=*) , intent(in)  :: varname                 ! variable name
    integer          , intent(in)  :: xtype                   ! external type
    integer          , intent(in)  :: ndims                   ! number of dims
    integer          , intent(inout) :: varid                 ! returned var id
    integer          , intent(in), optional :: dimid(:)       ! dimids
    character(len=*) , intent(in), optional :: long_name      ! attribute
    character(len=*) , intent(in), optional :: units          ! attribute
    character(len=*) , intent(in), optional :: cell_method    ! attribute
    character(len=*) , intent(in), optional :: comment        ! attribute
    character(len=*) , intent(in), optional :: flag_meanings(:) ! attribute
    real(r8)         , intent(in), optional :: missing_value  ! attribute for real
    real(r8)         , intent(in), optional :: fill_value     ! attribute for real
    integer          , intent(in), optional :: imissing_value ! attribute for int
    integer          , intent(in), optional :: ifill_value    ! attribute for int
    integer          , intent(in), optional :: flag_values(:)  ! attribute for int
    integer          , intent(in), optional :: nvalid_range(2)  ! attribute for int
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: n                   ! indices
    integer :: ldimid(4)           ! local dimid
    integer :: dimid0(1)           ! local dimid
    integer :: status              ! error status 
    integer :: lxtype              ! local external type (in case logical variable)
    type(var_desc_t)   :: vardesc  ! local vardesc
    character(len=128) :: dimname  ! temporary
    character(len=256) :: str      ! temporary
    character(len=*),parameter :: subname='ncd_defvar_bynf' ! subroutine name
!-----------------------------------------------------------------------

    varid = -1

    dimid0 = 0
    ldimid = 0
    if (present(dimid)) then
       ldimid(1:ndims) = dimid(1:ndims)
    else   ! ndims must be zero if dimid not present
       if (ndims /= 0) then
          write(iulog,*) subname//' ERROR: dimid not supplied and ndims ne 0 ',trim(varname),ndims
          call endrun()
       endif
    endif
       
    if ( xtype == ncd_log )then
       lxtype = ncd_int
    else
       lxtype = xtype
    end if
    if (masterproc .and. debug > 1) then
       write(iulog,*) 'Error in defining variable = ', trim(varname)
       write(iulog,*) subname//' ',trim(varname),lxtype,ndims,ldimid(1:ndims)
    endif
    
    if (ndims >  0) then 
       status = pio_inq_dimname(ncid,ldimid(ndims),dimname)
    end if

    ! Define variable
    if (present(dimid)) then
       status = PIO_def_var(ncid,trim(varname),lxtype,dimid(1:ndims),vardesc)
    else
       status = PIO_def_var(ncid,trim(varname),lxtype,dimid0        ,vardesc)
    endif
    varid = vardesc%varid

    !
    ! Add attributes
    !
    if (present(long_name)) then
       call ncd_putatt(ncid, varid, 'long_name', trim(long_name))
    end if
    if (present(flag_values)) then
       status = PIO_put_att(ncid,varid,'flag_values',flag_values)
       if ( .not. present(flag_meanings)) then
          write(iulog,*) 'Error in defining variable = ', trim(varname)
          call endrun( subname//" ERROR:: flag_values set -- but not flag_meanings" )
       end if
    end if
    if (present(flag_meanings)) then
       if ( .not. present(flag_values)) then
          write(iulog,*) 'Error in defining variable = ', trim(varname)
          call endrun( subname//" ERROR:: flag_meanings set -- but not flag_values" )
       end if
       if ( size(flag_values) /= size(flag_meanings) ) then
          write(iulog,*) 'Error in defining variable = ', trim(varname)
          call endrun( subname//" ERROR:: flag_meanings and flag_values dimension different")
       end if
       str = flag_meanings(1)
       do n = 1, size(flag_meanings)
          if ( index(flag_meanings(n), ' ') /= 0 )then
             write(iulog,*) 'Error in defining variable = ', trim(varname)
             call endrun( subname//" ERROR:: flag_meanings has an invalid space in it" )
          end if
          if ( n > 1 ) str = trim(str)//" "//flag_meanings(n)
       end do
       status = PIO_put_att(ncid,varid,'flag_meanings', trim(str) )
    end if
    if (present(comment)) then
       call ncd_putatt(ncid, varid, 'comment', trim(comment))
    end if
    if (present(units)) then
       call ncd_putatt(ncid, varid, 'units', trim(units))
    end if
    if (present(cell_method)) then
       str = 'time: ' // trim(cell_method)
       call ncd_putatt(ncid, varid, 'cell_methods', trim(str))
    end if
    if (present(fill_value)) then
       call ncd_putatt(ncid, varid, '_FillValue', fill_value, lxtype)
    end if
    if (present(missing_value)) then
       call ncd_putatt(ncid, varid, 'missing_value', missing_value, lxtype)
    end if
    if (present(ifill_value)) then
       call ncd_putatt(ncid, varid, '_FillValue', ifill_value, lxtype)
    end if
    if (present(imissing_value)) then
       call ncd_putatt(ncid, varid, 'missing_value', imissing_value, lxtype)
    end if
    if (present(nvalid_range)) then
       status = PIO_put_att(ncid,varid,'valid_range', nvalid_range )
    end if
    if ( xtype == ncd_log )then
       status = PIO_put_att(ncid,varid,'flag_values',     (/0, 1/) )
       status = PIO_put_att(ncid,varid,'flag_meanings',  "FALSE TRUE" )
       status = PIO_put_att(ncid,varid,'valid_range',    (/0, 1/) )
    end if

  end subroutine ncd_defvar_bynf

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_defvar_bygrid
!
! !INTERFACE:
  subroutine ncd_defvar_bygrid(ncid, varname, xtype, &
                               dim1name, dim2name, dim3name, dim4name, dim5name, &
                               long_name, units, cell_method, missing_value, fill_value, &
                               imissing_value, ifill_value, switchdim, comment, &
                               flag_meanings, flag_values, nvalid_range )
!
! !DESCRIPTION:
!  Define a netcdf variable
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid                 ! netcdf file id
    character(len=*), intent(in)  :: varname                 ! variable name
    integer         , intent(in)  :: xtype                   ! external type
    character(len=*), intent(in), optional :: dim1name       ! dimension name
    character(len=*), intent(in), optional :: dim2name       ! dimension name
    character(len=*), intent(in), optional :: dim3name       ! dimension name
    character(len=*), intent(in), optional :: dim4name       ! dimension name
    character(len=*), intent(in), optional :: dim5name       ! dimension name
    character(len=*), intent(in), optional :: long_name      ! attribute
    character(len=*), intent(in), optional :: units          ! attribute
    character(len=*), intent(in), optional :: cell_method    ! attribute
    character(len=*), intent(in), optional :: comment        ! attribute
    character(len=*), intent(in), optional :: flag_meanings(:) ! attribute
    real(r8)        , intent(in), optional :: missing_value  ! attribute for real
    real(r8)        , intent(in), optional :: fill_value     ! attribute for real
    integer         , intent(in), optional :: imissing_value ! attribute for int
    integer         , intent(in), optional :: ifill_value    ! attribute for int
    logical         , intent(in), optional :: switchdim      ! true=> permute dim1 and dim2 for output
    integer         , intent(in), optional :: flag_values(:)  ! attribute for int
    integer         , intent(in), optional :: nvalid_range(2)  ! attribute for int
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: n              ! indices
    integer :: ndims          ! dimension counter
    integer :: dimid(5)       ! dimension ids
    integer :: varid          ! variable id
    integer :: itmp           ! temporary
    character(len=256) :: str ! temporary
    character(len=*),parameter :: subname='ncd_defvar_bygrid' ! subroutine name
!-----------------------------------------------------------------------

    dimid(:) = 0

    ! Determine dimension ids for variable

    if (present(dim1name)) call ncd_inqdid(ncid, dim1name, dimid(1))
    if (present(dim2name)) call ncd_inqdid(ncid, dim2name, dimid(2))
    if (present(dim3name)) call ncd_inqdid(ncid, dim3name, dimid(3))
    if (present(dim4name)) call ncd_inqdid(ncid, dim4name, dimid(4))
    if (present(dim5name)) call ncd_inqdid(ncid, dim5name, dimid(5))

    ! Permute dim1 and dim2 if necessary

    if (present(switchdim)) then
       itmp = dimid(2)
       dimid(2) = dimid(1)
       dimid(1) = itmp
    end if

    ! Define variable

    ndims = 0
    if (present(dim1name)) then
       do n = 1, size(dimid)
          if (dimid(n) /= 0) ndims = ndims + 1
       end do
    end if

    call ncd_defvar_bynf(ncid,varname,xtype,ndims,dimid,varid, &
                         long_name=long_name, units=units, cell_method=cell_method, &
                         missing_value=missing_value, fill_value=fill_value, &
                         imissing_value=imissing_value, ifill_value=ifill_value, &
                         comment=comment, flag_meanings=flag_meanings, &
                         flag_values=flag_values, nvalid_range=nvalid_range )

  end subroutine ncd_defvar_bygrid

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_log_var0_nf
!
! !INTERFACE:
  subroutine ncd_io_log_var0_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global integer variable
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid      ! netcdf file id
    character(len=*) , intent(in)    :: flag      ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname   ! variable name
    logical          , intent(inout) :: data      ! raw data
    logical, optional, intent(out)   :: readvar   ! was var read?
    integer, optional, intent(in)    :: nt        ! time sample index
    logical          , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(1), count(1)   ! output bounds
    integer :: status               ! error code
    integer :: idata                ! raw integer data
    logical :: varpresent           ! if true, variable is on tape
    integer :: temp(1)              ! temporary
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_log_var0_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column .and. present(posNOTonfile) ) then
             if ( .not. posNOTonfile )then
                call endrun( subname// &
                ' ERROR: scalar var is NOT compatable with posNOTonfile = .false.' )
             end if
          endif
          status = pio_get_var(ncid, varid, idata)
          if (      idata == 0 )then
             data = .false.
          else if ( idata == 1 )then
             data = .true.
          else
             call endrun( subname// &
             ' ERROR: bad integer value for logical data' )
          end if
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = nt
          count(1) = 1
       else
          start(1) = 1
          count(1) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       if ( data )then
          temp(1) = 1
       else
          temp(1) = 0
       end if
       status = pio_put_var(ncid, varid, start, count, temp)

    endif   ! flag

  end subroutine ncd_io_log_var0_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_int_var0_nf
!
! !INTERFACE:
  subroutine ncd_io_int_var0_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global integer variable
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid      ! netcdf file id
    character(len=*) , intent(in)    :: flag      ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname   ! variable name
    integer          , intent(inout) :: data      ! raw data
    logical, optional, intent(out)   :: readvar   ! was var read?
    integer, optional, intent(in)    :: nt        ! time sample index
    logical          , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(1), count(1)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    integer :: temp(1)              ! temporary
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_int_var0_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          status = pio_get_var(ncid, varid, data)
          if (single_column .and. present(posNOTonfile) ) then
             if ( .not. posNOTonfile )then
                call endrun( subname// &
                ' ERROR: scalar var is NOT compatable with posNOTonfile = .false.' )
             end if
          endif
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = nt
          count(1) = 1
       else
          start(1) = 1
          count(1) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       temp(1) = data
       status = pio_put_var(ncid, varid, start, count, temp)

    endif   ! flag

  end subroutine ncd_io_int_var0_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_real_var0_nf
!
! !INTERFACE:
  subroutine ncd_io_real_var0_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global real variable
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid      ! netcdf file id
    character(len=*) , intent(in)    :: flag      ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname   ! variable name
    real(r8)         , intent(inout) :: data      ! raw data
    logical, optional, intent(out)   :: readvar   ! was var read?
    integer, optional, intent(in)    :: nt        ! time sample index
    logical          , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(1), count(1)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    real(r8):: temp(1)              ! temporary                
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_real_var0_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          status = pio_get_var(ncid, vardesc, data)
          if (single_column .and. present(posNOTonfile) ) then
             if ( .not. posNOTonfile )then
                call endrun( subname// &
                ' ERROR: scalar var is NOT compatable with posNOTonfile = .false.' )
             end if
          endif
       endif
       if (present(readvar)) readvar = varpresent

    else if (flag == 'write') then

       if (present(nt))      then
          start(1) = nt
          count(1) = 1
       else
          start(1) = 1
          count(1) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       temp(1) = data
       status = pio_put_var(ncid, varid, start, count, temp)

    endif   ! flag

  end subroutine ncd_io_real_var0_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_int_var1_nf
!
! !INTERFACE:
  subroutine ncd_io_int_var1_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global integer array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid      ! netcdf file id
    character(len=*) , intent(in)    :: flag      ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname   ! variable name
    integer          , intent(inout) :: data(:)   ! raw data
    logical, optional, intent(out)   :: readvar   ! was var read?
    integer, optional, intent(in)    :: nt        ! time sample index
    logical          , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(2), count(2)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_int_var1_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          status = pio_get_var(ncid, varid, data)
          if (single_column .and. present(posNOTonfile) ) then
             if ( .not. posNOTonfile )then
                call endrun( subname// &
                ' ERROR: 1D var is NOT compatable with posNOTonfile = .false.' )
             end if
          endif
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = 1
          count(1) = size(data)
          start(2) = nt
          count(2) = 1
       else
          start(1) = 1
          count(1) = size(data)
          start(2) = 1
          count(2) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       status = pio_put_var(ncid, varid, start, count, data)

    endif   ! flag

  end subroutine ncd_io_int_var1_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_log_var1_nf
!
! !INTERFACE:
  subroutine ncd_io_log_var1_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global integer array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid      ! netcdf file id
    character(len=*) , intent(in)    :: flag      ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname   ! variable name
    logical          , intent(inout) :: data(:)   ! raw data
    logical, optional, intent(out)   :: readvar   ! was var read?
    integer, optional, intent(in)    :: nt        ! time sample index
    logical          , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(2), count(2)   ! output bounds
    integer :: status               ! error code
    integer, pointer :: idata(:)    ! Temporary integer data to send to file
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_log_var1_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          allocate( idata(size(data)) ) 
          status = pio_get_var(ncid, varid, idata)
          if (single_column .and. present(posNOTonfile) ) then
             if ( .not. posNOTonfile )then
                call endrun( subname// &
                ' ERROR: 1D var is NOT compatable with posNOTonfile = .false.' )
             end if
          endif
          data = (idata == 1)
          if ( any(idata /= 0 .and. idata /= 1) )then
             call endrun( subname// &
             ' ERROR: read in bad integer value(s) for logical data' )
          end if
          deallocate( idata )
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = 1
          count(1) = size(data)
          start(2) = nt
          count(2) = 1
       else
          start(1) = 1
          count(1) = size(data)
          start(2) = 1
          count(2) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       allocate( idata(size(data)) ) 
       where( data )
          idata = 1
       elsewhere
          idata = 0
       end where
       status = pio_put_var(ncid, varid, start, count, idata)
       deallocate( idata )

    endif   ! flag

  end subroutine ncd_io_log_var1_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_real_var1_nf
!
! !INTERFACE:
  subroutine ncd_io_real_var1_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global real array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid                ! netcdf file id
    character(len=*) , intent(in)    :: flag                ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname             ! variable name
    real(r8)         , intent(inout) :: data(:)             ! raw data
    logical          , optional, intent(out):: readvar      ! was var read?
    integer          , optional, intent(in) :: nt           ! time sample index
    logical          , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(2), count(2)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_real_var1_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          status = pio_get_var(ncid, varid, data)
          if (single_column .and. present(posNOTonfile) ) then
             if ( .not. posNOTonfile )then
                call endrun( subname// &
                ' ERROR: 1D var is NOT compatable with posNOTonfile = .false.' )
             end if
          endif
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = 1
          start(2) = nt
          count(1) = size(data)
          count(2) = 1
       else
          start(1) = 1
          start(2) = 1
          count(1) = size(data)
          count(2) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       status = pio_put_var(ncid, varid, start, count, data)

    endif   ! flag

  end subroutine ncd_io_real_var1_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_char_var1_nf
!
! !INTERFACE:
  subroutine ncd_io_char_var1_nf(varname, data, flag, ncid, readvar, nt )
!
! !DESCRIPTION:
! netcdf I/O of global char array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid             ! netcdf file id
    character(len=*) , intent(in)    :: flag             ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname          ! variable name
    character(len=*) , intent(inout) :: data             ! raw data
    logical          , optional, intent(out):: readvar   ! was var read?
    integer          , optional, intent(in) :: nt        ! time sample index
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                   ! netCDF variable id
    integer :: m                       ! indices
    integer :: start(2), count(2)      ! output bounds
    integer :: status                  ! error code
    logical :: varpresent              ! if true, variable is on tape
    character(len=32) :: vname         ! variable error checking
    character(len=1)  :: tmpString(128)! temp for manipulating output string
    type(var_desc_t)  :: vardesc       ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_char_var1_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          status = pio_get_var(ncid, varid, data)
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       call ncd_inqvid  (ncid, varname, varid, vardesc)

       if (present(nt))      then
          count(1) = len(data)
          count(2) = 1
          do m = 1,count(1)
             tmpString(m:m) = data(m:m)
          end do
          if ( count(1) > size(tmpString) )then
             write(iulog,*) subname//' ERROR: input string size is too large:'//trim(data)
          end if
          start(1) = 1
          start(2) = nt
          status = pio_put_var(ncid, varid, start=start, count=count, &
                               ival=tmpString(1:count(1)) )
       else
          status = pio_put_var(ncid, varid, data )
       end if

    endif   ! flag

  end subroutine ncd_io_char_var1_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_int_var2_nf
!
! !INTERFACE:
  subroutine ncd_io_int_var2_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global integer 2D array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid                 ! netcdf file id
    character(len=*) , intent(in)    :: flag                 ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname              ! variable name
    integer          , intent(inout) :: data(:,:)            ! raw data
    logical          , optional, intent(out):: readvar       ! was var read?
    integer          , optional, intent(in) :: nt            ! time sample index
    logical          , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(3), count(3)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    logical :: found                ! if true, found lat/lon dims on file
    character(len=*),parameter :: subname='ncd_io_int_var2_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             call scam_field_offsets(ncid,'undefined',vardesc,&
                  start,count,found=found,posNOTonfile=posNOTonfile)
             if ( found )then
                status = pio_get_var(ncid, varid, start, count, data)
             else
                status = pio_get_var(ncid, varid, data)
             end if
          else
             status = pio_get_var(ncid, varid, data)
          endif
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = 1
          start(2) = 1
          start(3) = nt
          count(1) = size(data, dim=1)
          count(2) = size(data, dim=2)
          count(3) = 1
       else
          start(1) = 1
          start(2) = 1
          start(3) = 1
          count(1) = size(data, dim=1)
          count(2) = size(data, dim=2)
          count(3) = 1
       end if
       call ncd_inqvid(ncid, varname, varid, vardesc)
       status = pio_put_var(ncid, varid, start, count, data)

    endif   

  end subroutine ncd_io_int_var2_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_real_var2_nf
!
! !INTERFACE:
  subroutine ncd_io_real_var2_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global real 2D  array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid                ! netcdf file id
    character(len=*), intent(in)    :: flag                ! 'read' or 'write'
    character(len=*), intent(in)    :: varname             ! variable name
    real(r8)        , intent(inout) :: data(:,:)           ! raw data
    logical         , optional, intent(out):: readvar      ! was var read?
    integer         , optional, intent(in) :: nt           ! time sample index
    logical         , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(3), count(3)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    logical :: found                ! if true, found lat/lon dims on file
    character(len=*),parameter :: subname='ncd_io_real_var2_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             call scam_field_offsets(ncid,'undefined',vardesc,start,count,&
                                     found=found,posNOTonfile=posNOTonfile)
             if ( found )then
                status = pio_get_var(ncid, varid, start, count, data)
             else
                status = pio_get_var(ncid, varid, data)
             end if
          else
             status = pio_get_var(ncid, varid, data)
          endif
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = 1
          start(2) = 1
          start(3) = nt
          count(1) = size(data, dim=1)
          count(2) = size(data, dim=2)
          count(3) = 1
       else
          start(1) = 1
          start(2) = 1
          start(3) = 1
          count(1) = size(data, dim=1)
          count(2) = size(data, dim=2)
          count(3) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       status = pio_put_var(ncid, varid, start, count, data)

    endif   

  end subroutine ncd_io_real_var2_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_char_var2_nf
!
! !INTERFACE:
  subroutine ncd_io_char_var2_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global character array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid                ! netcdf file id
    character(len=*), intent(in)    :: flag                ! 'read' or 'write'
    character(len=*), intent(in)    :: varname             ! variable name
    character(len=*), intent(inout) :: data(:)             ! raw data
    logical         , optional, intent(out):: readvar      ! was var read?
    integer         , optional, intent(in) :: nt           ! time sample index
    logical         , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(3), count(3)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    logical :: found                ! if true, found lat/lon dims on file
    character(len=*),parameter :: subname='ncd_io_char_var2_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          data   = ' '
          status = pio_get_var(ncid, varid, data)
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       call ncd_inqvid  (ncid, varname, varid, vardesc)
       if (present(nt))      then
          start(1) = 1
          start(2) = 1
          start(3) = nt
          count(1) = len(data)
          count(2) = size(data)
          count(3) = 1
          status = pio_put_var(ncid, varid, start, count, data)
       else
          status = pio_put_var(ncid, varid, data)
       end if

    endif   

  end subroutine ncd_io_char_var2_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_char_var3_nf
!
! !INTERFACE:
  subroutine ncd_io_char_var3_nf(varname, data, flag, ncid, readvar, nt )
!
! !DESCRIPTION:
! netcdf I/O of global character array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid             ! netcdf file id
    character(len=*), intent(in)    :: flag             ! 'read' or 'write'
    character(len=*), intent(in)    :: varname          ! variable name
    character(len=*), intent(inout) :: data(:,:)        ! raw data
    logical         , optional, intent(out):: readvar   ! was var read?
    integer         , optional, intent(in) :: nt        ! time sample index
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(4), count(4)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    character(len=*),parameter :: subname='ncd_io_char_var3_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          data   = ' '
          status = pio_get_var(ncid, varid, data)
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       call ncd_inqvid  (ncid, varname, varid, vardesc)
       if (present(nt))      then
          start(:) = 1
          start(4) = nt
          count(1) = len(data)
          count(2) = size(data,dim=1)
          count(3) = size(data,dim=2)
          count(4) = 1
          status = pio_put_var(ncid, varid, start, count, data)
       else
          status = pio_put_var(ncid, varid, data)
       end if

    endif   

  end subroutine ncd_io_char_var3_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_char_varn_strt_nf
!
! !INTERFACE:
  subroutine ncd_io_char_varn_strt_nf(vardesc, data, flag, ncid, &
                                      start )
!
! !DESCRIPTION:
! netcdf I/O of global character array with start indices input
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid             ! netcdf file id
    character(len=*), intent(in)    :: flag             ! 'read' or 'write'
    type(var_desc_t), intent(in)    :: vardesc          ! local vardesc pointer
    character(len=*), intent(inout) :: data             ! raw data for this index
    integer         , intent(in)    :: start(:)         ! output bounds
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: status               ! error code
    character(len=*),parameter :: subname='ncd_io_char_varn_strt_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       status = pio_get_var(ncid, vardesc, start, data )

    elseif (flag == 'write') then

       status = pio_put_var(ncid, vardesc, start, data )

    endif   

  end subroutine ncd_io_char_varn_strt_nf

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_int_var1
!
! !INTERFACE:
  subroutine ncd_io_int_var1(varname, data, dim1name, &
                             flag, ncid, nt, readvar)
!
! !DESCRIPTION:
! I/O for 1d integer field
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid             ! netcdf file id
    character(len=*) , intent(in)    :: flag             ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname          ! variable name
    integer          , pointer       :: data(:)          ! local decomposition data
    character(len=*) , intent(in)    :: dim1name         ! dimension name
    integer          , optional, intent(in) :: nt        ! time sample index
    logical          , optional, intent(out):: readvar   ! true => variable is on initial dataset (read only)
!
! !REVISION HISTORY:
!
! !LOCAL VARIABLES:
!EOP
    character(len=8)  :: clmlevel   ! clmlevel
    character(len=32) :: dimname    ! temporary
    integer           :: n          ! index      
    integer           :: iodnum     ! iodesc num in list
    integer           :: varid      ! varid
    integer           :: ndims      ! ndims for var
    integer           :: ndims_iod  ! ndims iodesc for var
    integer           :: dims(4)    ! dim sizes       
    integer           :: dids(4)    ! dim ids
    integer           :: start(3)   ! netcdf start index
    integer           :: count(3)   ! netcdf count index
    integer           :: status     ! error code  
    logical           :: varpresent ! if true, variable is on tape
    integer           :: xtype      ! netcdf data type
    integer                , pointer  :: compDOF(:)
    type(iodesc_plus_type) , pointer  :: iodesc_plus
    type(var_desc_t)                  :: vardesc
    character(len=*),parameter :: subname='ncd_io_int_var1' ! subroutine name
!-----------------------------------------------------------------------

    clmlevel = dim1name

    if (masterproc .and. debug > 1) then
       write(iulog,*) subname//' ',trim(flag),' ',trim(varname),' ',trim(clmlevel)
    end if

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             start(:) = 1
             count(:) = 1
             call scam_field_offsets(ncid,clmlevel,vardesc,start,count)
             if (trim(clmlevel) == grlnd) then
                if (present(nt)) then
                   start(3) = nt
                   count(3) = 1
                end if
             else
                if (present(nt)) then
                   start(2) = nt
                   count(2) = 1
                end if
             end if
             status = pio_get_var(ncid, varid, start, count, data)
          else
             status = pio_inq_varndims(ncid, vardesc, ndims)
             status = pio_inq_vardimid(ncid, vardesc, dids)
             status = pio_inq_vartype (ncid, vardesc, xtype)
             status = pio_inq_dimname(ncid,dids(ndims),dimname)
             if ('time' == trim(dimname)) then
                ndims_iod = ndims - 1
             else
                ndims_iod = ndims
             end if
             do n = 1,ndims_iod
                status = pio_inq_dimlen(ncid,dids(n),dims(n))
             enddo
             call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                  xtype, iodnum)
             iodesc_plus => iodesc_list(iodnum)
             if (present(nt)) then
                call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
             end if
             call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, data, status)
          end if
       end if
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       call ncd_inqvid(ncid, varname ,varid, vardesc)
       status = pio_inq_varndims(ncid, vardesc, ndims)
       status = pio_inq_vardimid(ncid, vardesc, dids)
       status = pio_inq_vartype (ncid, vardesc, xtype)
       status = pio_inq_dimname(ncid,dids(ndims),dimname)
       if ('time' == trim(dimname)) then
          ndims_iod = ndims - 1
       else
          ndims_iod = ndims
       end if
       do n = 1,ndims_iod
          status = pio_inq_dimlen(ncid,dids(n),dims(n))
       enddo
       call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
            xtype, iodnum)
       iodesc_plus => iodesc_list(iodnum)
       if (present(nt)) then
          call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
       end if
       call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, data, status, fillval=0)

    else

       if (masterproc) then
          write(iulog,*) subname//' ERROR: unsupported flag ',trim(flag)
          call endrun()
       endif

    endif

  end subroutine ncd_io_int_var1

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_log_var1
!
! !INTERFACE:
  subroutine ncd_io_log_var1(varname, data, dim1name, &
                             flag, ncid, nt, readvar)
!
! !DESCRIPTION:
! I/O for 1d integer field
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid             ! netcdf file id
    character(len=*) , intent(in)    :: flag             ! 'read' or 'write'
    character(len=*) , intent(in)    :: varname          ! variable name
    logical          , pointer       :: data(:)          ! local decomposition data
    character(len=*) , intent(in)    :: dim1name         ! dimension name
    integer          , optional, intent(in) :: nt        ! time sample index
    logical          , optional, intent(out):: readvar   ! true => variable is on initial dataset (read only)
!
! !REVISION HISTORY:
!
! !LOCAL VARIABLES:
!EOP
    character(len=8)  :: clmlevel   ! clmlevel
    character(len=32) :: dimname    ! temporary
    integer           :: n          ! index      
    integer           :: iodnum     ! iodesc num in list
    integer           :: varid      ! varid
    integer           :: ndims      ! ndims for var
    integer           :: ndims_iod  ! ndims iodesc for var
    integer           :: dims(4)    ! dim sizes       
    integer           :: dids(4)    ! dim ids
    integer           :: start(3)   ! netcdf start index
    integer           :: count(3)   ! netcdf count index
    integer           :: status     ! error code  
    integer, pointer :: idata(:)    ! Temporary integer data to send to file
    logical           :: varpresent ! if true, variable is on tape
    integer           :: xtype      ! netcdf data type
    integer                , pointer  :: compDOF(:)
    type(iodesc_plus_type) , pointer  :: iodesc_plus
    type(var_desc_t)                  :: vardesc
    character(len=*),parameter :: subname='ncd_io_log_var1' ! subroutine name
!-----------------------------------------------------------------------

    if (masterproc .and. debug > 1) then
       write(iulog,*) subname//' ',trim(flag),' ',trim(varname),' ',trim(clmlevel)
    end if

    clmlevel = dim1name

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          allocate( idata(size(data)) ) 
          if (single_column) then
             start(:) = 1
             count(:) = 1
             call scam_field_offsets(ncid,clmlevel,vardesc,start,count)
             if (trim(clmlevel) == grlnd) then
                if (present(nt)) then
                   start(3) = nt
                   count(3) = 1
                end if
             else
                if (present(nt)) then
                   start(2) = nt
                   count(2) = 1
                end if
             end if
             status = pio_get_var(ncid, varid, start, count, idata)
          else
             status = pio_inq_varndims(ncid, vardesc, ndims)
             status = pio_inq_vardimid(ncid, vardesc, dids)
             status = pio_inq_vartype (ncid, vardesc, xtype)
             status = pio_inq_dimname(ncid,dids(ndims),dimname)
             if ('time' == trim(dimname)) then
                ndims_iod = ndims - 1
             else
                ndims_iod = ndims
             end if
             do n = 1,ndims_iod
                status = pio_inq_dimlen(ncid,dids(n),dims(n))
             enddo
             call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                  xtype, iodnum)
             iodesc_plus => iodesc_list(iodnum)
             if (present(nt)) then
                call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
             end if
             call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, idata, status)
          end if
          data = (idata == 1)
          if ( any(idata /= 0 .and. idata /= 1) )then
             call endrun( subname// &
             ' ERROR: read in bad integer value(s) for logical data' )
          end if
          deallocate( idata )
       end if
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       call ncd_inqvid(ncid, varname ,varid, vardesc)
       status = pio_inq_varndims(ncid, vardesc, ndims)
       status = pio_inq_vardimid(ncid, vardesc, dids)
       status = pio_inq_vartype (ncid, vardesc, xtype)
       status = pio_inq_dimname(ncid,dids(ndims),dimname)
       if ('time' == trim(dimname)) then
          ndims_iod = ndims - 1
       else
          ndims_iod = ndims
       end if
       do n = 1,ndims_iod
          status = pio_inq_dimlen(ncid,dids(n),dims(n))
       enddo
       call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
            xtype, iodnum)
       iodesc_plus => iodesc_list(iodnum)
       if (present(nt)) then
          call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
       end if
       allocate( idata(size(data)) ) 
       where( data )
          idata = 1
       elsewhere
          idata = 0
       end where
       call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, idata, status, fillval=0)
       deallocate( idata )

    else

       if (masterproc) then
          write(iulog,*) subname//' ERROR: unsupported flag ',trim(flag)
          call endrun()
       endif

    endif

  end subroutine ncd_io_log_var1

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_real_var1
!
! !INTERFACE:
  subroutine ncd_io_real_var1(varname, data, dim1name, &
                              flag, ncid, nt, readvar, cnvrtnan2fill)
!
! !DESCRIPTION:
! I/O for 1d real field
!
! !USES:
    use shr_infnan_mod  , only : shr_infnan_isnan
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid                 ! netcdf file id
    character(len=*), intent(in)  :: flag                   ! 'read' or 'write'
    character(len=*), intent(in)  :: varname                ! variable name
    real(r8)        , pointer     :: data(:)                ! local decomposition data
    character(len=*), intent(in)  :: dim1name               ! dimension name
    integer         , optional, intent(in) :: nt            ! time sample index
    logical         , optional, intent(in) :: cnvrtnan2fill ! true => convert any NaN's to _FillValue (spval)
    logical         , optional, intent(out):: readvar       ! true => variable is on initial dataset (read only)
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    character(len=8)  :: clmlevel   ! clmlevel
    character(len=32) :: dimname    ! temporary
    integer           :: iodnum     ! iodesc num in list
    integer           :: varid      ! varid
    integer           :: ndims      ! ndims for var
    integer           :: ndims_iod  ! ndims iodesc for var
    integer           :: n          ! index      
    integer           :: dims(4)    ! dim sizes       
    integer           :: dids(4)    ! dim ids
    integer           :: start(3)   ! netcdf start index
    integer           :: count(3)   ! netcdf count index
    integer           :: status     ! error code  
    logical           :: varpresent ! if true, variable is on tape
    integer           :: xtype      ! netcdf data type
    integer                , pointer  :: compDOF(:)
    type(iodesc_plus_type) , pointer  :: iodesc_plus
    type(var_desc_t)                  :: vardesc
    character(len=*),parameter :: subname='ncd_io_real_var1' ! subroutine name
!-----------------------------------------------------------------------

    clmlevel = dim1name

    if (masterproc .and. debug > 1) then
       write(iulog,*) trim(subname),' ',trim(flag),' ',trim(varname),' ',trim(clmlevel)
    endif

    if ( present(cnvrtnan2fill) )then
       if (.not. cnvrtnan2fill) then
          call endrun( subname//' ERROR: cnvrtnan2fill present but NOT set to true -- MUST set it to TRUE if used' )
       endif
    end if

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             start(:) = 1
             count(:) = 1
             call scam_field_offsets(ncid,clmlevel,vardesc,start,count)
             if (trim(clmlevel) == grlnd) then
                if (present(nt)) then
                   start(3) = nt
                   count(3) = 1
                end if
             else
                if (present(nt)) then
                   start(2) = nt
                   count(2) = 1
                end if
             end if
             status = pio_get_var(ncid, varid, start, count, data)
          else
             status = pio_inq_varndims(ncid, vardesc, ndims)
             status = pio_inq_vardimid(ncid,vardesc, dids)
             status = pio_inq_vartype(ncid, vardesc, xtype)
             status = pio_inq_dimname(ncid,dids(ndims),dimname)
             if ('time' == trim(dimname)) then
                ndims_iod = ndims - 1
             else
                ndims_iod = ndims
             end if
             do n = 1,ndims_iod
                status = pio_inq_dimlen(ncid,dids(n),dims(n))
             enddo
             call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                  xtype, iodnum)
             iodesc_plus => iodesc_list(iodnum)
             if (present(nt)) then
                call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
             end if
             call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, data, status)
          end if
          if ( present(cnvrtnan2fill) )then
             do n = lbound(data,dim=1), ubound(data,dim=1)
                if ( data(n) == spval )then
                   data(n) = nan
                end if
             end do
          end if
       end if
       if (present(readvar)) readvar = varpresent
       
    elseif (flag == 'write') then
       
       call ncd_inqvid(ncid, varname ,varid, vardesc)
       status = pio_inq_varndims(ncid, vardesc, ndims)
       status = pio_inq_vardimid(ncid, vardesc, dids)
       status = pio_inq_vartype (ncid, vardesc, xtype)
       status = pio_inq_dimname(ncid,dids(ndims),dimname)
       if ('time' == trim(dimname)) then
          ndims_iod = ndims - 1
       else
          ndims_iod = ndims
       end if
       do n = 1,ndims_iod
          status = pio_inq_dimlen(ncid,dids(n),dims(n))
       enddo
       call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
            xtype, iodnum)
       iodesc_plus => iodesc_list(iodnum)
       if (present(nt)) then
          call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
       end if
       if ( present(cnvrtnan2fill) )then
          do n = lbound(data,dim=1), ubound(data,dim=1)
             if ( shr_infnan_isnan( data(n) ) )then
                data(n) = spval
             end if
          end do
       end if
       call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, data, status, fillval=spval)
       
    else
       
       if (masterproc) then
          write(iulog,*) subname,' error: unsupported flag ',trim(flag)
          call endrun()
       endif
       
    endif

  end subroutine ncd_io_real_var1

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_int_var2
!
! !INTERFACE:
  subroutine ncd_io_int_var2(varname, data, dim1name, &
                         lowerb2, upperb2, flag, ncid, nt, readvar)
!
! !DESCRIPTION:
! Netcdf i/o of 2d initial integer field out to netCDF file
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid          ! netcdf file id
    character(len=*) , intent(in)  :: flag            ! 'read' or 'write'
    character(len=*) , intent(in)  :: varname         ! variable name
    integer          , pointer     :: data(:,:)       ! local decomposition input data
    character(len=*) , intent(in)  :: dim1name        ! dimension 1 name
    integer, optional, intent(in)  :: nt              ! time sample index
    integer, optional, intent(in)  :: lowerb2,upperb2 ! lower and upper bounds of second dimension
    logical, optional, intent(out) :: readvar         ! true => variable is on initial dataset (read only)
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer           :: ndim1,ndim2       
    character(len=8)  :: clmlevel   ! clmlevel
    character(len=32) :: dimname    ! temporary      
    integer           :: status     ! error status
    integer           :: ndims      ! ndims total for var
    integer           :: ndims_iod  ! ndims iodesc for var
    integer           :: varid      ! varid
    integer           :: n          ! index      
    integer           :: dims(4)    ! dim sizes       
    integer           :: dids(4)    ! dim ids
    integer           :: iodnum     ! iodesc num in list
    integer           :: start(4)   ! netcdf start index
    integer           :: count(4)   ! netcdf count index
    logical           :: varpresent ! if true, variable is on tape
    integer           :: xtype      ! netcdf data type
    integer           :: lb1,lb2
    integer           :: ub1,ub2
    type(iodesc_plus_type) , pointer  :: iodesc_plus
    type(var_desc_t)                  :: vardesc
    character(len=*),parameter :: subname='ncd_io_int_var2' ! subroutine name
!-----------------------------------------------------------------------

    clmlevel = dim1name      

    if (masterproc .and. debug > 1) then
       write(iulog,*) trim(subname),' ',trim(flag),' ',trim(varname),' ',trim(clmlevel)
    end if

    if (flag == 'read') then
       
       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             start(:) = 1
             count(:) = 1
             call scam_field_offsets(ncid, clmlevel, vardesc, start, count)
             status = pio_get_var(ncid, vardesc, start, count, data)
             if (trim(clmlevel) == grlnd) then
                count(3) = size(data,dim=2)
                if (present(nt)) then
                   start(4) = nt
                   count(4) = 1
                end if
             else
                count(2) = size(data,dim=2)
                if (present(nt)) then
                   start(3) = nt
                   count(3) = 1
                end if
             end if
          else
             status = pio_inq_varndims(ncid, vardesc, ndims)
             status = pio_inq_vardimid(ncid, vardesc, dids)
             status = pio_inq_vartype (ncid, vardesc, xtype)
             status = pio_inq_dimname(ncid, dids(ndims), dimname)
             if (ndims == 0) then
                write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
                call endrun()
             end if
             if ('time' == trim(dimname)) then
                ndims_iod = ndims - 1
             else
                ndims_iod = ndims
             end if
             do n = 1,ndims_iod
                status = pio_inq_dimlen(ncid,dids(n),dims(n))
             enddo
             call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                     xtype, iodnum)
             iodesc_plus => iodesc_list(iodnum)
             if (present(nt)) then
                call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
             end if
             call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, data, status)
          end if
       end if
       if (present(readvar)) readvar = varpresent

    else if (flag == 'write') then

       call ncd_inqvid(ncid, varname ,varid, vardesc)
       status = pio_inq_varndims(ncid, vardesc, ndims)
       status = pio_inq_vardimid(ncid, vardesc , dids)
       status = pio_inq_vartype (ncid, vardesc, xtype)
       if (ndims == 0) then
          write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
          call endrun()
       end if
       status = pio_inq_dimname(ncid,dids(ndims),dimname)
       if ('time' == trim(dimname)) then
          ndims_iod = ndims - 1
       else
          ndims_iod = ndims
       end if
       do n = 1,ndims_iod
          status = pio_inq_dimlen(ncid,dids(n),dims(n))
       enddo
       call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
               xtype, iodnum)
       iodesc_plus => iodesc_list(iodnum)
       if (present(nt)) then
          call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
       end if
       call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, data, status, fillval=0)

    else
       
       if (masterproc) then
          write(iulog,*) subname,' error: unsupported flag ',trim(flag)
          call endrun()
       endif
       
    endif

  end subroutine ncd_io_int_var2

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_real_var2
!
! !INTERFACE:
  subroutine ncd_io_real_var2(varname, data, dim1name, &
                               lowerb2, upperb2, flag, ncid, nt, readvar, switchdim, cnvrtnan2fill)
!
! !DESCRIPTION:
! Netcdf i/o of 2d initial integer field out to netCDF file
!
! !USES:
    use shr_infnan_mod  , only : shr_infnan_isnan
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid          ! netcdf file id
    character(len=*) , intent(in)  :: flag            ! 'read' or 'write'
    character(len=*) , intent(in)  :: varname         ! variable name
    real(r8)         , pointer     :: data(:,:)       ! local decomposition input data
    character(len=*) , intent(in)  :: dim1name        ! dimension 1 name
    integer, optional, intent(in)  :: nt              ! time sample index
    integer, optional, intent(in)  :: lowerb2,upperb2 ! lower and upper bounds of second dimension
    logical, optional, intent(in)  :: cnvrtnan2fill   ! true => convert any NaN's to _FillValue (spval)
    logical, optional, intent(out) :: readvar         ! true => variable is on initial dataset (read only)
    logical, optional, intent(in)  :: switchdim       ! true=> permute dim1 and dim2 for output
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    real(r8), pointer :: temp(:,:)
    integer           :: ndim1,ndim2       
    character(len=8)  :: clmlevel   ! clmlevel
    character(len=32) :: dimname    ! temporary      
    integer           :: status     ! error status
    integer           :: ndims      ! ndims total for var
    integer           :: ndims_iod  ! ndims iodesc for var
    integer           :: varid      ! varid
    integer           :: n          ! index      
    integer           :: dims(4)    ! dim sizes       
    integer           :: dids(4)    ! dim ids
    integer           :: iodnum     ! iodesc num in list
    integer           :: start(4)   ! netcdf start index
    integer           :: count(4)   ! netcdf count index
    logical           :: varpresent ! if true, variable is on tape
    integer           :: xtype      ! netcdf data type
    integer           :: i,j      
    integer           :: lb1,lb2
    integer           :: ub1,ub2
    integer           :: itemp      ! integer temporary if switchdim is on
    type(iodesc_plus_type) , pointer  :: iodesc_plus
    type(var_desc_t)                  :: vardesc
    character(len=*),parameter :: subname='ncd_io_real_var2' ! subroutine name
!-----------------------------------------------------------------------

    clmlevel = dim1name      

    if (masterproc .and. debug > 1) then
       write(iulog,*) trim(subname),' ',trim(flag),' ',trim(varname),' ',trim(clmlevel)
    end if

    if ( present(cnvrtnan2fill) )then
       if (.not. cnvrtnan2fill) then
          call endrun( subname//' ERROR: cnvrtnan2fill present but NOT set to true -- MUST set it to TRUE if used' )
       endif
    end if

    lb1 = lbound(data, dim=1)
    ub1 = ubound(data, dim=1)
    lb2 = lbound(data, dim=2)
    ub2 = ubound(data, dim=2)
    if (present(switchdim)) then
       if (present(lowerb2)) lb2 = lowerb2
       if (present(upperb2)) ub2 = upperb2
       allocate(temp(lb2:ub2,lb1:ub1))
    end if

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             start(:) = 1
             count(:) = 1
             call scam_field_offsets(ncid, clmlevel, vardesc, start, count)
             if (trim(clmlevel) == grlnd) then
                count(3) = size(data,dim=2)
                if (present(switchdim)) then
                   itemp    = count(1)
                   count(1) = count(3)
                   count(3) = itemp
                   itemp    = start(1)
                   start(1) = start(3)
                   start(3) = itemp
                end if
                if (present(nt)) then 
                   start(4) = nt
                   count(4) = 1
                end if
             else
                count(2) = size(data,dim=2)
                if (present(switchdim)) then
                   itemp    = count(1)
                   count(1) = count(2)
                   count(2) = itemp
                   itemp    = start(1)
                   start(1) = start(2)
                   start(2) = itemp
                end if
                if (present(nt)) then 
                   start(3) = nt
                   count(3) = 1
                end if
             end if
             status = pio_get_var(ncid, vardesc, start, count, data)
          else
             status = pio_inq_varndims(ncid, vardesc, ndims)
             status = pio_inq_vartype(ncid, vardesc, xtype)
             status = pio_inq_vardimid(ncid,vardesc, dids)
             status = pio_inq_dimname(ncid, dids(ndims), dimname)
             if (ndims == 0) then
                write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
                call endrun()
             end if
             if ('time' == trim(dimname)) then
                ndims_iod = ndims - 1
             else
                ndims_iod = ndims
             end if
             do n = 1,ndims_iod
                status = pio_inq_dimlen(ncid,dids(n),dims(n))
             enddo
             if (present(switchdim)) then
                call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                     xtype, iodnum, switchdim=.true.)
             else
                call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                     xtype, iodnum)
             end if
             iodesc_plus => iodesc_list(iodnum)
             if (present(nt)) then
                call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
             end if
             if (present(switchdim)) then
                call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, temp, status)
                do j = lb2,ub2
                do i = lb1,ub1
                   data(i,j) = temp(j,i) 
                end do
                end do
             else
                call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, data, status)
             end if
          end if
          if ( present(cnvrtnan2fill) )then
             do j = lb2,ub2
             do i = lb1,ub1
                if ( data(i,j) == spval )then
                   data(i,j) = nan
                end if
             end do
             end do
          end if
       end if
       if (present(readvar)) readvar = varpresent

    else if (flag == 'write') then

       call ncd_inqvid(ncid, varname ,varid, vardesc)
       status = pio_inq_varndims(ncid, vardesc, ndims)
       status = pio_inq_vardimid(ncid, vardesc , dids)
       status = pio_inq_vartype (ncid, vardesc, xtype)
       if (ndims == 0) then
          write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
          call endrun()
       end if
       status = pio_inq_dimname(ncid,dids(ndims),dimname)
       if ('time' == trim(dimname)) then
          ndims_iod = ndims - 1
       else
          ndims_iod = ndims
       end if
       do n = 1,ndims_iod
          status = pio_inq_dimlen(ncid,dids(n),dims(n))
       enddo
       if (present(switchdim)) then
          call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
               xtype, iodnum, switchdim=.true.)
       else
          call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
               xtype, iodnum)
       end if
       iodesc_plus => iodesc_list(iodnum)
       if (present(nt)) then
          call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
       end if
       if (present(switchdim)) then
          do j = lb2,ub2
          do i = lb1,ub1
             temp(j,i) = data(i,j)
          end do
          end do
          call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, temp, status, fillval=spval)
       else
          call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, data, status, fillval=spval)
       end if
       if ( present(cnvrtnan2fill) )then
          do j = lb2,ub2
          do i = lb1,ub1
             if ( shr_infnan_isnan(data(i,j)) )then
                data(i,j) = spval
             end if
          end do
          end do
       end if

    else

       if (masterproc) then
          write(iulog,*) subname,' error: unsupported flag ',trim(flag)
          call endrun()
       endif

    endif

    if (present(switchdim)) then
       deallocate(temp)
    end if

  end subroutine ncd_io_real_var2

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_int_var3
!
! !INTERFACE:
  subroutine ncd_io_int_var3(varname, data, dim1name, &
                               flag, ncid, nt, readvar)
!
! !DESCRIPTION:
! Netcdf i/o of 2d initial integer field out to netCDF file
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid          ! netcdf file id
    character(len=*) , intent(in)  :: flag            ! 'read' or 'write'
    character(len=*) , intent(in)  :: varname         ! variable name
    integer          , pointer     :: data(:,:,:)     ! local decomposition input data
    character(len=*) , intent(in)  :: dim1name        ! dimension 1 name
    integer, optional, intent(in)  :: nt              ! time sample index
    logical, optional, intent(out) :: readvar         ! true => variable is on initial dataset (read only)
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer           :: ndim1,ndim2       
    character(len=8)  :: clmlevel   ! clmlevel
    character(len=32) :: dimname    ! temporary      
    integer           :: status     ! error status
    integer           :: ndims      ! ndims total for var
    integer           :: ndims_iod  ! ndims iodesc for var
    integer           :: varid      ! varid
    integer           :: n          ! index      
    integer           :: dims(4)    ! dim sizes       
    integer           :: dids(4)    ! dim ids
    integer           :: iodnum     ! iodesc num in list
    integer           :: start(5)   ! netcdf start index
    integer           :: count(5)   ! netcdf count index
    logical           :: varpresent ! if true, variable is on tape
    integer           :: xtype      ! netcdf data type
    type(iodesc_plus_type) , pointer  :: iodesc_plus
    type(var_desc_t)                  :: vardesc
    character(len=*),parameter :: subname='ncd_io_int_var3' ! subroutine name
!-----------------------------------------------------------------------

    clmlevel = dim1name      

    if (masterproc .and. debug > 1) then
       write(iulog,*) trim(subname),' ',trim(flag),' ',trim(varname),' ',trim(clmlevel)
    end if

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             start(:) = 1
             count(:) = 1
             call scam_field_offsets(ncid, clmlevel, vardesc, start, count)
             if (trim(clmlevel) == grlnd) then
                count(3) = size(data,dim=2)
                count(4) = size(data,dim=3)
                if (present(nt)) then
                   start(5) = nt
                   count(5) = 1
                end if
             else
                count(2) = size(data,dim=2)
                count(3) = size(data,dim=3)
                if (present(nt)) then
                   start(4) = nt
                   count(4) = 1
                end if
             end if
             status = pio_get_var(ncid, vardesc, start, count, data)
          else
             status = pio_inq_varndims(ncid, vardesc, ndims)
             status = pio_inq_vardimid(ncid,vardesc, dids)
             status = pio_inq_vartype(ncid, vardesc, xtype)
             status = pio_inq_dimname(ncid, dids(ndims), dimname)
             if (ndims == 0) then
                write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
                call endrun()
             end if
             if ('time' == trim(dimname)) then
                ndims_iod = ndims - 1
             else
                ndims_iod = ndims
             end if
             do n = 1,ndims_iod
                status = pio_inq_dimlen(ncid,dids(n),dims(n))
             enddo
             call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                  xtype, iodnum)
             iodesc_plus => iodesc_list(iodnum)
             if (present(nt)) then
                call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
             end if
             call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, data, status)
          end if
       end if
       if (present(readvar)) readvar = varpresent

    else if (flag == 'write') then

       call ncd_inqvid(ncid, varname ,varid, vardesc)
       status = pio_inq_varndims(ncid, vardesc, ndims)
       status = pio_inq_vardimid(ncid, vardesc , dids)
       status = pio_inq_vartype (ncid, vardesc, xtype)
       if (ndims == 0) then
          write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
          call endrun()
       end if
       status = pio_inq_dimname(ncid,dids(ndims),dimname)
       if ('time' == trim(dimname)) then
          ndims_iod = ndims - 1
       else
          ndims_iod = ndims
       end if
       do n = 1,ndims_iod
          status = pio_inq_dimlen(ncid,dids(n),dims(n))
       enddo
       call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
            xtype, iodnum)
       iodesc_plus => iodesc_list(iodnum)
       if (present(nt)) then
          call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
       end if
       call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, data, status)

    else

       if (masterproc) then
          write(iulog,*) subname,' error: unsupported flag ',trim(flag)
          call endrun()
       endif

    endif

  end subroutine ncd_io_int_var3

!-----------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_real_var3
!
! !INTERFACE:
  subroutine ncd_io_real_var3(varname, data, dim1name, &
                               flag, ncid, nt, readvar)
!
! !DESCRIPTION:
! Netcdf i/o of 2d initial integer field out to netCDF file
!
! !USES:
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t), intent(inout) :: ncid          ! netcdf file id
    character(len=*) , intent(in)  :: flag            ! 'read' or 'write'
    character(len=*) , intent(in)  :: varname         ! variable name
    real(r8)         , pointer     :: data(:,:,:)     ! local decomposition input data
    character(len=*) , intent(in)  :: dim1name        ! dimension 1 name
    integer, optional, intent(in)  :: nt              ! time sample index
    logical, optional, intent(out) :: readvar         ! true => variable is on initial dataset (read only)
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    real(r8), allocatable :: temp(:,:)
    integer               :: ndim1,ndim2       
    character(len=8)  :: clmlevel   ! clmlevel
    character(len=32) :: dimname    ! temporary      
    integer           :: status     ! error status
    integer           :: ndims      ! ndims total for var
    integer           :: ndims_iod  ! ndims iodesc for var
    integer           :: varid      ! varid
    integer           :: n          ! index      
    integer           :: dims(4)    ! dim sizes       
    integer           :: dids(4)    ! dim ids
    integer           :: iodnum     ! iodesc num in list
    integer           :: start(5)   ! netcdf start index
    integer           :: count(5)   ! netcdf count index
    logical           :: varpresent ! if true, variable is on tape
    integer           :: xtype      ! netcdf data type
    type(iodesc_plus_type) , pointer  :: iodesc_plus
    type(var_desc_t)                  :: vardesc
    character(len=*),parameter :: subname='ncd_io_real_var3' ! subroutine name
!-----------------------------------------------------------------------

    clmlevel = dim1name      

    if (masterproc .and. debug > 1) then
       write(iulog,*) trim(subname),' ',trim(flag),' ',trim(varname),' ',trim(clmlevel)
    end if

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             start(:) = 1
             count(:) = 1
             call scam_field_offsets(ncid, clmlevel, vardesc, start, count)
             if (trim(clmlevel) == grlnd) then
                count(3) = size(data,dim=2)
                count(4) = size(data,dim=3)
                if (present(nt)) then 
                   start(5) = nt
                   count(5) = 1
                end if
             else
                count(2) = size(data,dim=2)
                count(3) = size(data,dim=3)
                if (present(nt)) then
                   start(4) = nt
                   count(4) = 1
                end if
             end if
             status = pio_get_var(ncid, vardesc, start, count, data)
          else
             status = pio_inq_varndims(ncid, vardesc, ndims)
             status = pio_inq_vardimid(ncid, vardesc, dids)
             status = pio_inq_vartype(ncid, vardesc, xtype)
             status = pio_inq_dimname(ncid, dids(ndims), dimname)
             if (ndims == 0) then
                write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
                call endrun()
             end if
             if ('time' == trim(dimname)) then
                ndims_iod = ndims - 1
             else
                ndims_iod = ndims
             end if
             do n = 1,ndims_iod
                status = pio_inq_dimlen(ncid,dids(n),dims(n))
             enddo
             call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
                  xtype, iodnum)
             iodesc_plus => iodesc_list(iodnum)
             if (present(nt)) then
                call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
             end if
             call pio_read_darray(ncid, vardesc, iodesc_plus%iodesc, data, status)
          end if
       end if
       if (present(readvar)) readvar = varpresent

    else if (flag == 'write') then

       call ncd_inqvid(ncid, varname ,varid, vardesc)
       status = pio_inq_varndims(ncid, vardesc, ndims)
       status = pio_inq_vardimid(ncid, vardesc , dids)
       status = pio_inq_vartype (ncid, vardesc, xtype)
       if (ndims == 0) then
          write(iulog,*) trim(subname),' ERROR: ndims must be greater than 0'
          call endrun()
       end if
       status = pio_inq_dimname(ncid,dids(ndims),dimname)
       if ('time' == trim(dimname)) then
          ndims_iod = ndims - 1
       else
          ndims_iod = ndims
       end if
       do n = 1,ndims_iod
          status = pio_inq_dimlen(ncid,dids(n),dims(n))
       enddo
       call ncd_getiodesc(ncid, clmlevel, ndims_iod, dims(1:ndims_iod), dids(1:ndims_iod), &
            xtype, iodnum)
       iodesc_plus => iodesc_list(iodnum)
       if (present(nt)) then
          call pio_setframe(vardesc, int(nt,kind=PIO_Offset))
       end if
       call pio_write_darray(ncid, vardesc, iodesc_plus%iodesc, data, status, fillval=spval)

    else

       if (masterproc) then
          write(iulog,*) subname,' error: unsupported flag ',trim(flag)
          call endrun()
       endif

    endif

  end subroutine ncd_io_real_var3


!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: ncd_io_real_var3_nf
!
! !INTERFACE:
  subroutine ncd_io_real_var3_nf(varname, data, flag, ncid, readvar, nt, posNOTonfile)
!
! !DESCRIPTION:
! netcdf I/O of global real 3D  array
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t),intent(inout) :: ncid                ! netcdf file id
    character(len=*), intent(in)    :: flag                ! 'read' or 'write'
    character(len=*), intent(in)    :: varname             ! variable name
    real(r8)        , intent(inout) :: data(:,:,:)           ! raw data
    logical         , optional, intent(out):: readvar      ! was var read?
    integer         , optional, intent(in) :: nt           ! time sample index
    logical         , optional, intent(in) :: posNOTonfile ! position is NOT on this file
!
! !REVISION HISTORY:
!
!
! !LOCAL VARIABLES:
!EOP
    integer :: varid                ! netCDF variable id
    integer :: start(4), count(4)   ! output bounds
    integer :: status               ! error code
    logical :: varpresent           ! if true, variable is on tape
    character(len=32) :: vname      ! variable error checking
    type(var_desc_t)  :: vardesc    ! local vardesc pointer
    logical :: found                ! if true, found lat/lon dims on file
    character(len=*),parameter :: subname='ncd_io_real_var3_nf'
!-----------------------------------------------------------------------

    if (flag == 'read') then

       call ncd_inqvid(ncid, varname, varid, vardesc, readvar=varpresent)
       if (varpresent) then
          if (single_column) then
             call scam_field_offsets(ncid,'undefined',vardesc, start,count, &
                                     found=found,posNOTonfile=posNOTonfile)
             if ( found )then
                status = pio_get_var(ncid, varid, start, count, data)
             else
                status = pio_get_var(ncid, varid, data)
             end if
          else
             status = pio_get_var(ncid, varid, data)
          endif
       endif
       if (present(readvar)) readvar = varpresent

    elseif (flag == 'write') then

       if (present(nt))      then
          start(1) = 1
          start(2) = 1
          start(3) = nt
          count(1) = size(data, dim=1)
          count(2) = size(data, dim=2)
          count(3) = 1
       else
          start(1) = 1
          start(2) = 1
          start(3) = 1
          count(1) = size(data, dim=1)
          count(2) = size(data, dim=2)
          count(3) = 1
       end if
       call ncd_inqvid  (ncid, varname, varid, vardesc)
       status = pio_put_var(ncid, varid, start, count, data)

    endif   

  end subroutine ncd_io_real_var3_nf

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: subroutine scam_field_offsets
!
! !INTERFACE:
  subroutine scam_field_offsets( ncid, dim1name, vardesc, start, count, &
                                 found, posNOTonfile)
!
! !DESCRIPTION: 
! Read/Write initial data from/to netCDF instantaneous initial data file 
!
! !USES:
    use clm_varpar  , only : maxpatch
    use clm_varctl  , only : scmlon,scmlat,single_column
    use nanMod      , only : nan, bigint
    use shr_scam_mod, only : shr_scam_getCloseLatLon
    use shr_string_mod, only: shr_string_toLower
!
! !ARGUMENTS:
    implicit none
    type(file_desc_t) , intent(inout) :: ncid         ! netcdf file id
    character(len=*)  , intent(in)    :: dim1name     ! dimension 1 name
    type(Var_desc_t)  , intent(inout) :: vardesc      ! variable descriptor
    integer           , intent(inout) :: start(:)     ! start index
    integer           , intent(inout) :: count(:)     ! count to retrieve
    logical, optional , intent(out)   :: found        ! if present return true if found
                                                      ! dimensions on file else false
                                                      ! if NOT present abort if can't find
    logical, optional , intent(in)    :: posNOTonfile ! Position is NOT on this file
!
! !CALLED FROM: subroutine inicfields
!
! !REVISION HISTORY:
! Created by John Truesdale

!
! !LOCAL VARIABLES:
!EOP
    integer :: data_offset                   ! offset into land array 1st column 
    integer :: ndata                         ! number of column (or pft points to read)
    real(r8) , pointer :: cols1dlon(:)       ! holds cols1d_ixy var
    real(r8) , pointer :: cols1dlat(:)       ! holds cols1d_jxy var
    real(r8) , pointer :: pfts1dlon(:)       ! holds pfts1d_ixy var
    real(r8) , pointer :: pfts1dlat(:)       ! holds pfts1d_jxy var
    real(r8) , pointer :: land1dlon(:)       ! holds land1d_ixy var
    real(r8) , pointer :: land1dlat(:)       ! holds land1d_jxy var
    integer :: cols(maxpatch)                ! grid cell columns for scam
    integer :: pfts(maxpatch)                ! grid cell pfts for scam
    integer :: landunits(maxpatch)           ! grid cell landunits for scam
    integer :: cc,i                          ! index variable
    integer :: totpfts                       ! total number of pfts
    integer :: totcols                       ! total number of columns
    integer :: totlandunits                  ! total number of landunits
    integer, allocatable :: dids(:)                       ! dim ids
    integer :: dimid                         ! netCDF dimension id
    integer :: varid                         ! netCDF variable id
    integer :: status                        ! return code
    integer :: latidx,lonidx                 ! latitude/longitude indices
    real(r8):: closelat,closelon             ! closest latitude and longitude indices
    integer :: ndims,dimlen                  ! number of dimensions in desired variable
    character(len=32) :: dimname             ! dimension name
    character(len=32) :: subname = 'scam_field_offsets'
!------------------------------------------------------------------------

    if ( present(posNOTonfile) )then
       if ( posNOTonfile )then
          if ( .not. present(found) )then
             call endrun( subname// &
                  'ERROR: Bad subroutine calling structure posNOTonfile sent, but found was NOT!')
          end if
          found = .false.
          return
       end if
    end if

    ! find closest land grid cell for this point

    if ( present(found) )then
       call shr_scam_getCloseLatLon(ncid,scmlat,scmlon,closelat,closelon,latidx,lonidx,found)
       if ( .not. found ) return
    else
       call shr_scam_getCloseLatLon(ncid,scmlat,scmlon,closelat,closelon,latidx,lonidx)
    end if
     
    call ncd_inqvdims(ncid,ndims,vardesc)
    if (dim1name == 'column') then

       status = pio_inq_dimid(ncid, 'column', dimid)
       status = pio_inq_dimlen(ncid, dimid, totcols)

       allocate (cols1dlon(totcols))
       allocate (cols1dlat(totcols))
       
       status = pio_inq_varid(ncid, 'cols1d_lon', varid)
       status = pio_get_var(ncid, varid, cols1dlon)
       status = pio_inq_varid(ncid, 'cols1d_lat', varid)
       status = pio_get_var(ncid, varid, cols1dlat)
       
       cols(:)     = bigint
       data_offset = bigint
       i = 1
       ndata = 0
       do cc = 1, totcols
          if (cols1dlon(cc) == closelon.and.cols1dlat(cc) == closelat) then
             cols(i)=cc
             ndata  =i
             i=i+1
          end if
       end do
       if (ndata == 0) then
          write(iulog,*)'couldnt find any columns for this latitude ',latidx,' and longitude ',lonidx
          call endrun( subname//'ERROR:: no columns for this position' )
       else
          data_offset=cols(1)
       end if
       
       deallocate (cols1dlon)
       deallocate (cols1dlat)
       
       start(ndims) = data_offset
       count(ndims) = ndata
       
    else if (dim1name == 'pft') then
       
       status = pio_inq_dimid(ncid, 'pft', dimid)
       status = pio_inq_dimlen(ncid, dimid, totpfts)

       allocate (pfts1dlon(totpfts))
       allocate (pfts1dlat(totpfts))

       status = pio_inq_varid(ncid, 'pfts1d_lon', varid)
       status = pio_get_var(ncid, varid, pfts1dlon)

       status = pio_inq_varid(ncid, 'pfts1d_lat', varid)
       status = pio_get_var(ncid, varid, pfts1dlat)
       
       pfts(:)     = bigint
       data_offset = bigint
       i     = 1
       ndata = 0
       do cc = 1, totpfts
          if (pfts1dlon(cc) == closelon.and.pfts1dlat(cc) == closelat) then
             pfts(i)=cc
             ndata  =i
             i=i+1
          end if
       end do
       if (ndata == 0) then
          write(iulog,*)'couldnt find any pfts for this latitude ',closelat,' and longitude ',closelon
          call endrun( subname//'ERROR:: no PFTs for this position' )
       else
          data_offset=pfts(1)
       end if
       
       deallocate (pfts1dlon)
       deallocate (pfts1dlat)
       
       start(ndims) = data_offset
       count(ndims) = ndata
       
    else if (dim1name == 'landunit') then
       
       status = pio_inq_dimid(ncid, 'landunit', dimid)
       status = pio_inq_dimlen(ncid, dimid, totlandunits)

       allocate (land1dlon(totlandunits))
       allocate (land1dlat(totlandunits))

       status = pio_inq_varid(ncid, 'land1d_lon', varid)
       status = pio_get_var(ncid, varid, land1dlon)

       status = pio_inq_varid(ncid, 'land1d_lat', varid)
       status = pio_get_var(ncid, varid, land1dlat)
       
       landunits(:) = bigint
       data_offset  = bigint
       i     = 1
       ndata = 0
       do cc = 1, totlandunits
          if (land1dlon(cc) == closelon.and.land1dlat(cc) == closelat) then
             landunits(i)=cc
             ndata  =i
             i=i+1
          end if
       end do
       if (ndata == 0) then
          write(iulog,*)'couldnt find any landunits for this latitude ',closelat,' and longitude ',closelon
          call endrun( subname//'ERROR:: no landunits for this position' )
       else
          data_offset=landunits(1)
       end if
       
       deallocate (land1dlon)
       deallocate (land1dlat)
       
       start(ndims) = data_offset
       count(ndims) = ndata
       
    else
       status = pio_inq_varndims(ncid, vardesc, ndims)
       allocate(dids(ndims))
       status = pio_inq_vardimid(ncid, vardesc, dids)
       do i = 1,ndims
          status = pio_inq_dimname(ncid,dids(i),dimname)
	  dimname=shr_string_toLower(dimname)
          status = pio_inq_dimlen(ncid,dids(i),dimlen)
          if ( trim(dimname)=='nj'.or. trim(dimname)=='lat'.or. trim(dimname)=='lsmlat') then
	     start(i)=latidx
             count(i)=1
          else if ( trim(dimname)=='ni'.or. trim(dimname)=='lon'.or. trim(dimname)=='lsmlon') then
             start(i)=lonidx
             count(i)=1
          else
             start(i)=1
             count(i)=dimlen
          end if
       enddo
       deallocate(dids)
    endif

  end subroutine scam_field_offsets

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: subroutine ncd_getiodesc
!
! !INTERFACE:
  subroutine ncd_getiodesc(ncid, clmlevel, ndims, dims, dimids, &
       xtype, iodnum, switchdim) 
       
!
! !DESCRIPTION: 
! Returns an index to an io descriptor
!
! !USES:
!
! !ARGUMENTS:

    type(file_desc_t), intent(inout) :: ncid       ! PIO file descriptor
    character(len=8) , intent(in)    :: clmlevel   ! clmlevel
    integer          , intent(in)    :: ndims      ! ndims for var      
    integer          , intent(in)    :: dims(:)    ! dim sizes
    integer          , intent(in)    :: dimids(:)  ! dim ids
    integer          , intent(in)    :: xtype      ! file external type
    integer          , intent(out)   :: iodnum     ! iodesc num in list
    logical,optional , intent(in)    :: switchdim  ! switch level dimension and first dim 

! !REVISION HISTORY:
! Created by Mariana Vertenstein

!
! !LOCAL VARIABLES:
!EOP
    integer :: k,m,n,cnt                     ! indices
    integer :: basetype                      ! pio basetype
    integer :: gsmap_lsize                   ! local size of gsmap
    integer :: gsmap_gsize                   ! global size of gsmap
    integer :: fullsize                      ! size of entire array on cdf
    integer :: gsize                         ! global size of clmlevel
    integer :: vsize                         ! other dimensions
    integer :: vsize1, vsize2                ! other dimensions
    integer :: status                        ! error status
    logical :: found                         ! true => found created iodescriptor
    integer :: ndims_file                    ! temporary
    character(len=64) dimname_file           ! dimension name on file
    character(len=64) dimname_iodesc         ! dimension name from io descriptor
    type(mct_gsMap),pointer       :: gsmap   ! global seg map
    integer, pointer,dimension(:) :: gsmOP   ! gsmap ordered points
    integer, pointer  :: compDOF(:)
    character(len=32) :: subname = 'ncd_getiodesc'
!------------------------------------------------------------------------

    ! Determining if need to create a new io descriptor

    n = 1
    found = .false.
    do while (n <= num_iodesc .and. .not.found)
       if (ndims == iodesc_list(n)%ndims .and. xtype == iodesc_list(n)%type) then
          found = .true.
          ! First found implies that dimension sizes are the same 
          do m = 1,ndims
             if (dims(m) /= iodesc_list(n)%dims(m)) then
                found = .false.
             endif
          enddo
          ! If found - then also check that dimension names are equal - 
          ! dimension ids in iodescriptor are only used to query dimension
          ! names associated with that iodescriptor
          if (found) then
             do m = 1,ndims
                status = PIO_inq_dimname(ncid,dimids(m),dimname_file)
                status = PIO_inquire(ncid, ndimensions=ndims_file)
                if (iodesc_list(n)%dimids(m) > ndims_file) then 
                   found = .false.
                   exit
                else
                   status = PIO_inq_dimname(ncid,iodesc_list(n)%dimids(m),dimname_iodesc)
                   if (trim(dimname_file) .ne. trim(dimname_iodesc)) then
                      found = .false.
                      exit
                   end if
                end if
             end do
          end if
          if (found) then
             iodnum = n
             if (iodnum > num_iodesc) then
                write(iulog,*) trim(subname),' ERROR: iodnum out of range ',iodnum,num_iodesc
                call endrun()
             endif
             RETURN
          endif
       endif
       n = n + 1
    enddo

    ! Creating a new io descriptor

    if (ndims > 0) then 
       num_iodesc = num_iodesc + 1
       if (num_iodesc > max_iodesc) then
          write(iulog,*) trim(subname),' ERROR num_iodesc gt max_iodesc ',max_iodesc
          call endrun()
       endif
       iodnum = num_iodesc
       if (masterproc .and. debug > 1) then
          write(iulog,*) trim(subname),' creating iodesc at iodnum,ndims,dims(1:ndims),xtype',&
               iodnum,ndims,dims(1:ndims),xtype
       endif
    end if

    if (xtype == pio_double ) then
       basetype = PIO_DOUBLE
    else if (xtype == pio_real) then
       basetype  = PIO_DOUBLE
    else if (xtype == pio_int) then
       basetype = PIO_INT
    end if

    call get_clmlevel_gsmap(clmlevel,gsmap)
    gsize = get_clmlevel_gsize(clmlevel)
    gsmap_lsize = mct_gsmap_lsize(gsmap,mpicom)
    gsmap_gsize = mct_gsmap_gsize(gsmap)

    call mct_gsmap_OP(gsmap,iam,gsmOP)

    fullsize = 1
    do n = 1,ndims
       fullsize = fullsize*dims(n)
    enddo

    vsize = fullsize / gsize
    if (mod(fullsize,gsize) /= 0) then
       write(iulog,*) subname,' ERROR in vsize ',fullsize,gsize,vsize
       call endrun()
    endif

    allocate(compDOF(gsmap_lsize*vsize))

    if (present(switchdim)) then
       if (switchdim) then
          cnt = 0
          do m = 1,gsmap_lsize
             do n = 1,vsize
                cnt = cnt + 1
                compDOF(cnt) = (gsmOP(m)-1)*vsize + n
             enddo
          enddo
       else
          write(iulog,*) subname,' ERROR switch dims present must have switchdim true' 
          call endrun()
       end if
    else         ! currently allow for up to two vertical dimensions
       if (vsize /= 1 .and. vsize /= dims(ndims)) then
          vsize1 = vsize/dims(ndims)
          vsize2 = dims(ndims)
          if (vsize1*vsize2 /= vsize) then
             write(iulog,*)'vsize1= ',vsize1,' vsize2= ',vsize2,' vsize= ',vsize
             call endrun('error in vsize1 and vsize2 computation')
          end if
          cnt = 0
          do k = 1,vsize2
             do n = 1,vsize1
                do m = 1,gsmap_lsize
                   cnt = cnt + 1
                   compDOF(cnt) = (k-1)*vsize1*gsmap_gsize + (n-1)*gsmap_gsize +  gsmOP(m) 
                enddo
             enddo
          end do
       else
          cnt = 0
          do n = 1,vsize
             do m = 1,gsmap_lsize
                cnt = cnt + 1
                compDOF(cnt) = (n-1)*gsmap_gsize + gsmOP(m)
             enddo
          enddo
       end if
    end if

    if (debug > 1) then
       do m = 0,npes-1
          if (iam == m) then
             write(iulog,*) trim(subname),' sizes1  = ',iam,gsize,gsmap_gsize,gsmap_lsize
             write(iulog,*) trim(subname),' sizes2  = ',iam,fullsize,npes,vsize
             write(iulog,*) trim(subname),' compDOF = ',iam,size(compDOF),minval(compDOF),maxval(compDOF)
             call shr_sys_flush(iulog)
          endif
          call mpi_barrier(mpicom,status)
       enddo
    endif

    deallocate(gsmOP)

    call pio_initdecomp(pio_subsystem, baseTYPE, dims(1:ndims), compDOF, iodesc_list(iodnum)%iodesc)

    deallocate(compDOF)

    iodesc_list(iodnum)%type  = xtype
    iodesc_list(iodnum)%ndims = ndims
    iodesc_list(iodnum)%dims  = 0
    iodesc_list(iodnum)%dims(1:ndims)   = dims(1:ndims)
    iodesc_list(iodnum)%dimids(1:ndims) = dimids(1:ndims)


  end subroutine ncd_getiodesc

  !=======================================================================

end module ncdio_pio
