subroutine read_superwinds(nread,ndata,nodata,infile,obstype,lunout, &
            twind,sis)
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    read_superwinds   read in and reformat wind superobs
!   prgmmr: parrish          org: np22       date: 2004-03-17
!
! abstract: read in and reformat data for wind superobs
!           from non-bufr file
!
! program history log:
!   2004-03-17  parrish
!   2004-06-22  parrish, document
!   2004-07-29  treadon - add only to module use, add intent in/out
!   2005-08-02  derber  - modify to use convinfo file
!   2005-09-08  derber - modify to use input group time window
!   2005-10-11  treadon - change convinfo read to free format
!   2005-10-17  treadon - add grid and earth relative obs location to output file
!   2005-10-18  treadon - remove array obs_load and call to sumload 
!   2005-10-26  treadon - add routine tag to convinfo printout
!   2006-01-04  liu - correct unit error when bounding longitude
!   2006-02-03  derber  - modify for new obs control and obs count
!   2006-02-08  derber  - modify to use new convinfo module
!   2006-02-24  derber  - modify to take advantage of convinfo module
!   2007-03-01  tremolet - measure time from beginning of assimilation window
!   2008-04-17  safford - rm unused vars
!
!   input argument list:
!     nread    - counter for all data on this pe
!     infile   - input file array
!     obstype  - observation type array for each processor ( = "superuv" for superob winds)
!     lunout   - output unit number to write reformated data
!     twind    - input group time window (hours)
!
!   output argument list:
!     nread    - counter for all data on this pe
!     ndata    - number of observation records
!     nodata   - number of observation data
!     sis      - satellite/instrument/sensor indicator
!
!   remarks: 
!   input file format: 
!    rec 1: number of superobs,iord,iuvw,nbar,ref_date_super(yr,mon,day,hr,min,sec)
!    rec 2,etc: suplon,suplat,suphgt,suptime,supyhat(nbar),suprhat(nbar),supbigu(nbar,nbar)
!       suplon,suplat -- coordinates of superob centroid (degrees)
!       suptime       -- superob time, relative to ref_date_super (hours)
!       supyhat       -- superob
!       suprhat       -- superob error variance
!       supbigu       -- superob forward model
!
!      the forward model is like this
!
!      given u,v, (and w if iuvw=3) interpolated to suplon,suplat,suphgt, then
!
!  iuvw=2:
!                                | u |
!             yhat(model) =  U * | v | 
!                                
!                 where U is a 2x2 matrix and yhat is a 2-vector
!
!  iuvw=3:
!                                | u |
!             yhat(model) =  U * | v | 
!                                | w |
!                                
!                 where U is a 3x3 matrix and yhat is a 3-vector
!
!   for now we will only allow iuvw=2, and also iord=0, which means this is a conventional
!    (except for the u-v transformation to yhat) superob.
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
  use kinds, only: r_kind,r_single,i_kind
  use constants, only: deg2rad,rad2deg,izero,ione,zero,one,r60inv
  use gridmod, only: regional,nlat,nlon,tll2xy,rotate_wind_ll2xy,rlats,rlons
  use gridmod, only: check_rotate_wind
  use convinfo, only: nconvtype,ctwind, &
        ncmiter,ncgroup,ncnumgrp,icuse,ioctype
  use obsmod, only: iadate,offtime_data
  use gsi_4dvar, only: l4dvar,winlen,time_4dvar
  implicit none

! Declare passed variables
  character(len=*),intent(in   ) :: obstype,infile
  character(len=*),intent(in   ) :: sis
  real(r_kind)    ,intent(in   ) :: twind
  integer(i_kind) ,intent(in   ) :: lunout
  integer(i_kind) ,intent(inout) :: nread,ndata,nodata

! Declare local parameters
  real(r_kind),parameter:: r360=360.0_r_kind

