module clm_glclnd

!-----------------------------------------------------------------------
!BOP
!
! !MODULE: clm_glclnd
!
! !DESCRIPTION:
! Handle arrays used for exchanging data between glc and land model.
! Based on clm_atmlnd (but without mapping routines because glc data
!  is send and received on the lnd decomposition, at least for now).
!
! The fields sent from the lnd component to the glc component via
!  the coupler are labeled 's2x', or sno to coupler.
! The fields received by the lnd component from the glc component
!  via the coupler are labeled 'x2s', or coupler to sno.
! 'Sno' is a misnomer in that the exchanged data are related to
!  the ice beneath the snow, not the snow itself.  But by CESM convention,
! 'ice' refers to sea ice, not land ice.
!
! !USES:
  use decompMod   , only : get_proc_bounds
  use shr_kind_mod, only : r8 => shr_kind_r8
  use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=)
  use spmdMod     , only : masterproc
  use clm_varpar  , only : maxpatch_glcmec
  use clm_varctl  , only : iulog
  use abortutils  , only : endrun
!
! !REVISION HISTORY:
! Created by William Lipscomb, Dec. 2007, based on clm_atmlnd.F90.
!
! !PUBLIC TYPES:
  implicit none
  private
  save

!----------------------------------------------------
! glc -> land variables structure
!----------------------------------------------------
  type, public :: glc2lnd_type
     real(r8), pointer :: frac(:,:) => null()
     real(r8), pointer :: topo(:,:) => null()
     real(r8), pointer :: hflx(:,:) => null()
     real(r8), pointer :: icemask(:) => null()   
  end type glc2lnd_type

!----------------------------------------------------
! land -> glc variables structure
!----------------------------------------------------
  type, public :: lnd2glc_type
     real(r8), pointer :: tsrf(:,:) => null()
     real(r8), pointer :: topo(:,:) => null()
     real(r8), pointer :: qice(:,:) => null()
  end type lnd2glc_type

  type (lnd2glc_type), public, target :: clm_s2x  ! s2x fields on clm grid
  type (glc2lnd_type), public, target :: clm_x2s  ! x2s fields on clm grid

! !PUBLIC MEMBER FUNCTIONS:
  public :: init_glc2lnd_type
  public :: init_lnd2glc_type
  public :: update_clm_s2x
!
! !PRIVATE MEMBER FUNCTIONS:

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

contains


!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: init_glc2lnd_type
!
! !INTERFACE:
  subroutine init_glc2lnd_type(beg, end, x2s)
!
! !DESCRIPTION:
! Initialize glc variables required by the land
!
! !ARGUMENTS:
  implicit none
  integer, intent(in) :: beg, end
  type (glc2lnd_type), intent(inout):: x2s
!
! !REVISION HISTORY:
! Created by William Lipscomb, based on init_atm2lnd_type
!EOP
!
! !LOCAL VARIABLES:
  real(r8) :: ival   ! initial value
!------------------------------------------------------------------------

  allocate(x2s%frac(beg:end,0:maxpatch_glcmec))
  allocate(x2s%topo(beg:end,0:maxpatch_glcmec))
  allocate(x2s%hflx(beg:end,0:maxpatch_glcmec))
  allocate(x2s%icemask(beg:end))
  
! ival = nan      ! causes core dump in map_maparray, tcx fix
  ival = 0.0_r8

  x2s%frac(beg:end,0:) = ival
  x2s%topo(beg:end,0:) = ival
  x2s%hflx(beg:end,0:) = ival
  x2s%icemask(beg:end)= ival

end subroutine init_glc2lnd_type

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: init_lnd2glc_type
!
! !INTERFACE:
  subroutine init_lnd2glc_type(beg, end, s2x)
!
! !DESCRIPTION:
! Initialize land variables required by glc
!
! !ARGUMENTS:
  implicit none
  integer, intent(in) :: beg, end
  type (lnd2glc_type), intent(inout):: s2x
