#include <misc.h>
#include <params.h>

      subroutine radclw(lat     ,lwupcgs ,tnm     ,qnm     ,o3vmr   , 2,12
     $                  pmid    ,pint    ,pmln    ,piln    ,plco2   ,
     $                  plh2o   ,n2o     ,ch4     ,cfc11   ,cfc12   ,
     $                  cld     ,tclrsf  ,qrl     ,flns    ,flnt    ,
     $                  flnsc   ,flntc   ,flwds   )
C-----------------------------------------------------------------------
C
C Compute longwave radiation heating rates and boundary fluxes
C
C Uses broad band absorptivity/emissivity method to compute clear sky;
C assumes randomly overlapped clouds with variable cloud emissivity to
C include effects of clouds.
C
C Computes clear sky absorptivity/emissivity at lower frequency (in
C general) than the model radiation frequency; uses previously computed
C and stored values for efficiency
C
C Note: This subroutine contains vertical indexing which proceeds
C       from bottom to top rather than the top to bottom indexing 
C       used in the rest of the model.
C
C---------------------------Code history--------------------------------
C
C Original version:  CCM1
C Standardized:      J. Rosinski, June 1992
C Reviewed:          J. Kiehl, B. Briegleb, August 1992
C Reviewed:          J. Kiehl, April 1996
C Reviewed:          B. Briegleb, May 1996
C
C-----------------------------------------------------------------------
c
c $Id: radclw.F,v 1.1.20.3 2000/02/25 21:24:11 zender Exp $
c
#include <implicit.h>
C------------------------------Parameters-------------------------------
#include <prgrid.h>
#include <pagrid.h>
C-----------------------------------------------------------------------
      integer plevp2,plevp3,plevp4
      parameter (plevp2=plev+2,plevp3=plev+3,plevp4=plev+4)
C------------------------------Commons----------------------------------
#include <comlun.h>
C-----------------------------------------------------------------------
#include <comtim.h>
C-----------------------------------------------------------------------
#include <crdcon.h>
C-----------------------------------------------------------------------
#include <comctl.h>
C-----------------------------------------------------------------------
#include <coreiorad.h>
C------------------------------Arguments--------------------------------
c++csz
#ifdef CRM_SRB
#include <crmsrb.h>
#endif /* not CRM_SRB */
c--csz
C
C Input arguments
C
      integer lat               ! Model latitude index

      real lwupcgs(plond)       ! Longwave up flux in CGS units
C
C Input arguments which are only passed to other routines
C
      real tnm(plond,plev)      ! Level temperature
      real qnm(plond,plev)      ! Level moisture field
      real o3vmr(plond,plev)    ! ozone volume mixing ratio
      real pmid(plond,plev)     ! Level pressure
      real pint(plond,plevp)    ! Model interface pressure
      real pmln(plond,plev)     ! Ln(pmid)
      real piln(plond,plevp)    ! Ln(pint)
      real plco2(plond,plevp)   ! Path length co2
      real plh2o(plond,plevp)   ! Path length h2o
      real n2o(plond,plev)      ! nitrous oxide mass mixing ratio
      real ch4(plond,plev)      ! methane mass mixing ratio
      real cfc11(plond,plev)    ! cfc11 mass mixing ratio
      real cfc12(plond,plev)    ! cfc12 mass mixing ratio
C                               
C Input/Output arguments        
C                               
      real cld(plond,plevp)     ! Cloud cover
      real tclrsf(plond,plevp)  ! Clear sky fraction
C                               
C Output arguments              
C                               
      real qrl(plond,plev)      ! Longwave heating rate
      real flns(plond)          ! Surface cooling flux
      real flnt(plond)          ! Net outgoing flux
      real flnsc(plond)         ! Clear sky surface cooing
      real flntc(plond)         ! Net clear sky outgoing flux
      real flwds(plond)         ! Down longwave flux at surface
