subroutine da_cloud_detect_airs(isensor,nchannels,ndim,kts,kte,n,iv) 1,2

!** *CLOUD_DETECT_AIRS* - CLOUD FLAGGING FOR AIRS AND IASI

!    AUTHOR: THOMAS AULIGNE      DATE : 01/08/2005
!
!    PURPOSE.
!    -------
!    FLAG THE PRESENCE OF CLOUD CONTAMINATION IN AIRS AND IASI CHANNELS
!
!**  INTERFACE.
!    ---------
!    WHERE nchannels    : Number of channels
!          kts          : model level corresponding to 100hPa (top of initial cloud search)
!          kte          : model level corresponding to surface (lower extent of cloud)            
!          rad_obs      : Potentially cloudy observations
!          rad_clr      : Clear radiance from Model
!          rad_ovc      : Model overcast radiance estimates
!          cloud_flag   : Cloud flag by channel; 1=clear, -1=cloudy
!
!**  EXTERNALS
!    ---------
!    N2QN1  - Minimization algorithm (double-precision constrained version of M1QN3)
!
!    MODIFICATIONS
!    -------------
!    NONE
!**  -----------------------------------------

IMPLICIT NONE

!* 0.1 Global arrays
INTEGER,INTENT(IN)    :: isensor             ! sensor index. 
INTEGER,INTENT(IN)    :: nchannels           ! number of channels 
INTEGER,INTENT(IN)    :: ndim                ! model levels between surface (lower extent of cloud) and 100hPa (top of cloud search)     
INTEGER,INTENT(IN)    :: kts                 ! model level corresponding to 100hPa (top of initial cloud search)
INTEGER,INTENT(IN)    :: kte                 ! model level corresponding to surface (lower extent of cloud)
INTEGER,INTENT(IN)    :: n                   ! pixel index 
type (iv_type), intent(inout)  :: iv         ! O-B structure.

INTEGER,PARAMETER     :: NITER             = 100
INTEGER,PARAMETER     :: NBAND             = 1
LOGICAL,PARAMETER     :: LPRECON           = .false.
INTEGER,PARAMETER     :: NEIGNVEC          = 4
INTEGER,PARAMETER     :: AIRS_Max_Channels = 2378

!! local declarations 
INTEGER               :: ichan(nchannels)    ! AIRS and IASI channel IDs
REAL                  :: rad_obs(nchannels)  ! Observed radiance
REAL                  :: rad_clr(nchannels)  ! Model clear radiance estimates
REAL                  :: rad_ovc(nchannels,ndim-1) ! RT overcast radiance estimates
double precision      :: px(ndim) !neignvec)        ! Cloud fractions
REAL                  :: rad_cld(nchannels)
INTEGER               :: ich,ilev,jlev,i,j,JBAND
double precision      :: ZF, ZF_CLR
double precision      :: ZG(ndim)
double precision      :: binf(ndim), bsup(ndim)
REAL                  :: AMAT(nchannels,ndim)
INTEGER               :: NCHAN
LOGICAL               :: LMATCH
INTEGER               :: Band_Size(5)
INTEGER               :: Bands(AIRS_Max_Channels,5) 
integer               :: cldtoplevel

! Hessian evaluation
 REAL                 :: hessian(ndim,ndim), eignvec(ndim,ndim), eignval(ndim)

!! local declarations for N2QN1 !!
INTEGER               :: NRZ, impres, io, IMODE, NSIM, nit, izs(2)
double precision      :: ZDF1, ZDXMIN, ZEPSG
double precision ,ALLOCATABLE :: ZRZ(:)
real, allocatable     :: RZS(:)
INTEGER, ALLOCATABLE  :: IZ(:)
DOUBLE PRECISION, ALLOCATABLE :: DZS(:)

REAL :: ZHOOK_HANDLE

! Initializations
      Band_Size(:)   = 0
      Bands(:,:)     = 0 
      Band_Size(1:5) = (/86, 0, 0, 16, 0 /)
 
      Bands(1:Band_Size(1),1) = &
&    (/                                                 &              !&      1,   6,   7,  10,  11,  15,  16,  17,  20,  21, &
&                                                       &              !&     22,  24,  27,  28,  30,  36,  39,  40,  42,  51, &
&                                                       &              !&     52,  54,  55,  56,  59,  62,  63,  68,  69,  71, &
&                                                       &              !&     72,  73,  74,  75,  76,  77,  78,  79,  80,  82, &
&                     92,  93,  98,  99, 101, 104, 105, &              !&     83,  84,  86,  92,  93,  98,  99, 101, 104, 105, &
&     108, 110, 111, 113, 116, 117, 123, 124, 128, 129, &
&     138, 139, 144, 145, 150, 151, 156, 157, 159, 162, &
&     165, 168, 169, 170, 172, 173, 174, 175, 177, 179, &
&     180, 182, 185, 186, 190, 192,      198, 201, 204, &              !&     180, 182, 185, 186, 190, 192, 193, 198, 201, 204, &
&     207, 210,      215, 216,      221,      226, 227, &              !&     207, 210, 213, 215, 216, 218, 221, 224, 226, 227, &
&     232,                     252, 253, 256, 257, 261, &              !&     232, 239, 248, 250, 251, 252, 253, 256, 257, 261, &
&     262, 267, 272, 295, 299,      305,           310, &              !&     262, 267, 272, 295, 299, 300, 305, 308, 309, 310, &
&          321, 325, 333, 338, 355, 362, 375, 453, 475, &              !&     318, 321, 325, 333, 338, 355, 362, 375, 453, 475, &
&     484, 497, 528, 587, 672, 787, 791, 843, 870, 914, &
&     950 /)

