!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

module IRF_mod

!BOP
! !MODULE: IRF_mod
!
! Impulse response functions (IRFs) are diagnostics tracers in a
! GCM. The tracers are set to specified patterns (e.g. point impulses
! localized in space) and the GCM computes tendencies (e.g. advective and
! mixing fluxes) based on these patterns. The tracers are reset to their
! respective patterns at every model timestep. The time-mean of the computed
! tendencies are the output of interest. This diagnostic output provides a
! representation of the GCM's circulation operators (advection and mixing).
! Two target applications of IRFs in CESM-POP are to provide inputs for
! offline tracer transport models and to provide a representation of model
! circulation for the preconditioner in the Newton-Krylov based solver
! for fast tracer spinup.
!
! IRF_NT is set as a key-value pair in CESM's OCN_TRACER_MODULE_OPT in env_build.xml
!
! !DESCRIPTION:
!
! !REVISION HISTORY:
!  SVN:$Id: $

! !USES:

   use blocks, only: nx_block, ny_block
   use domain_size, only: km
   use kinds_mod

   implicit none

   private

! !PUBLIC MEMBER FUNCTIONS:

   public :: IRF_tracer_cnt, &
             IRF_init,       &
             IRF_reset

!EOP
!BOC

!-----------------------------------------------------------------------
!  module variables required by passive_tracer
!-----------------------------------------------------------------------

   integer(int_kind), parameter :: IRF_tracer_cnt = IRF_NT

!EOC
!*****************************************************************************

contains

!*****************************************************************************
!BOP
! !IROUTINE: IRF_init
! !INTERFACE:

 subroutine IRF_init(tracer_d_module, TRACER_MODULE)

! !DESCRIPTION:
!  Initialize IRF tracer module. This involves setting metadata, reading
!  the module's namelist and setting initial conditions.
!
! !REVISION HISTORY:
!  same as module

! !USES:

   use broadcast
   use constants, only: c0, blank_fmt, delim_fmt, ndelim_fmt
   use communicate, only: my_task, master_task
   use domain, only: nblocks_clinic
   use domain_size, only: max_blocks_clinic
   use exit_mod, only: sigAbort, exit_POP
   use io_tools, only: document
   use io_types, only: stdout, nml_in, nml_filename
   use passive_tracer_tools, only: read_field
   use prognostic, only: oldtime, curtime, tracer_field
   use grid, only: KMT

   use netcdf

! !INPUT/OUTPUT PARAMETERS:

   type (tracer_field), dimension(:), intent(inout) :: &
      tracer_d_module   ! descriptors for each tracer

   real(r8), dimension(:,:,:,:,:,:), &
      intent(inout) :: TRACER_MODULE

!EOP
!BOC
!-----------------------------------------------------------------------
!  local variables
!-----------------------------------------------------------------------

   character(*), parameter :: subname = 'IRF_mod:IRF_init'

   character(char_len) :: &
      irf_tracer_file              ! filename for tracer impulse patterns

   integer(int_kind) :: &
      irf_tracer_file_ind_start, & ! starting index for tracers from irf_tracer_file
      stat,                      & ! status of netCDF call
      ncid,                      & ! netCDF file id
      varid,                     & ! netCDF variable id
      irf_tracer_file_nchar,     & ! character length of variable names in irf_tracer_file
      char_pos,                  & ! character position in a string
      n,                         & ! index for looping over tracers
      iblock,                    & ! index for looping over blocks
      k,                         & ! index for looping over depth levels
      nml_error                    ! namelist i/o error flag

   integer (int_kind), dimension(2) :: &
      varnames_dimids              ! dimids for tracer names variable

   namelist /irf_nml/ &
      irf_tracer_file, irf_tracer_file_ind_start

!-----------------------------------------------------------------------
!  default namelist settings
!-----------------------------------------------------------------------

   irf_tracer_file = 'unknown'
   irf_tracer_file_ind_start = 1

!-----------------------------------------------------------------------
!  read namelist input
!-----------------------------------------------------------------------

   if (my_task == master_task) then
      open (nml_in, file=nml_filename, status='old',iostat=nml_error)
      if (nml_error /= 0) then
         nml_error = -1
      else
         nml_error =  1
      endif
      do while (nml_error > 0)
         read(nml_in, nml=irf_nml,iostat=nml_error)
      end do
      if (nml_error == 0) close(nml_in)
   endif

   call broadcast_scalar(nml_error, master_task)
   if (nml_error /= 0) then
      call document(subname, 'irf_nml not found')
      call exit_POP(sigAbort, 'stopping in ' /&
                           &/ subname)
   endif

   if (my_task == master_task) then
      write(stdout,blank_fmt)
      write(stdout,ndelim_fmt)
      write(stdout,blank_fmt)
      write(stdout,*) ' IRF:'
      write(stdout,blank_fmt)
      write(stdout,*) ' IRF namelist settings:'
      write(stdout,blank_fmt)
      write(stdout,irf_nml)
      write(stdout,blank_fmt)
      write(stdout,delim_fmt)
   endif

!-----------------------------------------------------------------------
!  broadcast all namelist variables
!-----------------------------------------------------------------------

   call broadcast_scalar(irf_tracer_file, master_task)
   call broadcast_scalar(irf_tracer_file_ind_start, master_task)

