!-------------------------------------- LICENCE BEGIN ------------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer, 
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms 
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer 
!version 3 or (at your option) any later version that should be found at: 
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html 
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software; 
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec), 
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------
***S/P ISCCP_SIM - PART OF THE ISCCP CLOUD SIMULATOR PACKAGE
*

      SUBROUTINE ISCCP_SIM(tau, ptop,                                     ! OUTPUT 1
     1                     il1, il2, npoints, nlev, top_height,           ! INPUT
     2                  pfull, phalf, qv, frac_out, dtau_in, dem_in, at,
     3                  skt, emsfc_lw, sunlit)
      implicit none
*
*Author
*
*
*        Jason Cole Dec. 16, 2005
*
*Revisions
*
* 001
*
*Object
*
* There seems to three distinct parts in the original ISCCP simulator
* 1. Generation of subgrid columns
* 2. Computation of cloud top pressure and optical thickness for subcolumns
* 3. GCM grid results computed using results from 2.
* I have rewritten the code so that these functions are in seperate subroutines.
* In the process I have replace the cloud generator with that created by Raisasen
* and I have added the diagnostic of cloud inhomogeneity following some code
* from Robert Pincus.
* I have also modified the code so that it works on only 1 subcolumn at a time to
*  save memory
* Jason Cole Dec. 16, 2005	

* Copyright Steve Klein and Mark Webb 2002 - all rights reserved.
*
* This code is available without charge with the following conditions:
*
*  1. The code is available for scientific purposes and is not for 
*     commercial use.
*  2. Any improvements you make to the code should be made available 
*     to the to the authors for incorporation into a future release.
*  3. The code should not be used in any way that brings the authors 
*     or their employers into disrepute.

!     NOTE:   the maximum number of levels and columns is set by
!             the following parameter statement
      
!     -----
!     Input 
!     -----
      INTEGER il1, il2                  !  start and end point in horizontal
      INTEGER npoints                   !  number of model points in the horizontal
      INTEGER nlev                      !  number of model levels in column

      INTEGER sunlit(npoints)           !  1 for day points, 0 for night time


      REAL pfull(npoints,nlev)	      	!  pressure of full model levels (Pascals)
                                        !  pfull(npoints,1)    is    top level of model
                                        !  pfull(npoints,nlev) is bottom level of model

      REAL phalf(npoints,nlev+1)        !  pressure of half model levels (Pascals)
                                        !  phalf(npoints,1)    is    top       of model
                                        !  phalf(npoints,nlev+1) is the surface pressure

      REAL qv(npoints,nlev)             !  water vapor specific humidity (kg vapor/ kg air)
                                        !         on full model levels

      REAL dtau_in(npoints,nlev)        !  mean 0.67 micron optical depth of stratiform
					!  clouds in each model level
                                        !  NOTE:  this the cloud optical depth of only the
                                        !         cloudy part of the grid box, it is not weighted
                                        !         with the 0 cloud optical depth of the clear
                                        !         part of the grid box

      REAL frac_out(npoints,nlev)       ! Cloud mask 0 = no cloud, 1 = cloud


      INTEGER top_height                !  1 = adjust top height using both a computed
                                        !  infrared brightness temperature and the visible
					!  optical depth to adjust cloud top pressure. Note
					!  that this calculation is most appropriate to compare
					!  to ISCCP data during sunlit hours.
                                        !  2 = do not adjust top height, that is cloud top
                                        !  pressure is the actual cloud top pressure
                                        !  in the model
					!  3 = adjust top height using only the computed
					!  infrared brightness temperature. Note that this
					!  calculation is most appropriate to compare to ISCCP
					!  IR only algortihm (i.e. you can compare to nighttime
					!  ISCCP data with this option)

!
!     The following input variables are used only if top_height = 1 or top_height = 3
!
      REAL skt(npoints)                 !  skin Temperature (K)
      REAL emsfc_lw(npoints)            !  10.5 micron emissivity of surface (fraction)
      REAL at(npoints,nlev)             !  temperature in each model level (K)
      REAL dem_in(npoints,nlev)         !  10.5 micron longwave emissivity of stratiform
					!  clouds in each
                                        !  model level.  Same note applies as in dtau_in.
!     ------
!     Output
!     ------
      
      REAL tau(npoints)              !  optical thickness in each column
      
      REAL ptop(npoints)             !  cloud top pressure (mb) in each column