! Declare local variables  
  logical outside
  integer(i_kind) ndata_in,iord_in,iuvw_in,nbar_in
  integer(i_kind) iyref,imref,idref,ihref,idate
  real(r_single)suplon0,suplat0,suphgt,suptime0,supyhat(2),suprhat(2),supbigu(2,2)
  real(r_single)suptime,supid(2)
  real(r_kind) supid8
  equivalence(supid(1),supid8)
  real(r_kind) rstation_id,usage
  real(r_kind),allocatable,dimension(:,:):: cdata_all
  integer(i_kind) lnbufr,i,maxobs,ikx,idomsfc
  integer(i_kind) ilon,ilat,k,icount,nchanl,nreal

  real(r_kind) dlat,dlon,dlat_earth,dlon_earth,sfcr,skint,ff10,t4dv,toff
  real(r_kind) u0,v0,superror,uob,vob,superrinv(2)

  integer(i_kind) idate5(5),minobs,minan
  real(r_kind) time_correction



!**************************************************************************
! Initialize variables
  lnbufr=10_i_kind
  maxobs=2e6_i_kind
  nreal=21_i_kind
  nchanl=izero
  ilon=ione
  ilat=2_i_kind

  ikx = izero
  do i=1,nconvtype
     if(trim(obstype) == trim(ioctype(i)))ikx=i
  end do
  if(ikx == izero)then
     write(6,*) ' READSUPERWIND: NO DATA REQUESTED'
     return
  end if
  allocate(cdata_all(nreal,maxobs))

  
! Open, then read date from bufr data
  open(lnbufr,file=infile,form='unformatted')
  rewind lnbufr
  read(lnbufr,end=1010,err=1010)ndata_in,iord_in,iuvw_in,nbar_in,iyref,imref,idref,ihref
  if(offtime_data) then

!      obtain time correction for observations to account for analysis
!                  time being different from obs file time

     idate5(1)=iyref
     idate5(2)=imref
     idate5(3)=idref
     idate5(4)=ihref
     idate5(5)=izero
     call w3fs21(idate5,minobs)          !  obs ref time in minutes relative to historic date
     call w3fs21(iadate,minan)           !  analysis ref time in minutes relative to historic date

!     add obs reference time, then subtract analysis time to get obs time relative to analysis

     time_correction=float(minobs-minan)*r60inv

  else
     time_correction=zero
  end if
  idate=1000000*iyref+10000*imref+100*idref+ihref
  call time_4dvar(idate,toff)
  rstation_id=999._r_kind
  write(6,*)'READ_SUPERWINDS:  ndata_in,iord_in,iuvw_in,nbar_in =', &
       ndata_in,iord_in,iuvw_in,nbar_in
  if(iord_in/=izero.or.iuvw_in/=2_i_kind.or.nbar_in/=2_i_kind) then
     write(6,*)'READ_SUPERWINDS:  ***ERROR*** iord =',iord_in,' iuvw=',iuvw_in,' nbar=',nbar_in
     write(6,*)'  currently only able to do iord=0 (traditional superob), iuvw=2 (u,v only), and nbar=2'
     call stop2(97)
  end if

  
! Loop to read in data
  do icount=1,ndata_in
     nread=nread+2_i_kind
     read(lnbufr)suplon0,suplat0,suphgt,suptime0,supyhat,suprhat,supbigu,supid

     t4dv = toff + suptime0
     if (l4dvar) then
        if (t4dv<zero .OR. t4dv>winlen) cycle
     else
        suptime=suptime0 + time_correction
        if(abs(suptime) > ctwind(ikx) .or. abs(suptime) > twind)cycle
     endif
     dlat_earth = suplat0
     dlon_earth = suplon0
     if (dlon_earth>=r360) dlon_earth = dlon_earth - r360
     if (dlon_earth<zero ) dlon_earth = dlon_earth + r360
     dlat_earth = dlat_earth*deg2rad
     dlon_earth = dlon_earth*deg2rad
     if(regional)then
        call tll2xy(dlon_earth,dlat_earth,dlon,dlat,outside)
        if(outside) cycle
     else
        dlat = dlat_earth
        dlon = dlon_earth
        call grdcrd(dlat,ione,rlats,nlat,ione)
        call grdcrd(dlon,ione,rlons,nlon,ione)
     endif

     ndata=min(ndata+ione,maxobs)
     nodata=min(nodata+ione,maxobs)

