subroutine da_read_obs_bufrseviri (obstype,iv,infile)	  1,31

! subprogram:    read_seviri                  read bufr format seviri data
   !--------------------------------------------------------
   !  Purpose: read in NCEP bufr eos AIRS/AMSUA/HSB 1b data
   !            to innovation structure
   !
   !   METHOD: use F90 sequantial data structure to avoid read file twice
   !            so that da_scan_bufrairs is not necessary any more.
   !            1. read file radiance data in sequential data structure
   !            2. do gross QC check
   !            3. assign sequential data structure to innovation structure
   !                  and deallocate sequential data structure
   !
   !  HISTORY: 2013/03/26 - Creation            Hongli Wang 
   !
   !------------------------------------------------------------------------------

  implicit none

  real(r_kind)     :: POinT001 =   0.001_r_kind
  real(r_kind)     :: POinT01  =   0.01_r_kind
  real(r_kind)     :: TEN      =  10.0_r_kind
  real(r_kind)     :: R45      =  45.0_r_kind
  real(r_kind)     :: R60      =  60.0_r_kind
  real(r_kind)     :: R90      =  90.0_r_kind
  real(r_kind)     :: R180     = 180.0_r_kind
  real(r_kind)     :: R360     = 360.0_r_kind  

  character(9)      ,  intent (in)  :: obstype
  type (iv_type)    ,intent (inout) :: iv
#ifdef BUFR  
  real(kind=8)    ::  obs_time  
  type (datalink_type), pointer  :: head, p, current, prev
  type(info_type)                :: info
  type(model_loc_type)           :: loc 
  type(model_loc_type)           :: loc_fov  

!!! for seviri
  character(80),  intent (in) :: infile

  character(8)       :: subset,subcsr,subasr
  character(80)      :: hdrsevi                             ! seviri header

  integer(i_kind)    :: nchanl,ilath,ilonh,ilzah,iszah,irec 
  integer(i_kind)    :: nhdr,nchn,ncld,nbrst !,idate,lnbufr
  integer(i_kind)    :: ireadmg,ireadsb,iret

  real(r_double),allocatable,dimension(:)   :: hdr         
  real(r_double),allocatable,dimension(:,:) :: datasev1,datasev2   

  logical            :: clrsky,allsky,allchnmiss
  real               :: rclrsky
  integer :: kidsat 
  integer(i_kind)    :: idate5(6)
  integer (i_kind), allocatable :: ptotal(:), nread(:) 
  integer(i_kind)    :: idate, im, iy, idd, ihh
