subroutine da_read_obs_bufrssmis (obstype,iv,infile) 1,23

   !---------------------------------------------------------------------------
   !  Purpose: read in NCEP bufr SSM/IS data to innovation structure
   !
   !   METHOD: use F90 sequential data structure to avoid reading file twice  
   !            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
   !---------------------------------------------------------------------------



   use da_control

   implicit none

   character(5) ,     intent (in)    :: obstype    ! ssmis
   character(20),     intent (in)    :: infile     ! ssmis.bufr
   type (iv_type),    intent (inout) :: iv

#ifdef BUFR

   integer(i_kind), parameter :: bufsat_dmsp16 = 249  ! DMSP16 BUFR identifier
   integer(i_kind), parameter :: bufsat_dmsp17 = 285  ! DMSP17 BUFR identifier
   integer(i_kind), parameter :: bufsat_dmsp18 = 286  ! DMSP18 BUFR identifier
   integer(i_kind), parameter :: n1bhdr = 15
   integer(i_kind), parameter :: maxchanl = 24
   real(r_kind),    parameter :: tbmin = 70.0_r_kind
   real(r_kind),    parameter :: tbmax = 320.0_r_kind

   character(80) :: hdr1b
   !data hdr1b /'SAID FOVN YEAR MNTH DAYS HOUR MINU SECO CLAT CLON SLNM ORBN SELV SURF RAINF'/
   data hdr1b /'SAID FOVN YEAR MNTH DAYS HOUR MINU SECO CLAT CLON SLNM ORBN SELV SFLG RFLAG'/
   character(10) :: date
   character(8)  :: subset, subfgn
   character(20) :: filename

   logical :: outside, outside_all

   integer(i_kind) :: iost, inst, lnbufr, ifgat
   integer(i_kind) :: num_bufr(7),numbufr,ibufr
   integer(i_kind) :: ihh, i, j, n, k, slnm, ifov, idd, ireadmg, ireadsb
   integer(i_kind) :: iret, idate, im, iy
   integer(i_kind) :: jc, incangl, bch, landsea_mask, rain_flag
   integer(i_kind) :: platform_id, satellite_id, sensor_id, nchan, num_ssmis_file
   integer(i_kind) :: num_ssmis_local, num_ssmis_global, num_ssmis_used, num_ssmis_thinned
   integer(i_kind) :: num_ssmis_used_tmp

   real(r_double), dimension(2,maxchanl) :: bufrtbb
   real(r_double), dimension(n1bhdr)     :: bfr1bhdr

   ! pixel information
   integer(i_kind)   ::  year,month,day,hour,minute,second  ! observation time
   real(kind=8)    ::  obs_time
   real(r_double), allocatable ::  tb_inv(:)          !  bright temperatures

   type (datalink_type), pointer  :: head, p, current, prev
   type(info_type)                :: info
   type(model_loc_type)           :: loc

   ! thinning variables
   integer(i_kind) :: itt,itx,iobs,iout
   real(r_kind)    :: terrain,timedif,crit,dist
   real(r_kind)    :: dlon_earth,dlat_earth
   logical         :: iuse
   real, allocatable :: in(:), out(:)
   logical           :: found, head_found

   integer(i_kind), allocatable :: ptotal(:), nread(:)

   call da_trace_entry("da_read_obs_bufrssmis")

   allocate(nread(1:rtminit_nsensor))
   allocate(ptotal(0:num_fgat_time))
   nread(1:rtminit_nsensor) = 0
   ptotal(0:num_fgat_time) = 0

   platform_id  = 2                 ! for DMSP series
   sensor_id    = 10                ! for SSMIS
   nchan        = nchan_ssmis

   allocate (tb_inv(nchan))
   num_ssmis_file    = 0
   num_ssmis_local   = 0
   num_ssmis_global  = 0
   num_ssmis_used    = 0
   num_ssmis_thinned = 0
   iobs = 0                 ! for thinning, argument is inout

   ! 0.0  Open unit to satellite bufr file and read file header
   !--------------------------------------------------------------

