!===============================================================================
! SVN $Id: seq_io_mod.F90 23596 2010-06-07 19:36:18Z tcraig $
! SVN $URL: https://svn-ccsm-models.cgd.ucar.edu/drv/seq_mct/branch_tags/cesm1_0_rel_tags/cesm1_0_rel01_drvseq3_1_32/driver/seq_io_mod.F90 $
!===============================================================================
!BOP ===========================================================================
!
! !MODULE: seq_io_mod -- reads and writes driver files
!
! !DESCRIPTION:
!    Writes attribute vectors to netcdf
!
! !REMARKS:
!
! !REVISION HISTORY:
!    2007-Oct-26 - T. Craig first version
!    2007-Dec-06 - T. Craig update and improve
!    2008-Feb-16 - J. Edwards convert to PIO
!
! !INTERFACE: ------------------------------------------------------------------


module seq_io_mod 3,18

  ! !USES:

  use shr_kind_mod, only: r8 => shr_kind_r8, in => shr_kind_in
  use shr_kind_mod, only: cl => shr_kind_cl, cs => shr_kind_cs
  use shr_sys_mod       ! system calls
  use seq_cdata_mod     ! cdata
  use seq_comm_mct, only : logunit, seq_comm_setptrs, CPLID
  use seq_flds_mod, only : seq_flds_lookup
  use mct_mod           ! mct wrappers
  use pio

  implicit none
  private

! !PUBLIC TYPES:

  ! none

! !PUBLIC MEMBER FUNCTIONS:

  public seq_io_init
  public seq_io_wopen
  public seq_io_close
  public seq_io_redef
  public seq_io_enddef
  public seq_io_date2yyyymmdd
  public seq_io_sec2hms
  public seq_io_read
  public seq_io_write

! !PUBLIC DATA MEMBERS

  ! none

!EOP


  interface seq_io_read 18
     module procedure seq_io_read_av
     module procedure seq_io_read_int
     module procedure seq_io_read_int1d
     module procedure seq_io_read_r8
     module procedure seq_io_read_r81d
  end interface

  interface seq_io_write 77
     module procedure seq_io_write_av
     module procedure seq_io_write_int
     module procedure seq_io_write_int1d
     module procedure seq_io_write_r8
     module procedure seq_io_write_r81d
     module procedure seq_io_write_time
  end interface

!-------------------------------------------------------------------------------
! Local data
!-------------------------------------------------------------------------------

   character(*),parameter :: prefix = "seq_io_"
   character(CL)          :: wfilename = ''
   real(r8)    ,parameter :: fillvalue = SHR_CONST_SPVAL

   character(*),parameter :: modName = "(seq_io_mod) "
   integer(in) ,parameter :: debug = 0 ! internal debug level

   integer(IN)          ,save :: cpl_io_type
   type(file_desc_t)    ,save :: cpl_io_file
   type(iosystem_desc_t),save :: cpl_io_subsystem

   character(*),parameter :: version ='cpl7v10'
   character(*),parameter :: version0='cpl7v00'

!=================================================================================
contains
!=================================================================================

!=================================================================================
!BOP =============================================================================
!
! !IROUTINE: seq_io_init - initialize io for coupler
!
! !DESCRIPTION:
!    Read the pio_inparm namelist and initialize the pio subsystem
!
! !REVISION HISTORY:
!    2009-Sep-30 - B. Kauffman - consolidation, clean up
!    2009-Feb-17 - J. Edwards - initial version
!
! !INTERFACE: --------------------------------------------------------------------


subroutine seq_io_init(nlfilename) 1,11

   use shr_string_mod, only : shr_string_toupper
   use shr_file_mod,   only : shr_file_getunit, shr_file_freeunit
   use shr_mpi_mod,    only : shr_mpi_bcast
   use pio, only : pio_iotype_netcdf, pio_iotype_pnetcdf, pio_iotype_netcdf4c, pio_iotype_netcdf4p

   implicit none

! !INPUT/OUTPUT PARAMETERS:

   character(*), intent(in) :: nlfilename