C
C---------------------------Local variables-----------------------------
C
      integer i,ii              ! Longitude indices
      integer k                 ! Level index
      integer k1                ! Level index
      integer k2                ! Level index
      integer k3                ! Level index
      integer km                ! Level index
      integer km1               ! Level index
      integer km2               ! Level index
      integer km3               ! Level index
      integer km4               ! Level index
C                               
      real tmp(plond)           ! Temporary workspace
      real tmp1                 ! Temporary 1
      real absbt(plond)         ! Downward emission at model top
      real plol(plond,plevp)    ! O3 pressure wghted path length
      real plos(plond,plevp)    ! O3 path length
      real co2em(plond,plevp)   ! Layer co2 normalized planck funct. derivative
      real co2eml(plond,plev)   ! Interface co2 normalized planck funct. deriv.
      real delt(plond)          ! Diff t**4 mid layer to top interface
      real delt1(plond)         ! Diff t**4 lower intrfc to mid layer
      real bk1(plond)           ! Absrptvty for vertical quadrature
      real bk2(plond)           ! Absrptvty for vertical quadrature
      real ful(plond,plevp)     ! Total upwards longwave flux
      real fsul(plond,plevp)    ! Clear sky upwards longwave flux
      real fdl(plond,plevp)     ! Total downwards longwave flux
      real fsdl(plond,plevp)    ! Clear sky downwards longwv flux
      real fclb4(plond,plev)    ! Sig t**4 for cld bottom interfc
      real fclt4(plond,plev)    ! Sig t**4 for cloud top interfc
      real s(plond,plevp,plevp) ! Flx integral sum
      real tplnka(plond,plevp)  ! Planck fnctn temperature
      real s2c(plond,plevp)     ! H2o cont amount
      real s2t(plond,plevp)     ! H2o cont temperature
      real w(plond,plevp)       ! H2o path
      real tplnke(plond)        ! Planck fnctn temperature
      real h2otr(plond,plevp)   ! H2o trnmsn for o3 overlap
      real co2t(plond,plevp)    ! Prs wghted temperature path
      real tint(plond,plevp)    ! Interface temperature
      real tint4(plond,plevp)   ! Interface temperature**4
      real tlayr(plond,plevp)   ! Level temperature
      real tlayr4(plond,plevp)  ! Level temperature**4
      real rtclrsf(plond,plevp) ! 1./tclrsf(i,k)
      real gocp                 ! gravit/cpair

      integer klov(plond)       ! Cloud lowest level index
      integer khiv(plond)       ! Cloud highest level index
      integer khivm(plond)      ! khiv(i) - 1
      integer indx(plond)       ! index vector of gathered array values
      integer npts              ! number of values satisfying some criterion
      integer khighest          ! indx of highest level for some criterion

      logical done(plond)       ! some criterion has been satisfied
      logical start(plond)      ! begin some test

      pointer (pabsems,absems)
      pointer (pabsnxt,absnxt(plond,plev,4))
      pointer (pabstot,abstot(plond,plevp,plevp))
      pointer (pemstot,emstot(plond,plevp))

      real absems(plngbuf)      ! Absorbs's and emiss's in buffer
      real absnxt               ! Nearest layer absorptivities
      real abstot               ! Non-adjacent layer absorptivites
      real emstot               ! Total emissivity
c
c Trace gas variables
c
      real ucfc11(plond,plevp)  ! CFC11 path length
      real ucfc12(plond,plevp)  ! CFC12 path length
      real un2o0(plond,plevp)   ! N2O path length
      real un2o1(plond,plevp)   ! N2O path length (hot band)
      real uch4(plond,plevp)    ! CH4 path length
      real uco211(plond,plevp)  ! CO2 9.4 micron band path length
      real uco212(plond,plevp)  ! CO2 9.4 micron band path length
      real uco213(plond,plevp)  ! CO2 9.4 micron band path length
      real uco221(plond,plevp)  ! CO2 10.4 micron band path length
      real uco222(plond,plevp)  ! CO2 10.4 micron band path length
      real uco223(plond,plevp)  ! CO2 10.4 micron band path length
      real bn2o0(plond,plevp)   ! pressure factor for n2o
      real bn2o1(plond,plevp)   ! pressure factor for n2o
      real bch4(plond,plevp)    ! pressure factor for ch4
      real uptype(plond,plevp)  ! p-type continuum path length
      real abplnk1(14,plond,plevp)  ! non-nearest layer Plack factor
      real abplnk2(14,plond,plevp)  ! nearest layer factor