!
!     ------
!     Working variables added when program updated to mimic Mark Webb's PV-Wave code
!     ------


      REAL dem(npoints),bb(npoints)     !  working variables for 10.5 micron longwave 
					!  emissivity in part of
					!  gridbox under consideration

      REAL ptrop(npoints)
      REAL attrop(npoints)
      REAL attropmin (npoints)
      REAL atmax(npoints)
      REAL atmin(npoints)
      REAL btcmin(npoints)
      REAL transmax(npoints)

      INTEGER i,j,ilev,ibox,itrop(npoints)
      INTEGER match(npoints,nlev-1)
      INTEGER nmatch(npoints)
      INTEGER levmatch(npoints)
   
!variables needed for water vapor continuum absorption
      real fluxtop_clrsky(npoints),trans_layers_above_clrsky(npoints)
      real taumin(npoints)
      real dem_wv(npoints,nlev), wtmair, wtmh20, Navo, grav, pstd, t0
      real press(npoints), dpress(npoints), atmden(npoints)
      real rvh20(npoints), wk(npoints), rhoave(npoints)
      real rh20s(npoints), rfrgn(npoints)
      real tmpexp(npoints),tauwv(npoints)
      
      character*1 cchar(6),cchar_realtops(6)
      integer icycle
      REAL tb(npoints)
      REAL emcld(npoints)
      REAL fluxtop(npoints)
      REAL trans_layers_above(npoints)
      real isccp_taumin,fluxtopinit(npoints),tauir(npoints)

      integer num1,jj
      real rec2p13,tauchk

      character*10 ftn09

! Specific to GEM implementation
      REAL tmpexp2D(npoints),tmpexp3D(npoints,nlev)
      REAL tmplog2D(npoints),tmplog3D(npoints,nlev)

      DATA isccp_taumin / 0.3 /
      DATA cchar / ' ','-','1','+','I','+'/
      DATA cchar_realtops / ' ',' ','1','1','I','I'/

      tauchk = -1.*log(0.9999999)
      rec2p13=1./2.13

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

      if (top_height .eq. 1 .or. top_height .eq. 3) then 

      do j=il1, il2 !1,npoints 
          ptrop(j)=5000.
          atmin(j) = 400.
          attropmin(j) = 400.
          atmax(j) = 0.
          attrop(j) = 120.
          itrop(j) = 1
      enddo 

      do 12 ilev=1,nlev
        do j=il1, il2 !1,npoints 
         if (pfull(j,ilev) .lt. 40000. .and.
     &          pfull(j,ilev) .gt.  5000. .and.
     &          at(j,ilev) .lt. attropmin(j)) then
                ptrop(j) = pfull(j,ilev)
                attropmin(j) = at(j,ilev)
                attrop(j) = attropmin(j)
                itrop(j)=ilev
           end if
           if (at(j,ilev) .gt. atmax(j)) atmax(j)=at(j,ilev)
           if (at(j,ilev) .lt. atmin(j)) atmin(j)=at(j,ilev)
        enddo
12    continue

      end if

!
!     ---------------------------------------------------!
!     COMPUTE CLOUD OPTICAL DEPTH FOR EACH COLUMN and
!     put into vector tau
 
!initialize tau and albedocld to zero
        do j=il1, il2 !1,npoints 
            tau(j)=0.
        enddo

!compute total cloud optical depth for each column     
      do ilev=1,nlev
            !increment tau for each of the boxes
         do j=il1, il2 !1,npoints 
            if (frac_out(j,ilev).eq.1) then
               tau(j)=tau(j)
     &                    + dtau_in(j,ilev)
            endif
         enddo
      enddo ! ilev

!     ---------------------------------------------------!
!     COMPUTE INFRARED BRIGHTNESS TEMPERATURES
!     AND CLOUD TOP TEMPERATURE SATELLITE SHOULD SEE
!
!     again this is only done if top_height = 1 or 3
!
!     fluxtop is the 10.5 micron radiance at the top of the
!              atmosphere
!     trans_layers_above is the total transmissivity in the layers
!             above the current layer
!     fluxtop_clrsky(j) and trans_layers_above_clrsky(j) are the clear
!             sky versions of these quantities.

      if (top_height .eq. 1 .or. top_height .eq. 3) then


!----------------------------------------------------------------------
!    
!             DO CLEAR SKY RADIANCE CALCULATION FIRST
!
!compute water vapor continuum emissivity
!this treatment follows Schwarkzopf and Ramasamy
!JGR 1999,vol 104, pages 9467-9499.
!the emissivity is calculated at a wavenumber of 955 cm-1, 
!or 10.47 microns 
        wtmair = 28.9644
        wtmh20 = 18.01534
        Navo = 6.023E+23
        grav = 9.806650E+02
        pstd = 1.013250E+06
        t0 = 296.

