module tracer_data 27,8
!----------------------------------------------------------------------- 
! module used to read (and interpolate) offline tracer data (sources and
! mixing ratios)
! Created by: Francis Vitt -- 2 May 2006
! Modified by : Jim Edwards -- 10 March 2009
!----------------------------------------------------------------------- 

  use shr_kind_mod, only : r8 => shr_kind_r8,r4 => shr_kind_r4, shr_kind_cl, SHR_KIND_CS
  use time_manager, only : get_curr_date, get_step_size, get_calendar, get_curr_calday
  use spmd_utils,   only : masterproc
  use ppgrid,       only : pcols, pver, pverp, begchunk, endchunk
  use abortutils,   only : endrun
  use cam_logfile,  only : iulog
  use phys_buffer,  only : pbuf, pbuf_get_fld_idx
  use time_manager, only : set_time_float_from_date, set_date_from_time_float
  use pio,          only : file_desc_t, var_desc_t, &
                           pio_seterrorhandling, pio_internal_error, pio_bcast_error, &
                           pio_setdebuglevel, &
                           pio_char, pio_noerr, &
                           pio_inq_dimid, pio_inq_varid, &
                           pio_def_dim, pio_def_var, &
                           pio_put_att, pio_put_var, &
                           pio_get_var, pio_get_att, pio_nowrite, pio_inq_dimlen, &
                           pio_inq_vardimid, pio_inq_dimlen, pio_closefile

  implicit none

  private  ! all unless made public
  save 

  public :: trfld, input3d, input2d, trfile
  public :: trcdata_init
  public :: advance_trcdata
  public :: get_fld_data
  public :: get_fld_ndx
  public :: write_trc_restart
  public :: read_trc_restart
  public :: init_trc_restart


  ! !PUBLIC MEMBERS

  type input3d
     real(r8), dimension(:,:,:), pointer :: data
  endtype input3d

  type input2d
     real(r8), dimension(:,:), pointer :: data
  endtype input2d

  type trfld
     real(r8), dimension(:,:,:), pointer :: data
     type(input3d), dimension(4) :: input
     character(len=32) :: srcnam
     character(len=32) :: fldnam
     character(len=32) :: units
     type(var_desc_t) :: var_id
     integer :: chnk_offset
     integer :: coords(4) ! LATDIM | LONDIM | LEVDIM | TIMDIM
     integer :: order(4) ! LATDIM | LONDIM | LEVDIM | TIMDIM
  endtype trfld

  type trfile
     type(input2d), dimension(4) :: ps_in
     character(len=shr_kind_cl) :: pathname = ' '
     character(len=shr_kind_cl) :: curr_filename = ' '
     character(len=shr_kind_cl) :: next_filename = ' '
     type(file_desc_t) :: curr_fileid
     type(file_desc_t) :: next_fileid

     type(var_desc_t), pointer :: currfnameid    ! pio restart file var id 
     type(var_desc_t), pointer :: nextfnameid    ! pio restart file var id

     character(len=shr_kind_cl) :: filenames_list = ''
     real(r8) :: datatimem = -1.e36_r8     ! time of prv. values read in
     real(r8) :: datatimep = -1.e36_r8     ! time of nxt. values read in
     real(r8) :: datatimes(4)
     integer :: interp_recs
     real(r8), pointer, dimension(:) :: curr_data_times
     real(r8), pointer, dimension(:) :: next_data_times
     logical :: remove_trc_file = .false.  ! delete file when finished with it
     real(r8) :: offset_time
     integer :: cyc_ndx_beg
     integer :: cyc_ndx_end
     integer :: cyc_yr = 0
     real(r8) :: one_yr = 0
     real(r8) :: curr_mod_time ! model time - calendar day
     real(r8) :: next_mod_time ! model time - calendar day - next time step
     integer :: nlon
     integer :: nlat
     integer :: nlev
     integer :: nilev
     integer :: ps_coords(3) ! LATDIM | LONDIM | TIMDIM
     integer :: ps_order(3) ! LATDIM | LONDIM | TIMDIM
     real(r8), pointer, dimension(:) :: lons
     real(r8), pointer, dimension(:) :: lats
     real(r8), pointer, dimension(:) :: levs 
     real(r8), pointer, dimension(:) :: ilevs 
     real(r8), pointer, dimension(:) :: hyam 
     real(r8), pointer, dimension(:) :: hybm 
     real(r8), pointer, dimension(:,:) :: ps 
     real(r8)                        :: p0
     type(var_desc_t) :: ps_id
     logical :: has_ps = .false.
     logical :: in_pbuf = .false.
     logical :: zonal_ave = .false.
     logical :: surf_data = .false.
     logical :: alt_data = .false.     
     logical :: cyclical = .false.
     logical :: fill_in_months = .false.
     logical :: fixed = .false.
     logical :: initialized = .false.
     logical :: top_bndry = .false.
  endtype trfile

  integer, public, parameter :: MAXTRCRS = 100

  integer, parameter :: LONDIM = 1
  integer, parameter :: LATDIM = 2
  integer, parameter :: LEVDIM = 3
  integer, parameter :: TIMDIM = 4

  integer, parameter :: PS_TIMDIM = 3

  integer, parameter :: ZA_LATDIM = 1
  integer, parameter :: ZA_LEVDIM = 2
  integer, parameter :: ZA_TIMDIM = 3

  integer, parameter :: nm=1    ! array index for previous (minus) data
  integer, parameter :: np=2    ! array indes for next (plus) data
  character(len=SHR_KIND_CS) :: calendar

contains

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

  subroutine trcdata_init( specifier, filename, filelist, datapath, flds, file, & 5,36
                           rmv_file, data_ymd, data_tod, data_type )

    use mo_constants,    only : d2r
    use cam_control_mod, only : nsrest
    use commap,          only : clat, clon
    use dyn_grid,        only : get_dyn_grid_parm
    use string_utils,    only : to_upper

    implicit none

    character(len=*),    intent(in)    :: specifier(:)
    character(len=*),    intent(in)    :: filename
    character(len=*),    intent(in)    :: filelist
    character(len=*),    intent(in)    :: datapath
    type(trfld), dimension(:), pointer :: flds
    type(trfile),        intent(inout) :: file
    logical,             intent(in)    :: rmv_file
    integer,             intent(in)    :: data_ymd
    integer,             intent(in)    :: data_tod
    character(len=*),    intent(in)    :: data_type

    integer :: f, mxnflds, astat
    integer :: str_yr, str_mon, str_day
    integer :: lon_dimid, lat_dimid, lev_dimid, tim_dimid
    integer :: dimids(4), did
    type(var_desc_t) :: varid
    integer :: idx
    integer :: plon, plat, ierr
    real(r8) :: start_time, time1, time2

    calendar = get_calendar()

    call specify_fields( specifier, flds )

    file%datatimep=-1.e36_r8
    file%datatimem=-1.e36_r8

    mxnflds = 0 
    if (associated(flds)) mxnflds = size( flds )

    if (mxnflds < 1) return
    
    file%remove_trc_file = rmv_file
    file%pathname = trim(datapath)
    file%filenames_list = trim(filelist)

    file%fill_in_months = .false.
    file%cyclical = .false.  

