#include <misc.h>
#include <preproc.h>


module filterMod 5,3

!-----------------------------------------------------------------------
!BOP
!
! !MODULE: filterMod
!
! !DESCRIPTION:
! Module of filters used for processing columns and pfts of particular
! types, including lake, non-lake, urban, soil, snow, non-snow, and
! naturally-vegetated patches.
!
! !USES:
  use shr_kind_mod, only: r8 => shr_kind_r8
  use abortutils, only : endrun
  use clm_varctl, only : iulog
!
! !PUBLIC TYPES:
  implicit none
  save

  private

  type clumpfilter
#if (defined CNDV)
     integer, pointer :: natvegp(:)      ! CNDV nat-vegetated (present) filter (pfts)
     integer :: num_natvegp              ! number of pfts in nat-vegetated filter
#endif

     integer, pointer :: lakep(:)        ! lake filter (pfts)
     integer :: num_lakep                ! number of pfts in lake filter
     integer, pointer :: nolakep(:)      ! non-lake filter (pfts)
     integer :: num_nolakep              ! number of pfts in non-lake filter
     integer, pointer :: lakec(:)        ! lake filter (columns)
     integer :: num_lakec                ! number of columns in lake filter
     integer, pointer :: nolakec(:)      ! non-lake filter (columns)
     integer :: num_nolakec              ! number of columns in non-lake filter

     integer, pointer :: soilc(:)        ! soil filter (columns)
     integer :: num_soilc                ! number of columns in soil filter 
     integer, pointer :: soilp(:)        ! soil filter (pfts)
     integer :: num_soilp                ! number of pfts in soil filter 

     integer, pointer :: snowc(:)        ! snow filter (columns) 
     integer :: num_snowc                ! number of columns in snow filter 
     integer, pointer :: nosnowc(:)      ! non-snow filter (columns) 
     integer :: num_nosnowc              ! number of columns in non-snow filter 

     integer, pointer :: hydrologyc(:)   ! hydrology filter (columns)
     integer :: num_hydrologyc           ! number of columns in hydrology filter 

     integer, pointer :: urbanl(:)       ! urban filter (landunits)
     integer :: num_urbanl               ! number of landunits in urban filter 
     integer, pointer :: nourbanl(:)     ! non-urban filter (landunits)
     integer :: num_nourbanl             ! number of landunits in non-urban filter 

     integer, pointer :: urbanc(:)       ! urban filter (columns)
     integer :: num_urbanc               ! number of columns in urban filter
     integer, pointer :: nourbanc(:)     ! non-urban filter (columns)
     integer :: num_nourbanc             ! number of columns in non-urban filter

     integer, pointer :: urbanp(:)       ! urban filter (pfts)
     integer :: num_urbanp               ! number of pfts in urban filter
     integer, pointer :: nourbanp(:)     ! non-urban filter (pfts)
     integer :: num_nourbanp             ! number of pfts in non-urban filter

     integer, pointer :: nolakeurbanp(:) ! non-lake, non-urban filter (pfts)
     integer :: num_nolakeurbanp         ! number of pfts in non-lake, non-urban filter

  end type clumpfilter
  public clumpfilter

  type(clumpfilter), allocatable, public :: filter(:)
!
  public allocFilters   ! allocate memory for filters
  public setFilters     ! set filters
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! 11/13/03, Peter Thornton: Added soilp and num_soilp
! Jan/08, S. Levis: Added crop-related filters
!
!EOP
!-----------------------------------------------------------------------

contains

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: allocFilters
!
! !INTERFACE:

  subroutine allocFilters() 1,5
!
! !DESCRIPTION:
! Allocate CLM filters.
!
! !USES:
    use clmtype
    use decompMod , only : get_proc_clumps, get_clump_bounds
!
! !ARGUMENTS:
    implicit none
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! 2004.04.27 DGVM naturally-vegetated filter added by Forrest Hoffman
!
!EOP
!
! LOCAL VARAIBLES:
    integer :: nc          ! clump index
    integer :: nclumps     ! total number of clumps on this processor
    integer :: begp, endp  ! per-clump beginning and ending pft indices
    integer :: begc, endc  ! per-clump beginning and ending column indices
    integer :: begl, endl  ! per-clump beginning and ending landunit indices
    integer :: begg, endg  ! per-clump beginning and ending gridcell indices
    integer :: ier         ! error status