! LOCAL

   integer(IN)   :: iam, mpicom, npes, ierr, unitn
   logical       :: iamroot
   character(CS) :: cpl_io_typename
   integer(IN)   :: cpl_io_stride
   integer(IN)   :: cpl_io_numtasks
   integer(IN)   :: cpl_io_root
   integer(IN),parameter :: cpl_io_root_default = 0

   namelist /pio_inparm/ cpl_io_stride, cpl_io_root, cpl_io_numtasks, cpl_io_typename

   character(*),parameter :: subName =   '(seq_io_init) '
   character(*),parameter :: F00     = "('(seq_io_init) ',4a)"
   character(*),parameter :: F01     = "('(seq_io_init) ',a,i6)"

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

    call seq_comm_setptrs(CPLID, iam=iam, mpicom=mpicom,npes=npes, iamroot=iamroot)

    !--------------------------------------------------------------------------
    ! read io nml parameters 
    !--------------------------------------------------------------------------
    cpl_io_stride   = -1 ! set based on cpl_io_numtasks value when initialized < 0
    cpl_io_numtasks = -1 ! set based on cpl_io_stride   value when initialized < 0
    cpl_io_root     =  cpl_io_root_default
    cpl_io_typename = 'netcdf'

    if (iamroot) then
       if (debug > 0) then
          write(logunit,F00) 'pio init parameters: before nml read'
          write(logunit,F01) '   cpl_io_stride   = ',cpl_io_stride
          write(logunit,F01) '   cpl_io_root     = ',cpl_io_root
          write(logunit,F00) '   cpl_io_typename = ',cpl_io_typename
          write(logunit,F01) '   cpl_io_numtasks = ',cpl_io_numtasks
       end if

       unitn=shr_file_getunit()
       open( unitn, file=trim(nlfilename), status='old' )
       ierr = 1
       do while( ierr /= 0 )
          read(unitn,nml=pio_inparm,iostat=ierr)
          if (ierr < 0) then
             call shr_sys_abort( subname//':: namelist read returns an'// &
                                 ' end of file or end of record condition' )
          end if
       end do
       close(unitn)
       call shr_file_freeUnit( unitn )

       if (debug > 0) then
          write(logunit,F00) 'pio init parameters: after nml read'
          write(logunit,F01) '   cpl_io_stride   = ',cpl_io_stride
          write(logunit,F01) '   cpl_io_root     = ',cpl_io_root
          write(logunit,F00) '   cpl_io_typename = ',cpl_io_typename
          write(logunit,F01) '   cpl_io_numtasks = ',cpl_io_numtasks
       end if

       if      ( shr_string_toupper(cpl_io_typename) .eq. 'NETCDF' ) then
          cpl_io_type = pio_iotype_netcdf
       else if ( shr_string_toupper(cpl_io_typename) .eq. 'PNETCDF') then
          cpl_io_type = pio_iotype_pnetcdf
       else if ( shr_string_toupper(cpl_io_typename) .eq. 'NETCDF4P') then
          cpl_io_type = pio_iotype_netcdf4p
       else if ( shr_string_toupper(cpl_io_typename) .eq. 'NETCDF4C') then
          cpl_io_type = pio_iotype_netcdf4c
       else
          write(logunit,*) subName,'Bad io_type argument - using iotype_netcdf'
          cpl_io_type=pio_iotype_netcdf
       end if
    end if
    call shr_mpi_bcast(cpl_io_type , mpicom)
    call shr_mpi_bcast(cpl_io_stride  , mpicom)
    call shr_mpi_bcast(cpl_io_root    , mpicom)
    call shr_mpi_bcast(cpl_io_numtasks, mpicom)

    !--------------------------------------------------------------------------
    ! check/set/correct io pio parameters
    !--------------------------------------------------------------------------


    if (cpl_io_stride>0.and.cpl_io_numtasks<0) then
       cpl_io_numtasks = npes/cpl_io_stride
    else if(cpl_io_numtasks>0 .and. cpl_io_stride<0) then
       cpl_io_stride = npes/cpl_io_numtasks
    else if(cpl_io_numtasks<0 .and. cpl_io_stride<0) then
       cpl_io_stride = 4
       cpl_io_numtasks = npes/cpl_io_stride
       cpl_io_numtasks = max(1, cpl_io_numtasks)
    end if

    if (cpl_io_root<0) then
       cpl_io_root = cpl_io_root_default
    endif
    cpl_io_root = min(cpl_io_root,npes-1)

    if (cpl_io_root + (cpl_io_stride)*(cpl_io_numtasks-1) >= npes .or. &
       cpl_io_stride<=0 .or. cpl_io_numtasks<=0 .or. cpl_io_root < 0 .or. &
       cpl_io_root > npes-1) then
       write(logunit,*) subName,'cpl_io_stride, iotasks or root out of bounds - resetting to defaults ', &
		cpl_io_stride, cpl_io_numtasks, cpl_io_root
       cpl_io_stride = max(1,npes/4)
       cpl_io_numtasks = npes/cpl_io_stride
       cpl_io_root = min(1,npes-1)
    end if

    !--------------------------------------------------------------------------
    ! init pio library
    !--------------------------------------------------------------------------
    if (iamroot) then
       write(logunit,F00) 'pio init parameters: '
       write(logunit,F01) '   cpl_io_stride   = ',cpl_io_stride
       write(logunit,F01) '   cpl_io_root     = ',cpl_io_root
       write(logunit,F00) '   cpl_io_typename = ',cpl_io_typename
       write(logunit,F01) '   cpl_io_numtasks = ',cpl_io_numtasks
    end if

!   call pio_init(iam, mpicom, cpl_io_numtasks, cpl_io_root, cpl_io_stride, PIO_REARR_BOX, cpl_io_subsystem)
    call pio_init(iam, mpicom, cpl_io_numtasks, 0, cpl_io_stride, PIO_REARR_BOX, &
                  cpl_io_subsystem, base=cpl_io_root)
    
    cpl_io_file%fh=-1

  end subroutine seq_io_init

!===============================================================================
!BOP ===========================================================================
!
! !IROUTINE: seq_io_wopen - open netcdf file
!
! !DESCRIPTION:
!    open netcdf file
!
! !REVISION HISTORY:
!    2007-Oct-26 - T. Craig - initial version
!
! !INTERFACE: ------------------------------------------------------------------