! does not work when compiled with pathf90
!    select case ( to_upper(data_type) )
    select case ( data_type )
    case( 'FIXED' )
       file%fixed = .true.
    case( 'INTERP_MISSING_MONTHS' )
       file%fill_in_months = .true.
    case( 'CYCLICAL' )
       file%cyclical = .true.
       file%cyc_yr = data_ymd/10000
    case( 'SERIAL' )
    case default 
       write(iulog,*) 'trcdata_init: invalid data type: '//trim(data_type)//' file: '//trim(filename)
       write(iulog,*) 'trcdata_init: valid data types: SERIAL | CYCLICAL | FIXED | INTERP_MISSING_MONTHS '
       call endrun('trcdata_init: invalid data type: '//trim(data_type)//' file: '//trim(filename))
    endselect

    if (masterproc) then
       write(iulog,*) 'trcdata_init: data type: '//trim(data_type)//' file: '//trim(filename)
    endif

    if ( len_trim(file%curr_filename)<1 .or. file%fixed ) then ! initial run
       file%curr_filename = trim(filename)

       call get_model_time(file)

       if ( data_ymd > 0 .and. .not. file%cyclical ) then
          str_yr = data_ymd/10000
          str_mon = (data_ymd - str_yr*10000)/100
          str_day = data_ymd - str_yr*10000 - str_mon*100
          call set_time_float_from_date( start_time, str_yr, str_mon, str_day, data_tod )
          file%offset_time = start_time - file%curr_mod_time
       else
          file%offset_time = 0
       endif
    endif

    call set_time_float_from_date( time2, 2, 1, 1, 0 )
    call set_time_float_from_date( time1, 1, 1, 1, 0 )
    file%one_yr = time2-time1

    if ( file%cyclical ) then
       file%cyc_ndx_beg = -1
       file%cyc_ndx_end = -1
       if ( file%cyc_yr /= 0 ) then
          call set_time_float_from_date( time1, file%cyc_yr  , 1, 1, 0 )
          call set_time_float_from_date( time2, file%cyc_yr+1, 1, 1, 0 )
          file%one_yr = time2-time1
       endif

       call open_trc_datafile( file%curr_filename, file%pathname, file%curr_fileid, file%curr_data_times, &
            cyc_ndx_beg=file%cyc_ndx_beg, cyc_ndx_end=file%cyc_ndx_end, cyc_yr=file%cyc_yr )
    else
       call open_trc_datafile( file%curr_filename, file%pathname, file%curr_fileid, file%curr_data_times )
       file%curr_data_times = file%curr_data_times - file%offset_time
    endif

    call pio_seterrorhandling(File%curr_fileid, PIO_BCAST_ERROR)
    ierr = pio_inq_dimid( file%curr_fileid, 'lon', idx )
    call pio_seterrorhandling(File%curr_fileid, PIO_INTERNAL_ERROR)

    file%zonal_ave = (ierr/=PIO_NOERR)

    plon = get_dyn_grid_parm('plon')
    plat = get_dyn_grid_parm('plat')

    if ( .not. file%zonal_ave ) then

       call get_dimension( file%curr_fileid, 'lon', file%nlon, dimid=lon_dimid, data=file%lons )

       file%lons =  file%lons * d2r

    endif
    
    ierr = pio_inq_dimid( file%curr_fileid, 'time', tim_dimid )

    call get_dimension( file%curr_fileid, 'lat', file%nlat, dimid=lat_dimid, data=file%lats )
    file%lats =  file%lats * d2r

    allocate( file%ps(file%nlon,file%nlat), stat=astat )
    if( astat /= 0 ) then
       write(iulog,*) 'trcdata_init: file%ps allocation error = ',astat
       call endrun('trcdata_init: failed to allocate x array')
    end if

    call pio_seterrorhandling(File%curr_fileid, PIO_BCAST_ERROR)
    ierr = pio_inq_varid( file%curr_fileid, 'PS', file%ps_id )
    file%has_ps = (ierr==PIO_NOERR)
    ierr = pio_inq_dimid( file%curr_fileid, 'altitude', idx )
    file%alt_data = (ierr==PIO_NOERR)
    if(file%alt_data) then
       file%surf_data=.false.
    else
       ierr = pio_inq_dimid( file%curr_fileid, 'lev', idx )
       file%surf_data = (ierr/=PIO_NOERR)
    end if
    call pio_seterrorhandling(File%curr_fileid, PIO_INTERNAL_ERROR)

    if ( file%has_ps) then
       ierr = pio_inq_vardimid (file%curr_fileid, file%ps_id, dimids(1:3))
       do did = 1,3
          if      ( dimids(did) == lon_dimid ) then
             file%ps_coords(LONDIM) = did
             file%ps_order(did) = LONDIM
          else if ( dimids(did) == lat_dimid ) then
             file%ps_coords(LATDIM) = did
             file%ps_order(did) = LATDIM
          else if ( dimids(did) == tim_dimid ) then
             file%ps_coords(PS_TIMDIM) = did
             file%ps_order(did) = PS_TIMDIM
          endif
       enddo
    endif

    if (masterproc) then 
       write(iulog,*) 'trcdata_init: file%has_ps = ' , file%has_ps 
    endif ! masterproc

    if (file%alt_data) then
       call get_dimension( file%curr_fileid, 'altitude_int', file%nilev,  data=file%ilevs  )
       call get_dimension( file%curr_fileid, 'altitude',     file%nlev, dimid=lev_dimid, data=file%levs  )
    else
       if (.not.file%surf_data) then
          call get_dimension( file%curr_fileid, 'lev', file%nlev, dimid=lev_dimid, data=file%levs  )
          file%levs =  file%levs*100._r8 ! mbar->pascals
       else
          file%nlev = 1
          lev_dimid = -1
       endif
    endif

    if (file%has_ps) then

       allocate( file%hyam(file%nlev),  file%hybm(file%nlev), stat=astat )
       if( astat /= 0 ) then
          write(iulog,*) 'trcdata_init: file%hyam,file%hybm allocation error = ',astat
          call endrun('trcdata_init: failed to allocate file%hyam and file%hybm arrays')
       end if
       call pio_seterrorhandling(File%curr_fileid, PIO_BCAST_ERROR)
       ierr = pio_inq_varid( file%curr_fileid, 'P0', varid)
       call pio_seterrorhandling(File%curr_fileid, PIO_INTERNAL_ERROR)

       if ( ierr == PIO_NOERR ) then
          ierr = pio_get_var( file%curr_fileid, varid, file%p0 )
       else
          file%p0 = 100000._r8
       endif
       ierr = pio_inq_varid( file%curr_fileid, 'hyam', varid )
       ierr = pio_get_var( file%curr_fileid, varid, file%hyam )
       ierr = pio_inq_varid( file%curr_fileid, 'hybm', varid )
       ierr = pio_get_var( file%curr_fileid, varid, file%hybm )
       
       allocate( file         %ps  (pcols,begchunk:endchunk), stat=astat   )
       if( astat/= 0 ) then
          write(iulog,*) 'trcdata_init: failed to allocate file%ps array; error = ',astat
          call endrun
       end if
       allocate( file%ps_in(1)%data(pcols,begchunk:endchunk), stat=astat   )
       if( astat/= 0 ) then
          write(iulog,*) 'trcdata_init: failed to allocate file%ps_in(1)%data array; error = ',astat
          call endrun
       end if
       allocate( file%ps_in(2)%data(pcols,begchunk:endchunk), stat=astat   )
       if( astat/= 0 ) then
          write(iulog,*) 'trcdata_init: failed to allocate file%ps_in(2)%data array; error = ',astat
          call endrun
       end if
       if( file%fill_in_months ) then
          allocate( file%ps_in(3)%data(pcols,begchunk:endchunk), stat=astat   )
          if( astat/= 0 ) then
             write(*,*) 'trcdata_init: failed to allocate file%ps_in(3)%data array; error = ',astat
             call endrun
          end if
          allocate( file%ps_in(4)%data(pcols,begchunk:endchunk), stat=astat   )
          if( astat/= 0 ) then
             write(*,*) 'trcdata_init: failed to allocate file%ps_in(4)%data array; error = ',astat
             call endrun
          end if
       end if
    endif
     

    flds_loop: do f = 1,mxnflds

       ! allocate memory only if not already in pbuf

       if ( .not. file%in_pbuf ) then
          if ( file%surf_data .or. file%top_bndry ) then
             allocate( flds(f)         %data(pcols,1,begchunk:endchunk), stat=astat   )
          else
             allocate( flds(f)         %data(pcols,pver,begchunk:endchunk), stat=astat   )
          endif
          if( astat/= 0 ) then
             write(iulog,*) 'trcdata_init: failed to allocate flds(f)%data array; error = ',astat
             call endrun
          end if
          flds(f)%chnk_offset = 0
       else
          idx = pbuf_get_fld_idx(flds(f)%fldnam, failcode=-1 )
          flds(f)%data => pbuf(idx)%fld_ptr(1,:,:,:,1)
          flds(f)%chnk_offset = -begchunk+1
       endif
       allocate( flds(f)%input(1)%data(pcols,file%nlev,begchunk:endchunk), stat=astat   )
       if( astat/= 0 ) then
          write(iulog,*) 'trcdata_init: failed to allocate flds(f)%input(1)%data array; error = ',astat
          call endrun
       end if
       allocate( flds(f)%input(2)%data(pcols,file%nlev,begchunk:endchunk), stat=astat   )
       if( astat/= 0 ) then
          write(iulog,*) 'trcdata_init: failed to allocate flds(f)%input(2)%data array; error = ',astat
          call endrun
       end if
       
       if( file%fill_in_months ) then
          allocate( flds(f)%input(3)%data(pcols,file%nlev,begchunk:endchunk), stat=astat   )
          if( astat/= 0 ) then
             write(*,*) 'trcdata_init: failed to allocate flds(f)%input(3)%data array; error = ',astat
             call endrun
          end if
          allocate( flds(f)%input(4)%data(pcols,file%nlev,begchunk:endchunk), stat=astat   )
          if( astat/= 0 ) then
             write(*,*) 'trcdata_init: failed to allocate flds(f)%input(4)%data array; error = ',astat
             call endrun
          end if
       endif

       ierr = pio_inq_varid( file%curr_fileid, flds(f)%srcnam, flds(f)%var_id )
       if ( file%zonal_ave ) then
          ierr = pio_inq_vardimid (file%curr_fileid, flds(f)%var_id, dimids(1:3))
          do did = 1,3
             if      ( dimids(did) == lat_dimid ) then
                flds(f)%coords(ZA_LATDIM) = did
                flds(f)%order(did) = ZA_LATDIM
             else if ( dimids(did) == lev_dimid ) then
                flds(f)%coords(ZA_LEVDIM) = did
                flds(f)%order(did) = ZA_LEVDIM
             else if ( dimids(did) == tim_dimid ) then
                flds(f)%coords(ZA_TIMDIM) = did
                flds(f)%order(did) = ZA_TIMDIM
             endif
          enddo
       else if ( file%surf_data ) then
          ierr = pio_inq_vardimid (file%curr_fileid, flds(f)%var_id, dimids(1:3))
          do did = 1,3
             if      ( dimids(did) == lon_dimid ) then
                flds(f)%coords(LONDIM) = did
                flds(f)%order(did) = LONDIM
             else if ( dimids(did) == lat_dimid ) then
                flds(f)%coords(LATDIM) = did
                flds(f)%order(did) = LATDIM
             else if ( dimids(did) == tim_dimid ) then
                flds(f)%coords(PS_TIMDIM) = did
                flds(f)%order(did) = PS_TIMDIM
             endif
          enddo
       else
          ierr = pio_inq_vardimid (file%curr_fileid, flds(f)%var_id, dimids)
          do did = 1,4
             if      ( dimids(did) == lon_dimid ) then
                flds(f)%coords(LONDIM) = did
                flds(f)%order(did) = LONDIM
             else if ( dimids(did) == lat_dimid ) then
                flds(f)%coords(LATDIM) = did
                flds(f)%order(did) = LATDIM
             else if ( dimids(did) == lev_dimid ) then
                flds(f)%coords(LEVDIM) = did
                flds(f)%order(did) = LEVDIM
             else if ( dimids(did) == tim_dimid ) then
                flds(f)%coords(TIMDIM) = did
                flds(f)%order(did) = TIMDIM
             endif
          enddo
       endif
       flds(f)%units = ''
       ierr = pio_get_att( file%curr_fileid, flds(f)%var_id, 'units', flds(f)%units)

    enddo flds_loop

  endsubroutine trcdata_init

!-----------------------------------------------------------------------
! Reads more data if needed and interpolates data to current model time 
!-----------------------------------------------------------------------

  subroutine advance_trcdata( flds, file, state ) 5,4
    use physics_types,only : physics_state

    implicit none

    type(trfile), intent(inout) :: file
    type(trfld), intent(inout) :: flds(:)
    type(physics_state), intent(in):: state(begchunk:endchunk)                 

    real(r8) :: data_time

    if ( .not.( file%fixed .and. file%initialized ) ) then

       call get_model_time(file)

       data_time = file%datatimep

       if ( file%cyclical ) then
          ! wrap around
          if ( (file%datatimep<file%datatimem) .and. (file%curr_mod_time>file%datatimem) ) then
             data_time = data_time + file%one_yr 
          endif
       endif

       if ( file%curr_mod_time > data_time ) then
          call read_next_trcdata( flds, file )
       end if

    endif
    
    ! need to inperpolate the data, regardless !
    ! each mpi task needs to interpolate
    call interpolate_trcdata( flds, file, state )

    file%initialized = .true.

  end subroutine advance_trcdata

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

  subroutine get_fld_data( flds, field_name, data, ncol, lchnk )

    implicit none

    type(trfld), intent(inout) :: flds(:)
    character(len=*), intent(in) :: field_name
    real(r8), intent(out) :: data(:,:)
    integer, intent(in) :: lchnk
    integer, intent(in) :: ncol
    
    integer :: f, nflds

    data(:,:) = 0._r8
    nflds = size(flds)

    do f = 1, nflds
       if ( trim(flds(f)%fldnam) == trim(field_name) ) then
          data(:ncol,:) = flds(f)%data(:ncol,:,lchnk+flds(f)%chnk_offset )
       endif
    enddo

 end subroutine get_fld_data

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

  subroutine get_fld_ndx( flds, field_name, idx  )

    implicit none

    type(trfld), intent(in) :: flds(:)
    character(len=*), intent(in) :: field_name
    integer, intent(out) :: idx    
    integer :: f, nflds

    idx = -1
    nflds = size(flds)

    do f = 1, nflds
       if ( trim(flds(f)%fldnam) == trim(field_name) ) then
          idx = f
          return
       endif
    enddo

  end subroutine get_fld_ndx

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

  subroutine get_model_time(file) 5,9
    implicit none
    type(trfile), intent(inout) :: file

    integer yr, mon, day, ncsec  ! components of a date

    call get_curr_date(yr, mon, day, ncsec)

    if ( file%cyclical ) yr = file%cyc_yr
    call set_time_float_from_date( file%curr_mod_time, yr, mon, day, ncsec )
    file%next_mod_time = file%curr_mod_time + get_step_size()/86400._r8

  end subroutine get_model_time

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

  subroutine check_files( file ) 2,15

    use shr_sys_mod, only: shr_sys_system
    use ioFileMod, only: getfil

    implicit none

    type(trfile), intent(inout) :: file

    !-----------------------------------------------------------------------
    ! 	... local variables
    !-----------------------------------------------------------------------
    character(len=shr_kind_cl) :: ctmp
    character(len=shr_kind_cl) :: loc_fname   
    integer            :: istat, astat

    if (file%next_mod_time > file%curr_data_times(size(file%curr_data_times))) then
       if ( .not. associated(file%next_data_times) ) then
          ! open next file if not already opened...
          file%next_filename = incr_filename( file%curr_filename, filenames_list=file%filenames_list, datapath=file%pathname )
          call open_trc_datafile( file%next_filename, file%pathname, file%next_fileid, file%next_data_times )
          file%next_data_times = file%next_data_times - file%offset_time
       endif
    endif
    
    if ( associated(file%next_data_times) ) then
       if (file%curr_mod_time >= file%next_data_times(1)) then

          ! close current file ...
          call pio_closefile( file%curr_fileid )
          ! remove if requested
          if( file%remove_trc_file ) then
             call getfil( file%curr_filename, loc_fname, 0 )
             write(iulog,*) 'check_files: removing file = ',trim(loc_fname) 
             ctmp = 'rm -f ' // trim(loc_fname) 
             write(iulog,*) 'check_files: fsystem issuing command - '
             write(iulog,*) trim(ctmp)
             call shr_sys_system( ctmp, istat )
          end if

          file%curr_filename = file%next_filename
          file%curr_fileid = file%next_fileid

          deallocate( file%curr_data_times, stat=astat )
          if( astat/= 0 ) then
             write(iulog,*) 'check_files: failed to deallocate file%curr_data_times array; error = ',astat
             call endrun
          end if
          allocate( file%curr_data_times( size( file%next_data_times ) ), stat=astat )
          if( astat/= 0 ) then
             write(iulog,*) 'check_files: failed to allocate file%curr_data_times array; error = ',astat
             call endrun
          end if
          file%curr_data_times(:) = file%next_data_times(:)

          file%next_filename = ''

          deallocate( file%next_data_times, stat=astat )
          if( astat/= 0 ) then
             write(iulog,*) 'check_files: failed to deallocate file%next_data_times array; error = ',astat
             call endrun
          end if
          nullify( file%next_data_times )

       endif
    endif

  end subroutine check_files

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

  function incr_filename( filename, filenames_list, datapath ) 2,20

    !-----------------------------------------------------------------------
    ! 	... Increment or decrement a date string withing a filename
    !           the filename date section is assumed to be of the form
    !           yyyy-dd-mm
    !-----------------------------------------------------------------------

    use string_utils, only : incstr
    use shr_file_mod, only : shr_file_getunit, shr_file_freeunit

    implicit none


    character(len=*),           intent(in) :: filename ! present dynamical dataset filename
    character(len=*), optional, intent(in) :: filenames_list 
    character(len=*), optional, intent(in) :: datapath
    character(len=shr_kind_cl) :: incr_filename      ! next filename in the sequence

    ! set new next_filename ...

    !-----------------------------------------------------------------------
    !	... local variables
    !-----------------------------------------------------------------------
    integer :: pos, pos1, istat
    character(len=shr_kind_cl) :: fn_new, line, filepath
    character(len=6)   :: seconds
    character(len=5)   :: num
    integer :: ios,unitnumber

    if (( .not. present(filenames_list)) .or.(len_trim(filenames_list) == 0)) then
       !-----------------------------------------------------------------------
       !	... ccm type filename
       !-----------------------------------------------------------------------
       pos = len_trim( filename )
       fn_new = filename(:pos)
       if ( masterproc ) write(iulog,*) 'incr_flnm: old filename = ',trim(fn_new)
       if( fn_new(pos-2:) == '.nc' ) then
          pos = pos - 3
       end if
       istat = incstr( fn_new(:pos), 1 )
       if( istat /= 0 ) then
          write(iulog,*) 'incr_flnm: incstr returned ', istat
          write(iulog,*) '           while trying to decrement ',trim( fn_new )
          call endrun
       end if

    else

       ! open filenames_list
       if ( masterproc ) write(iulog,*) 'incr_flnm: old filename = ',trim(filename)
       if ( masterproc ) write(iulog,*) 'incr_flnm: open filenames_list : ',trim(filenames_list)
       unitnumber = shr_file_getUnit()
       if ( present(datapath) ) then
         filepath = trim(datapath) //'/'// trim(filenames_list)
       else
         filepath = trim(datapath)
       endif

       open( unit=unitnumber, file=filepath, iostat=ios, status="OLD")
       if (ios /= 0) then
          call endrun('not able to open filenames_list file: '//trim(filepath))
       endif

       ! read file names
       read( unit=unitnumber, fmt='(A)', iostat=ios ) line 
       if (ios /= 0) then
          call endrun('not able to increment file name from filenames_list file: '//trim(filenames_list))
       endif
       do while( trim(line) /= trim(filename) )
          read( unit=unitnumber, fmt='(A)', iostat=ios ) line 
          if (ios /= 0) then
             call endrun('not able to increment file name from filenames_list file: '//trim(filenames_list))
          endif
       enddo

       read( unit=unitnumber, fmt='(A)', iostat=ios ) line 
       if (ios /= 0) then
          call endrun('not able to increment file name from filenames_list file: '//trim(filenames_list))
       endif
       fn_new = trim(line)

       close(unit=unitnumber)
       call shr_file_freeUnit(unitnumber)
    endif
    incr_filename = trim(fn_new)
    if ( masterproc ) write(iulog,*) 'incr_flnm: new filename = ',trim(incr_filename)

  end function incr_filename

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

  subroutine find_times( itms, fids, time, file, datatimem, datatimep, times_found ) 5,5

    implicit none

    type(trfile), intent(in) :: file
    real(r8), intent(out) :: datatimem, datatimep

    integer, intent(out) :: itms(2) ! record numbers that bracket time
    type(file_desc_t), intent(out) :: fids(2) ! ids of files that contains these recs

    real(r8), intent(in) :: time    ! time of interest
    logical, intent(inout)  :: times_found

    integer :: np1        ! current forward time index of dataset
    integer :: n,i      ! 
    integer :: curr_tsize, next_tsize, all_tsize
    integer :: astat
    integer :: cyc_tsize

    real(r8), allocatable, dimension(:):: all_data_times

    curr_tsize = size(file%curr_data_times)
    next_tsize = 0
    if ( associated(file%next_data_times)) next_tsize = size(file%next_data_times)

    all_tsize = curr_tsize + next_tsize

    allocate( all_data_times( all_tsize ), stat=astat )
    if( astat/= 0 ) then
       write(iulog,*) 'find_times: failed to allocate all_data_times array; error = ',astat
       call endrun
    end if

    all_data_times(:curr_tsize) = file%curr_data_times(:)
    if (next_tsize > 0) all_data_times(curr_tsize+1:all_tsize) = file%next_data_times(:)

    if ( .not. file%cyclical ) then
       if ( all( all_data_times(:) > time ) ) then
          write(iulog,*) 'FIND_TIMES: ALL data times are after ', time
          write(iulog,*) 'FIND_TIMES: data times: ',all_data_times(:)
          write(iulog,*) 'FIND_TIMES: time: ',time
          call endrun('find_times: all(all_data_times(:) > time) '// trim(file%curr_filename) )
       endif

       ! find bracketing times 
       find_times_loop : do n=1, all_tsize-1
          np1 = n + 1
          datatimem = all_data_times(n)   !+ file%offset_time
          datatimep = all_data_times(np1) !+ file%offset_time
          if ( (time .ge. datatimem) .and. (time .le. datatimep) ) then
             times_found = .true.
             exit find_times_loop
          endif
       enddo find_times_loop

    else

       cyc_tsize = file%cyc_ndx_end - file%cyc_ndx_beg + 1

       if ( cyc_tsize > 1 ) then

          call findplb(all_data_times(file%cyc_ndx_beg:file%cyc_ndx_end),cyc_tsize, time, n )

          if (n == cyc_tsize) then
             np1 = 1
          else
             np1 = n+1
          endif

          datatimem = all_data_times(n  +file%cyc_ndx_beg-1)   
          datatimep = all_data_times(np1+file%cyc_ndx_beg-1) 
          times_found = .true.

       endif
    endif

    if ( .not. times_found ) then
       if (masterproc) then
          write(iulog,*)'FIND_TIMES: Failed to find dates bracketing desired time =', time
          write(iulog,*)' datatimem = ',file%datatimem
          write(iulog,*)' datatimep = ',file%datatimep
          write(iulog,*)' all_data_times = ',all_data_times
          !call endrun()
          return
       endif
    endif

    deallocate( all_data_times, stat=astat )
    if( astat/= 0 ) then
       write(iulog,*) 'find_times: failed to deallocate all_data_times array; error = ',astat
       call endrun
    end if
  
    if ( .not. file%cyclical ) then
      itms(1) = n
      itms(2) = np1
    else
      itms(1) = n   +file%cyc_ndx_beg-1
      itms(2) = np1 +file%cyc_ndx_beg-1
    endif

    fids(:) = file%curr_fileid

    do i=1,2
       if ( itms(i) > curr_tsize ) then 
          itms(i) = itms(i) - curr_tsize 
          fids(i) = file%next_fileid
       endif
    enddo

  end subroutine find_times

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

  subroutine read_next_trcdata( flds, file ) 1,23
    implicit none

    type (trfile), intent(inout) :: file
    type (trfld),intent(inout) :: flds(:)

    integer :: recnos(4),i,f,nflds      ! 
    integer :: cnt4(4)            ! array of counts for each dimension
    integer :: strt4(4)           ! array of starting indices
    integer :: cnt3(3)            ! array of counts for each dimension
    integer :: strt3(3)           ! array of starting indices
    type(file_desc_t) :: fids(4)
    logical :: times_found 

    integer :: cur_yr, cur_mon, cur_day, cur_sec, yr1, yr2, mon, date, sec
    real(r8) :: series1_time, series2_time
    type(file_desc_t) :: fid1, fid2
   
    nflds = size(flds)
    times_found = .false.
    
    do while( .not. times_found )
       call find_times( recnos, fids, file%curr_mod_time, file,file%datatimem, file%datatimep, times_found )
       if ( .not. times_found ) then
          call check_files( file )
       endif
    enddo
          
    file%interp_recs = 2

    if ( file%fill_in_months ) then

       if( file%datatimep-file%datatimem > file%one_yr ) then

          call get_curr_date(cur_yr, cur_mon, cur_day, cur_sec)

          call set_date_from_time_float(file%datatimem, yr1, mon, date, sec )
          call set_date_from_time_float(file%datatimep, yr2, mon, date, sec )

          call set_time_float_from_date( series1_time, yr1, cur_mon, cur_day, cur_sec )
          call set_time_float_from_date( series2_time, yr2, cur_mon, cur_day, cur_sec )

          fid1 = fids(1)
          fid2 = fids(2)
          file%cyclical = .true.
          call set_cycle_indices( fid1, file%cyc_ndx_beg, file%cyc_ndx_end, yr1)
          call find_times( recnos(1:2), fids(1:2), series1_time, file, file%datatimes(1), file%datatimes(2), times_found )

          if ( .not. times_found ) then
              call endrun('read_next_trcdata: time not found for series1_time')
          endif
          call set_cycle_indices( fid2, file%cyc_ndx_beg, file%cyc_ndx_end, yr2)

          if ( fid1%fh /= fid2%fh ) then
            file%cyc_ndx_beg = file%cyc_ndx_beg + size(file%curr_data_times)
            file%cyc_ndx_end = file%cyc_ndx_end + size(file%curr_data_times)
          endif
          call find_times( recnos(3:4), fids(3:4), series2_time, file, file%datatimes(3), file%datatimes(4), times_found )
          if ( .not. times_found ) then
              call endrun('read_next_trcdata: time not found for series2_time')
          endif
          file%cyclical = .false.
          file%interp_recs = 4

          call set_date_from_time_float( file%datatimes(1), yr1, mon, date, sec )
          call set_time_float_from_date( file%datatimem, cur_yr,  mon, date, sec )
          if (file%datatimes(1) > file%datatimes(2) ) then ! wrap around
            if ( cur_mon == 1 ) then 
               call set_time_float_from_date( file%datatimem, cur_yr-1,  mon, date, sec )
            endif 
          endif

          call set_date_from_time_float( file%datatimes(2), yr1, mon, date, sec )
          call set_time_float_from_date( file%datatimep, cur_yr,  mon, date, sec )
          if (file%datatimes(1) > file%datatimes(2) ) then ! wrap around
            if ( cur_mon == 12 ) then
              call set_time_float_from_date( file%datatimep, cur_yr+1,  mon, date, sec )
            endif 
          endif

       endif

    endif

    !
    ! Set up hyperslab corners
    !
    strt4(:) = 1
    strt3(:) = 1

    do i=1,file%interp_recs

       do f = 1,nflds
          if ( file%zonal_ave ) then
             cnt3(flds(f)%coords(ZA_LATDIM)) = file%nlat
             cnt3(flds(f)%coords(ZA_LEVDIM)) = file%nlev
             cnt3(flds(f)%coords(ZA_TIMDIM)) = 1
             strt3(flds(f)%coords(ZA_TIMDIM)) = recnos(i)
             call read_za_trc( fids(i), flds(f)%var_id, flds(f)%input(i)%data, strt3, cnt3, file, &
                  (/ flds(f)%order(ZA_LATDIM),flds(f)%order(ZA_LEVDIM) /) )
          else if ( file%surf_data ) then
             cnt3( flds(f)%coords(LONDIM)) = file%nlon
             cnt3( flds(f)%coords(LATDIM)) = file%nlat
             cnt3( flds(f)%coords(PS_TIMDIM)) = 1
             strt3(flds(f)%coords(PS_TIMDIM)) = recnos(i)
             call read_2d_trc( fids(i), flds(f)%var_id, flds(f)%input(i)%data(:,1,:), strt3, cnt3, file, &
                 (/ flds(f)%order(LONDIM),flds(f)%order(LATDIM) /) )
          else
             cnt4(flds(f)%coords(LONDIM)) = file%nlon
             cnt4(flds(f)%coords(LATDIM)) = file%nlat
             cnt4(flds(f)%coords(LEVDIM)) = file%nlev
             cnt4(flds(f)%coords(TIMDIM)) = 1
             strt4(flds(f)%coords(TIMDIM)) = recnos(i)
             call read_3d_trc( fids(i), flds(f)%var_id, flds(f)%input(i)%data, strt4, cnt4, file, &
                  (/ flds(f)%order(LONDIM),flds(f)%order(LATDIM),flds(f)%order(LEVDIM) /))

          endif

       enddo

       if ( file%has_ps ) then
          cnt3(file%ps_coords(LONDIM)) = file%nlon
          cnt3(file%ps_coords(LATDIM)) = file%nlat
          cnt3(file%ps_coords(PS_TIMDIM)) = 1
          strt3(file%ps_coords(PS_TIMDIM)) = recnos(i)
          call read_2d_trc( fids(i), file%ps_id, file%ps_in(i)%data, strt3, cnt3, file, &
               (/ file%ps_order(LONDIM),file%ps_order(LATDIM) /) )
       endif

    enddo

  end subroutine read_next_trcdata

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



  subroutine read_2d_trc( fid, vid, loc_arr, strt, cnt, file, order ) 2,17
    use interpolate_data,  only : lininterp_init, lininterp, interp_type, lininterp_finish
    use phys_grid, only : pcols, begchunk, endchunk, get_ncols_p, get_rlat_all_p, get_rlon_all_p	
    use mo_constants, only : pi
    use dycore,            only: dycore_is		
    use polar_avg,         only: polar_average

    implicit none
    type(file_desc_t), intent(in) :: fid
    type(var_desc_t), intent(in) :: vid
    integer, intent(in) :: strt(:), cnt(:), order(2)
    real(r8),intent(out)  :: loc_arr(:,:)
    type (trfile), intent(in) :: file

    real(r8) :: to_lats(pcols), to_lons(pcols), wrk(pcols)
    real(r8), allocatable, target :: wrk2d(:,:)
    real(r8), pointer :: wrk2d_in(:,:)
    integer :: tsize, c, i, j, ierr, ncols
    real(r8), parameter :: zero=0_r8, twopi=2_r8*pi
    type(interp_type) :: lon_wgts, lat_wgts    

     nullify(wrk2d_in)
     allocate( wrk2d(cnt(1),cnt(2)), stat=ierr )
     if( ierr /= 0 ) then
        write(iulog,*) 'read_2d_trc: wrk2d allocation error = ',ierr
        call endrun
     end if

     if(order(1)/=1 .or. order(2)/=2 .or. cnt(1)/=file%nlon .or. cnt(2)/=file%nlat) then
        allocate( wrk2d_in(file%nlon, file%nlat), stat=ierr )
        if( ierr /= 0 ) then
           write(iulog,*) 'read_2d_trc: wrk2d_in allocation error = ',ierr
           call endrun
        end if
     end if


    ierr = pio_get_var( fid, vid, strt, cnt, wrk2d )
    if(associated(wrk2d_in)) then
       wrk2d_in = reshape( wrk2d(:,:),(/file%nlon,file%nlat/), order=order )
       deallocate(wrk2d)
    else
       wrk2d_in => wrk2d
    end if

    j=1
    do c=begchunk,endchunk
       ncols = get_ncols_p(c)
       call get_rlat_all_p(c, pcols, to_lats)
       call get_rlon_all_p(c, pcols, to_lons)

       call lininterp_init(file%lons, file%nlon, to_lons, ncols, 2, lon_wgts, zero, twopi)
       call lininterp_init(file%lats, file%nlat, to_lats, ncols, 1, lat_wgts)

       call lininterp(wrk2d_in, file%nlon, file%nlat, loc_arr(1:ncols,c-begchunk+1), ncols, lon_wgts, lat_wgts)    
       
       call lininterp_finish(lon_wgts)
       call lininterp_finish(lat_wgts)
    end do

    if(allocated(wrk2d)) then
       deallocate(wrk2d)
    else
       deallocate(wrk2d_in)
    end if
    if(dycore_is('LR')) call polar_average(loc_arr)
  end subroutine read_2d_trc

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


  subroutine read_za_trc( fid, vid, loc_arr, strt, cnt, file, order ) 1,12
    use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish
    use phys_grid,        only : pcols, begchunk, endchunk, get_ncols_p, get_rlat_all_p, get_rlon_all_p	
    use mo_constants,     only : pi
    use dycore,           only : dycore_is		
    use polar_avg,        only : polar_average

    implicit none
    type(file_desc_t), intent(in) :: fid
    type(var_desc_t), intent(in) :: vid
    integer, intent(in) :: strt(:), cnt(:), order(2)
    real(r8),intent(out)  :: loc_arr(:,:,:)
    type (trfile), intent(in) :: file
    type(interp_type) :: lat_wgts
    real(r8) :: to_lats(pcols), to_lons(pcols), wrk(pcols)
    real(r8), allocatable, target :: wrk2d(:,:)
    real(r8), pointer :: wrk2d_in(:,:)
    integer :: tsize, c, i, j, k, ierr, ncols

     nullify(wrk2d_in)
     allocate( wrk2d(cnt(1),cnt(2)), stat=ierr )
     if( ierr /= 0 ) then
        write(iulog,*) 'read_2d_trc: wrk2d allocation error = ',ierr
        call endrun
     end if

     if(order(1)/=1 .or. order(2)/=2 .or. cnt(1)/=file%nlat .or. cnt(2)/=file%nlev) then
        allocate( wrk2d_in(file%nlat, file%nlev), stat=ierr )
        if( ierr /= 0 ) then
           write(iulog,*) 'read_2d_trc: wrk2d_in allocation error = ',ierr
           call endrun
        end if
     end if


    ierr = pio_get_var( fid, vid, strt, cnt, wrk2d )
    if(associated(wrk2d_in)) then
       wrk2d_in = reshape( wrk2d(:,:),(/file%nlon,file%nlat/), order=order )
       deallocate(wrk2d)
    else
       wrk2d_in => wrk2d
    end if

    j=1
    do c=begchunk,endchunk
       ncols = get_ncols_p(c)
       call get_rlat_all_p(c, pcols, to_lats)

       call lininterp_init(file%lats, file%nlat, to_lats, ncols, 1, lat_wgts)
       do k=1,file%nlev
          call lininterp(wrk2d_in(:,k), file%nlat, wrk(1:ncols), ncols, lat_wgts)    
          loc_arr(1:ncols,k,c-begchunk+1) = wrk(1:ncols)
       end do
       call lininterp_finish(lat_wgts)
    end do
  end subroutine read_za_trc

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


  subroutine read_3d_trc( fid, vid, loc_arr, strt, cnt, file, order) 1,19
    use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish
    use phys_grid,        only : pcols, begchunk, endchunk, get_ncols_p, get_rlat_all_p, get_rlon_all_p	
    use mo_constants,     only : pi
    use dycore,           only : dycore_is		
    use polar_avg,        only : polar_average
    use dycore,           only  : dycore_is

    implicit none

    type(file_desc_t), intent(in) :: fid
    type(var_desc_t), intent(in) :: vid
    integer, intent(in) :: strt(:), cnt(:), order(3)
    real(r8),intent(out)  :: loc_arr(:,:,:)
    
    type (trfile), intent(in) :: file

    integer :: i,j,k, astat, c, ncols

    integer                     :: jlim(2), jl, ju, ierr
    integer                     :: gndx
    real(r8), allocatable, target :: wrk3d(:,:,:)
    real(r8), pointer :: wrk3d_in(:,:,:)
    real(r8) :: to_lons(pcols), to_lats(pcols)
    real(r8), parameter :: zero=0_r8, twopi=2_r8*pi
    type(interp_type) :: lon_wgts, lat_wgts    

    loc_arr(:,:,:) = 0._r8
    nullify(wrk3d_in)
    allocate(wrk3d(cnt(1),cnt(2),cnt(3)), stat=ierr)
    if( ierr /= 0 ) then
       write(iulog,*) 'read_3d_trc: wrk3d allocation error = ',ierr
       call endrun
    end if

    ierr = pio_get_var( fid, vid, strt, cnt, wrk3d )
    if(order(1)/=1 .or. order(2)/=2 .or. order(3)/=3 .or. &
         cnt(1)/=file%nlon.or.cnt(2)/=file%nlat.or.cnt(3)/=file%nlev) then
       allocate(wrk3d_in(file%nlon,file%nlat,file%nlev),stat=ierr)
       if( ierr /= 0 ) then
          write(iulog,*) 'read_3d_trc: wrk3d allocation error = ',ierr
          call endrun
       end if
       wrk3d_in = reshape( wrk3d(:,:,:),(/file%nlon,file%nlat,file%nlev/), order=order )
       deallocate(wrk3d)
    else
       wrk3d_in => wrk3d
    end if

    j=1
    do c=begchunk,endchunk
       ncols = get_ncols_p(c)
       call get_rlat_all_p(c, pcols, to_lats)
       call get_rlon_all_p(c, pcols, to_lons)

       call lininterp_init(file%lons, file%nlon, to_lons(1:ncols), ncols, 2, lon_wgts, zero, twopi)
       call lininterp_init(file%lats, file%nlat, to_lats(1:ncols), ncols, 1, lat_wgts)


       call lininterp(wrk3d_in, file%nlon, file%nlat, file%nlev, loc_arr(:,:,c-begchunk+1), ncols, pcols, lon_wgts, lat_wgts)    	


       call lininterp_finish(lon_wgts)
       call lininterp_finish(lat_wgts)
    end do
    if(allocated(wrk3d)) then
       deallocate( wrk3d, stat=astat )
    else
       deallocate( wrk3d_in, stat=astat )
    end if
    if( astat/= 0 ) then
       write(iulog,*) 'read_3d_trc: failed to deallocate wrk3d array; error = ',astat
       call endrun
    endif
    if(dycore_is('LR')) call polar_average(file%nlev, loc_arr)
  end subroutine read_3d_trc

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


  subroutine interpolate_trcdata( flds, file, state ) 1,6
    use mo_util,      only : rebin
    use physics_types,only : physics_state
    use physconst,    only : cday

    implicit none

    type (trfld),intent(inout) :: flds(:)
    type (trfile), intent(inout) :: file
    type(physics_state), intent(in):: state(begchunk:endchunk)                 

    real(r8) :: fact1, fact2
    real(r8) :: deltat
    integer :: f,nflds,c,ncol, i,k
    real(r8) :: ps(pcols)
    real(r8) :: datain(pcols,file%nlev)
    real(r8) :: pin(pcols,file%nlev)

    real(r8)            :: model_z(pverp)
    real(r8), parameter :: m2km  = 1.e-3_r8

    nflds = size(flds)

    if ( file%interp_recs == 4 ) then
       deltat = file%datatimes(3) - file%datatimes(1)
       fact1 = (file%datatimes(3) - file%datatimem)/deltat
       fact2 = 1._r8-fact1
!$OMP PARALLEL DO PRIVATE (C, NCOL)
       do c = begchunk,endchunk
          ncol = state(c)%ncol
          if ( file%has_ps ) then
             file%ps_in(1)%data(:ncol,c) = fact1*file%ps_in(1)%data(:ncol,c) + fact2*file%ps_in(3)%data(:ncol,c) 
          endif
          do f = 1,nflds
             flds(f)%input(1)%data(:ncol,:,c) = fact1*flds(f)%input(1)%data(:ncol,:,c) + fact2*flds(f)%input(3)%data(:ncol,:,c) 
          enddo
       enddo

       deltat = file%datatimes(4) - file%datatimes(2)
       fact1 = (file%datatimes(4) - file%datatimep)/deltat
       fact2 = 1._r8-fact1

!$OMP PARALLEL DO PRIVATE (C, NCOL)
       do c = begchunk,endchunk
          ncol = state(c)%ncol
          if ( file%has_ps ) then
             file%ps_in(2)%data(:ncol,c) = fact1*file%ps_in(2)%data(:ncol,c) + fact2*file%ps_in(4)%data(:ncol,c) 
          endif
          do f = 1,nflds
             flds(f)%input(2)%data(:ncol,:,c) = fact1*flds(f)%input(2)%data(:ncol,:,c) + fact2*flds(f)%input(4)%data(:ncol,:,c) 
          enddo
       enddo

    endif
    file%interp_recs = 2

    deltat = file%datatimep - file%datatimem

    if ( file%cyclical .and. (deltat < 0._r8) ) then
       deltat = deltat+file%one_yr
       if ( file%datatimep >= file%curr_mod_time ) then
          fact1 = (file%datatimep - file%curr_mod_time)/deltat
       else
          fact1 = (file%datatimep+file%one_yr - file%curr_mod_time)/deltat
       endif
    else
          fact1 = (file%datatimep - file%curr_mod_time)/deltat
    endif

    ! this assures that FIXED data are b4b on restarts
    if ( file%fixed ) then
       fact1 = dble(int(fact1*cday+.5_r8))/dble(cday)
    endif
    fact2 = 1._r8-fact1

!$OMP PARALLEL DO PRIVATE (C, NCOL, PS, I, K, PIN, F, DATAIN, MODEL_Z)
    do c = begchunk,endchunk
       ncol = state(c)%ncol
       if (file%surf_data) then
          do f = 1,nflds
             do i = 1,ncol
                flds(f)%data(i,1,c+flds(f)%chnk_offset) = &
                     fact1*flds(f)%input(nm)%data(i,1,c) + fact2*flds(f)%input(np)%data(i,1,c) 
             enddo
          enddo
       elseif (file%alt_data) then
          do f = 1,nflds
             datain(:ncol,:) = fact1*flds(f)%input(nm)%data(:ncol,:,c) + fact2*flds(f)%input(np)%data(:ncol,:,c) 
             do i = 1,ncol
                model_z(1:pverp) = m2km * state(c)%zi(i,pverp:1:-1)
                call rebin( file%nlev, pver, file%ilevs, model_z, datain(i,:), flds(f)%data(i,:,c+flds(f)%chnk_offset) )
             enddo
          enddo
       else
          if ( file%has_ps ) then
             ps(:ncol) = fact1*file%ps_in(nm)%data(:ncol,c) + fact2*file%ps_in(np)%data(:ncol,c) 
             do i = 1,ncol
                do k = 1,file%nlev
                   pin(i,k) = file%p0*file%hyam(k) + ps(i)*file%hybm(k)
                enddo
             enddo
          else
             do k = 1,file%nlev
                pin(:,k) = file%levs(k)
             enddo
          endif
          do f = 1,nflds
             datain(:ncol,:) = fact1*flds(f)%input(nm)%data(:ncol,:,c) + fact2*flds(f)%input(np)%data(:ncol,:,c)
             if ( file%top_bndry ) then
                call vert_interp_ub(ncol, file%nlev, file%levs,  datain(:ncol,:), flds(f)%data(:ncol,:,c+flds(f)%chnk_offset) )
             else
                call vert_interp(ncol, file%nlev, pin, state(c)%pmid, datain, flds(f)%data(:,:,c+flds(f)%chnk_offset) )
             endif
          enddo
       endif

    enddo

  end subroutine interpolate_trcdata

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

  subroutine get_dimension( fid, dname, dsize, dimid, data ) 11,2
    implicit none
    type(file_desc_t), intent(in) :: fid
    character(*), intent(in) :: dname
    integer, intent(out) :: dsize

    integer, optional, intent(out) :: dimid
    real(r8), optional, pointer, dimension(:) :: data

    integer :: vid, ierr, id

    ierr = pio_inq_dimid( fid, dname, id )
    ierr = pio_inq_dimlen( fid, id, dsize )
    
    if ( present(dimid) ) then
       dimid = id
    endif

    if ( present(data) ) then
       if ( associated(data) ) then
          deallocate(data, stat=ierr)
          if( ierr /= 0 ) then
             write(iulog,*) 'get_dimension: data deallocation error = ',ierr
             call endrun('get_dimension: failed to deallocate data array')
          end if
       endif
       allocate( data(dsize), stat=ierr )
       if( ierr /= 0 ) then
          write(iulog,*) 'get_dimension: data allocation error = ',ierr
          call endrun('get_dimension: failed to allocate data array')
       end if

       ierr =  pio_inq_varid( fid, dname, vid )
       ierr =  pio_get_var( fid, vid, data )
    endif

  end subroutine get_dimension

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

  subroutine set_cycle_indices( fileid, cyc_ndx_beg, cyc_ndx_end, cyc_yr ) 2,4

    implicit none

    type(file_desc_t), intent(in)  :: fileid
    integer, intent(out) :: cyc_ndx_beg
    integer, intent(out) :: cyc_ndx_end
    integer, intent(in)  :: cyc_yr

    integer, allocatable , dimension(:) :: dates, datesecs
    integer :: timesize, i, astat, year, ierr
    type(var_desc_T) :: dateid
    call get_dimension( fileid, 'time', timesize )
    cyc_ndx_beg=-1

    allocate( dates(timesize), stat=astat  )
    if( astat/= 0 ) then
       write(*,*) 'set_cycle_indices: failed to allocate dates array; error = ',astat
       call endrun
    end if

    ierr = pio_inq_varid(   fileid, 'date',  dateid  )
    ierr = pio_get_var( fileid, dateid, dates )

    do i=1,timesize
       year = dates(i) / 10000
       if ( year == cyc_yr ) then
          if  (cyc_ndx_beg < 0)  then
             cyc_ndx_beg = i
          endif
          cyc_ndx_end = i
       endif
    enddo
    deallocate( dates, stat=astat  )
    if( astat/= 0 ) then
       write(*,*) 'set_cycle_indices: failed to deallocate dates array; error = ',astat
       call endrun
    end if
    if (cyc_ndx_beg < 0) then
       write(*,*) 'set_cycle_indices: cycle year not found : ' , cyc_yr
       call endrun('set_cycle_indices: cycle year not found')
    endif

  end subroutine set_cycle_indices
!-----------------------------------------------------------------------

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

  subroutine open_trc_datafile( fname, path, piofile, times, cyc_ndx_beg, cyc_ndx_end, cyc_yr ) 3,13

    use ioFileMod,     only: getfil
    use cam_pio_utils, only: cam_pio_openfile

    implicit none

    character(*), intent(in) :: fname
    character(*), intent(in) :: path
    type(file_desc_t), intent(inout) :: piofile
    real(r8), pointer :: times(:)

    integer, optional, intent(out) :: cyc_ndx_beg
    integer, optional, intent(out) :: cyc_ndx_end
    integer, optional, intent(in) :: cyc_yr

    character(len=shr_kind_cl) :: filen, filepath
    integer :: year, month, day, dsize, i, timesize
    integer :: dateid,secid
    integer, allocatable , dimension(:) :: dates, datesecs
    integer :: astat, ierr

    filepath = trim(path) // '/' // trim(fname)
    !
    ! open file and get fileid
    !
    call getfil( filepath, filen, 0 )
    call cam_pio_openfile( piofile, filen, PIO_NOWRITE)
    if(masterproc) write(iulog,*)'open_trc_datafile: ',trim(filen)

    call get_dimension(piofile, 'time', timesize)
    
    if ( associated(times) ) then
       deallocate(times, stat=ierr)
       if( ierr /= 0 ) then
          write(iulog,*) 'open_trc_datafile: data deallocation error = ',ierr
          call endrun('open_trc_datafile: failed to deallocate data array')
       end if
    endif
    allocate( times(timesize), stat=ierr )
    if( ierr /= 0 ) then
       write(iulog,*) 'open_trc_datafile: data allocation error = ',ierr
       call endrun('open_trc_datafile: failed to allocate data array')
    end if

    allocate( dates(timesize), stat=astat  )
    if( astat/= 0 ) then
       if(masterproc) write(iulog,*) 'open_trc_datafile: failed to allocate dates array; error = ',astat
       call endrun
    end if
    allocate( datesecs(timesize), stat=astat  )
    if( astat/= 0 ) then
       if(masterproc) write(iulog,*) 'open_trc_datafile: failed to allocate datesec array; error = ',astat
       call endrun
    end if

    ierr =  pio_inq_varid( piofile, 'date',    dateid  )
    call pio_seterrorhandling( piofile, PIO_BCAST_ERROR)
    ierr = pio_inq_varid( piofile, 'datesec', secid  )
    call pio_seterrorhandling( piofile, PIO_INTERNAL_ERROR)
    
    if(ierr==PIO_NOERR) then
       ierr = pio_get_var( piofile, secid,  datesecs  )
    else
       datesecs=0
    end if

    ierr =  pio_get_var( piofile, dateid, dates )

    do i=1,timesize
       year = dates(i) / 10000
       month = mod(dates(i),10000)/100
       day = mod(dates(i),100)
       call set_time_float_from_date( times(i), year, month, day, datesecs(i) )
       if ( present(cyc_yr) ) then
          if ( year == cyc_yr ) then
             if ( present(cyc_ndx_beg) .and. (cyc_ndx_beg < 0) ) then
                cyc_ndx_beg = i
             endif
             if ( present(cyc_ndx_end) ) then
                cyc_ndx_end = i
             endif
          endif
       endif
    enddo

    deallocate( dates, stat=astat  )
    if( astat/= 0 ) then
       if(masterproc) write(iulog,*) 'open_trc_datafile: failed to deallocate dates array; error = ',astat
       call endrun
    end if
    deallocate( datesecs, stat=astat  )       
    if( astat/= 0 ) then
       if(masterproc) write(iulog,*) 'open_trc_datafile: failed to deallocate datesec array; error = ',astat
       call endrun
    end if
       
    if ( present(cyc_yr) .and. present(cyc_ndx_beg) ) then
       if (cyc_ndx_beg < 0) then
          write(iulog,*) 'open_trc_datafile: cycle year not found : ' , cyc_yr
          call endrun('open_trc_datafile: cycle year not found')
       endif
    endif

  end subroutine open_trc_datafile

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

  subroutine specify_fields( specifier, fields ) 1,2

    implicit none

    character(len=*), intent(in) :: specifier(:)
    type(trfld), pointer, dimension(:) :: fields

    integer :: fld_cnt, astat
    integer :: i,j
    character(len=shr_kind_cl) :: str1, str2
    character(len=32), allocatable, dimension(:) :: fld_name,  src_name
    integer :: nflds

    nflds = size(specifier)

    allocate(fld_name(nflds),  src_name(nflds), stat=astat )
    if( astat/= 0 ) then
       write(iulog,*) 'specify_fields: failed to allocate fld_name, src_name arrays; error = ',astat
       call endrun
    end if

    fld_cnt = 0

    count_cnst: do i = 1, nflds

       if ( len_trim( specifier(i) ) == 0 ) then
          exit count_cnst
       endif

       j = scan( specifier(i),':')

       if (j > 0) then
          str1 = trim(adjustl( specifier(i)(:j-1) ))
          str2 = trim(adjustl( specifier(i)(j+1:) ))
          fld_name(i) = trim(adjustl( str1 ))
          src_name(i) = trim(adjustl( str2 ))
       else
          fld_name(i) = trim(adjustl( specifier(i) ))
          src_name(i) = trim(adjustl( specifier(i) ))
       endif

       fld_cnt = fld_cnt + 1

    enddo count_cnst

    if( fld_cnt < 1 ) then
       return
    end if

    !-----------------------------------------------------------------------
    ! 	... allocate field type array
    !-----------------------------------------------------------------------
    allocate( fields(fld_cnt), stat=astat )
    if( astat/= 0 ) then
       write(iulog,*) 'specify_fields: failed to allocate fields array; error = ',astat
       call endrun
    end if

    do i = 1,fld_cnt
       fields(i)%fldnam = fld_name(i)
       fields(i)%srcnam = src_name(i)
    enddo

    deallocate(fld_name, src_name)

  end subroutine specify_fields

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


  subroutine init_trc_restart( whence, piofile, tr_file ) 4

    implicit none
    character(len=*), intent(in) :: whence
    type(file_desc_t), intent(inout) :: piofile
    type(trfile), intent(inout) :: tr_file
 
    character(len=32) :: name
    integer :: ioerr, mcdimid, maxlen
 

    ! Dimension should already be defined in restart file
    call pio_seterrorhandling(pioFile, PIO_BCAST_ERROR)
    ioerr = pio_inq_dimid(pioFile,'max_chars', mcdimid)
    call pio_seterrorhandling(pioFile, PIO_INTERNAL_ERROR)
    ! but define it if nessasary
    if(ioerr/= PIO_NOERR) then
       ioerr = pio_def_dim(pioFile, 'max_chars', SHR_KIND_CL, mcdimid)
    end if

    if(len_trim(tr_file%curr_filename)>1) then
       allocate(tr_file%currfnameid)
       name = trim(whence)//'_curr_fname'
       ioerr = pio_def_var(pioFile, name,pio_char,  (/mcdimid/), tr_file%currfnameid)
       ioerr = pio_put_att(pioFile, tr_file%currfnameid, 'offset_time', tr_file%offset_time)
       maxlen = len_trim(tr_file%curr_filename)
       ioerr = pio_put_att(pioFile, tr_file%currfnameid, 'actual_len', maxlen)	
    else
       nullify(tr_file%currfnameid)
    end if

    if(len_trim(tr_file%next_filename)>1) then
       allocate(tr_file%nextfnameid)
       name = trim(whence)//'_next_fname'
       ioerr = pio_def_var(pioFile, name,pio_char,  (/mcdimid/), tr_file%nextfnameid)
       maxlen = len_trim(tr_file%next_filename)
       ioerr = pio_put_att(pioFile, tr_file%nextfnameid, 'actual_len', maxlen)
    else
       nullify(tr_file%nextfnameid)
    end if
  end subroutine init_trc_restart
!-------------------------------------------------------------------------
! writes file names to restart file
!-------------------------------------------------------------------------

  subroutine write_trc_restart( piofile, tr_file ) 4

    implicit none

    type(file_desc_t), intent(inout) :: piofile
    type(trfile), intent(inout) :: tr_file

    integer :: ioerr, slen   ! error status
    if(associated(tr_file%currfnameid)) then
       ioerr = pio_put_var(pioFile, tr_file%currfnameid, tr_file%curr_filename)
       deallocate(tr_file%currfnameid)
       nullify(tr_file%currfnameid)
    end if
    if(associated(tr_file%nextfnameid)) then
       ioerr = pio_put_var(pioFile, tr_file%nextfnameid, tr_file%next_filename)
       deallocate(tr_file%nextfnameid)
       nullify(tr_file%nextfnameid)
    end if
  end subroutine write_trc_restart

!-------------------------------------------------------------------------
! reads file names from restart file
!-------------------------------------------------------------------------

  subroutine read_trc_restart( whence, piofile, tr_file ) 4

    implicit none

    character(len=*), intent(in) :: whence
    type(file_desc_t), intent(inout) :: piofile
    type(trfile), intent(inout) :: tr_file
    type(var_desc_t) :: vdesc
    character(len=64) :: name
    integer :: ioerr   ! error status
    integer :: slen

    call PIO_SetErrorHandling(piofile, PIO_BCAST_ERROR)
    name = trim(whence)//'_curr_fname'
    ioerr = pio_inq_varid(piofile, name, vdesc)
    if(ioerr==PIO_NOERR) then
       tr_file%curr_filename=' '
       ioerr = pio_get_att(piofile, vdesc, 'offset_time', tr_file%offset_time)
       ioerr = pio_get_att(piofile, vdesc, 'actual_len', slen)
       ioerr = pio_get_var(piofile, vdesc, tr_file%curr_filename)
       if(slen<SHR_KIND_CL) tr_file%curr_filename(slen+1:)=' '
    end if

    name = trim(whence)//'_next_fname'
    ioerr = pio_inq_varid(piofile, name, vdesc)
    if(ioerr==PIO_NOERR) then
       tr_file%next_filename=' '
       ioerr = pio_get_att(piofile, vdesc, 'actual_len', slen)
       ioerr = pio_get_var(piofile, vdesc, tr_file%next_filename)
       if(slen<SHR_KIND_CL) tr_file%next_filename(slen+1:)=' '
    end if
    call PIO_SetErrorHandling(piofile, PIO_INTERNAL_ERROR)



  end subroutine read_trc_restart

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

  subroutine vert_interp( ncol, levsiz, pin, pmid, datain, dataout) 1
    !----------------------------------------------------------------------- 
    ! 
    ! Interpolate data from current time-interpolated values to model levels
    !--------------------------------------------------------------------------
    implicit none
    ! Arguments
    !
    integer,  intent(in)  :: ncol                ! number of atmospheric columns
    integer,  intent(in)  :: levsiz
    real(r8), intent(in)  :: pin(pcols,levsiz)
    real(r8), intent(in)  :: pmid(pcols,pver)          ! level pressures 
    real(r8), intent(in)  :: datain(pcols,levsiz)
    real(r8), intent(out) :: dataout(pcols,pver)     
    !
    ! local storage
    !

    integer ::  i                   ! longitude index
    integer ::  k, kk, kkstart      ! level indices
    integer ::  kupper(pcols)       ! Level indices for interpolation
    real(r8) :: dpu                ! upper level pressure difference
    real(r8) :: dpl                ! lower level pressure difference

    !--------------------------------------------------------------------------
    !
    ! Initialize index array
    !
    do i=1,ncol
       kupper(i) = 1
    end do

    do k=1,pver
       !
       ! Top level we need to start looking is the top level for the previous k
       ! for all column points
       !
       kkstart = levsiz
       do i=1,ncol
          kkstart = min0(kkstart,kupper(i))
       end do
       !
       ! Store level indices for interpolation
       !
       do kk=kkstart,levsiz-1
          do i=1,ncol
             if (pin(i,kk).lt.pmid(i,k) .and. pmid(i,k).le.pin(i,kk+1)) then
                kupper(i) = kk
             end if
          end do
       end do
       ! interpolate or extrapolate...
       do i=1,ncol
          if (pmid(i,k) .lt. pin(i,1)) then
             dataout(i,k) = datain(i,1)*pmid(i,k)/pin(i,1)
          else if (pmid(i,k) .gt. pin(i,levsiz)) then
             dataout(i,k) = datain(i,levsiz)
          else
             dpu = pmid(i,k) - pin(i,kupper(i))
             dpl = pin(i,kupper(i)+1) - pmid(i,k)
             dataout(i,k) = (datain(i,kupper(i) )*dpl + &
                  datain(i,kupper(i)+1)*dpu)/(dpl + dpu)
          end if
       end do
    end do
  end subroutine vert_interp

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

  subroutine vert_interp_ub( ncol, nlevs, plevs,  datain, dataout ) 1,1
    use hycoef, only : hyai, ps0

    !----------------------------------------------------------------------- 
    ! 
    ! Interpolate data from current time-interpolated values to top interface pressure
    !  -- from mo_tgcm_ubc.F90
    !--------------------------------------------------------------------------
    implicit none
    ! Arguments
    !
    integer,  intent(in)  :: ncol
    integer,  intent(in)  :: nlevs
    real(r8), intent(in)  :: plevs(nlevs)
    real(r8), intent(in)  :: datain(ncol,nlevs)
    real(r8), intent(out) :: dataout(ncol)   

    !
    ! local variables
    !
    integer  :: i,ku,kl,kk
    real(r8) :: pinterp, delp
    
    pinterp = ps0 * hyai(1)

    if( pinterp <= plevs(1) ) then
       kl = 1
       ku = 1
       delp = 0._r8
    else if( pinterp >= plevs(nlevs) ) then
       kl = nlevs
       ku = nlevs
       delp = 0._r8
    else

       do kk = 2,nlevs
          if( pinterp <= plevs(kk) ) then
             ku = kk
             kl = kk - 1
             delp = log( pinterp/plevs(kk) ) / log( plevs(kk-1)/plevs(kk) )
             exit
          end if
       end do

    end if

    do i = 1,ncol
       dataout(i) = datain(i,kl) + delp * (datain(i,ku) - datain(i,kl))
    end do

  end subroutine vert_interp_ub
!------------------------------------------------------------------------------

end module tracer_data