!------------------------------------------------------------------------

    ! Determine clump variables for this processor

    nclumps = get_proc_clumps()
    ier = 0
    if( .not. allocated(filter)) then
       allocate(filter(nclumps), stat=ier)
    end if
    if (ier /= 0) then
       write(iulog,*) 'allocFilters(): allocation error for clumpsfilters'
       call endrun
    end if

    ! Loop over clumps on this processor

!$OMP PARALLEL DO PRIVATE (nc,begg,endg,begl,endl,begc,endc,begp,endp)
    do nc = 1, nclumps
       call get_clump_bounds(nc, begg, endg, begl, endl, begc, endc, begp, endp)

       allocate(filter(nc)%lakep(endp-begp+1))
       allocate(filter(nc)%nolakep(endp-begp+1))
       allocate(filter(nc)%nolakeurbanp(endp-begp+1))

       allocate(filter(nc)%lakec(endc-begc+1))
       allocate(filter(nc)%nolakec(endc-begc+1))

       allocate(filter(nc)%soilc(endc-begc+1))
       allocate(filter(nc)%soilp(endp-begp+1))

       allocate(filter(nc)%snowc(endc-begc+1))
       allocate(filter(nc)%nosnowc(endc-begc+1))

#if (defined CNDV)
       allocate(filter(nc)%natvegp(endp-begp+1))
#endif

       allocate(filter(nc)%hydrologyc(endc-begc+1))

       allocate(filter(nc)%urbanp(endp-begp+1))
       allocate(filter(nc)%nourbanp(endp-begp+1))

       allocate(filter(nc)%urbanc(endc-begc+1))
       allocate(filter(nc)%nourbanc(endc-begc+1))

       allocate(filter(nc)%urbanl(endl-begl+1))
       allocate(filter(nc)%nourbanl(endl-begl+1))

    end do
!$OMP END PARALLEL DO

  end subroutine allocFilters

!------------------------------------------------------------------------
!BOP
!
! !IROUTINE: setFilters
!
! !INTERFACE:

  subroutine setFilters() 3,5
!
! !DESCRIPTION:
! Set CLM filters.
!
! !USES:
    use clmtype
    use decompMod , only : get_proc_clumps, get_clump_bounds
    use clm_varcon, only : istsoil, isturb, icol_road_perv, istice_mec
!
! !ARGUMENTS:
    implicit none
!
! !REVISION HISTORY:
! Created by Mariana Vertenstein
! 2004.04.27 DGVM naturally-vegetated filter added by Forrest Hoffman
! 2005.09.12 Urban related filters added by Mariana Vertenstein
!
!EOP
!
! LOCAL VARAIBLES:
    integer , pointer :: ctype(:) ! column type
    integer :: nc          ! clump index
    integer :: c,l,p       ! column, landunit, pft indices
    integer :: nclumps     ! total number of clumps on this processor
    integer :: fl          ! lake filter index
    integer :: fnl,fnlu    ! non-lake filter index
    integer :: fs          ! soil filter index
    integer :: f, fn       ! general indices
    integer :: begp, endp  ! per-clump beginning and ending pft indices
    integer :: begc, endc  ! per-clump beginning and ending column indices
    integer :: begl, endl  ! per-clump beginning and ending landunit indices
    integer :: begg, endg  ! per-clump beginning and ending gridcell indices
!------------------------------------------------------------------------

    ctype => clm3%g%l%c%itype

    ! Loop over clumps on this processor

    nclumps = get_proc_clumps()