!!! end for seviri

  ! Number of channels for sensors in BUFR
  integer(i_kind),parameter :: nchan = 8       
  integer(i_kind),parameter :: n_totchan  = 12 
  integer(i_kind),parameter :: maxinfo    =  33
  integer(i_kind)   :: inst,platform_id,satellite_id,sensor_id
  real(r_kind)      :: crit
  integer(i_kind)   :: ifgat, iout, iobs
  logical           :: outside, outside_all, iuse,outside_fov

  integer           :: numbufr,ibufr,jj  
  logical :: found, head_found 
  real(r_kind)      :: step, start,step_adjust
  character(len=4)  :: senname
  integer(i_kind)   :: size,size_tmp
  character(10)     :: date
  real(r_kind)      :: sstime, tdiff, t4dv
  integer(i_kind)   :: nmind

  ! Other work variables
  real(r_kind)     :: clr_amt,piece
  real(r_kind)     :: dlon, dlat
  real(r_kind)     :: dlon_earth,dlat_earth,dlon_earth_deg,dlat_earth_deg
  real(r_kind)     :: lza, lzaest,sat_height_ratio
  real(r_kind)     :: pred, crit1, dist1
  real(r_kind)     :: sat_zenang
  real(r_kind)     :: radi
  real(r_kind)     :: tsavg,vty,vfr,sty,stp,sm,sn,zz,ff10,sfcr
  real(r_kind),dimension(0:4) :: rlndsea
  real(r_kind),dimension(0:3) :: sfcpct
  real(r_kind),dimension(0:3) :: ts
  real(r_kind),dimension(10) :: sscale
  real(r_kind),dimension(n_totchan) :: temperature
  real(r_kind),allocatable,dimension(:):: data_all
  real(r_kind) disterr,disterrmax,rlon00,rlat00

  logical          :: assim,valid
  logical          :: seviri 
  logical          :: data_on_edges,luse
  integer(i_kind)  :: nreal, ityp,ityp2, isflg
  integer(i_kind)  :: ifov, instr, ioff, ilat, ilon, sensorindex
  integer(i_kind)  :: num_seviri_file
  integer(i_kind)  :: num_seviri_local, num_seviri_global, num_seviri_used, num_seviri_thinned 
  integer(i_kind)  :: num_seviri_used_tmp  
  integer(i_kind)  :: i, j, l, iskip, ifovn, bad_line

  integer(i_kind)  :: itx, k, nele, itt, n
  integer(i_kind)  :: iexponent
  integer(i_kind)  :: idomsfc
  integer(i_kind)  :: ntest
  integer(i_kind)  :: error_status
  integer(i_kind)  :: num_bufr(7)

  integer          :: iost, lnbufr 
  character(20)    ::filename  
  real, allocatable :: in(:), out(:)

  ! Set standard parameters
  integer(i_kind),parameter:: ichan=-999  ! fov-based surface code is not channel specific for seviri 
  real(r_kind),parameter:: expansion=one  ! exansion factor for fov-based location code. 
  real(r_kind),parameter:: tbmin  = 50._r_kind
  real(r_kind),parameter:: tbmax  = 550._r_kind
  real(r_kind),parameter:: earth_radius = 6371000._r_kind

  ilath=8                      ! the position of latitude in the header
  ilonh=9                      ! the position of longitude in the header
  ilzah=10                     ! satellite zenith angle
  iszah=11                     ! solar zenith angle
  subcsr='NC021043'            ! sub message
  subasr='NC021042'            ! sub message

   if(trace_use) call da_trace_entry("da_read_obs_bufrseviri")

  !  0.0  Initialize variables
  !-----------------------------------
  sensor_id = 21 !seviri
  disterrmax=zero
  ntest=0
  nreal  = maxinfo
  seviri= obstype == 'seviri'

  bad_line=-1
  step  = 1.0
  start = 0.0
  step_adjust = 1.0_r_kind
  senname = 'SEVIRI'
  num_bufr(:)=0
  numbufr=0
  allocate(nread(1:rtminit_nsensor))
  allocate(ptotal(0:num_fgat_time))
  nread(1:rtminit_nsensor) = 0
  ptotal(0:num_fgat_time) = 0
  iobs = 0                 ! for thinning, argument is inout  
  num_seviri_file    = 0
  num_seviri_local   = 0
  num_seviri_global  = 0
  num_seviri_used    = 0
  num_seviri_thinned = 0  

  ! 1.0 Assign file names and prepare to read bufr files 
  !-------------------------------------------------------------------------

   if (num_fgat_time>1) then
      do i=1,7
         call da_get_unit(lnbufr)
         write(filename,fmt='(A,2I1,A)') trim(infile),0,i,'.bufr'
         open(unit   = lnbufr, FILE   = trim(filename),iostat =  iost, form = 'unformatted', STATUS = 'OLD')
         if (iost == 0) then
            numbufr=numbufr+1
            num_bufr(numbufr)=i
         else
            close (lnbufr)
         end if
         call da_free_unit(lnbufr)
      end do
   else
     numbufr=1
   end if

 
   if (numbufr==0) numbufr=1
 
  bufrfile:  do ibufr=1,numbufr
   if (num_fgat_time==1) then
      filename=trim(infile)//'.bufr'
   else
      if ((numbufr ==1) .and. (num_bufr(ibufr) == 0)) then
         filename=trim(infile)//'.bufr'
      else
         write(filename,fmt='(A,2I1,A)') trim(infile),0,num_bufr(ibufr),'.bufr'
      end if
   end if 

   ! dont change, WRFDA uses specified units to read radiance data
   lnbufr = 92 
   open(unit=lnbufr,file=trim(filename),form='unformatted', &
      iostat = iost, status = 'old' ) !,convert='little_endian')
   if (iost /= 0) then
      call da_warning(__FILE__,__LINE__, &
         (/"Cannot open file "//infile/))
      if(trace_use) call da_trace_exit("da_read_obs_bufrsevri")
      return
   end if

   ! Open BUFR table
   call openbf(lnbufr,'IN',lnbufr) 
   call datelen(10)
   call readmg(lnbufr,subset,idate,iret)

   ! Check the data set
  if( iret/=0) then
     write(message(1),fmt='(A)')'SKIP PROCESSING OF SEVIRI FILE'
     write(message(2),fmt='(A,I2,A)')'infile = ', lnbufr, infile
     call da_warning(__FILE__,__LINE__,message(1:2))
     if(trace_use) call da_trace_exit("da_read_obs_bufrseviri")
     return 
  endif

  clrsky=.false.
  allsky=.false.
  if(subset == subcsr) then
     clrsky=.true.
     write(message(1),fmt='(A)')'READ SEVIRI FILE'
     write(message(2),fmt='(A,L1,2A)')'clrsky= ', clrsky,' subset= ', subset
     call da_message(message(1:2))
  elseif(subset == subasr) then
     allsky=.true.
     write(message(1),fmt='(A)')'READ SEVIRI FILE'
     write(message(2),fmt='(A,L1,2A)')'allsky= ', allsky,' subset= ', subset
     call da_message(message(1:2))
  else
     write(message(1),fmt='(A)')'SKIP PROCESSING OF UNKNOWN SEVIRI FILE'
     write(message(2),fmt='(A,I2,3A)')'infile=', lnbufr, infile,' subset=', subset
     call da_warning(__FILE__,__LINE__,message(1:2))
     if(trace_use) call da_trace_exit("da_read_obs_bufrseviri")
     return 
  endif

  ! Set BUFR string based on seviri data set
  if (clrsky) then
     hdrsevi='SAID YEAR MNTH DAYS HOUR MINU SECO CLATH CLONH SAZA SOZA'
     nhdr=11
     nchn=12
     ncld=nchn
     nbrst=nchn
  else if (allsky) then
     hdrsevi='SAID YEAR MNTH DAYS HOUR MINU SECO CLATH CLONH'
     nhdr=9
     nchn=11
     ncld=2
     nbrst=nchn*6                ! channel dependent: all, clear, cloudy, low,
                                 !middle and high clouds
  endif
  allocate(datasev1(1,ncld))     ! not channel dependent
  allocate(datasev2(1,nbrst))    ! channel dependent: all, clear, cloudy, low,
                                 !middle and high clouds
  allocate(hdr(nhdr))



   iy=0
   im=0
   idd=0
   ihh=0

   sensorindex=1  
   write(unit=date,fmt='( i10)') idate
   read(unit=date,fmt='(i4,3i2)') iy,im,idd,ihh
   write(unit=stdout,fmt='(a,4i4,2x,a)') &
      'Bufr file date is ',iy,im,idd,ihh,trim(infile)

   ! 2.0 Loop to read bufr file and assign information to a sequential structure
   !-------------------------------------------------------------------------

   ! Allocate arrays to hold data
   nele=nreal+nchan
   allocate(data_all(nele))
   if ( ibufr == 1 ) then
      allocate (head)
      nullify  ( head % next )
      p => head
   end if
  

! Big loop to read data file

  do while(ireadmg(lnbufr,subset,idate)>=0)  

     read_loop: do while (ireadsb(lnbufr)==0)
         num_seviri_file = num_seviri_file + 1	 

    ! Read SEVIRI information
         call ufbint(lnbufr,hdr,nhdr,1,iret,hdrsevi)				

        kidsat = nint(hdr(1))
        ! SAID 55 is meteosat-8  or msg-1
        ! SAID 56 is meteosat-9  or msg-2
        ! SAID 57 is meteosat-10 or msg-3
        if ( ( kidsat > 57) .or. ( kidsat < 55) ) then 
           write(unit=message(1),fmt='(A,I6)') 'Unknown platform: ', kidsat
           call da_warning(__FILE__,__LINE__,message(1:1))
        end if
        platform_id  = 12  ! MSG - Meteosat Second Generation
        if ( kidsat == 55 ) then
            satellite_id = 1
        else if ( kidsat == 56 ) then
            satellite_id = 2
        else if ( kidsat == 57 ) then
            satellite_id = 3
        end if

        if (clrsky) then     ! asr bufr has no sza
        ! remove the obs whose satellite zenith angles larger than 65 degree
           if ( hdr(ilzah) > 65.0 ) cycle read_loop
        end if

        call ufbint(lnbufr,datasev1,1,ncld,iret,'NCLDMNT')

        if(iret /= 1) cycle read_loop
        do n=1,ncld
           if(datasev1(1,n)>= 0.0 .and. datasev1(1,n) <= 100.0 ) then
              rclrsky=datasev1(1,n)
               ! first QC filter out data with less clear sky fraction
               if ( rclrsky < 70.0 ) cycle read_loop
               !if ( rclrsky < 90.0 ) cycle read_loop
           end if
        end do

        call ufbrep(lnbufr,datasev2,1,nbrst,iret,'TMBRST')
        
        ! Check if data of channel 1-11 are missing

        allchnmiss=.true.
        do n=1,11
           if(datasev2(1,n)<500.)  then
              allchnmiss=.false.
           end if
        end do
        if(allchnmiss) cycle read_loop

        ! Check observing position
         info%lat  =  hdr(ilath)           ! latitude
         info%lon  =  hdr(ilonh)           ! longitude
         if( abs(info%lat) > R90  .or. abs(info%lon) > R360 .or. &
         (abs(info%lat) == R90 .and. info%lon /= ZERO) )then
         write(unit=stdout,fmt=*) &
         'READ_SEVIRI:  ### ERROR IN READING ', senname, ' BUFR DATA:', &
               ' STRANGE OBS POINT (LAT,LON):', info%lat, info%lon
            cycle read_loop
         end if		 
	 		 
         call da_llxy (info, loc, outside, outside_all)	
         if (outside_all) cycle
	     inst = 0	 
         do i = 1, rtminit_nsensor
            if (platform_id  == rtminit_platform(i) &
               .and. satellite_id == rtminit_satid(i)    &
               .and. sensor_id    == rtminit_sensor(i)) then
               inst = i
               exit
            end if
         end do	 
         if (inst == 0) cycle read_loop		 
		 
        ! Check obs time
         idate5(1) = nint(hdr(2)) ! year
         idate5(2) = nint(hdr(3)) ! month
         idate5(3) = nint(hdr(4)) ! day
         idate5(4) = nint(hdr(5)) ! hour
         idate5(5) = nint(hdr(6)) ! minute
         idate5(6) = nint(hdr(7)) ! second		
		
         if( idate5(1) < 1900 .or. idate5(1) > 3000 .or. &
             idate5(2) < 1    .or. idate5(2) >   12 .or. &
             idate5(3) < 1    .or. idate5(3) >   31 .or. &
             idate5(4) < 0    .or. idate5(4) >   24 .or. &
             idate5(5) < 0    .or. idate5(5) >   60 ) then

            write(message(1),fmt='(A)')'ERROR IN READING SEVIRI BUFR DATA'
            write(message(2),fmt='(A,5I8)')'STRANGE OBS TIME (YMDHM):', idate5(1:5)
            call da_warning(__FILE__,__LINE__,message(1:2))
            cycle read_loop
         end if

         call da_get_julian_time(idate5(1),idate5(2),idate5(3),idate5(4),idate5(5),obs_time)		
         if ( obs_time < time_slots(0) .or.  &
           obs_time >= time_slots(num_fgat_time) ) cycle read_loop
         do ifgat=1,num_fgat_time
            if ( obs_time >= time_slots(ifgat-1) .and.  &
                obs_time  < time_slots(ifgat) ) exit
         end do	
         num_seviri_global = num_seviri_global + 1
         ptotal(ifgat) = ptotal(ifgat) + 1  

         if (outside) cycle ! No good for this PE		
         num_seviri_local = num_seviri_local + 1
		 
         write(unit=info%date_char, &
         fmt='(i4.4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2)')  &
         idate5(1), '-', idate5(2), '-', idate5(3), '_', idate5(4), &
         ':', idate5(5), ':', idate5(6)
         info%elv = 0.0  !aquaspot%selv		   
		 
         ! 3.0  Make Thinning
         ! Map obs to thinning grid
         !-------------------------------------------------------------------
         if (thinning) then
            dlat_earth = info%lat
            dlon_earth = info%lon
            if (dlon_earth<zero) dlon_earth = dlon_earth+r360
            if (dlon_earth>=r360) dlon_earth = dlon_earth-r360
            dlat_earth = dlat_earth*deg2rad
            dlon_earth = dlon_earth*deg2rad
            crit = 1. 
            call map2grids(inst,ifgat,dlat_earth,dlon_earth,crit,iobs,itx,1,itt,iout,iuse)
            if (.not. iuse) then
               num_seviri_thinned=num_seviri_thinned+1
               cycle
            end if
         end if		

         ! data SEVIRI channel number(CHNM) and radiance (SCRA)

         num_seviri_used = num_seviri_used + 1		 
         nread(inst) = nread(inst) + 1								
         iskip = 0
         do i=1,n_totchan
            ! check that tb is within reasonal bound
            if ( datasev2(1,i) < tbmin .or. datasev2(1,i) > tbmax ) then
               temperature(i) = missing_r
            else 
               temperature(i) = datasev2(1,i)
            end if
         end do

         if(iskip > 0)write(6,*) ' READ_SEVIRI : iskip > 0 ',iskip

         do l=1,nchan
            data_all(l+nreal) = temperature(l+3)   ! brightness temerature
         end do
				
    ! 4.0 assign information to sequential radiance structure
    !--------------------------------------------------------------------------
    !        iscan = nint(hdr(ilzah))+1.001_r_kind 
         allocate ( p % tb_inv (1:nchan ))
         p%info             = info
         p%loc              = loc
         p%landsea_mask     = 1
         p%scanpos          = nint(hdr(ilzah))+1.001_r_kind 
         p%satzen           = hdr(ilzah)               ! satellite zenith angle (deg)
         p%satazi           = 0.0                      ! satellite azimuth angle (deg) 
         p%solzen           = 0.0                      ! solar zenith angle (deg)  
         p%solazi           = 0.0                      ! solar azimuth angle (deg) 
         p%tb_inv(1:nchan)  = data_all(nreal+1:nreal+nchan)
         p%sensor_index     = inst
         p%ifgat            = ifgat		

         allocate (p%next)   ! add next data
         p => p%next
         nullify (p%next) 		
     end do read_loop
  end do
  call closbf(lnbufr)
end do bufrfile

deallocate(data_all) ! Deallocate data arrays

  
   if (thinning .and. num_seviri_global > 0 ) then

#ifdef DM_PARALLEL 
      
      ! Get minimum crit and associated processor index.
      j = 0
      do ifgat = 1, num_fgat_time
         do n = 1, iv%num_inst
            j = j + thinning_grid(n,ifgat)%itxmax
         end do 
      end do
   
      allocate ( in  (j) )
      allocate ( out (j) )
      j = 0
      do ifgat = 1, num_fgat_time
         do n = 1, iv%num_inst
            do i = 1, thinning_grid(n,ifgat)%itxmax
               j = j + 1
               in(j) = thinning_grid(n,ifgat)%score_crit(i)
            end do
         end do 
      end do
      call mpi_reduce(in, out, j, true_mpi_real, mpi_min, root, comm, ierr)

      call wrf_dm_bcast_real (out, j)

      j = 0
      do ifgat = 1, num_fgat_time
         do n = 1, iv%num_inst
            do i = 1, thinning_grid(n,ifgat)%itxmax
               j = j + 1
               if ( ABS(out(j)-thinning_grid(n,ifgat)%score_crit(i)) > 1.0E-10 ) thinning_grid(n,ifgat)%ibest_obs(i) = 0
            end do
         end do
      end do

      deallocate( in  )
      deallocate( out )

#endif

      ! Delete the nodes which being thinning out
      p => head
      prev => head
      head_found = .false.
      num_seviri_used_tmp = num_seviri_used
      do j = 1, num_seviri_used_tmp
         n = p%sensor_index
         ifgat = p%ifgat
         found = .false.

         do i = 1, thinning_grid(n,ifgat)%itxmax
            if ( thinning_grid(n,ifgat)%ibest_obs(i) == j .and. thinning_grid(n,ifgat)%score_crit(i) < 9.99e6_r_kind ) then
               found = .true.
               exit
            end if
         end do

         ! free current data
         if ( .not. found ) then
            current => p
            p => p%next
            if ( head_found ) then
               prev%next => p
            else
               head => p
               prev => p
            end if
            deallocate ( current % tb_inv )
            deallocate ( current )
            num_seviri_thinned = num_seviri_thinned + 1
            num_seviri_used = num_seviri_used - 1
            nread(n) = nread(n) - 1
            continue
         end if

         if ( found .and. head_found ) then
            prev => p
            p => p%next
            continue
         end if

         if ( found .and. .not. head_found ) then
            head_found = .true.
            head => p
            prev => p
            p => p%next
         end if

      end do

   end if  ! End of thinning

   iv%total_rad_pixel   = iv%total_rad_pixel + num_seviri_used
   iv%total_rad_channel = iv%total_rad_channel + num_seviri_used*nchan

   iv%info(radiance)%nlocal = iv%info(radiance)%nlocal + num_seviri_used
   iv%info(radiance)%ntotal = iv%info(radiance)%ntotal + num_seviri_global

   do i = 1, num_fgat_time
      ptotal(i) = ptotal(i) + ptotal(i-1)
      iv%info(radiance)%ptotal(i) = iv%info(radiance)%ptotal(i) + ptotal(i)
   end do
   if ( iv%info(radiance)%ptotal(num_fgat_time) /= iv%info(radiance)%ntotal ) then
      write(unit=message(1),fmt='(A,I10,A,I10)') &
          "Number of ntotal:",iv%info(radiance)%ntotal," is different from the sum of ptotal:", iv%info(radiance)%ptotal(num_fgat_time)
      call da_warning(__FILE__,__LINE__,message(1:1))
   endif

   write(unit=stdout,fmt='(a)') '   num_seviri_file num_seviri_global  num_seviri_local   num_seviri_used num_seviri_thinned'
   write(stdout,'(5(8x,i10))') num_seviri_file, num_seviri_global, num_seviri_local, num_seviri_used, num_seviri_thinned

  

   !  5.0 allocate innovation radiance structure
   !----------------------------------------------------------------  
 

   do i = 1, iv%num_inst 
    
      if (nread(i) < 1) cycle
      iv%instid(i)%num_rad  = nread(i)
      iv%instid(i)%info%nlocal = nread(i)
      write(UNIT=stdout,FMT='(a,i3,2x,a,3x,i10)') &
        'Allocating space for radiance innov structure', &
         i, iv%instid(i)%rttovid_string, iv%instid(i)%num_rad
      call da_allocate_rad_iv (i, nchan, iv)
	  
   end do

   !  6.0 assign sequential structure to innovation structure
   !-------------------------------------------------------------
   nread(1:rtminit_nsensor) = 0
   p => head

   do n = 1, num_seviri_used
      i = p%sensor_index 
      nread(i) = nread(i) + 1 
  
      call da_initialize_rad_iv (i, nread(i), iv, p)
  
      current => p
      p => p%next
      ! free current data
      deallocate ( current % tb_inv )
      deallocate ( current )
   end do
   deallocate ( p )
   deallocate (nread)
   deallocate (ptotal)

   call closbf(lnbufr)
   close(lnbufr)

   call da_free_unit(lnbufr)

   if(trace_use) call da_trace_exit("da_read_obs_bufrseviri")
#else
   call da_error(__FILE__,__LINE__,(/"Needs to be compiled with a BUFR library"/))
#endif  


end subroutine da_read_obs_bufrseviri