! COMPUTE THE EXP ALL AT ONCE
        do ilev=1,nlev
          do j=il1, il2 !1,npoints
            tmpexp3D(j,ilev) = -0.02*(at(j,ilev)-t0)
          end do
        end do
        CALL VSEXP(tmpexp3D,tmpexp3D,nlev*(il2-il1+1))
   
        do 125 ilev=1,nlev
          do j=il1, il2 !1,npoints 
!press and dpress are dyne/cm2 = Pascals *10
               press(j) = pfull(j,ilev)*10.
               dpress(j) = (phalf(j,ilev+1)-phalf(j,ilev))*10
!atmden = g/cm2 = kg/m2 / 10 
               atmden(j) = dpress(j)/grav
               rvh20(j) = qv(j,ilev)*wtmair/wtmh20
               wk(j) = rvh20(j)*Navo*atmden(j)/wtmair
               rhoave(j) = (press(j)/pstd)*(t0/at(j,ilev))
               rh20s(j) = rvh20(j)*rhoave(j)
               rfrgn(j) = rhoave(j)-rh20s(j)
!               tmpexp(j) = exp(-0.02*(at(j,ilev)-t0))
               tauwv(j) = wk(j)*1.e-20*( 
     &           (0.0224697*rh20s(j)*tmpexp3D(j,ilev)) + 
     &                (3.41817e-7*rfrgn(j)) )*0.98
               dem_wv(j,ilev) = 1. - exp( -1. * tauwv(j))
          enddo
125     continue

!initialize variables
        do j=il1, il2 !1,npoints 
          fluxtop_clrsky(j) = 0.
          trans_layers_above_clrsky(j)=1.
        enddo

! COMPUTE THE EXP ALL AT ONCE
        do ilev=1,nlev
          do j=il1, il2 !1,npoints
            tmpexp3D(j,ilev) = 1307.27/at(j,ilev)
          end do
        end do
        CALL VSEXP(tmpexp3D,tmpexp3D,nlev*(il2-il1+1))

        do ilev=1,nlev
          do j=il1, il2 !1,npoints 
 
! Black body emission at temperature of the layer

!	        bb(j)=1 / ( exp(1307.27/at(j,ilev)) - 1. )
               bb(j)=1 / ( tmpexp3D(j,ilev) - 1. )
	        !bb(j)= 5.67e-8*at(j,ilev)**4

! increase TOA flux by flux emitted from layer
! times total transmittance in layers above

                fluxtop_clrsky(j) = fluxtop_clrsky(j) 
     &            + dem_wv(j,ilev)*bb(j)*trans_layers_above_clrsky(j) 
            
! update trans_layers_above with transmissivity
! from this layer for next time around loop

                trans_layers_above_clrsky(j)=
     &            trans_layers_above_clrsky(j)*(1.-dem_wv(j,ilev))
                   

          enddo   
        enddo   !loop over level

! COMPUTE THE EXP ALL AT ONCE
          do j=il1, il2 !1,npoints
            tmpexp2D(j) = 1307.27/skt(j)
          end do

        CALL VSEXP(tmpexp2D,tmpexp2D,(il2-il1+1))
        
        do j=il1, il2 !1,npoints 
!add in surface emission
!          bb(j)=1/( exp(1307.27/skt(j)) - 1. )
          bb(j)=1/( tmpexp2D(j) - 1. )
          !bb(j)=5.67e-8*skt(j)**4

          fluxtop_clrsky(j) = fluxtop_clrsky(j) + emsfc_lw(j) * bb(j) 
     &     * trans_layers_above_clrsky(j)
        enddo


!
!           END OF CLEAR SKY CALCULATION
!
!----------------------------------------------------------------

!loop over columns 
        do j=il1, il2 !1,npoints
           fluxtop(j)=0.
           trans_layers_above(j)=1.
        enddo

! COMPUTE THE EXP ALL AT ONCE
        do ilev=1,nlev
          do j=il1, il2 !1,npoints
            tmpexp3D(j,ilev) = 1307.27/at(j,ilev)
          end do
        end do
        CALL VSEXP(tmpexp3D,tmpexp3D,nlev*(il2-il1+1))

        do ilev=1,nlev
           do j=il1, il2 !1,npoints 
! Black body emission at temperature of the layer