C
C
C------------------------------Externals--------------------------------
C
      integer intmax
      external intmax
C
C-----------------------------------------------------------------------
C
C Set pointer variables
C
      if (incorrad) then
        pabsems = loc(bigbufc(1,lat))
      else
        call getmem('RADCLW  ',plngbuf,pabsems)
      endif
      pabstot = loc(absems(1                                   ))
      pabsnxt = loc(absems(1 + plond*plevp*plevp               ))
      pemstot = loc(absems(1 + plond*plevp*plevp + plond*plev*4))
C
C Initialize and recompute the tclrsf array
C
      do i=1,plon
        rtclrsf(i,1) = 1.0/tclrsf(i,1)
      end do 
C
      do k=1,plev
        do i=1,plon
          fclb4(i,k) = 0.
          fclt4(i,k) = 0.
          tclrsf(i,k+1) = tclrsf(i,k)*(1. - cld(i,k+1))
          rtclrsf(i,k+1) = 1./tclrsf(i,k+1)
        end do
      end do
C
C Calculate some temperatures needed to derive absorptivity and
C emissivity, as well as some h2o path lengths
C
      call radtpl(tnm     ,lwupcgs ,qnm     ,pint    ,plh2o   ,
     $            tplnka  ,s2c     ,s2t     ,w       ,tplnke  ,
     $            tint    ,tint4   ,tlayr   ,tlayr4  ,pmln    ,
     $            piln    )
      if (doabsems) then
C
C Compute ozone path lengths at frequency of a/e calculation.
C
        call radoz2(o3vmr   ,pint    ,plol    ,plos    )
c
c Compute trace gas path lengths
c
        call trcpth(tnm     ,pint    ,cfc11   ,cfc12   ,n2o     ,
     $              ch4     ,qnm     ,ucfc11  ,ucfc12  ,un2o0   ,
     $              un2o1   ,uch4    ,uco211  ,uco212  ,uco213  ,
     $              uco221  ,uco222  ,uco223  ,bn2o0   ,bn2o1   ,
     $              bch4    ,uptype  )
C
C
C Compute total emissivity:
C
        call radems(s2c     ,s2t     ,w       ,tplnke  ,plh2o   ,
     $              pint    ,plco2   ,tint    ,tint4   ,tlayr   ,
     $              tlayr4  ,plol    ,plos    ,ucfc11  ,ucfc12  , 
     $              un2o0   ,un2o1   ,uch4    ,uco211  ,uco212  ,
     $              uco213  ,uco221  ,uco222  ,uco223  ,uptype  ,
     $              bn2o0   ,bn2o1   ,bch4    ,co2em   ,co2eml  ,
     $              co2t    ,h2otr   ,abplnk1 ,abplnk2 ,emstot  )
C
C Compute total absorptivity:
C
        call radabs(pmid    ,pint    ,co2em   ,co2eml  ,tplnka  ,
     $              s2c     ,s2t     ,w       ,h2otr   ,plco2   ,
     $              plh2o   ,co2t    ,tint    ,tlayr   ,plol    ,
     $              plos    ,pmln    ,piln    ,ucfc11  ,ucfc12  , 
     $              un2o0   ,un2o1   ,uch4    ,uco211  ,uco212  ,
     $              uco213  ,uco221  ,uco222  ,uco223  ,uptype  ,
     $              bn2o0   ,bn2o1   ,bch4    ,abplnk1 ,abplnk2 ,
     $              abstot  ,absnxt  )
C
C Write abs/ems info to ssd when out-of-core.
C
        if (.not.incorrad) then
          call writeric(nabem   ,absems(1),plngbuf ,lat     )
        endif
      else