!  rotate forward matrix to account for input u,v being in regional coordinate
!
!                           forward model for superobs:
!
!                      yhat(1) = bigu(1,1)*u(earth) + bigu(1,2)*v(earth)
!                      yhat(2) = bigu(2,1)*u(earth) + bigu(2,2)*v(earth)
!
!                       error variance is rhat(1), rhat(2)
!
!                                              T  T     -1                      T
!                  2*Jo = (yhat_ob - bigu*(u,v)  )  rhat   (yhat_ob - bigu*(u,v) )
!
!  in rotated coordinate, we multiply bigu by rotation matrix since u,v are no longer earth relative
!
!                      ue =  epsilonv*ur -   deltav*vr   (subroutine rotate_wind_xy2ll)
!                      ve = -epsilonu*ur +   deltau*vr
!
!              bigur(1,1) =  epsilonv*bigue(1,1) - epsilonu*bigue(1,2)  (subroutine rotate_wind_ll2xy)
!              bigvr(1,1) =   -deltav*bigue(1,1) +   deltau*bigue(1,2)
!              bigur(2,1) =  epsilonv*bigue(2,1) - epsilonu*bigue(2,2)
!              bigvr(2,1) =   -deltav*bigue(2,1) +   deltau*bigue(2,2)

     if(regional) then
        do i=1,2
           u0=supbigu(i,1)
           v0=supbigu(i,2)
           call rotate_wind_ll2xy(u0,v0,uob,vob,dlon_earth,dlon,dlat)
           supbigu(i,1)=uob
           supbigu(i,2)=vob
        end do
     end if
     
     superror=sqrt(suprhat(1))
     superrinv(2)=superror/(sqrt(suprhat(2))+1.e-20_r_kind)
     if(suprhat(2)<1.e-20_r_single)superrinv(2)=zero
     superrinv(1)=one
     usage = zero
     if(icuse(ikx) < izero)usage=100._r_kind
     if(ncnumgrp(ikx) > izero )then                     ! cross validation on
        if(mod(ndata,ncnumgrp(ikx))== ncgroup(ikx)-ione)usage=ncmiter(ikx)
     end if

     call deter_sfc2(dlat_earth,dlon_earth,t4dv,idomsfc,skint,ff10,sfcr)

!    Load superobs wind data into output array
     cdata_all(1,ndata)=dlon     ! grid relative longitude
     cdata_all(2,ndata)=dlat     ! grid relative latitude
     cdata_all(3,ndata)=suphgt
     cdata_all(4,ndata)=t4dv
     cdata_all(5,ndata)=supyhat(1)*superrinv(1)
     cdata_all(6,ndata)=supyhat(2)*superrinv(2)
     cdata_all(7,ndata)=superror
     cdata_all( 8,ndata)=supbigu(1,1)*superrinv(1)
     cdata_all( 9,ndata)=supbigu(2,1)*superrinv(2)
     cdata_all(10,ndata)=supbigu(1,2)*superrinv(1)
     cdata_all(11,ndata)=supbigu(2,2)*superrinv(2)
     cdata_all(12,ndata)=ikx            !  type number--later change for different radar sources
     cdata_all(13,ndata)=rstation_id    ! station id
     cdata_all(14,ndata)=usage          ! usage parameter
     cdata_all(15,ndata)= idomsfc       ! dominate surface type
     cdata_all(16,ndata)= skint         ! skin temperature
     cdata_all(17,ndata)= ff10          ! 10 meter wind factor
     cdata_all(18,ndata)= sfcr          ! surface roughness

     cdata_all(19,ndata)=supid8         ! 8byte character string, first 4 are radar station id,
                                        !   second 4 are mean range of superob from radar 
                                        !    (integer, in km, between 0 and 9999)
     cdata_all(20,ndata)=dlon_earth*rad2deg     ! earth relative longitude (degrees)
     cdata_all(21,ndata)=dlat_earth*rad2deg     ! earth relative latitude (degrees)


! End of data read loop
  end do


! Write observations to scratch file
  write(lunout) obstype,sis,nreal,nchanl,ilat,ilon
  write(lunout) ((cdata_all(k,i),k=1,nreal),i=1,ndata)

! Close units
1010 continue
  close(lnbufr)
  deallocate(cdata_all)

! Generate stats on regional wind rotation
  if (regional) call check_rotate_wind('read_superwinds')

! End of routine
  return
  
end subroutine read_superwinds