!      Bands(1:Band_Size(2),2) = &
!&    (/ 1003, 1012, 1019, 1024, 1030, 1038, 1048, 1069, 1079, 1082,  &
!&       1083, 1088, 1090, 1092, 1095, 1104, 1111, 1115, 1116, 1119,  &
!&       1120, 1123, 1130, 1138, 1142, 1178, 1199, 1206, 1221, 1237,  &
!&       1252, 1260, 1263, 1266, 1278, 1285 /)

!      Bands(1:Band_Size(3),3) = &
!&    (/       1301, 1304, 1329, 1371, 1382, 1415, 1424, 1449, 1455, &  !&    1290, 1301, 1304, 1329, 1371, 1382, 1415, 1424, 1449, 1455, &  
!&       1466,       1477,             1500, 1519,       1538, 1545, &  !&    1466, 1471, 1477, 1479, 1488, 1500, 1519, 1520, 1538, 1545, &  
!&       1565, 1574, 1583, 1593,       1627, 1636,       1652, 1669, &  !&    1565, 1574, 1583, 1593, 1614, 1627, 1636, 1644, 1652, 1669, & 
!&                   1694, 1708,       1723, 1740, 1748,       1756, &  !&    1674, 1681, 1694, 1708, 1717, 1723, 1740, 1748, 1751, 1756, &
!&             1766, 1771, 1777,       1783, 1794, 1800,       1806, &  !&    1763, 1766, 1771, 1777, 1780, 1783, 1794, 1800, 1803, 1806, &
!&             1826, 1843  /)                                           !&    1812, 1826, 1843  /)

      Bands(1:Band_Size(4),4) = &
&    (/ 1852, 1865, 1866,       1868, 1869, 1872, 1873,       1876, &  !&    1852, 1865, 1866, 1867, 1868, 1869, 1872, 1873, 1875, 1876, 
&             1881, 1882, 1883,                   1911, 1917, 1918, &  !&    1877, 1881, 1882, 1883, 1884, 1897, 1901, 1911, 1917, 1918, &
&                   1924, 1928        /)                               !&    1921, 1923, 1924, 1928, 1937  /)   

!      Bands(1:Band_Size(5),5) = &
!&    (/ 1938, 1939, 1941, 1946, 1947, 1948, 1958, 1971, 1973, 1988, &
!&       1995, 2084, 2085, 2097, 2098, 2099, 2100, 2101, 2103, 2104, &
!&       2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, &
!&       2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2128, 2134, &
!&       2141, 2145, 2149, 2153, 2164, 2189, 2197, 2209, 2226, 2234, &
!&       2280, 2318, 2321, 2325, 2328, 2333, 2339, 2348, 2353, 2355, &
!&       2363, 2370, 2371, 2377  /)  

    ichan        = iv%instid(isensor)%ichan(1:nchannels)
    rad_clr      = iv%instid(isensor)%rad_xb(1:nchannels,n)              !iv%instid(isensor)%tb_xb(1:nchan,n)
    rad_obs      = iv%instid(isensor)%rad_obs(1:nchannels,n)             !iv%instid(isensor)%tb_inv(1:nchan,n) + rad_clr
    rad_ovc      = iv%instid(isensor)%rad_ovc(1:nchannels,kts+1:kte,n)

    nchan        = 0
    AMAT(:,:)    = 0.0
    px(1:ndim-1) = 0.0
    px(ndim)     = 1.0
    ZF_CLR       = 0.0
    nit          = niter

!do ich=1,nchannels  
!   CALL CRTM_Planck_Radiance(11,ichan(ich),tb_obs(ich),rad_obs(ich))
!   CALL CRTM_Planck_Radiance(11,ichan(ich),tb_clr(ich),rad_clr(ich))
!end do                

    !--------------------!
    !   Loop over band   ! 
    !--------------------!
    BAND_LOOP: DO JBAND = 1, NBAND
      DO i = 1, Band_Size(JBAND)
        LMATCH = .FALSE.
        DO ich=1,nchannels        
          IF (ichan(ich)/= Bands(i,JBAND)) CYCLE 
          IF ((rad_obs(ich)<=0.0).OR.(rad_obs(ich)>1000.0)) CYCLE
          IF ((rad_clr(ich)<=0.0).OR.(rad_clr(ich)>1000.0)) CYCLE
          IF (ANY(rad_ovc(ich,1:NDIM-1)<=0.0)) CYCLE
          IF (ANY(rad_ovc(ich,1:NDIM-1)>1000.0)) CYCLE

          LMATCH               = .TRUE.    !! Found match for channel
          nchan                = nchan +1
          AMAT(nchan,1:ndim-1) = rad_ovc(ich,1:NDIM-1) / rad_obs(ich)
	  AMAT(nchan,ndim)     = rad_clr(ich) / rad_obs(ich)
          ZF_CLR               = ZF_CLR + 0.5*(AMAT(nchan,ndim)-1.0)**2   
        ENDDO
        IF (.NOT. LMATCH) WRITE(*,*) &
           'CLOUD_DETECT_AIRS: No matching for channel:',i,Bands(i,JBAND) 
      ENDDO	
    ENDDO BAND_LOOP                      ! Loop over band
    
    !--------------------!
    ! Hessian evaluation !
    !--------------------!
    IF (LPRECON) THEN