C
C Get total abs/ems info from ssd when out-oc-core.
C
        if (.not.incorrad) then
          call readric(nabem   ,absems(1),plngbuf ,lat     )
        endif
      end if
C
C Find the lowest and highest level cloud for each grid point
C Note: Vertical indexing here proceeds from bottom to top
C
      do i=1,plon
        klov(i) = 0
        done(i) = .false.
      end do
      do k=1,plev
        do i=1,plon
          if (.not.done(i) .and. cld(i,plevp2-k).gt.0.0) then
            done(i) = .true.
            klov(i) = k
          end if
        end do
      end do
      call whenne(plon,klov,1,0,indx,npts)
      do i=1,plon
        khiv(i) = klov(i)
        done(i) = .false.
      end do
      do k=plev,1,-1
CDIR$ IVDEP
        do ii=1,npts
          i=indx(ii)
          if (.not.done(i) .and. cld(i,plevp2-k).gt.0.0) then
            done(i) = .true.
            khiv(i) = k
          end if
        end do
      end do
      do i=1,plon
        khivm(i) = khiv(i) - 1
      end do
C
C Note: Vertical indexing here proceeds from bottom to top
C
      do ii=1,npts
        i=indx(ii)
        do k=klov(i),khiv(i)
          fclt4(i,plevp-k) = stebol*tint4(i,plevp2-k)
          fclb4(i,plevp-k) = stebol*tint4(i,plevp3-k)
        end do
      end do
C
C Compute sums used in integrals (all longitude points)
C
C Definition of bk1 & bk2 depends on finite differencing.  for
C trapezoidal rule bk1=bk2. trapezoidal rule applied for nonadjacent
C layers only.
C
C delt=t**4 in layer above current sigma level km.
C delt1=t**4 in layer below current sigma level km.
C
      do i=1,plon
        delt(i) = tint4(i,plev) - tlayr4(i,plevp)
        delt1(i) = tlayr4(i,plevp) - tint4(i,plevp)
        s(i,plevp,plevp) = stebol*(delt1(i)*absnxt(i,plev,1) +
     $                             delt (i)*absnxt(i,plev,4))
        s(i,plev,plevp)  = stebol*(delt (i)*absnxt(i,plev,2) +
     $                             delt1(i)*absnxt(i,plev,3))
      end do
      do k=1,plev-1
        do i=1,plon
          bk2(i) = (abstot(i,k,plev) + abstot(i,k,plevp))*0.5
          bk1(i) = bk2(i)
          s(i,k,plevp) = stebol*(bk2(i)*delt(i) + bk1(i)*delt1(i))
        end do
      end do
C
C All k, km>1
C
      do km=plev,2,-1
        do i=1,plon
          delt(i)  = tint4(i,km-1) - tlayr4(i,km)
          delt1(i) = tlayr4(i,km) - tint4(i,km)
        end do
        do k=plevp,1,-1
          if (k.eq.km) then
            do i=1,plon
              bk2(i) = absnxt(i,km-1,4)
              bk1(i) = absnxt(i,km-1,1)
            end do
          else if(k.eq.km-1) then
            do i=1,plon
              bk2(i) = absnxt(i,km-1,2)
              bk1(i) = absnxt(i,km-1,3)
            end do
          else
            do i=1,plon
              bk2(i) = (abstot(i,k,km-1) + abstot(i,k,km))*0.5
              bk1(i) = bk2(i)
            end do
          end if
          do i=1,plon
            s(i,k,km) = s(i,k,km+1) + stebol*
     $                  (bk2(i)*delt(i) + bk1(i)*delt1(i))
          end do
        end do
      end do
C
C Computation of clear sky fluxes always set first level of fsul
C
      do i=1,plon
        fsul(i,plevp) = lwupcgs(i)
      end do
C
C Downward clear sky fluxes store intermediate quantities in down flux
C Initialize fluxes to clear sky values.
C
      do i=1,plon
        tmp(i) = fsul(i,plevp) - stebol*tint4(i,plevp)
        fsul(i,1) = fsul(i,plevp) - abstot(i,1,plevp)*tmp(i) + s(i,1,2)
        fsdl(i,1) = stebol*(tplnke(i)**4)*emstot(i,1)
        ful(i,1) = fsul(i,1)
        fdl(i,1) = fsdl(i,1)
      end do