subroutine seq_io_wopen(filename,cdata,clobber,cdf64) 5,2

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(*),intent(in) :: filename
    type(seq_cdata),intent(in) :: cdata
    logical,optional,intent(in):: clobber
    logical,optional,intent(in):: cdf64

    !EOP

    logical :: exists
    logical :: lclobber
    logical :: lcdf64
    integer :: iam
    integer :: rcode
    integer :: nmode
    character(CL)  :: lversion
    character(*),parameter :: subName = '(seq_io_wopen) '
    
!-------------------------------------------------------------------------------
!
!-------------------------------------------------------------------------------

    lversion=trim(version0)

    lclobber = .false.
    if (present(clobber)) lclobber=clobber

    lcdf64 = .false.
    if (present(cdf64)) lcdf64=cdf64

    call seq_comm_setptrs(CPLID,iam=iam)

    if (cpl_io_file%fh<0) then
       ! filename not open
       inquire(file=trim(filename),exist=exists)
       if (exists) then
          if (lclobber) then
             nmode = pio_clobber
             if (lcdf64) nmode = ior(nmode,PIO_64BIT_OFFSET)
             rcode = pio_createfile(cpl_io_subsystem, cpl_io_file, cpl_io_type, trim(filename), nmode)
             if(iam==0) write(logunit,*) subname,' create file ',trim(filename)
             rcode = pio_put_att(cpl_io_file,pio_global,"file_version",version)
          else
             rcode = pio_openfile(cpl_io_subsystem, cpl_io_file, cpl_io_type, trim(filename), pio_write)
             if(iam==0) write(logunit,*) subname,' open file ',trim(filename)
             call pio_seterrorhandling(cpl_io_file,PIO_BCAST_ERROR)
             rcode = pio_get_att(cpl_io_file,pio_global,"file_version",lversion)
             call pio_seterrorhandling(cpl_io_file,PIO_INTERNAL_ERROR)
             if (trim(lversion) /= trim(version)) then
                rcode = pio_redef(cpl_io_file)
                rcode = pio_put_att(cpl_io_file,pio_global,"file_version",version)
                rcode = pio_enddef(cpl_io_file)
             endif
          endif
       else
          nmode = pio_noclobber
          if (lcdf64) nmode = ior(nmode,PIO_64BIT_OFFSET)
          rcode = pio_createfile(cpl_io_subsystem, cpl_io_file, cpl_io_type, trim(filename), nmode)
          if(iam==0) write(logunit,*) subname,' create file ',trim(filename)
          rcode = pio_put_att(cpl_io_file,pio_global,"file_version",version)
       endif
    elseif (trim(wfilename) /= trim(filename)) then
       ! filename is open, better match open filename
       if(iam==0) write(logunit,*) subname,' different file currently open ',trim(filename)
       call shr_sys_abort()
    else
       ! filename is already open, just return
    endif

end subroutine seq_io_wopen

!===============================================================================
!BOP ===========================================================================
!
! !IROUTINE: seq_io_close - close netcdf file
!
! !DESCRIPTION:
!    close netcdf file
!
! !REVISION HISTORY:
!    2007-Oct-26 - T. Craig - initial version
!
! !INTERFACE: ------------------------------------------------------------------


subroutine seq_io_close(filename,cdata) 4,2

    use pio, only : pio_closefile

    implicit none

    ! !INPUT/OUTPUT PARAMETERS:
    character(*),intent(in) :: filename
    type(seq_cdata),intent(in) :: cdata

    !EOP

    integer :: iam
    integer :: rcode
    character(*),parameter :: subName = '(seq_io_close) '

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

    call seq_comm_setptrs(CPLID,iam=iam)


    if (cpl_io_file%fh<0) then
       ! filename not open, just return
    elseif (trim(wfilename) /= trim(filename)) then
       ! filename matches, close it
       call pio_closefile(cpl_io_file)
       cpl_io_file%fh=-1
    else
       ! different filename is open, abort
       if(iam==0) write(logunit,*) subname,' different file currently open ',trim(filename)
       call shr_sys_abort()
    endif

    wfilename = ''

end subroutine seq_io_close

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


subroutine seq_io_redef(filename) 1
    character(len=*), intent(in) :: filename
    integer :: rcode

    rcode = pio_redef(cpl_io_file)
end subroutine seq_io_redef

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


subroutine seq_io_enddef(filename) 4
    character(len=*), intent(in) :: filename
    integer :: rcode

    rcode = pio_enddef(cpl_io_file)
end subroutine seq_io_enddef

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


character(len=10) function seq_io_date2yyyymmdd (date) 3,1

! Input arguments

   integer, intent(in) :: date

! Local workspace

   integer :: year    ! year of yyyy-mm-dd
   integer :: month   ! month of yyyy-mm-dd
   integer :: day     ! day of yyyy-mm-dd

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

   if (date < 0) then
      call shr_sys_abort ('seq_io_date2yyyymmdd: negative date not allowed')
   end if

   year  = date / 10000
   month = (date - year*10000) / 100
   day   = date - year*10000 - month*100

   write(seq_io_date2yyyymmdd,80) year, month, day
80 format(i4.4,'-',i2.2,'-',i2.2)

end function seq_io_date2yyyymmdd

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


character(len=8) function seq_io_sec2hms (seconds) 3,3

! Input arguments

   integer, intent(in) :: seconds