!-----------------------------------------------------------------------
!  read in tracer names on master_task
!  jump out of master_task conditional if an error is encountered
!  broadcast values that were read in
!-----------------------------------------------------------------------

   if (my_task == master_task) then
      stat = nf90_open(irf_tracer_file, 0, ncid)
      if (stat /= 0) then
         write(stdout,*) 'error from nf90_open: ', nf90_strerror(stat)
         go to 99
      endif

      stat = nf90_inq_varid(ncid, 'var_names', varid)
      if (stat /= 0) then
         write(stdout,*) 'error from nf90_inq_varid for var_names: ', &
                         nf90_strerror(stat)
         go to 99
      endif

      stat = nf90_inquire_variable(ncid, varid, dimids=varnames_dimids)
      if (stat /= 0) then
         write(stdout,*) 'error from nf90_inquire_variable for dimids for var_names: ', &
                         nf90_strerror(stat)
         go to 99
      endif

      stat = nf90_inquire_dimension(ncid, varnames_dimids(1), len=irf_tracer_file_nchar)
      if (stat /= 0) then
         write(stdout,*) 'error from nf90_inquire_dimension for len of 1st dim of var_names: ', &
                         nf90_strerror(stat)
         go to 99
      endif

      do n = 1, IRF_tracer_cnt
         tracer_d_module(n)%short_name = ''
         stat = nf90_get_var(ncid, varid, tracer_d_module(n)%short_name, &
                             start=(/ 1, n+irf_tracer_file_ind_start-1 /), &
                             count=(/ irf_tracer_file_nchar, 1 /))
         if (stat /= 0) then
            write(stdout,*) 'error from nf90_get_var for varname ', n, ': ', &
                            nf90_strerror(stat)
            go to 99
         endif

         ! replace trailing null characters with spaces
         char_pos = index(tracer_d_module(n)%short_name, char(0))
         if ( char_pos > 0 ) then
            tracer_d_module(n)%short_name(char_pos:char_len) = ' '
         endif
      end do

      stat = nf90_close(ncid)
      if (stat /= 0) then
         write(stdout,*) 'error from nf90_close: ', nf90_strerror(stat)
         go to 99
      endif

   endif

99 call broadcast_scalar(stat, master_task)
   if (stat /= 0) call exit_POP(sigAbort, 'stopping in ' /&
                                                          &/ subname)

   do n = 1, IRF_tracer_cnt
      call broadcast_scalar(tracer_d_module(n)%short_name, master_task)
   end do

!-----------------------------------------------------------------------
!  initialize other tracer_d values
!-----------------------------------------------------------------------

   do n = 1, IRF_tracer_cnt
      tracer_d_module(n)%long_name  = tracer_d_module(n)%short_name
      tracer_d_module(n)%units      = '1'
      tracer_d_module(n)%tend_units = '1/s'
      tracer_d_module(n)%flux_units = '1/cm^2/s'
   end do

!-----------------------------------------------------------------------
!  initialize tracers
!
!  Because the IRF tracers are reset to their initial state at the end
!  of every timestep, they do not really evolve in time. So it is never
!  necessary to read them from the model restart file. So the code is
!  hardwired to always initialize the tracers from the irf_tracer_file.
!
!  apply land mask to tracers
!-----------------------------------------------------------------------

   do n = 1, IRF_tracer_cnt
      call read_field('nc', irf_tracer_file, &
                      tracer_d_module(n)%short_name, &
                      TRACER_MODULE(:,:,:,n,oldtime,:))
   end do

   !$OMP PARALLEL DO PRIVATE(iblock,n,k)
   do iblock=1,nblocks_clinic
      do n = 1,IRF_tracer_cnt
         do k = 1,km
            where (k > KMT(:,:,iblock))
               TRACER_MODULE(:,:,k,n,oldtime,iblock) = c0
            end where
            TRACER_MODULE(:,:,k,n,curtime,iblock) = &
               TRACER_MODULE(:,:,k,n,oldtime,iblock)
         end do
      end do
   end do

!-----------------------------------------------------------------------
!EOC

 end subroutine IRF_init

!***********************************************************************
!BOP
! !IROUTINE: IRF_reset
! !INTERFACE:

 subroutine IRF_reset(TRACER_MODULE_OLD, TRACER_MODULE_RESET)

! !DESCRIPTION:
!  reset IRF newtime values to oldtime values
!
! !REVISION HISTORY:
!  same as module

! !INPUT PARAMETERS:

   real(r8), dimension(:,:,:,:), intent(in) :: &
      TRACER_MODULE_OLD    ! IRF tracers at oldtime

! !INPUT/OUTPUT PARAMETERS:

   real(r8), dimension(:,:,:,:), intent(inout) :: &
      TRACER_MODULE_RESET  ! IRF tracers at time level being reset

!EOP
!BOC
!-----------------------------------------------------------------------

   TRACER_MODULE_RESET = TRACER_MODULE_OLD

!-----------------------------------------------------------------------
!EOC

 end subroutine IRF_reset

!***********************************************************************

end module IRF_mod

!|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