!
! !REVISION HISTORY:
! Created by William Lipscomb, based on init_lnd2atm_type
!
!EOP
!
! !LOCAL VARIABLES:
  real(r8) :: ival   ! initial value
!------------------------------------------------------------------------

  allocate(s2x%tsrf(beg:end,0:maxpatch_glcmec))
  allocate(s2x%topo(beg:end,0:maxpatch_glcmec))
  allocate(s2x%qice(beg:end,0:maxpatch_glcmec))

! ival = nan      ! causes core dump in map_maparray, tcx fix
  ival = 0.0_r8

  s2x%tsrf(beg:end,0:) = ival
  s2x%topo(beg:end,0:) = ival
  s2x%qice(beg:end,0:) = ival

end subroutine init_lnd2glc_type

!------------------------------------------------------------------------------
!BOP
!
! !IROUTINE: update_clm_s2x
!
! !INTERFACE:
  subroutine update_clm_s2x(init)
!
! !DESCRIPTION:
! Assign values to clm_s2x based on the appropriate derived types
!
! !USES:
  use clmtype     
  use domainMod   , only : ldomain
  use clm_varcon  , only : istice_mec
  use clm_atmlnd  , only : clm_l2a, clm_a2l
  use clm_varcon  , only : spval, tfrz
!
! !ARGUMENTS:
  implicit none

  logical, intent(in)   :: init    ! if true=>only set a subset of fields
!
! !REVISION HISTORY:
! Written by William Lipscomb, Feb. 2009 
!

    integer :: begg, endg              ! per-proc beginning and ending gridcell indices
    integer :: begc, endc              ! per-proc beginning and ending column indices
    integer :: c, l, g, n              ! indices
    integer , pointer :: ityplun(:)    ! landunit type
    integer , pointer :: clandunit(:)  ! column's landunit index
    integer , pointer :: cgridcell(:)  ! column's gridcell index

    ! Assign local pointers to derived type members

    clandunit => col%landunit
    cgridcell => col%gridcell
    ityplun   => lun%itype

    ! Get processor bounds
    call get_proc_bounds(begg, endg, begc=begc, endc=endc)

    ! Initialize qice because otherwise it will remain unset if init=true;
    ! note that the value here is the value qice will keep if these
    ! conditions hold. Also, need to set a reasonable default for elevation class 0,
    ! which is used by the CLM4.5 code, but not by CLM4.0.

    clm_s2x%qice(:,0:) = 0._r8

    ! and initialize the other variables just to be safe; also need to set a reasonable
    ! default for elevation class 0 (for tsrf, note that we initialize other elevation
    ! classes to 0, to remain consistent with what was done before, but set elevation
    ! class 0 to a reasonable default, because it will remain at its default value).

    clm_s2x%tsrf(:,0)  = tfrz
    clm_s2x%tsrf(:,1:) = 0._r8
    clm_s2x%topo(:,:)  = 0._r8

    ! Fill the clm_s2x vector on the clm grid

    do c = begc, endc
       l = clandunit(c)
       g = cgridcell(c)

       ! Following assumes all elevation classes are populated
       if (ityplun(l) == istice_mec) then
          n = c - lun%coli(l) + 1    ! elevation class index

          ! t_soisno and glc_topo are valid even in initialization, so tsrf and topo
          ! are set here regardless of the value of init. But qflx_glcice is not valid
          ! until the run loop; thus, in initialization, we will use the default value
          ! for qice, as set above.
          clm_s2x%tsrf(g,n) = ces%t_soisno(c,1)
          clm_s2x%topo(g,n) = cps%glc_topo(c)
          if (.not. init) then
             clm_s2x%qice(g,n) = cwf%qflx_glcice(c)

             ! Check for bad values of qice
             if ( abs(clm_s2x%qice(g,n)) > 1.0_r8 .and. clm_s2x%qice(g,n) /= spval) then
                write(iulog,*) 'WARNING: qice out of bounds: g, n, qice =', g, n, clm_s2x%qice(g,n)
             endif
          end if

       endif    ! istice_mec
    enddo        ! c

end subroutine update_clm_s2x

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

end module clm_glclnd