C
C fsdl(i,plevp) assumes isothermal layer
C
      do k=2,plev
        do i=1,plon
          fsul(i,k) = fsul(i,plevp) - abstot(i,k,plevp)*tmp(i) +
     $                  s(i,k,k+1)
          ful(i,k) = fsul(i,k)
          fsdl(i,k) = stebol*(tplnke(i)**4)*emstot(i,k) -
     $                (s(i,k,2) - s(i,k,k+1))
          fdl(i,k) = fsdl(i,k)
        end do
      end do
C
C Store the downward emission from level 1 = total gas emission * sigma
C t**4.  fsdl does not yet include all terms
C
      do i=1,plon
        ful(i,plevp) = fsul(i,plevp)
        absbt(i) = stebol*(tplnke(i)**4)*emstot(i,plevp)
        fsdl(i,plevp) = absbt(i) - s(i,plevp,2)
        fdl(i,plevp) = fsdl(i,plevp)
      end do
C
C Modifications for clouds
C
C Further qualify longitude subset for computations.  Select only those
C locations where there are clouds (total cloud fraction <= 1.e-3 treated 
C as clear)
C
      call whenflt(plon,tclrsf(1,plevp),1,0.999,indx,npts)
C
C Compute downflux at level 1 for cloudy sky
C
      do ii=1,npts
        i=indx(ii)
C
C First clear sky flux plus flux from cloud at level 1
C
        fdl(i,plevp) = fsdl(i,plevp)*tclrsf(i,plev)*
     $         rtclrsf(i,plevp-khiv(i)) + fclb4(i,plev-1)*cld(i,plev)
      end do
C
C Flux emitted by other layers
C Note: Vertical indexing here proceeds from bottom to top
C
      khighest = khiv(intmax(plon,khiv,1))
      do km=3,khighest
        km1 = plevp - km
        km2 = plevp2 - km
        km4 = plevp4 - km
CDIR$ IVDEP
        do ii=1,npts
          i=indx(ii)
          if (km.le.khiv(i)) then
            tmp1 = cld(i,km2)*tclrsf(i,plev)*rtclrsf(i,km2)
            fdl(i,plevp) = fdl(i,plevp) +
     $                       (fclb4(i,km1) - s(i,plevp,km4))*tmp1
          end if
        end do
      end do
C
C Note: Vertical indexing here proceeds from bottom to top
C
      do k=1,khighest-1
        k1 = plevp - k
        k2 = plevp2 - k
        k3 = plevp3 - k
CDIR$ IVDEP
        do ii=1,npts
          i=indx(ii)
          if (k.ge.klov(i) .and. k.le.khivm(i)) then
            ful(i,k2) = fsul(i,k2)*(tclrsf(i,plevp)*rtclrsf(i,k1))
          end if
        end do
        do km=1,k
          km1 = plevp - km
          km2 = plevp2 - km
          km3 = plevp3 - km
CDIR$ IVDEP
          do ii=1,npts
            i=indx(ii)
            if (k.le.khivm(i) .and. km.ge.klov(i) .and.
     $          km.le.khivm(i)) then
c
              ful(i,k2) = ful(i,k2) +
     $                   (fclt4(i,km1) + s(i,k2,k3) - s(i,k2,km3))*
     $                   cld(i,km2)*(tclrsf(i,km1)*rtclrsf(i,k1))
            end if
          end do
        end do                  ! km=1,k
      end do                    ! k=1,khighest-1
C
      do k=1,plevp
        k2 = plevp2 - k
        k3 = plevp3 - k
        do i=1,plon
          start(i) = .false.
        end do
CDIR$ IVDEP
        do ii=1,npts
          i=indx(ii)
          if (k.ge.khiv(i)) then
            start(i) = .true.
            ful(i,k2) = fsul(i,k2)*tclrsf(i,plevp)*
     $                 rtclrsf(i,plevp-khiv(i))
          end if
        end do
        do km=1,khighest
          km1 = plevp - km
          km2 = plevp2 - km
          km3 = plevp3 - km