!              bb(j)=1 / ( exp(1307.27/at(j,ilev)) - 1. )
              bb(j)=1 / ( tmpexp3D(j,ilev) - 1. )
             !bb(j)= 5.67e-8*at(j,ilev)**4
           enddo

           do j=il1, il2 !1,npoints 
             
! emissivity for point in this layer
              if (frac_out(j,ilev).eq.1) then
                 dem(j)= 1. - 
     &                ( (1. - dem_wv(j,ilev)) * (1. -  dem_in(j,ilev)) )
              else
                 dem(j)=  dem_wv(j,ilev)
              end if
                

! increase TOA flux by flux emitted from layer
! times total transmittance in layers above

              fluxtop(j) = fluxtop(j) 
     &                   + dem(j) * bb(j)
     &                   * trans_layers_above(j) 
            
! update trans_layers_above with transmissivity
! from this layer for next time around loop

              trans_layers_above(j)=
     &             trans_layers_above(j)*(1.-dem(j))
              
           enddo                ! j
        enddo                   ! ilev

! COMPUTE THE EXP ALL AT ONCE
          do j=il1, il2 !1,npoints
            tmpexp2D(j) = 1307.27/skt(j)
          end do
          CALL VSEXP(tmpexp2D,tmpexp2D,(il2-il1+1))

        do j=il1, il2 !1,npoints 
!add in surface emission
!           bb(j)=1/( exp(1307.27/skt(j)) - 1. )
           bb(j)=1/( tmpexp2D(j) - 1. )
          !bb(j)=5.67e-8*skt(j)**4
        end do

        do j=il1, il2 !1,npoints 

!add in surface emission

           fluxtop(j) = fluxtop(j) 
     &                + emsfc_lw(j) * bb(j) 
     &                * trans_layers_above(j) 
            
        end do

    
!now that you have the top of atmosphere radiance account
!for ISCCP procedures to determine cloud top temperature

!account for partially transmitting cloud recompute flux 
!ISCCP would see assuming a single layer cloud
!note choice here of 2.13, as it is primarily ice
!clouds which have partial emissivity and need the 
!adjustment performed in this section
!
!If it turns out that the cloud brightness temperature
!is greater than 260K, then the liquid cloud conversion
!factor of 2.56 is used.
!
!Note that this is discussed on pages 85-87 of 
!the ISCCP D level documentation (Rossow et al. 1996)

! COMPUTE THE EXP ALL AT ONCE
          do j=il1, il2 !1,npoints
            tmpexp2D(j) = 1307.27/(attrop(j)-5.)
          end do
          CALL VSEXP(tmpexp2D(il1),tmpexp2D(il1),(il2-il1+1))

          do j=il1, il2 !1,npoints  
!compute minimum brightness temperature and optical depth
!            btcmin(j) = 1. /  ( exp(1307.27/(attrop(j)-5.)) - 1. ) 
             btcmin(j) = 1. /  ( tmpexp2D(j) - 1. )   
          enddo 

          do j=il1, il2 !1,npoints  
             transmax(j) = (fluxtop(j)-btcmin(j))
     &                   /(fluxtop_clrsky(j)-btcmin(j))

!note that the initial setting of tauir(j) is needed so that
!tauir(j) has a realistic value should the next if block be
!bypassed
             tauir(j) = tau(j) * rec2p13
!             taumin(j) = -1.0*log(max(min(transmax(j),0.9999999),0.001))
             taumin(j) = max(min(transmax(j),0.9999999),0.001)             
          enddo 

          CALL VSLOG(taumin(il1),taumin(il1),(il2-il1+1))
          do j=il1, il2 !1,npoints
            taumin(j) = -1.0*taumin(j) 
          end do

          if (top_height .eq. 1) then
             do j=il1, il2 !1,npoints  
                if (transmax(j) .gt. 0.001 .and. 
     &               transmax(j) .le. 0.9999999) then
                   fluxtopinit(j) = fluxtop(j)
                   tauir(j) = tau(j) *rec2p13
                endif
             enddo
             do icycle=1,2

! COMPUTE THE EXP ALL AT ONCE
          do j=il1, il2 !1,npoints
            tmpexp2D(j) = -1. * tauir(j)
          end do
          CALL VSEXP(tmpexp2D(il1),tmpexp2D(il1),(il2-il1+1))

                do j=il1, il2 !1,npoints  
                   if (tau(j) .gt. (tauchk            )) then 
                      if (transmax(j) .gt. 0.001 .and. 
     &                     transmax(j) .le. 0.9999999) then