!      write(76,*) '**** HESSIAN ****'
      hessian(:,:)= 0.0      
      DO ilev=1, NDIM
        DO jlev=ilev, NDIM
          DO J=1,NCHAN
              hessian(ilev,jlev) = hessian(ilev,jlev)  + &
                                  (AMAT(J,ilev)-AMAT(J,NDIM)) * &
				  (AMAT(J,jlev)-AMAT(J,NDIM))
          ENDDO
          hessian(jlev,ilev) = hessian(ilev,jlev)   
        ENDDO
!	write(76,*) hessian(ilev,1:NDIM)
      ENDDO  
!!!      call da_eof_decomposition(ndim, hessian, eignvec, eignval)
    ENDIF
       
     !-----------------!
     ! n2qn1 minimizer !
     !-----------------!
      impres = 2
      io     = 66
      NSIM   = NITER+5
      ZDXMIN = 1.e-6
      ZEPSG  = 1.e-3 !e-9
      IMODE  = 1
      NRZ    = NDIM*(NDIM+9)/2 ! N2QN1
      ALLOCATE(IZ(2*NDIM +1))
      ALLOCATE(ZRZ(NRZ))
      ALLOCATE(DZS(NCHAN*NDIM))
      allocate(rzs(ndim*neignvec))
      binf   = -1000.0
      bsup   = 1000.0
      izs(1) = nchan
      izs(2) = neignvec
      rzs    = 0.0
      ZRZ    = 0.0
      dzs(1:NCHAN*NDIM)=RESHAPE(AMAT(1:NCHAN,1:NDIM),(/NCHAN*NDIM/))
	  
      IF (LPRECON) THEN
        IMODE = 2
        i     = 0
        DO ilev=1, NDIM
          DO jlev=ilev, NDIM
            i = i + 1
            ZRZ(i) = hessian(jlev,ilev)
          ENDDO
        ENDDO    
      ENDIF
!      rzs(1:ndim*neignvec)                  = RESHAPE(eignvec(1:ndim,1:neignvec),(/ndim*neignvec/))
!      rzs(ndim*neignvec+1:(ndim+1)*neignvec)= eignval(1:neignvec)

      call da_cloud_sim(0,NDIM,px,ZF,ZG,izs,RZS,DZS)
      ZDF1      = 1.e-1*ZF 


      call da_error(__FILE__,__LINE__, &
             (/"inria_n2qn1 is not implemented here, please contact the author of this subroutine."/))
!     call inria_n2qn1(da_cloud_sim,NDIM,px,ZF,ZG,(/(ZDXMIN,jlev=1,NDIM)/),ZDF1, &
!                ZEPSG,impres,io,IMODE,nit,NSIM,binf,bsup,IZ,ZRZ,izs,RZS,DZS)
  
      IF (ALLOCATED(IZ))  DEALLOCATE(IZ)       
      IF (ALLOCATED(ZRZ)) DEALLOCATE(ZRZ)       
      IF (ALLOCATED(DZS)) DEALLOCATE(DZS)       
      if (allocated(rzs)) deallocate(rzs)                 
         
      !-----------------!
      ! Cloudy radiance !
      !-----------------!
      DO ich=1,nchannels
        rad_cld(ich) = SUM(px(1:ndim-1) * rad_ovc(ich,1:ndim-1)) + px(ndim) * rad_clr(ich) 
	
	if (ABS(rad_cld(ich)-rad_clr(ich)) < 0.01*rad_clr(ich)) then
	   iv%instid(isensor)%cloud_flag(ich,n) = qc_good
	else
   	   iv%instid(isensor)%cloud_flag(ich,n) = qc_bad
	end if   
      ENDDO    
      
    ! Dump cloud top pressure
    do ilev = kte, kts+2, -1
      if (px(ilev-kts+1) > 0.01) cldtoplevel = ilev
    end do   
    
    if (rtm_option == rtm_option_rttov) then
#ifdef RTTOV
       iv%instid(isensor)%clwp(n) = coefs(isensor)%coef%ref_prfl_p(cldtoplevel)
#endif
    elseif (rtm_option == rtm_option_crtm) then
#ifdef CRTM
       iv%instid(isensor)%clwp(n) = iv%instid(isensor)%pm(cldtoplevel,n)
#endif
    end if  	    
    
 
end subroutine da_cloud_detect_airs