!$OMP PARALLEL DO PRIVATE (nc,begg,endg,begl,endl,begc,endc,begp,endp,f,fn,fl,fnl,fnlu,fs,p,c,l)
    do nc = 1,nclumps

       ! Determine clump boundaries

       call get_clump_bounds(nc, begg, endg, begl, endl, begc, endc, begp, endp)

       ! Create lake and non-lake filters at column-level 

       fl = 0
       fnl = 0
       do c = begc,endc
          l = clm3%g%l%c%landunit(c)
          if (clm3%g%l%lakpoi(l)) then
             fl = fl + 1
             filter(nc)%lakec(fl) = c
          else
             fnl = fnl + 1
             filter(nc)%nolakec(fnl) = c
          end if
       end do
       filter(nc)%num_lakec = fl
       filter(nc)%num_nolakec = fnl

       ! Create lake and non-lake filters at pft-level 
       ! Filter will only be active if weight of pft wrt gcell is nonzero

       fl = 0
       fnl = 0
       fnlu = 0
       do p = begp,endp
          l = clm3%g%l%c%p%landunit(p)
          if (clm3%g%l%c%p%wtgcell(p) > 0._r8    &
                      .or.                       &
              clm3%g%l%itype(l)==istice_mec) then  ! some glacier_mec columns have zero weight

             l = clm3%g%l%c%p%landunit(p)
             if (clm3%g%l%lakpoi(l) ) then
                fl = fl + 1
                filter(nc)%lakep(fl) = p
             else
                fnl = fnl + 1
                filter(nc)%nolakep(fnl) = p
                if (clm3%g%l%itype(l) /= isturb) then
                   fnlu = fnlu + 1
                   filter(nc)%nolakeurbanp(fnlu) = p
                end if
             end if
          end if
       end do
       filter(nc)%num_lakep = fl
       filter(nc)%num_nolakep = fnl
       filter(nc)%num_nolakeurbanp = fnlu

       ! Create soil filter at column-level

       fs = 0
       do c = begc,endc
          l = clm3%g%l%c%landunit(c)
          if (clm3%g%l%itype(l) == istsoil) then
             fs = fs + 1
             filter(nc)%soilc(fs) = c
          end if
       end do
       filter(nc)%num_soilc = fs

       ! Create soil filter at pft-level
       ! Filter will only be active if weight of pft wrt gcell is nonzero

       fs = 0
       do p = begp,endp
          if (clm3%g%l%c%p%wtgcell(p) > 0._r8) then
             l = clm3%g%l%c%p%landunit(p)
             if (clm3%g%l%itype(l) == istsoil) then
                fs = fs + 1
                filter(nc)%soilp(fs) = p
             end if
          end if
       end do
       filter(nc)%num_soilp = fs

       ! Create column-level hydrology filter (soil and Urban pervious road cols) 

       f = 0
       do c = begc,endc
          l = clm3%g%l%c%landunit(c)
          if (clm3%g%l%itype(l) == istsoil .or. ctype(c) == icol_road_perv ) then
             f = f + 1
             filter(nc)%hydrologyc(f) = c
          end if
       end do
       filter(nc)%num_hydrologyc = f

       ! Create landunit-level urban and non-urban filters

       f = 0
       fn = 0
       do l = begl,endl
          if (clm3%g%l%itype(l) == isturb) then
             f = f + 1
             filter(nc)%urbanl(f) = l
          else
             fn = fn + 1
             filter(nc)%nourbanl(fn) = l
          end if
       end do
       filter(nc)%num_urbanl = f
       filter(nc)%num_nourbanl = fn

       ! Create column-level urban and non-urban filters

       f = 0
       fn = 0
       do c = begc,endc
          l = clm3%g%l%c%landunit(c)
          if (clm3%g%l%itype(l) == isturb) then
             f = f + 1
             filter(nc)%urbanc(f) = c
          else
             fn = fn + 1
             filter(nc)%nourbanc(fn) = c
          end if
       end do
       filter(nc)%num_urbanc = f
       filter(nc)%num_nourbanc = fn

       ! Create pft-level urban and non-urban filters

       f = 0
       fn = 0
       do p = begp,endp
          l = clm3%g%l%c%p%landunit(p)
          if (clm3%g%l%itype(l) == isturb .and. clm3%g%l%c%p%wtgcell(p) > 0._r8) then
             f = f + 1
             filter(nc)%urbanp(f) = p
          else
             fn = fn + 1
             filter(nc)%nourbanp(fn) = p 
          end if
       end do
       filter(nc)%num_urbanp = f
       filter(nc)%num_nourbanp = fn

       ! Note: snow filters are reconstructed each time step in Hydrology2
       ! Note: CNDV "pft present" filter is reconstructed each time CNDV is run

    end do
!$OMP END PARALLEL DO

  end subroutine setFilters

end module filterMod