!                         emcld(j) = 1. - exp(-1. * tauir(j)  )
                         emcld(j) = 1. - tmpexp2D(j)
                         fluxtop(j) = fluxtopinit(j) -   
     &                        ((1.-emcld(j))*fluxtop_clrsky(j))
                         fluxtop(j)=max(1.E-06,
     &                        (fluxtop(j)/emcld(j)))
                         tb(j)= 1307.27
     &                             / (log(1. + (1./fluxtop(j))))
                         if (tb(j) .gt. 260.) then
                            tauir(j) = tau(j) / 2.56
                         end if			 
                      end if
                   end if
                enddo
             enddo
          endif
          
! COMPUTE THE LOG ALL AT ONCE (CLEAR AND CLOUDY SKY)
! CLOUDY COLUMNS
          do j=il1, il2 !1,npoints
            tmpexp2D(j) = 1. + (1./fluxtop(j))
          end do
          CALL VSLOG(tmpexp2D(il1),tmpexp2D(il1),(il2-il1+1))

! CLEAR COLUMNS
          do j=il1, il2 !1,npoints
            tmplog2D(j) = 1. + (1./fluxtop_clrsky(j))
          end do
          CALL VSLOG(tmplog2D(il1),tmplog2D(il1),(il2-il1+1))

          do j=il1, il2 !1,npoints
             if (tau(j) .gt. (tauchk            )) then 
!cloudy box
!                tb(j)= 1307.27/ (log(1. + (1./fluxtop(j))))
                tb(j)= 1307.27/ tmpexp2D(j)
                if (top_height.eq.1.and.tauir(j).lt.taumin(j)) then
                   tb(j) = attrop(j) - 5. 
                   tau(j) = 2.13*taumin(j)
                end if
             else
!clear sky brightness temperature
!                tb(j) = 1307.27/(log(1.+(1./fluxtop_clrsky(j))))
                tb(j) = 1307.27/tmplog2D(j)
             end if
          enddo                 ! j
          
      end if

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

!     
!     ---------------------------------------------------!
!     DETERMINE CLOUD TOP PRESSURE
!
!     again the 2 methods differ according to whether
!     or not you use the physical cloud top pressure (top_height = 2)
!     or the radiatively determined cloud top pressure (top_height = 1 or 3)
!

!segregate according to optical thickness
      if (top_height .eq. 1 .or. top_height .eq. 3) then  
!find level whose temperature
!most closely matches brightness temperature
         do j=il1, il2 !1,npoints 
            nmatch(j)=0
         enddo
         do 29 ilev=1,nlev-1
!cdir nodep
            do j=il1, il2 !1,npoints 
               if ((at(j,ilev)   .ge. tb(j) .and. 
     &              at(j,ilev+1) .lt. tb(j)) .or.
     &              (at(j,ilev) .le. tb(j) .and. 
     &              at(j,ilev+1) .gt. tb(j))) then 
   
                  nmatch(j)=nmatch(j)+1
                  if(abs(at(j,ilev)-tb(j)) .lt.
     &                 abs(at(j,ilev+1)-tb(j))) then
                     match(j,nmatch(j))=ilev
                  else
                     match(j,nmatch(j))=ilev+1
                  end if
               end if                        
            enddo
 29      continue

         do j=il1, il2 !1,npoints 
            if (nmatch(j) .ge. 1) then
               ptop(j)=pfull(j,match(j,nmatch(j)))
               levmatch(j)=match(j,nmatch(j))   
            else
               if (tb(j) .lt. atmin(j)) then
                  ptop(j)=ptrop(j)
                  levmatch(j)=itrop(j)
               end if
               if (tb(j) .gt. atmax(j)) then
                  ptop(j)=pfull(j,nlev)
                  levmatch(j)=nlev
               end if                                
            end if
         enddo                  ! j

      else                      ! if (top_height .eq. 1 .or. top_height .eq. 3) 
 
         do j=il1, il2 !1,npoints     
            ptop(j)=0.
         enddo
         do ilev=1,nlev
            do j=il1, il2 !1,npoints     
               if ((ptop(j) .eq. 0. )
     &              .and.(frac_out(j,ilev) .ne. 0)) then
                  ptop(j)=pfull(j,ilev)
                  levmatch(j)=ilev
               end if
            end do
         end do
      end if                            
      
      do j=il1, il2 !1,npoints
         if (tau(j) .le. (tauchk            )) then
            ptop(j)=0.
            levmatch(j)=0      
         endif 
      enddo

      return
      end