!   call da_get_unit(lnbufr)

   num_bufr(:)=0
   numbufr=0
   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

   lnbufr=98
   open(unit=lnbufr,file=trim(filename),form='unformatted', &
      iostat = iost, status = 'old')
   if (iost /= 0) then
      call da_warning(__FILE__,__LINE__, &
         (/"Cannot open file "//infile/))
      call da_trace_exit("da_read_obs_bufrssmis")
      return
   end if

   call openbf(lnbufr,'IN',lnbufr)
   call datelen(10)
   call readmg(lnbufr,subset,idate,iret)

   iy=0
   im=0
   idd=0
   ihh=0
   write(unit=date,fmt='( i10)') idate
   read(unit=date,fmt='(i4,3i2)') iy,im,idd,ihh
   write(unit=stdout,fmt=*) &
      'Bufr file date is ',iy,im,idd,ihh,infile

   ! Loop to read bufr file and assign information to a sequential structure
   !-------------------------------------------------------------------------
   if ( ibufr == 1 ) then
      allocate (head)
      nullify  ( head % next )
      p => head
   end if

! Set various variables depending on type of data to be read

   !subfgn = 'NC003003'
   subfgn = 'NC021201'
   incangl = 53.2_r_kind

   subset_loop: do while (ireadmg(lnbufr,subset,idate)==0)

      read_loop: do while (ireadsb(lnbufr)==0 .and. subset==subfgn)

         num_ssmis_file = num_ssmis_file + 1
         ! 1.0     Read header record and data record

         call ufbint(lnbufr,bfr1bhdr,n1bhdr,1,iret,hdr1b)
         call ufbrep(lnbufr,bufrtbb,2,maxchanl,iret,"CHNM TMBR" )

         ! check if observation outside range

         ! 2.0     Extract observation location and other required information
         !     QC1:  judge if data is in the domain, read next record if not
         !------------------------------------------------------------------------

         info%lat  =  bfr1bhdr(bufr_lat)
         info%lon  =  bfr1bhdr(bufr_lon)
         call da_llxy (info, loc, outside, outside_all)


         if (outside_all) cycle

         !  3.0     Extract other information

         info%elv  = 0.0
         landsea_mask = nint(bfr1bhdr(bufr_landsea_mask))   ! ssmis surface flag
                                                            ! 0:land, 2:near coast, 3:ice,
                                                            ! 4:possible ice, 5:ocean, 6:coast
         ! RTTOV surftype: 0:land, 1:sea, 2:sea ice
         if ( landsea_mask == 5 ) then
            landsea_mask = 1
         else if ( landsea_mask == 2 .or. landsea_mask == 6 ) then
            landsea_mask = 0
         else if ( landsea_mask == 3 .or. landsea_mask == 4 ) then
            landsea_mask = 2
         end if
         rain_flag = nint(bfr1bhdr(15))    ! 0:no rain, 1:rain

         !------------------------------------------------------
         !  3.1     Extract satellite id and scan position. 
   
         if (nint(bfr1bhdr(bufr_satellite_id)) == bufsat_dmsp16) then
            satellite_id = 16
         else if (nint(bfr1bhdr(bufr_satellite_id)) == bufsat_dmsp17) then
            satellite_id = 17
         else if (nint(bfr1bhdr(bufr_satellite_id)) == bufsat_dmsp18) then
            satellite_id = 18
         end if

         ! 3.3 Find wrfvar instrument index from RTTOV instrument triplet
         !     go to next data if id is not in the lists

         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

         !  3.1     Extract scan number and scan position. 

         slnm = nint(bfr1bhdr(11))
         ifov = nint(bfr1bhdr(bufr_ifov))

         !  3.2     Extract date information.
    
         year   = bfr1bhdr(bufr_year)   
         month  = bfr1bhdr(bufr_month)  
         day    = bfr1bhdr(bufr_day)    
         hour   = bfr1bhdr(bufr_hour)   
         minute = bfr1bhdr(bufr_minute) 
         second = bfr1bhdr(bufr_second) 

         write(unit=info%date_char, fmt='(i4,a,i2.2,a,i2.2,a,i2.2,a,i2.2,a,i2.2)')  &
            year, '-', month, '-', day, '_', hour, ':', minute, ':', second

         !  QC3: time consistency check with the background date

         if (year <= 99) then
            if (year < 78) then
               year = year + 2000
            else
               year = year + 1900
            end if
         end if

         call da_get_julian_time(year,month,day,hour,minute,obs_time)

         if (obs_time < time_slots(0) .or.  &
            obs_time >= time_slots(num_fgat_time)) cycle read_loop

         ! 3.2.1 determine FGAT index ifgat
   
         do ifgat=1,num_fgat_time
            if (obs_time >= time_slots(ifgat-1) .and.  &
                obs_time  < time_slots(ifgat)) exit
         end do

         num_ssmis_global = num_ssmis_global + 1
         ptotal(ifgat) = ptotal(ifgat) + 1

         if (outside) cycle ! No good for this PE

         num_ssmis_local = num_ssmis_local + 1

         !  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
            timedif = 0. !2.0_r_kind*abs(tdiff)        ! range:  0 to 6
            terrain = 0.01_r_kind*abs(bfr1bhdr(13))
            crit = 1. !0.01_r_kind+terrain + timedif !+ 10._r_kind*float(iskip)
            call map2grids(inst,ifgat,dlat_earth,dlon_earth,crit,iobs,itx,1,itt,iout,iuse)
            if (.not. iuse) then
               num_ssmis_thinned=num_ssmis_thinned+1
               cycle
            end if
         end if

         num_ssmis_used = num_ssmis_used + 1
         nread(inst) = nread(inst) + 1

         if (num_ssmis_used > max_ssmis_input) then
            write(unit=message(1),fmt='(A,I10,A)') &
               "Max number of ssmis",max_ssmis_input," reached"
            call da_warning(__FILE__,__LINE__,message(1:1))
            num_ssmis_used = num_ssmis_used - 1
            exit read_loop
         end if

         ! 3.4 extract satellite and solar angle
   
         ! 3.5 extract surface information

         ! 3.6 extract channel bright temperature
   
         tb_inv(1:nchan) = missing_r

         do jc = 1, nchan
            bch = nint(bufrtbb(1,jc))     !ch index from bufr
            tb_inv(jc) = bufrtbb(2,jc)
            if (tb_inv(jc) < tbmin .or. tb_inv(jc) > tbmax .or. bch /= jc) then
                tb_inv(jc) = missing_r
            end if
         end do

         if ( maxval(tb_inv(:)) > missing_r ) then

            !  4.0   assign information to sequential radiance structure
            !--------------------------------------------------------------------------
            allocate (p % tb_inv (1:nchan))
            p%info                = info
            p%loc                 = loc
            p%landsea_mask        = landsea_mask
            p%scanline            = slnm
            p%scanpos             = ifov
            p%satzen              = incangl
            p%satazi              = 0.0     ! dummy value
            p%solzen              = 0.0     ! dummy value
            p%tb_inv(1:nchan)     = tb_inv(1:nchan)
            p%sensor_index        = inst
            p%ifgat               = ifgat
            p%rain_flag           = rain_flag

            allocate (p%next)   ! add next data
            p => p%next
            nullify (p%next)

         else

            num_ssmis_local = num_ssmis_local - 1
            num_ssmis_used  = num_ssmis_used - 1

         end if

      end do read_loop

   end do subset_loop

  call closbf(lnbufr)
  close(lnbufr)

end do bufrfile

   if (thinning .and. num_ssmis_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_ssmis_used_tmp = num_ssmis_used
      do j = 1, num_ssmis_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_ssmis_thinned = num_ssmis_thinned + 1
            num_ssmis_used = num_ssmis_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_ssmis_used
   iv%total_rad_channel = iv%total_rad_channel + num_ssmis_used*nchan

   iv%info(radiance)%nlocal = iv%info(radiance)%nlocal + num_ssmis_used
   iv%info(radiance)%ntotal = iv%info(radiance)%ntotal + num_ssmis_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_ssmis_file, num_ssmis_global, num_ssmis_local, num_ssmis_used, num_ssmis_thinned'
   write(stdout,*) num_ssmis_file, num_ssmis_global, num_ssmis_local, num_ssmis_used, num_ssmis_thinned

   deallocate(tb_inv)  

   !  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_ssmis_used
      i = p%sensor_index
      nread(i) = nread(i) + 1
      call da_initialize_rad_iv (i, nread(i), iv, p)

      iv%instid(i)%rain_flag(n) = p%rain_flag

      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)

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

end subroutine da_read_obs_bufrssmis