CDIR$ IVDEP
          do ii=1,npts
            i=indx(ii)
            if (start(i) .and. km.ge.klov(i) .and. km.le.khiv(i)) then
              ful(i,k2) = ful(i,k2)  +
     $           (cld(i,km2)*tclrsf(i,km1)*rtclrsf(i,plevp-khiv(i)))*
     $           (fclt4(i,km1) + s(i,k2,k3) - s(i,k2,km3))
            end if
          end do
        end do                  ! km=1,khighest
      end do                    ! k=1,plevp
C
C Computation of the downward fluxes
C
      do k=2,khighest-1
        k1 = plevp - k
        k2 = plevp2 - k
        k3 = plevp3 - k
CDIR$ IVDEP
        do ii=1,npts
          i=indx(ii)
          if (k.le.khivm(i)) fdl(i,k2) = 0.
        end do
        do km=k+1,khighest
          km1 = plevp - km
          km2 = plevp2 - km
          km4 = plevp4 - km
CDIR$ IVDEP
          do ii=1,npts
            i=indx(ii)
            if (k.le.khiv(i) .and. km.ge.max0(k+1,klov(i)) .and.
     $          km.le.khiv(i)) then
C
              fdl(i,k2) = fdl(i,k2) +
     $                 (cld(i,km2)*tclrsf(i,k1)*rtclrsf(i,km2))*
     $                 (fclb4(i,km1) - s(i,k2,km4) + s(i,k2,k3))
            end if
          end do
        end do                  ! km=k+1,khighest
CDIR$ IVDEP
        do ii=1,npts
          i=indx(ii)
          if (k.le.khivm(i)) then
            fdl(i,k2) = fdl(i,k2) + fsdl(i,k2)*
     $                 (tclrsf(i,k1)*rtclrsf(i,plevp-khiv(i)))
          end if
        end do
      end do                    ! k=1,khighest-1
C
C End cloud modification loops
C
C All longitudes: store history tape quantities
C
      do i=1,plon
C
C Downward longwave flux
C
        flwds(i) = fdl(i,plevp)
C
C Net flux
C
        flns(i) = ful(i,plevp) - fdl(i,plevp)
C
C Clear sky flux at top of atmosphere
C
c++csz
c     Following line is CCM2-CCM3 definition of clear sky OLR
c     This definition differs from analogous flnt definition by emission of layer 0
c     This will be superseded in CCM4
        flntc(i) = fsul(i,1)
c     Following line defines clear sky OLR exactly analogously to all sky OLR
c     This produces exact agreement between FLNT and FLNTC for clear skies
c     This will be adopted in CCM4
c        flntc(i) = fsul(i,1) - fsdl(i,1)
c--csz
        flnsc(i) = fsul(i,plevp) - fsdl(i,plevp)
C
C Outgoing ir
C
        flnt(i) = ful(i,1) - fdl(i,1)
      end do
C
C Computation of longwave heating (k per sec)
C
      gocp = gravit/cpair
      do k=1,plev
        do i=1,plon
          qrl(i,k) = (ful(i,k) - fdl(i,k) - ful(i,k+1) + fdl(i,k+1))*
     $              gocp/((pint(i,k) - pint(i,k+1)))
        end do
      end do
      if (.not.incorrad) then
        call freemem(pabsems)
      end if
C
c++csz
#ifdef CRM_SRB
      do k=1,plevp              ! NB: plevp not plev
         do i=1,plon
c     Vertical profile of broadband fluxes
            flx_LW_dwn(i,k)=fdl(i,k)*0.001 ! [W m-2] Downwelling LW flux
            flx_LW_up(i,k)=ful(i,k)*0.001 ! [W m-2] Upwelling LW flux
         enddo                  ! end loop over i, lon
      enddo                     ! end loop over k, lev
#endif /* not CRM_SRB */
c--csz
      return
      end