! Local workspace

   integer :: hours     ! hours of hh:mm:ss
   integer :: minutes   ! minutes of hh:mm:ss
   integer :: secs      ! seconds of hh:mm:ss

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

   if (seconds < 0 .or. seconds > 86400) then
      write(logunit,*)'seq_io_sec2hms: bad input seconds:', seconds
      call shr_sys_abort()
   end if

   hours   = seconds / 3600
   minutes = (seconds - hours*3600) / 60
   secs    = (seconds - hours*3600 - minutes*60)

   if (minutes < 0 .or. minutes > 60) then
      write(logunit,*)'seq_io_sec2hms: bad minutes = ',minutes
      call shr_sys_abort()
   end if

   if (secs < 0 .or. secs > 60) then
      write(logunit,*)'seq_io_sec2hms: bad secs = ',secs
      call shr_sys_abort()
   end if

   write(seq_io_sec2hms,80) hours, minutes, secs
80 format(i2.2,':',i2.2,':',i2.2)

end function seq_io_sec2hms

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_write_av - write AV to netcdf file
  !
  ! !DESCRIPTION:
  !    Write AV to netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_write_av(filename,cdata,AV,dname,whead,wdata,nx,ny,nt,fillval,pre,tavg,& 1,4
	                     use_float)

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    type(mct_aVect) ,intent(in) :: AV       ! data to be written
    character(len=*),intent(in) :: dname    ! name of data
    logical,optional,intent(in) :: whead    ! write header
    logical,optional,intent(in) :: wdata    ! write data
    integer(in),optional,intent(in) :: nx   ! 2d grid size if available
    integer(in),optional,intent(in) :: ny   ! 2d grid size if available
    integer(in),optional,intent(in) :: nt   ! time sample
    real(r8),optional,intent(in) :: fillval ! fill value
    character(len=*),optional,intent(in) :: pre      ! prefix to variable name
    logical,optional,intent(in) :: tavg     ! is this a tavg
    logical,optional,intent(in) :: use_float ! write output as float rather than double

    !EOP

    integer(in) :: rcode
    integer(in) :: mpicom
    integer(in) :: iam
    integer(in) :: nf,ns,ng
    integer(in) :: i,j,k,n
    integer(in),target  :: dimid2(2)
    integer(in),target  :: dimid3(3)
    integer(in),pointer :: dimid(:)
    type(var_desc_t) :: varid
    type(io_desc_t) :: iodesc
    integer(kind=PIO_OffSet) :: frame
    type(mct_string) :: mstring     ! mct char type
    character(CL)    :: itemc       ! string converted to char
    character(CL)    :: name1       ! var name
    character(CL)    :: cunit       ! var units
    character(CL)    :: lname       ! long name
    character(CL)    :: sname       ! standard name
    character(CL)    :: lpre        ! local prefix
    logical :: exists
    logical :: lwhead, lwdata
    integer(in) :: lnx,lny
    real(r8) :: lfillvalue
    type(mct_gsMap),pointer :: gsmap
    type(mct_aVect) :: AVroot
    real(r8),pointer :: fld1(:,:)  ! needed to convert AVroot ng rAttr to 2d nx,ny
    character(*),parameter :: subName = '(seq_io_write_av) '

    integer :: lbnum
    integer, pointer :: Dof(:)

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

    lfillvalue = fillvalue
    if (present(fillval)) then
       lfillvalue = fillval
    endif

    lpre = trim(dname)
    if (present(pre)) then
       lpre = trim(pre)
    endif

    lwhead = .true.
    lwdata = .true.
    if (present(whead)) lwhead = whead
    if (present(wdata)) lwdata = wdata

    if (.not.lwhead .and. .not.lwdata) then
       ! should we write a warning?
       return
    endif

    call seq_cdata_setptrs(cdata,gsmap=gsmap)
    call seq_comm_setptrs(CPLID,iam=iam)	

    ng = mct_gsmap_gsize(gsmap)
    lnx = ng
    lny = 1
	
    nf = mct_aVect_nRattr(AV)
    if (nf < 1) then
       write(logunit,*) subname,' ERROR: nf = ',nf,trim(dname)
       call shr_sys_abort()
    endif

    if (present(nx)) then
       if (nx /= 0) lnx = nx
    endif
    if (present(ny)) then
       if (ny /= 0) lny = ny
    endif
    if (lnx*lny /= ng) then
       if(iam==0) write(logunit,*) subname,' ERROR: grid2d size not consistent ',ng,lnx,lny,trim(dname)
       call shr_sys_abort()
    endif

    if (lwhead) then
       rcode = pio_def_dim(cpl_io_file,trim(lpre)//'_nx',lnx,dimid2(1))
       rcode = pio_def_dim(cpl_io_file,trim(lpre)//'_ny',lny,dimid2(2))

       if (present(nt)) then
          dimid3(1:2) = dimid2
          rcode = pio_inq_dimid(cpl_io_file,'time',dimid3(3))
          dimid => dimid3
       else
          dimid => dimid2
       endif

       do k = 1,nf
          call mct_aVect_getRList(mstring,k,AV)
          itemc = mct_string_toChar(mstring)
          call mct_string_clean(mstring)
! "v0"    name1 = trim(prefix)//trim(dname)//'_'//trim(itemc)
          name1 = trim(lpre)//'_'//trim(itemc)
          call seq_flds_lookup(itemc,longname=lname,stdname=sname,units=cunit)
	  if (present(use_float)) then 
             rcode = pio_def_var(cpl_io_file,trim(name1),PIO_REAL,dimid,varid)
          else
             rcode = pio_def_var(cpl_io_file,trim(name1),PIO_DOUBLE,dimid,varid)
          end if
          rcode = pio_put_att(cpl_io_file,varid,"_FillValue",lfillvalue)
          rcode = pio_put_att(cpl_io_file,varid,"units",trim(cunit))
          rcode = pio_put_att(cpl_io_file,varid,"long_name",trim(lname))
          rcode = pio_put_att(cpl_io_file,varid,"standard_name",trim(sname))
          rcode = pio_put_att(cpl_io_file,varid,"internal_dname",trim(dname))
          if (present(tavg)) then
             if (tavg) then
                rcode = pio_put_att(cpl_io_file,varid,"cell_methods","time: mean")
             endif
          endif
       enddo

    else if (lwdata) then
       call mct_gsmap_OrderedPoints(gsmap, iam, Dof)
       call pio_initdecomp(cpl_io_subsystem, pio_double, (/lnx,lny/), dof, iodesc)
       deallocate(dof)

       do k = 1,nf
          call mct_aVect_getRList(mstring,k,AV)
          itemc = mct_string_toChar(mstring)
          call mct_string_clean(mstring)
! "v0"    name1 = trim(prefix)//trim(dname)//'_'//trim(itemc)
          name1 = trim(lpre)//'_'//trim(itemc)
          rcode = pio_inq_varid(cpl_io_file,trim(name1),varid)
          if (present(nt)) then
             frame = nt
          else
             frame = 1
          endif
          call pio_setframe(varid,frame)
          call pio_write_darray(cpl_io_file, varid, iodesc, av%rattr(k,:), rcode, fillval=lfillvalue)
       enddo

       call pio_freedecomp(cpl_io_file, iodesc)

    end if
  end subroutine seq_io_write_av

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_write_int - write AV to netcdf file
  !
  ! !DESCRIPTION:
  !    Write AV to netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_write_int(filename,cdata,idata,dname,whead,wdata) 1,1

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    integer(in)     ,intent(in) :: idata    ! data to be written
    character(len=*),intent(in) :: dname    ! name of data
    logical,optional,intent(in) :: whead    ! write header
    logical,optional,intent(in) :: wdata    ! write data

    !EOP

    integer(in) :: rcode
    integer(in) :: iam
    type(var_desc_t) :: varid
    logical :: exists
    logical :: lwhead, lwdata
    character(*),parameter :: subName = '(seq_io_write_int) '

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

    lwhead = .true.
    lwdata = .true.
    if (present(whead)) lwhead = whead
    if (present(wdata)) lwdata = wdata

    if (.not.lwhead .and. .not.lwdata) then
       ! should we write a warning?
       return
    endif

    call seq_comm_setptrs(CPLID,iam=iam)

    if (lwhead) then
       rcode = pio_def_var(cpl_io_file,trim(dname),PIO_INT,varid)

    else if (lwdata) then
       rcode = pio_inq_varid(cpl_io_file,trim(dname),varid)
       rcode = pio_put_var(cpl_io_file,varid,idata)

       !      write(logunit,*) subname,' wrote AV ',trim(dname),lwhead,lwdata
    endif

  end subroutine seq_io_write_int

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_write_int1d - write AV to netcdf file
  !
  ! !DESCRIPTION:
  !    Write AV to netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_write_int1d(filename,cdata,idata,dname,whead,wdata) 1,1

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    integer(in)     ,intent(in) :: idata(:) ! data to be written
    character(len=*),intent(in) :: dname    ! name of data
    logical,optional,intent(in) :: whead    ! write header
    logical,optional,intent(in) :: wdata    ! write data

    !EOP

    integer(in) :: rcode
    integer(in) :: iam
    integer(in) :: dimid(1)
    type(var_desc_t) :: varid
    integer(in) :: lnx
    logical :: exists
    logical :: lwhead, lwdata
    character(*),parameter :: subName = '(seq_io_write_int1d) '

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

    lwhead = .true.
    lwdata = .true.
    if (present(whead)) lwhead = whead
    if (present(wdata)) lwdata = wdata

    if (.not.lwhead .and. .not.lwdata) then
       ! should we write a warning?
       return
    endif

    call seq_comm_setptrs(CPLID,iam=iam)

    lnx = size(idata)

    if (lwhead) then
       rcode = pio_def_dim(cpl_io_file,trim(dname)//'_nx',lnx,dimid(1))
       rcode = pio_def_var(cpl_io_file,trim(dname),PIO_INT,dimid,varid)
    else if (lwdata) then
       rcode = pio_inq_varid(cpl_io_file,trim(dname),varid)
       rcode = pio_put_var(cpl_io_file,varid,idata)
    endif

       !      write(logunit,*) subname,' wrote AV ',trim(dname),lwhead,lwdata

  end subroutine seq_io_write_int1d

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_write_r8 - write AV to netcdf file
  !
  ! !DESCRIPTION:
  !    Write AV to netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_write_r8(filename,cdata,rdata,dname,whead,wdata) 1,1

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    real(r8)        ,intent(in) :: rdata    ! data to be written
    character(len=*),intent(in) :: dname    ! name of data
    logical,optional,intent(in) :: whead    ! write header
    logical,optional,intent(in) :: wdata    ! write data

    !EOP

    integer(in) :: rcode
    integer(in) :: iam
    type(var_desc_t) :: varid
    logical :: exists
    logical :: lwhead, lwdata
    character(*),parameter :: subName = '(seq_io_write_r8) '

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

    lwhead = .true.
    lwdata = .true.
    if (present(whead)) lwhead = whead
    if (present(wdata)) lwdata = wdata

    if (.not.lwhead .and. .not.lwdata) then
       ! should we write a warning?
       return
    endif
    call seq_comm_setptrs(CPLID,iam=iam)

    if (lwhead) then
       rcode = pio_def_var(cpl_io_file,trim(dname),PIO_DOUBLE,varid)
    endif

    if (lwdata) then
       rcode = pio_inq_varid(cpl_io_file,trim(dname),varid)
       rcode = pio_put_var(cpl_io_file,varid,rdata)
    endif


  end subroutine seq_io_write_r8

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_write_r81d - write AV to netcdf file
  !
  ! !DESCRIPTION:
  !    Write AV to netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_write_r81d(filename,cdata,rdata,dname,whead,wdata) 1,1

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    real(r8)        ,intent(in) :: rdata(:) ! data to be written
    character(len=*),intent(in) :: dname    ! name of data
    logical,optional,intent(in) :: whead    ! write header
    logical,optional,intent(in) :: wdata    ! write data

    !EOP

    integer(in) :: rcode
    integer(in) :: mpicom
    integer(in) :: iam
    integer(in) :: dimid(1)
    type(var_desc_t) :: varid
    integer(in) :: lnx
    logical :: exists
    logical :: lwhead, lwdata
    character(*),parameter :: subName = '(seq_io_write_r81d) '

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

    lwhead = .true.
    lwdata = .true.
    if (present(whead)) lwhead = whead
    if (present(wdata)) lwdata = wdata

    if (.not.lwhead .and. .not.lwdata) then
       ! should we write a warning?
       return
    endif
    call seq_comm_setptrs(CPLID,iam=iam)

    lnx = size(rdata)

    if (lwhead) then
       rcode = pio_def_dim(cpl_io_file,trim(dname)//'_nx',lnx,dimid(1))
       rcode = pio_def_var(cpl_io_file,trim(dname),PIO_DOUBLE,dimid,varid)
    else if (lwdata) then
       rcode = pio_inq_varid(cpl_io_file,trim(dname),varid)
       rcode = pio_put_var(cpl_io_file,varid,rdata)

       !      write(logunit,*) subname,' wrote AV ',trim(dname),lwhead,lwdata
    endif

  end subroutine seq_io_write_r81d

  !===============================================================================
!BOP ===========================================================================
!
! !IROUTINE: seq_io_write_time - write time variable to netcdf file
!
! !DESCRIPTION:
!    Write time variable to netcdf file
!
! !REVISION HISTORY:
!    2009-Feb-11 - M. Vertenstein - initial version
!
! !INTERFACE: ------------------------------------------------------------------


subroutine seq_io_write_time(filename,time_units,time_cal,time_val,nt,whead,wdata,tbnds) 1,1

! !INPUT/OUTPUT PARAMETERS:
   implicit none
   character(len=*),intent(in) :: filename      ! file
   character(len=*),intent(in) :: time_units    ! units of time
   character(len=*),intent(in) :: time_cal      ! calendar type
   real(r8)        ,intent(in) :: time_val      ! data to be written
   integer(in),optional,intent(in) :: nt
   logical,optional,intent(in) :: whead         ! write header
   logical,optional,intent(in) :: wdata         ! write data
   real(r8),optional,intent(in) :: tbnds(2)     ! time bounds

!EOP

   integer(in) :: rcode
   integer(in) :: iam
   integer(in) :: dimid(1)
   integer(in) :: dimid2(2)
   type(var_desc_t) :: varid
   integer(in) :: lnx
   logical :: exists
   logical :: lwhead, lwdata
   integer :: start(4),count(4)
   real(r8) :: time_val_1d(1)
   character(*),parameter :: subName = '(seq_io_write_time) '

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

   lwhead = .true.
   lwdata = .true.
   if (present(whead)) lwhead = whead
   if (present(wdata)) lwdata = wdata

   if (.not.lwhead .and. .not.lwdata) then
      ! should we write a warning?
      return
   endif

   call seq_comm_setptrs(CPLID,iam=iam)

   if (lwhead) then
      rcode = pio_def_dim(cpl_io_file,'time',PIO_UNLIMITED,dimid(1))
      rcode = pio_def_var(cpl_io_file,'time',PIO_DOUBLE,dimid,varid)
      rcode = pio_put_att(cpl_io_file,varid,'units',trim(time_units))
      if (trim(time_cal) == 'NO_LEAP') then
         rcode = pio_put_att(cpl_io_file,varid,'calendar','noleap')
      else if (trim(time_cal) == 'GREGORIAN') then
         rcode = pio_put_att(cpl_io_file,varid,'calendar','365_day')
      else
         rcode = pio_put_att(cpl_io_file,varid,'calendar','time_cal')
      end if
      if (present(tbnds)) then
         rcode = pio_put_att(cpl_io_file,varid,'bounds','time_bnds')
         dimid2(2)=dimid(1)
         rcode = pio_def_dim(cpl_io_file,'ntb',2,dimid2(1))
         rcode = pio_def_var(cpl_io_file,'time_bnds',PIO_DOUBLE,dimid2,varid)
      endif

   else if (lwdata) then
      start = 1
      count = 1
      if (present(nt)) then
         start(1) = nt
      endif
      time_val_1d(1) = time_val
      rcode = pio_inq_varid(cpl_io_file,'time',varid)
      rcode = pio_put_var(cpl_io_file,varid,start,count,time_val_1d)
      if (present(tbnds)) then
         rcode = pio_inq_varid(cpl_io_file,'time_bnds',varid)
         start = 1
         count = 1
         if (present(nt)) then
            start(2) = nt
         endif
         count(1) = 2
         rcode = pio_put_var(cpl_io_file,varid,start,count,tbnds)
      endif

      !      write(logunit,*) subname,' wrote time ',lwhead,lwdata
   endif

 end subroutine seq_io_write_time

!===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_read_av - read AV from netcdf file
  !
  ! !DESCRIPTION:
  !    Read AV from netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_read_av(filename,cdata,AV,dname,pre) 1,4

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    type(mct_aVect) ,intent(inout):: AV     ! data to be written
    character(len=*),intent(in) :: dname    ! name of data
    character(len=*),intent(in),optional :: pre      ! prefix name

    !EOP

    integer(in) :: rcode
    integer(in) :: iam
    integer(in) :: nf,ns,ng
    integer(in) :: i,j,k,n, ndims
    type(file_desc_t) :: pioid
    integer(in) :: dimid(2)
    type(var_desc_t) :: varid
    integer(in) :: lnx,lny
    type(mct_string) :: mstring     ! mct char type
    character(CL)    :: itemc       ! string converted to char
    logical :: exists
    type(mct_gsMap),pointer :: gsmap
    character(*),parameter :: subName = '(seq_io_read_av) '
    type(io_desc_t) :: iodesc
    integer(in), pointer :: dof(:)
    character(CL)  :: lversion
    character(CL)  :: name1
    character(CL)  :: lpre
    !-------------------------------------------------------------------------------
    !
    !-------------------------------------------------------------------------------

    lversion = trim(version0)

    lpre = trim(dname)
    if (present(pre)) then
       lpre = trim(pre)
    endif

    call seq_cdata_setptrs(cdata,gsmap=gsmap)
    call seq_comm_setptrs(CPLID,iam=iam)
    call mct_gsmap_OrderedPoints(gsmap, iam, Dof)

    ns = mct_aVect_lsize(AV)
    nf = mct_aVect_nRattr(AV)

    inquire(file=trim(filename),exist=exists)
    if (exists) then
       rcode = pio_openfile(cpl_io_subsystem, pioid, cpl_io_type, trim(filename),pio_nowrite)
       if(iam==0) write(logunit,*) subname,' open file ',trim(filename)
       call pio_seterrorhandling(pioid,PIO_BCAST_ERROR)
       rcode = pio_get_att(pioid,pio_global,"file_version",lversion)
       call pio_seterrorhandling(pioid,PIO_INTERNAL_ERROR)
    else
       if(iam==0) write(logunit,*) subname,' ERROR: file invalid ',trim(filename),' ',trim(dname)
       call shr_sys_abort()
    endif

    do k = 1,nf
       call mct_aVect_getRList(mstring,k,AV)
       itemc = mct_string_toChar(mstring)
       call mct_string_clean(mstring)
       if (trim(lversion) == trim(version)) then
          name1 = trim(lpre)//'_'//trim(itemc)
       else
          name1 = trim(prefix)//trim(dname)//'_'//trim(itemc)
       endif
       call pio_seterrorhandling(pioid, PIO_BCAST_ERROR)
       rcode = pio_inq_varid(pioid,trim(name1),varid)
       if (rcode == pio_noerr) then
          if (k==1) then
             rcode = pio_inq_varndims(pioid, varid, ndims)
             rcode = pio_inq_vardimid(pioid, varid, dimid(1:ndims))
             rcode = pio_inq_dimlen(pioid, dimid(1), lnx)
             if (ndims==2) then
                rcode = pio_inq_dimlen(pioid, dimid(2), lny)
             else
                lny = 1
             end if
             ng = lnx * lny
             if (ng /= mct_gsmap_gsize(gsmap)) then
                if (iam==0) write(logunit,*) subname,' ERROR: dimensions do not match',&
                     lnx,lny,mct_gsmap_gsize(gsmap)
                call shr_sys_abort()
             end if
             call pio_initdecomp(cpl_io_subsystem, pio_double, (/lnx,lny/), dof, iodesc)
             deallocate(dof)
          end if
          call pio_read_darray(pioid,varid,iodesc, av%rattr(k,:), rcode)
       else
          write(logunit,*)'seq_io_readav warning: field ',trim(itemc),' is not on restart file'
          write(logunit,*)'for backwards compatibility will set it to 0'
          av%rattr(k,:) = 0.0_r8
       end if
       call pio_seterrorhandling(pioid,PIO_INTERNAL_ERROR)
          
       !--- zero out fill value, this is somewhat arbitrary
       do n = 1,ns
          if (AV%rAttr(k,n) == fillvalue) then
              AV%rAttr(k,n) = 0.0_r8
          endif
       enddo
    enddo

    call pio_freedecomp(pioid, iodesc)
    call pio_closefile(pioid)

  end subroutine seq_io_read_av

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_read_int - read AV from netcdf file
  !
  ! !DESCRIPTION:
  !    Read AV from netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_read_int(filename,cdata,idata,dname) 1,1

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    integer         ,intent(inout):: idata  ! integer data
    character(len=*),intent(in) :: dname    ! name of data

    !EOP

    integer :: i1d(1)
    character(*),parameter :: subName = '(seq_io_read_int) '

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

    call seq_io_read_int1d(filename,cdata,i1d,dname)
    idata = i1d(1)

  end subroutine seq_io_read_int

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_read_int1d - read AV from netcdf file
  !
  ! !DESCRIPTION:
  !    Read AV from netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_read_int1d(filename,cdata,idata,dname) 2,2

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    integer(in)     ,intent(inout):: idata(:)  ! integer data
    character(len=*),intent(in) :: dname    ! name of data

    !EOP

    integer(in) :: rcode
    integer(in) :: iam
    type(file_desc_t) :: pioid 
    type(var_desc_t) :: varid
    logical :: exists
    character(CL)  :: lversion
    character(CL)  :: name1
    character(*),parameter :: subName = '(seq_io_read_int1d) '

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

    call seq_comm_setptrs(CPLID,iam=iam)

    lversion=trim(version0)

    inquire(file=trim(filename),exist=exists)
    if (exists) then
       rcode = pio_openfile(cpl_io_subsystem, pioid, cpl_io_type, trim(filename),pio_nowrite)
       !         write(logunit,*) subname,' open file ',trim(filename)
       call pio_seterrorhandling(pioid,PIO_BCAST_ERROR)
       rcode = pio_get_att(pioid,pio_global,"file_version",lversion)
       call pio_seterrorhandling(pioid,PIO_INTERNAL_ERROR)
    else
       if(iam==0) write(logunit,*) subname,' ERROR: file invalid ',trim(filename),' ',trim(dname)
       call shr_sys_abort()
    endif

    if (trim(lversion) == trim(version)) then
       name1 = trim(dname)
    else
       name1 = trim(prefix)//trim(dname)
    endif
    rcode = pio_inq_varid(pioid,trim(name1),varid)
    rcode = pio_get_var(pioid,varid,idata)

    call pio_closefile(pioid)

    !      write(logunit,*) subname,' read int ',trim(dname)


  end subroutine seq_io_read_int1d

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_read_r8 - read AV from netcdf file
  !
  ! !DESCRIPTION:
  !    Read AV from netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_read_r8(filename,cdata,rdata,dname) 1,1

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    real(r8)        ,intent(inout):: rdata  ! integer data
    character(len=*),intent(in) :: dname    ! name of data

    !EOP

    real(r8) :: r1d(1)
    character(*),parameter :: subName = '(seq_io_read_r8) '

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

    call seq_io_read_r81d(filename,cdata,r1d,dname)
    rdata = r1d(1)

  end subroutine seq_io_read_r8

  !===============================================================================
  !BOP ===========================================================================
  !
  ! !IROUTINE: seq_io_read_r81d - read AV from netcdf file
  !
  ! !DESCRIPTION:
  !    Read AV from netcdf file
  !
  ! !REVISION HISTORY:
  !    2007-Oct-26 - T. Craig - initial version
  !
  ! !INTERFACE: ------------------------------------------------------------------


  subroutine seq_io_read_r81d(filename,cdata,rdata,dname) 2,2

    ! !INPUT/OUTPUT PARAMETERS:
    implicit none
    character(len=*),intent(in) :: filename ! file
    type(seq_cdata) ,intent(in) :: cdata    ! cdata associated with AV
    real(r8)        ,intent(inout):: rdata(:)  ! integer data
    character(len=*),intent(in) :: dname    ! name of data

    !EOP

    integer(in) :: rcode
    integer(in) :: mpicom
    integer(in) :: iam
    type(file_desc_T) :: pioid 
    type(var_desc_t) :: varid
    logical :: exists
    character(CL)  :: lversion
    character(CL)  :: name1
    character(*),parameter :: subName = '(seq_io_read_r81d) '

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

    call seq_comm_setptrs(CPLID,iam=iam)

    lversion=trim(version0)

    inquire(file=trim(filename),exist=exists)
    if (exists) then
       rcode = pio_openfile(cpl_io_subsystem, pioid, cpl_io_type, trim(filename),pio_nowrite)
       !         write(logunit,*) subname,' open file ',trim(filename)
       call pio_seterrorhandling(pioid,PIO_BCAST_ERROR)
       rcode = pio_get_att(pioid,pio_global,"file_version",lversion)
       call pio_seterrorhandling(pioid,PIO_INTERNAL_ERROR)
    else
       if(iam==0) write(logunit,*) subname,' ERROR: file invalid ',trim(filename),' ',trim(dname)
       call shr_sys_abort()
    endif

    if (trim(lversion) == trim(version)) then
       name1 = trim(dname)
    else
       name1 = trim(prefix)//trim(dname)
    endif
    rcode = pio_inq_varid(pioid,trim(name1),varid)
    rcode = pio_get_var(pioid,varid,rdata)

    call pio_closefile(pioid)


    !      write(logunit,*) subname,' read int ',trim(dname)


  end subroutine seq_io_read_r81d

!===============================================================================
end module seq_io_mod