!
!##################################################################
!##################################################################
!######                                                      ######
!######                 SUBROUTINE GRDTOSNG                  ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!


SUBROUTINE grdtosng(nx,ny,nz,nz_tab,mxsng,nvar,nobsng,                  & 4,4
           xs,ys,zp,icatg,anx,qback,hqback,nlvqback,                    &
           shght,su,sv,spres,stheta,sqv,                                &
           stnsng,isrcsng,icatsng,elevsng,xsng,ysng,                    &
           obsng,qobsng,qualsng,odifsng,oanxsng,thesng,trnsng)
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!
!  Gridded data are interpolated to single-level locations to
!  produce observation differences.  For now, bilinear interpolation
!  is used to create a vertical sounding at the obs location
!  and that is interpolated in the vertical to obtain the
!  bacground value.
!
!-----------------------------------------------------------------------
!
!  AUTHOR:
!
!  Keith Brewster, CAPS, July, 1995
!
!  MODIFICATION HISTORY:
!  Sept, 1996 (KB)
!  Added count-reporting diagnostic output.
!
!  Dec., 1998 (KB)
!  Added correlation categories.
!
!  Feb., 1999 (KB)
!  Moved calculation of oanxsng variables to outside the IF (good)
!  block, so that it will always be available, for future
!  calculations.   Needed for determining qv thresholding from RH
!  thresholding.   Added sychronization of wind error flags, if one
!  component is judged to be in error, the other is also.
!
!  September, 2002 (KB)
!  Added processing for trnsng
!
!-----------------------------------------------------------------------
!
!  Variable Declarations:
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
!
  INTEGER :: nx,ny,nz,nz_tab
  INTEGER :: mxsng,nvar
  INTEGER :: nobsng
!
!-----------------------------------------------------------------------
!
!  Arrays defining model grid
!
!-----------------------------------------------------------------------
!
  REAL :: xs(nx)
  REAL :: ys(ny)
  REAL :: zp    (nx,ny,nz)     ! The physical height coordinate defined at
                               ! w-point of the staggered grid.
!
  INTEGER :: icatg(nx,ny)
!
!-----------------------------------------------------------------------
!
!  Background fields
!
!-----------------------------------------------------------------------
!
  REAL :: anx(nx,ny,nz,nvar)
  REAL :: qback(nvar,nz_tab)
  REAL :: hqback(nz_tab)
  INTEGER :: nlvqback
!
!-----------------------------------------------------------------------
!
!  Column-interpolated values (used internally only)
!
!-----------------------------------------------------------------------
!
  REAL :: shght(nz)
  REAL :: su(nz)
  REAL :: sv(nz)
  REAL :: spres(nz)
  REAL :: stheta(nz)
  REAL :: sqv(nz)
!
!-----------------------------------------------------------------------
!
!  Station variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=5) :: stnsng(mxsng)
  INTEGER :: isrcsng(mxsng)
  INTEGER :: icatsng(mxsng)

  REAL :: elevsng(mxsng)
  REAL :: xsng(mxsng)
  REAL :: ysng(mxsng)
  REAL :: obsng(nvar,mxsng)
  REAL :: qobsng(nvar,mxsng)
  INTEGER :: qualsng(nvar,mxsng)
  REAL :: odifsng(nvar,mxsng)
  REAL :: oanxsng(nvar,mxsng)
  REAL :: thesng(mxsng)
  REAL :: trnsng(mxsng)
!
!-----------------------------------------------------------------------
!
!  Misc internal variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: ista,ivar,kgrid,ktab,kntdom
  INTEGER :: ipt,jpt,ireturn,nlevs
  REAL :: selev,hgtgnd,hgtagl
  REAL :: whigh,wlow,wqhigh,wqlow,qbthe
!
!-----------------------------------------------------------------------
!
!  Beginning of executable code
!
!-----------------------------------------------------------------------
!
  kntdom=0
  DO ista=1,nobsng
!
!-----------------------------------------------------------------------
!
!  Find location in ARPS grid.
!
!-----------------------------------------------------------------------
!
    CALL findlc(nx,ny,xs,ys,xsng(ista),ysng(ista),                      &
                ipt,jpt,ireturn)
!
!-----------------------------------------------------------------------
!
!  Interpolated gridded data if extrapolation is not indicated.
!
!-----------------------------------------------------------------------
!
    IF(ireturn == 0) THEN
!      write(6,'(a,a)')  stnsng(ista),
!    :            ' inside ARPS domain, processing'

      kntdom=kntdom+1

!      write (6,'(2x,a,f12.2,a,f12.2,/
!    :             2x,a,i6,a,i6)')
!    :  ' location x= ',(0.001*xsng(ista)),
!    :         '   y= ',(0.001*ysng(ista)),
!    :  ' found near pt i= ',ipt,'   j= ',jpt
!      write (6,'(12x,a,f12.2,a,f12.2,/)')
!    :  'x= ',(0.001*xs(ipt)),'   y= ',(0.001*ys(jpt))
!
!-----------------------------------------------------------------------
!
!  Interpolate (in the horizontal) for the whole vertical column.
!
!-----------------------------------------------------------------------
!
      CALL colint(nx,ny,nz,nvar,                                        &
             xs,ys,zp,xsng(ista),ysng(ista),ipt,jpt,anx,                &
             su,sv,stheta,spres,shght,sqv,selev,                        &
             nlevs)
!
!-----------------------------------------------------------------------
!
!  Assign category
!
!-----------------------------------------------------------------------
!
      icatsng(ista)=icatg(ipt,jpt)
!
!-----------------------------------------------------------------------
!
!  Interpolate in the vertical at each obs level and compute
!  obs differences.
!
!-----------------------------------------------------------------------
!
      hgtgnd=0.5*(shght(2)+shght(1))
      trnsng(ista)=hgtgnd
      DO kgrid=2,nlevs-2
        IF(shght(kgrid) > elevsng(ista)) EXIT
      END DO
      whigh=(elevsng(ista)-shght(kgrid-1))/                             &
             (shght(kgrid)-shght(kgrid-1))
      wlow=1.-whigh
!
      hgtagl=AMIN1(hqback(nlvqback),                                    &
                   AMAX1(hqback(1),(elevsng(ista)-hgtgnd)))
      DO ktab=2,nlvqback-1
        IF(hqback(ktab) > hgtagl) EXIT
      END DO
      wqhigh=(hgtagl-hqback(ktab-1))/                                   &
             (hqback(ktab)-hqback(ktab-1))
      wqlow=1.-wqhigh
!
      oanxsng(1,ista)=(wlow*su(kgrid-1)+whigh*su(kgrid))
      IF(qualsng(1,ista) > 0) THEN
        odifsng(1,ista)=obsng(1,ista)-oanxsng(1,ista)
        qobsng(1,ista)=qobsng(1,ista)/                                  &
              (wqlow*qback(1,ktab-1)+wqhigh*qback(1,ktab))
      END IF

      oanxsng(2,ista)=(wlow*sv(kgrid-1)+whigh*sv(kgrid))
      IF(qualsng(2,ista) > 0) THEN
        odifsng(2,ista)=obsng(2,ista)-oanxsng(2,ista)
        qobsng(2,ista)=qobsng(2,ista)/                                  &
              (wqlow*qback(2,ktab-1)+wqhigh*qback(2,ktab))
      END IF

      oanxsng(3,ista)=EXP( wlow*LOG(spres(kgrid-1))+                    &
                            whigh*LOG(spres(kgrid)) )
      IF(qualsng(3,ista) > 0) THEN
        odifsng(3,ista)=obsng(3,ista)-oanxsng(3,ista)
        qobsng(3,ista)=qobsng(3,ista)/                                  &
              (wqlow*qback(3,ktab-1)+wqhigh*qback(3,ktab))
      END IF

      oanxsng(4,ista)=(wlow*stheta(kgrid-1)+whigh*stheta(kgrid))
      IF(qualsng(4,ista) > 0) THEN
        odifsng(4,ista)=obsng(4,ista)-oanxsng(4,ista)
        qbthe=wqlow*qback(4,ktab-1)+wqhigh*qback(4,ktab)
        thesng(ista)=( (obsng(4,ista)/qobsng(4,ista))+                  &
                       (oanxsng(4,ista)/qbthe) ) /                      &
                       ((1./qobsng(4,ista)) + (1./qbthe))
!        print *, ' Theta:anx,obs,qsrc,qback: ',
!    :            oanxsng(4,ista),obsng(4,ista),qobsng(4,ista),qbthe
        qobsng(4,ista)=qobsng(4,ista)/qbthe
!        print *, ' theta-sng qobs normalized: ',
!    :            thesng(ista),qobsng(4,ista)
      ELSE
        thesng(ista)=(wlow*stheta(kgrid-1)+whigh*stheta(kgrid))
      END IF

      oanxsng(5,ista)=(wlow*sqv(kgrid-1)+whigh*sqv(kgrid))
      IF(qualsng(5,ista) > 0) THEN
        odifsng(5,ista)=obsng(5,ista)-oanxsng(5,ista)
        qobsng(5,ista)=qobsng(5,ista)/                                  &
              (wqlow*qback(5,ktab-1)+wqhigh*qback(5,ktab))
      END IF
!
    ELSE
!
!      write(6,'(a,a)')  stnsng(ista),
!    :            ' outside ARPS domain, skipping'
!
      isrcsng(ista)=0
      icatsng(ista)=1

!      write(6,'(a,a,i4)') ' Extrapolation status returned from',
!    :                        ' subroutine findlc: ',ireturn
!      IF(ireturn.eq.-1) write(6,'(a)')
!    :      ' Extrapolation in x detected'
!      IF(ireturn.eq.-2) write(6,'(a)')
!    :      ' Extrapolation in y detected'
!      write (6,'(2x,a,f12.2,a,f12.2,/
!    :             2x,a,i6,a,i6/)')
!    :  ' location x= ',(0.001*xsng(ista)),
!    :         '   y= ',(0.001*ysng(ista)),
!    :  ' nearest pt i= ',ipt,'   j= ',jpt
!      write (6,'(12x,a,f12.2,a,f12.2/)')
!    :  'x= ',(0.001*xs(ipt)),'   y= ',(0.001*ys(jpt))

      DO ivar=1,nvar
        qualsng(ivar,ista)=-9
      END DO
    END IF
  END DO
!
  WRITE(6,'(//,1x,i5,a,i5,a)') kntdom,' of ',nobsng,                    &
          ' single-level stations are inside the ARPS domain'
  RETURN
END SUBROUTINE grdtosng
!
!##################################################################
!##################################################################
!######                                                      ######
!######                SUBROUTINE GRDTOUA                    ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!

SUBROUTINE grdtoua(nx,ny,nz,nz_tab,nzua,mxua,nvar,nobsua,               & 4,5
           xs,ys,zp,anx,qback,hqback,nlvqback,                          &
           shght,su,sv,spres,stheta,sqv,                                &
           stnua,isrcua,elevua,xua,yua,hgtua,                           &
           obsua,qobsua,qualua,nlevsua,                                 &
           odifua,oanxua,theua,trnua)
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!  Gridded data are interpolated to upper air locations to
!  produce observation differences.  For now, bilinear interpolation
!  is used to create a vertical sounding at the obs location
!  and that is interpolated in the vertical to obtain the
!  bacground value.
!
!  AUTHOR:
!
!  Keith Brewster, CAPS, July, 1995
!
!  MODIFICATION HISTORY:
!  Sept, 1996 (KB)
!  Added count-reporting diagnostic output.
!
!  September, 2002 (KB)
!  Added processing for trnua
!
!-----------------------------------------------------------------------
!
!  Variable Declarations:
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
!
  INTEGER :: nx,ny,nz,nz_tab
  INTEGER :: nzua,mxua,nvar
  INTEGER :: nobsua
!
!-----------------------------------------------------------------------
!
!  Arrays defining model grid
!
!-----------------------------------------------------------------------
!
  REAL :: xs(nx)
  REAL :: ys(ny)
  REAL :: zp    (nx,ny,nz)     ! The physical height coordinate defined at
                               ! w-point of the staggered grid.
!
!-----------------------------------------------------------------------
!
!  Background fields
!
!-----------------------------------------------------------------------
!
  REAL :: anx(nx,ny,nz,nvar)
  REAL :: qback(nvar,nz_tab)
  REAL :: hqback(nz_tab)
  INTEGER :: nlvqback
!
  REAL :: shght(nz)
  REAL :: su(nz)
  REAL :: sv(nz)
  REAL :: spres(nz)
  REAL :: stheta(nz)
  REAL :: sqv(nz)
!
!-----------------------------------------------------------------------
!
!  Station variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=5) :: stnua(mxua)
  INTEGER :: isrcua(mxua)
  REAL :: elevua(mxua)
  REAL :: xua(mxua),yua(mxua)
  REAL :: hgtua(nzua,mxua)
  REAL :: obsua(nvar,nzua,mxua)
  REAL :: qobsua(nvar,nzua,mxua)
  INTEGER :: qualua(nvar,nzua,mxua)
  INTEGER :: nlevsua(mxua)
  REAL :: odifua(nvar,nzua,mxua)
  REAL :: oanxua(nvar,nzua,mxua)
  REAL :: theua(nzua,mxua)
  REAL :: trnua(mxua)
!
!-----------------------------------------------------------------------
!
!  Misc. internal variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: ista,ivar,k,kgrid,ktab,kntdom
  INTEGER :: ipt,jpt,ireturn,nlevs
  REAL :: selev,hgtgnd,hgtagl
  REAL :: whigh,wlow,wqhigh,wqlow,qbthe
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
  kntdom=0
  DO ista=1,nobsua
!
!-----------------------------------------------------------------------
!
!  Find location in ARPS grid.
!
!-----------------------------------------------------------------------
!
    CALL findlc(nx,ny,xs,ys,xua(ista),yua(ista),                        &
                ipt,jpt,ireturn)
!
!-----------------------------------------------------------------------
!
!  Interpolate if extrapoltion is not indicated.
!
!-----------------------------------------------------------------------
!
    IF(ireturn == 0) THEN
!      write(6,'(a,a)')  stnua(ista),
!    :            ' inside ARPS domain, processing'

      kntdom=kntdom+1

!      write (6,'(2x,a,f12.2,a,f12.2,/
!    :             2x,a,i6,a,i6)')
!    :  ' location x= ',(0.001*xua(ista)),
!    :         '   y= ',(0.001*yua(ista)),
!    :  ' found near pt i= ',ipt,'   j= ',jpt
!      write (6,'(12x,a,f12.2,a,f12.2,/)')
!    :  'x= ',(0.001*xs(ipt)),'   y= ',(0.001*ys(jpt))
!
!-----------------------------------------------------------------------
!
!  Interpolate (in the horizontal) for the whole vertical column.
!
!-----------------------------------------------------------------------
!
      CALL colint(nx,ny,nz,nvar,                                        &
             xs,ys,zp,xua(ista),yua(ista),ipt,jpt,anx,                  &
             su,sv,stheta,spres,shght,sqv,selev,                        &
             nlevs)
!
!-----------------------------------------------------------------------
!
!  Convert pressure to ln(p) for interpolation
!
!-----------------------------------------------------------------------
!
      DO k=1,nlevs
        spres(k)=LOG(spres(k))
      END DO
!
!-----------------------------------------------------------------------
!
!  Interpolate in the vertical at each obs level and compute
!  obs differences.
!
!-----------------------------------------------------------------------
!
      hgtgnd=0.5*(shght(2)+shght(1))
      trnua(ista)=hgtgnd
      DO k=1,nlevsua(ista)
        DO kgrid=2,nlevs-1
          IF(shght(kgrid) > hgtua(k,ista)) GO TO 260
        END DO
        DO ivar=1,nvar
          qualua(ivar,k,ista)=-9
        END DO
        CYCLE
        260       CONTINUE
        whigh=(hgtua(k,ista)-shght(kgrid-1))/                           &
               (shght(kgrid)-shght(kgrid-1))
        wlow=1.-whigh
!
        hgtagl=AMIN1(hqback(nlvqback),                                  &
                     AMAX1(hqback(1),(hgtua(k,ista)-hgtgnd)))
        DO ktab=2,nlvqback-1
          IF(hqback(ktab) > hgtagl) EXIT
        END DO
!        281       CONTINUE
        wqhigh=(hgtagl-hqback(ktab-1))/                                 &
               (hqback(ktab)-hqback(ktab-1))
        wqlow=1.-wqhigh
!
        IF(qualua(1,k,ista) > 0) THEN
          oanxua(1,k,ista)=wlow*su(kgrid-1)+whigh*su(kgrid)
          odifua(1,k,ista)=obsua(1,k,ista)-oanxua(1,k,ista)
          qobsua(1,k,ista)=qobsua(1,k,ista)/                            &
              (wqlow*qback(1,ktab-1)+wqhigh*qback(1,ktab))
        END IF
        IF(qualua(2,k,ista) > 0) THEN
          oanxua(2,k,ista)=wlow*sv(kgrid-1)+whigh*sv(kgrid)
          odifua(2,k,ista)=obsua(2,k,ista)-oanxua(2,k,ista)
          qobsua(2,k,ista)=qobsua(2,k,ista)/                            &
              (wqlow*qback(2,ktab-1)+wqhigh*qback(2,ktab))
        END IF
        IF(qualua(3,k,ista) > 0) THEN
          oanxua(3,k,ista)=EXP( wlow*spres(kgrid-1)+                    &
                               whigh*spres(kgrid) )
          odifua(3,k,ista)=obsua(3,k,ista)-oanxua(3,k,ista)
          qobsua(3,k,ista)=qobsua(3,k,ista)/                            &
              (wqlow*qback(3,ktab-1)+wqhigh*qback(3,ktab))
        END IF
        IF(qualua(4,k,ista) > 0) THEN
          oanxua(4,k,ista)=wlow*stheta(kgrid-1)+whigh*stheta(kgrid)
          odifua(4,k,ista)=obsua(4,k,ista)-oanxua(4,k,ista)
          qbthe=wqlow*qback(4,ktab-1)+wqhigh*qback(4,ktab)
          theua(k,ista)=( (obsua(4,k,ista)/qobsua(4,k,ista))+           &
                       (oanxua(4,k,ista)/qbthe) ) /                     &
                       ((1./qobsua(4,k,ista)) + (1./qbthe))
          qobsua(4,k,ista)=qobsua(4,k,ista)/qbthe
        ELSE
          theua(k,ista)=wlow*stheta(kgrid-1)+whigh*stheta(kgrid)
        END IF
        IF(qualua(5,k,ista) > 0) THEN
          oanxua(5,k,ista)=wlow*sqv(kgrid-1)+whigh*sqv(kgrid)
          odifua(5,k,ista)=obsua(5,k,ista)-oanxua(5,k,ista)
          qobsua(5,k,ista)=qobsua(5,k,ista)/                            &
                 (wqlow*qback(5,ktab-1)+wqhigh*qback(5,ktab))
        END IF
      END DO
!
    ELSE
!
!      write(6,'(a,a)') stnua(ista),
!    :            ' outside ARPS domain, skipping'

      isrcua(ista)=0

!     write(6,'(a,a,i4)') ' Extrapolation status returned from',
!    :                        ' subroutine findlc: ',ireturn
!      IF(ireturn.eq.-1) write(6,'(a)')
!    :      ' Extrapolation in x detected'
!      IF(ireturn.eq.-2) write(6,'(a)')
!    :      ' Extrapolation in y detected'
!      write (6,'(2x,a,f12.2,a,f12.2,/
!    :             2x,a,i6,a,i6/)')
!    :  ' location x= ',(0.001*xua(ista)),
!    :         '   y= ',(0.001*yua(ista)),
!    :  ' nearest pt i= ',ipt,'   j= ',jpt
!      write (6,'(12x,a,f12.2,a,f12.2/)')
!    :  'x= ',(0.001*xs(ipt)),'   y= ',(0.001*ys(jpt))
!
      DO k=1,nzua
        DO ivar=1,nvar
          qualua(ivar,k,ista)=-9
        END DO
      END DO

    END IF   ! inside domain?

  END DO
! wdt
  !WRITE(6,'(//,1x,i5,a,i5,a)') kntdom,' of ',nobsua,                    &
  !        ' upper air profiles are inside the ARPS domain'
  PRINT *, kntdom,' of ',nobsua,                    &
           ' upper air profiles are inside the ARPS domain'
  RETURN
END SUBROUTINE grdtoua
!
!##################################################################
!##################################################################
!######                                                      ######
!######                SUBROUTINE GRDTORET                   ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!


SUBROUTINE grdtoret(nx,ny,nz,nztab,                                     & 4,4
           nzret,mxret,mxcolret,nvar,ncolret,                           &
           xs,ys,zp,anx,qback,hqback,nlvqback,                          &
           shght,su,sv,spres,stheta,sqv,                                &
           stnret,iret,xretc,yretc,hgtretc,                             &
           obsret,qobsret,qualret,nlevret,                              &
           odifret,oanxret,theretc,trnretc)

!-----------------------------------------------------------------------
!
!  PURPOSE:
!  Gridded data are interpolated to retrieval column locations to
!  produce observation differences.  For now, bilinear interpolation
!  is used to create a vertical sounding at the obs location
!  and that is interpolated in the vertical to obtain the
!  bacground value.
!
!  AUTHOR:
!
!  Keith Brewster, CAPS, July, 1995
!
!  MODIFICATION HISTORY:
!  Sept, 1996 (KB)
!  Added count-reporting diagnostic output.
!
!-----------------------------------------------------------------------
!
!  Variable Declarations:
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
!
  INTEGER :: nx,ny,nz,nztab
  INTEGER :: nzret,mxret,mxcolret,nvar
  INTEGER :: ncolret
!
!-----------------------------------------------------------------------
!
!  Arrays defining model grid
!
!-----------------------------------------------------------------------
!
  REAL :: xs(nx)
  REAL :: ys(ny)
  REAL :: zp    (nx,ny,nz)     ! The physical height coordinate defined at
                               ! w-point of the staggered grid.
!
!-----------------------------------------------------------------------
!
!  Background fields
!
!-----------------------------------------------------------------------
!
  REAL :: anx(nx,ny,nz,nvar)
  REAL :: qback(nvar,nztab)
  REAL :: hqback(nztab)
  INTEGER :: nlvqback
!
  REAL :: shght(nz)
  REAL :: su(nz)
  REAL :: sv(nz)
  REAL :: spres(nz)
  REAL :: stheta(nz)
  REAL :: sqv(nz)
!
!-----------------------------------------------------------------------
!
!  Station variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=5) :: stnret(mxret)
  INTEGER :: iret(mxcolret)
  REAL :: xretc(mxcolret),yretc(mxcolret)
  REAL :: hgtretc(nzret,mxcolret)
  REAL :: obsret(nvar,nzret,mxcolret)
  REAL :: qobsret(nvar,nzret,mxcolret)
  INTEGER :: qualret(nvar,nzret,mxcolret)
  INTEGER :: nlevret(mxcolret)
  REAL :: odifret(nvar,nzret,mxcolret)
  REAL :: oanxret(nvar,nzret,mxcolret)
  REAL :: theretc(nzret,mxcolret)
  REAL :: trnretc(mxcolret)
!
!-----------------------------------------------------------------------
!
!  Misc. internal variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: ista,ivar,k,kgrid,ktab,kntdom
  INTEGER :: ipt,jpt,ireturn,nlevs
  REAL :: selev,hgtgnd,hgtagl
  REAL :: whigh,wlow,wqhigh,wqlow,qbthe
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
  kntdom=0
  DO ista=1,ncolret
!
!-----------------------------------------------------------------------
!
!  Find location in ARPS grid.
!
!-----------------------------------------------------------------------
!
    CALL findlc(nx,ny,xs,ys,xretc(ista),yretc(ista),                    &
                ipt,jpt,ireturn)
!
!-----------------------------------------------------------------------
!
!  Interpolate if extrapoltion is not indicated.
!
!-----------------------------------------------------------------------
!
    IF(ireturn == 0) THEN
!      write(6,'(a,i4,a)')  'Column ',ista,
!    :            ' inside ARPS domain, processing'

      kntdom=kntdom+1

!      write (6,'(2x,a,f12.2,a,f12.2,/
!    :             2x,a,i6,a,i6)')
!    :  ' location x= ',(0.001*xua(ista)),
!    :         '   y= ',(0.001*yua(ista)),
!    :  ' found near pt i= ',ipt,'   j= ',jpt
!      write (6,'(12x,a,f12.2,a,f12.2,/)')
!    :  'x= ',(0.001*xs(ipt)),'   y= ',(0.001*ys(jpt))
!
!-----------------------------------------------------------------------
!
!  Interpolate (in the horizontal) for the whole vertical column.
!
!-----------------------------------------------------------------------
!
      CALL colint(nx,ny,nz,nvar,                                        &
             xs,ys,zp,xretc(ista),yretc(ista),ipt,jpt,anx,              &
             su,sv,stheta,spres,shght,sqv,selev,                        &
             nlevs)
!
!-----------------------------------------------------------------------
!
!  Convert pressure to ln(p) for interpolation
!
!-----------------------------------------------------------------------
!
      DO k=1,nlevs
        spres(k)=LOG(spres(k))
      END DO
!
!-----------------------------------------------------------------------
!
!  Interpolate in the vertical at each obs level and compute
!  obs differences.
!
!-----------------------------------------------------------------------
!
      hgtgnd=0.5*(shght(2)+shght(1))
      trnretc(ista)=hgtgnd
      DO k=1,nlevret(ista)
        DO kgrid=2,nlevs-1
          IF(shght(kgrid) > hgtretc(k,ista)) GO TO 260
        END DO
        DO ivar=1,nvar
          qualret(ivar,k,ista)=-9
        END DO
        CYCLE
        260       CONTINUE
        whigh=(hgtretc(k,ista)-shght(kgrid-1))/                         &
               (shght(kgrid)-shght(kgrid-1))
        wlow=1.-whigh
!
        hgtagl=AMIN1(hqback(nlvqback),                                  &
                     AMAX1(hqback(1),(hgtretc(k,ista)-hgtgnd)))
        DO ktab=2,nlvqback-1
          IF(hqback(ktab) > hgtagl) EXIT
        END DO
!        281       CONTINUE
        wqhigh=(hgtagl-hqback(ktab-1))/                                 &
               (hqback(ktab)-hqback(ktab-1))
        wqlow=1.-wqhigh
!
        IF(qualret(1,k,ista) > 0) THEN
          oanxret(1,k,ista)=wlow*su(kgrid-1)+whigh*su(kgrid)
          odifret(1,k,ista)=obsret(1,k,ista)-oanxret(1,k,ista)
          qobsret(1,k,ista)=qobsret(1,k,ista)/                          &
                 (wqlow*qback(1,ktab-1)+wqhigh*qback(1,ktab))
        END IF
        IF(qualret(2,k,ista) > 0) THEN
          oanxret(2,k,ista)=wlow*sv(kgrid-1)+whigh*sv(kgrid)
          odifret(2,k,ista)=obsret(2,k,ista)-oanxret(2,k,ista)
          qobsret(2,k,ista)=qobsret(2,k,ista)/                          &
                 (wqlow*qback(2,ktab-1)+wqhigh*qback(2,ktab))
        END IF
        IF(qualret(3,k,ista) > 0) THEN
          oanxret(3,k,ista)=EXP( wlow*spres(kgrid-1)+                   &
                                 whigh*spres(kgrid) )
          odifret(3,k,ista)=obsret(3,k,ista)-oanxret(3,k,ista)
          qobsret(3,k,ista)=qobsret(3,k,ista)/                          &
                 (wqlow*qback(3,ktab-1)+wqhigh*qback(3,ktab))
        END IF
        IF(qualret(4,k,ista) > 0) THEN
          oanxret(4,k,ista)=wlow*stheta(kgrid-1)+whigh*stheta(kgrid)
          odifret(4,k,ista)=obsret(4,k,ista)-oanxret(4,k,ista)
          qbthe=wqlow*qback(4,ktab-1)+wqhigh*qback(4,ktab)
          theretc(k,ista)=( (obsret(4,k,ista)/qobsret(4,k,ista))+       &
                       (oanxret(4,k,ista)/qbthe) ) /                    &
                       ((1./qobsret(4,k,ista)) + (1./qbthe))
          qobsret(4,k,ista)=qobsret(4,k,ista)/qbthe
        ELSE
          theretc(k,ista)=wlow*stheta(kgrid-1)+whigh*stheta(kgrid)
        END IF
        IF(qualret(5,k,ista) > 0) THEN
          oanxret(5,k,ista)=wlow*sqv(kgrid-1)+whigh*sqv(kgrid)
          odifret(5,k,ista)=obsret(5,k,ista)-oanxret(5,k,ista)
          qobsret(5,k,ista)=qobsret(5,k,ista)/                          &
                 (wqlow*qback(5,ktab-1)+wqhigh*qback(5,ktab))
        END IF
      END DO
!
    ELSE
!
!      write(6,'(a,a)') stnret(ista),
!    :            ' outside ARPS domain, skipping'

      iret(ista)=0

!     write(6,'(a,a,i4)') ' Extrapolation status returned from',
!    :                        ' subroutine findlc: ',ireturn
!      IF(ireturn.eq.-1) write(6,'(a)')
!    :      ' Extrapolation in x detected'
!      IF(ireturn.eq.-2) write(6,'(a)')
!    :      ' Extrapolation in y detected'
!      write (6,'(2x,a,f12.2,a,f12.2,/
!    :             2x,a,i6,a,i6/)')
!    :  ' location x= ',(0.001*xretc(ista)),
!    :         '   y= ',(0.001*yretc(ista)),
!    :  ' nearest pt i= ',ipt,'   j= ',jpt
!      write (6,'(12x,a,f12.2,a,f12.2/)')
!    :  'x= ',(0.001*xs(ipt)),'   y= ',(0.001*ys(jpt))
!
      DO k=1,nzret
        DO ivar=1,nvar
          qualret(ivar,k,ista)=-9
        END DO
      END DO

    END IF   ! inside domain?

  END DO
  WRITE(6,'(//,1x,i5,a,i5,a)') kntdom,' of ',ncolret,                   &
          ' retrieval columns are inside the ARPS domain'
  RETURN
END SUBROUTINE grdtoret
!
!##################################################################
!##################################################################
!######                                                      ######
!######                 SUBROUTINE COLINT                    ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!


SUBROUTINE colint(nx,ny,nz,nvar,                                        & 8,9
           xs,ys,zp,xpt,ypt,ipt,jpt,anx,                                &
           su,sv,stheta,spres,shght,sqv,selev,                          &
           nlevs)
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!
!  Interpolates ARPS history data in the horizontal to create
!  a column of data located at point xpt, ypt.
!
!  Bilinear interpolation is used.
!
!-----------------------------------------------------------------------
!
!  AUTHOR: Keith Brewster
!  April 1992.
!
!  MODIFICATION HISTORY:
!
!  October, 1992 (K. Brewster)
!  Conversion to ARPS 3.0.
!
!  October, 1994 (K. Brewster)
!  Conversion to ARPS 4.0.
!
!-----------------------------------------------------------------------
!
!  INPUT:
!
!    nx,ny,nz Dimensions of ARPS grids.
!
!    xs       x coordinate of scalar points in physical/comp. space (m)
!    ys       y coordinate of scalar points in physical/comp. space (m)
!    zp       z coordinate of scalar grid points in physical space (m)
!
!    xpt      x coordinate of desired sounding (m)
!    ypt      y coordinate of desired sounding (m)
!
!    ipt      i index of grid point just west of xpt,ypt
!    jpt      j index of grid point just south of xpt,ypt
!
!    anx      Background field
!
!  OUTPUT:
!
!    su       Interpolated u wind component.  (m/s)
!    sv       Interpolated v wind component.  (m/s)
!    stheta   Interpolated potential temperature (K).
!    spres    Interpolated pressure. (Pascals)
!    shght    Interpolated height (meters)
!    sqv      Interpolated specific humidity (kg/kg)
!    selev    Interpolated surface elevation (m)
!    nlevs    Number of above-ground sounding levels.
!
!-----------------------------------------------------------------------
!
!  Variable Declarations:
!
!-----------------------------------------------------------------------
!
!  Arguments -- location data
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE

  INTEGER :: nx,ny,nz,nvar     ! Dimensions of ARPS grids.
  REAL :: xs(nx)               ! x coordinate of grid points in
                               ! physical/comp. space (m)
  REAL :: ys(ny)               ! y coordinate of grid points in
                               ! physical/comp. space (m)
  REAL :: zp(nx,ny,nz)         ! z coordinate of grid points in
                               ! physical space (m)
  REAL :: xpt                  ! location to find in x coordinate (m)
  REAL :: ypt                  ! location to find in y coordinate (m)
  INTEGER :: ipt               ! i index to the west of desired
                               ! location
  INTEGER :: jpt               ! j index to the south of desired
                               ! location
!
!-----------------------------------------------------------------------
!
!  Arguments -- background field
!
!-----------------------------------------------------------------------
!
  REAL :: anx(nx,ny,nz,nvar)
!
!-----------------------------------------------------------------------
!
!  Arguments -- Extracted sounding variables
!
!-----------------------------------------------------------------------
!
  REAL :: su(nz),sv(nz),stheta(nz),sqv(nz)
  REAL :: spres(nz),shght(nz)
  REAL :: selev
  INTEGER :: nlevs
!
!-----------------------------------------------------------------------
!
!  Functions called
!
!-----------------------------------------------------------------------
!
  REAL :: aint2d
!
!-----------------------------------------------------------------------
!
!  Include files
!
!-----------------------------------------------------------------------
!
  INCLUDE 'phycst.inc'
!
!-----------------------------------------------------------------------
!
!  Misc. local variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: k,in,jn
  REAL :: delx,ddx,dely,ddy,w1,w2,w3,w4
  REAL :: t2,t3,hmid,tmid
!
!-----------------------------------------------------------------------
!
!  Find corner weights
!
!-----------------------------------------------------------------------
!
  in=ipt+1
  delx=xs(in)-xs(ipt)
  IF(ABS(delx) > 0.) THEN
    ddx=(xpt-xs(ipt))/delx
  ELSE
    ddx=0.
  END IF

  jn=jpt+1
  dely=ys(jn)-ys(jpt)
  IF(ABS(dely) > 0.) THEN
    ddy=(ypt-ys(jpt))/dely
  ELSE
    ddy=0.
  END IF

  w1=(1.-ddx)*(1.-ddy)
  w2=ddx*(1.-ddy)
  w3=ddx*ddy
  w4=(1.-ddx)*ddy
!
!-----------------------------------------------------------------------
!
!  Interpolate all variables at all levels.
!
!-----------------------------------------------------------------------
!
  nlevs=nz-1
  DO k=1,nz-1
    shght(k)=                                                           &
        aint2d(nx,ny,nz,    zp,ipt,jpt,k,in,jn,w1,w2,w3,w4)
    su(k)=                                                              &
        aint2d(nx,ny,nz, anx(1,1,1,1),ipt,jpt,k,in,jn,w1,w2,w3,w4)
    sv(k)=                                                              &
        aint2d(nx,ny,nz, anx(1,1,1,2),ipt,jpt,k,in,jn,w1,w2,w3,w4)
    spres(k)=                                                           &
        aint2d(nx,ny,nz, anx(1,1,1,3),ipt,jpt,k,in,jn,w1,w2,w3,w4)
    stheta(k)=                                                          &
        aint2d(nx,ny,nz, anx(1,1,1,4),ipt,jpt,k,in,jn,w1,w2,w3,w4)
    sqv(k)=                                                             &
        aint2d(nx,ny,nz, anx(1,1,1,5),ipt,jpt,k,in,jn,w1,w2,w3,w4)
  END DO
!
!-----------------------------------------------------------------------
!
!  Get height at scalar points, since zp was defined at w points.
!
!-----------------------------------------------------------------------
!
  selev=shght(2)
  DO k=1,nz-1
    shght(k)=0.5*(shght(k+1)+shght(k))
  END DO
!
!-----------------------------------------------------------------------
!
!  Get a value at the surface, by linearly interpolating
!  between the 1st and second levels.
!
!-----------------------------------------------------------------------
!
  w2=(selev-shght(1))/(shght(2)-shght(1))
  w1=1.-w2
  su(1)=w1*    su(1) + w2*    su(2)
  sv(1)=w1*    sv(1) + w2*    sv(2)
  stheta(1)=w1*stheta(1) + w2*stheta(2)
  sqv(1)=w1*   sqv(1) + w2*   sqv(2)
  shght(1)=selev
!
!-----------------------------------------------------------------------
!
!  Integrate downward to get the pressure at level 1.
!
!-----------------------------------------------------------------------
!
  t3=stheta(3)*(spres(3)/100000.)**rddcp
  t2=stheta(2)*(spres(2)/100000.)**rddcp
  hmid=0.5*(shght(2)+shght(1))
  tmid=t3+(((shght(3)-hmid)/(shght(3)-shght(2)))*(t2-t3))
  spres(1)=spres(2)*EXP(g*(shght(2)-shght(1))/(rd*tmid))
  RETURN
END SUBROUTINE colint
!
!##################################################################
!##################################################################
!######                                                      ######
!######                 SUBROUTINE QCDIFF                    ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!


SUBROUTINE qcdiff(nvar,nvarrad,nvarradin,mxsng,nsrcsng,                 & 3,3
           nzua,mxua,nsrcua,                                            &
           nzrad,mxrad,mxcolrad,nsrcrad,                                &
           nzret,mxret,mxcolret,nsrcret,                                &
           nobsng,nobsua,ncolrad,ncolret,nam_var,                       &
           stnsng,isrcsng,hgtsng,obsng,oanxsng,odifsng,                 &
           qcthrsng,qualsng,                                            &
           stnua,isrcua,hgtua,obsua,oanxua,odifua,                      &
           qcthrua,qualua,nlevsua,                                      &
           stnrad,irad,isrcrad,hgtradc,obsrad,odifrad,                  &
           qcthrrad,qualrad,nlevrad,                                    &
           stnret,iret,isrcret,hgtretc,                                 &
           obsret,oanxret,odifret,                                      &
           qcthrret,qualret,nlevret,                                    &
           obsknt,rejknt)
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!  Observation differences are compared to expected errors
!  and rejected if they exceed a threshold.
!
!  AUTHOR:
!
!  Keith Brewster, CAPS, July, 1995
!
!  MODIFICATION HISTORY:
!
!
!-----------------------------------------------------------------------
!
!  Variable Declarations:
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
!
!  Sizing variables
!
  INTEGER :: nvar,nvarrad,nvarradin,mxsng,nsrcsng
  INTEGER :: nzua,mxua,nsrcua
  INTEGER :: nzrad,mxrad,mxcolrad,nsrcrad
  INTEGER :: nzret,mxret,mxcolret,nsrcret
!
  INTEGER :: nobsng,nobsua,ncolrad,ncolret
  CHARACTER (LEN=6) :: nam_var(nvar)
!
!-----------------------------------------------------------------------
!
!  Station variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=5) :: stnsng(mxsng)
  INTEGER :: isrcsng(mxsng)
  REAL :: obsng(nvar,mxsng)
  REAL :: hgtsng(mxsng)
  REAL :: qcthrsng(nvar,nsrcsng)
  INTEGER :: qualsng(nvar,mxsng)
  REAL :: oanxsng(nvar,mxsng)
  REAL :: odifsng(nvar,mxsng)
!
  CHARACTER (LEN=5) :: stnua(mxua)
  INTEGER :: isrcua(mxua)
  REAL :: hgtua(nzua,mxua)
  REAL :: obsua(nvar,nzua,mxua)
  REAL :: oanxua(nvar,nzua,mxua)
  REAL :: odifua(nvar,nzua,mxua)
  REAL :: qcthrua(nvar,nsrcua)
  INTEGER :: qualua(nvar,nzua,mxua)
  INTEGER :: nlevsua(mxua)
!
  CHARACTER (LEN=5) :: stnrad(mxrad)
  INTEGER :: irad(mxcolrad)
  INTEGER :: isrcrad(0:mxrad)
  REAL :: hgtradc(nzrad,mxcolrad)
  REAL :: obsrad(nvarradin,nzrad,mxcolrad)
  REAL :: odifrad(nvarrad,nzrad,mxcolrad)
  REAL :: qcthrrad(nvarradin,nsrcrad)
  INTEGER :: qualrad(nvarrad,nzrad,mxcolrad)
  INTEGER :: nlevrad(mxcolrad)
!
  CHARACTER (LEN=5) :: stnret(mxret)
  INTEGER :: iret(mxcolret)
  INTEGER :: isrcret(0:mxret)
  REAL :: hgtretc(nzret,mxcolret)
  REAL :: obsret(nvar,nzret,mxcolret)
  REAL :: oanxret(nvar,nzret,mxcolret)
  REAL :: odifret(nvar,nzret,mxcolret)
  REAL :: qcthrret(nvar,nsrcret)
  INTEGER :: qualret(nvar,nzret,mxcolret)
  INTEGER :: nlevret(mxcolret)

  REAL :: obsknt(nvar)
  REAL :: rejknt(nvar)
!
!-----------------------------------------------------------------------
!
!  Misc. internal variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: ista,ivar,klev,jsrc
  REAL :: pctrej,vrdiff
  REAL :: tk,qvsat,qcthrqv
!
!-----------------------------------------------------------------------
!
!  Function f_qvsat and inline directive for Cray PVP
!
!-----------------------------------------------------------------------
!
  REAL :: f_qvsat

!fpp$ expand (f_qvsat)
!!dir$ inline always f_qvsat
!*$*  inline routine (f_qvsat)

!
!-----------------------------------------------------------------------
!
!  Include files
!
!-----------------------------------------------------------------------
!
  INCLUDE 'phycst.inc'
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!
!-----------------------------------------------------------------------
!
!  Check single-level observation differences
!
!-----------------------------------------------------------------------
!
  DO ivar=1,nvar
    obsknt(ivar)=0.
    rejknt(ivar)=0.
  END DO
  DO ista=1,nobsng
    IF(isrcsng(ista) /= 0) THEN
      DO ivar=1,nvar-1
        IF(qualsng(ivar,ista) > 0) THEN
          obsknt(ivar)=obsknt(ivar)+1.
          IF(ABS(odifsng(ivar,ista)) > qcthrsng(ivar,isrcsng(ista)) ) THEN
            WRITE(6,'(a,a,a,a)')                                        &
                ' Discarding ',nam_var(ivar),                           &
                ' at ',stnsng(ista)
            WRITE(6,'(a,f8.0,a,f16.6,a,f16.6,a,f16.6)')                 &
                ' Hgt= ',hgtsng(ista),' Ob= ',obsng(ivar,ista),         &
                ' Diff= ',odifsng(ivar,ista),                           &
                ' Thresh=',qcthrsng(ivar,isrcsng(ista))
            qualsng(ivar,ista)=-199
            rejknt(ivar)=rejknt(ivar)+1.
          END IF
        END IF
      END DO
      IF(qualsng(5,ista) > 0) THEN
        obsknt(5)=obsknt(5)+1.
        tk=oanxsng(4,ista)*((oanxsng(3,ista)/p0)**rddcp)
        qvsat=f_qvsat(oanxsng(3,ista),tk)
        qcthrqv=qcthrsng(5,isrcsng(ista))*qvsat
        IF(ABS(odifsng(5,ista)) > qcthrqv) THEN
          WRITE(6,'(a,a,a,a)')                                          &
                ' Discarding ',nam_var(5),                              &
                ' at ',stnsng(ista)
          WRITE(6,'(a,f8.0,a,f16.6,a,f16.6,a,f16.6)')                   &
                ' Hgt= ',hgtsng(ista),' Ob= ',obsng(5,ista),            &
                ' Diff= ',odifsng(5,ista),                              &
                ' Thresh=',qcthrqv
          qualsng(5,ista)=-199
          rejknt(5)=rejknt(5)+1.
        END IF
      END IF
!
!-----------------------------------------------------------------------
!
!  Synchronize wind component flags
!
!-----------------------------------------------------------------------
!
      IF(qualsng(1,ista) == -199) qualsng(2,ista)=-199
      IF(qualsng(2,ista) == -199) qualsng(1,ista)=-199

    END IF
  END DO
!
!-----------------------------------------------------------------------
!
!  Write statistics
!
!-----------------------------------------------------------------------
!
  WRITE(6,'(//a/a)') ' QC Statistics for single-level data',            &
                     ' Variable     Obs      Rejected    Percent'
  DO ivar=1,nvar
    pctrej=0.
    IF(obsknt(ivar) > 0.) pctrej=100.*rejknt(ivar)/obsknt(ivar)
    WRITE(6,'(2x,a,i10,i10,f8.1)')                                      &
        nam_var(ivar),nint(obsknt(ivar)),nint(rejknt(ivar)),pctrej
  END DO
  WRITE(6,'(/a)') ' '
!
!-----------------------------------------------------------------------
!
!    Check upper-air observation differences
!
!-----------------------------------------------------------------------
!
  DO ivar=1,nvar
    obsknt(ivar)=0.
    rejknt(ivar)=0.
  END DO
  DO ista=1,nobsua
    IF(isrcua(ista) /= 0) THEN
      DO klev=1,nlevsua(ista)
        DO ivar=1,nvar-1
          IF(qualua(ivar,klev,ista) > 0) THEN
            obsknt(ivar)=obsknt(ivar)+1.
            IF(ABS(odifua(ivar,klev,ista)) >   qcthrua(ivar,isrcua(ista)) ) THEN
              WRITE(6,'(a,a,a,a,a,i4)') ' Discarding UA ',              &
                  nam_var(ivar),' at sta ',stnua(ista),                 &
                  ' klev =',klev
              WRITE(6,'(a,f8.0,a,f16.6,a,f16.6,a,f16.6)')               &
                  ' Hgt= ',hgtua(klev,ista),                            &
                  ' Ob= ',obsua(ivar,klev,ista),                        &
                  ' Diff= ',odifua(ivar,klev,ista),                     &
                  ' Thresh=',qcthrua(ivar,isrcua(ista))
              qualua(ivar,klev,ista)=-199
              rejknt(ivar)=rejknt(ivar)+1.
            END IF
          END IF
        END DO
        IF(qualua(5,klev,ista) > 0) THEN
          obsknt(5)=obsknt(5)+1.
          tk=oanxua(4,klev,ista)*                                       &
                   ((oanxua(3,klev,ista)/p0)**rddcp)
          qvsat=f_qvsat(oanxua(3,klev,ista),tk)
          qcthrqv=qcthrua(5,isrcua(ista))*qvsat
          IF(ABS(odifua(5,klev,ista)) > qcthrqv) THEN
            WRITE(6,'(a,a,a,a)')                                        &
                ' Discarding ',nam_var(5),                              &
                ' at ',stnua(ista)
            WRITE(6,'(a,f8.0,a,f16.6,a,f16.6,a,f16.6)')                 &
                ' Hgt= ',hgtua(klev,ista),                              &
                ' Ob= ',obsua(5,klev,ista),                             &
                ' Diff= ',odifua(5,klev,ista),                          &
                ' Thresh=',qcthrqv
            qualua(5,klev,ista)=-199
            rejknt(5)=rejknt(5)+1.
          END IF
        END IF
!
!-----------------------------------------------------------------------
!
!  Synchronize wind component flags
!
!-----------------------------------------------------------------------
!
        IF(qualua(1,klev,ista) == -199) qualua(2,klev,ista)=-199
        IF(qualua(2,klev,ista) == -199) qualua(1,klev,ista)=-199

      END DO
    END IF
  END DO
!
!-----------------------------------------------------------------------
!
!  Write statistics
!
!-----------------------------------------------------------------------
!
  WRITE(6,'(//a/a)') ' QC Statistics for UA data',                      &
                     ' Variable     Obs      Rejected    Percent'
  DO ivar=1,nvar
    pctrej=0.
    IF(obsknt(ivar) > 0.) pctrej=100.*rejknt(ivar)/obsknt(ivar)
    WRITE(6,'(2x,a,i10,i10,f8.1)')                                      &
        nam_var(ivar),nint(obsknt(ivar)),nint(rejknt(ivar)),pctrej
  END DO
  WRITE(6,'(/a)') ' '
!
!-----------------------------------------------------------------------
!
!    Check radar data observation differences
!    Here radial wind difference is computed and compared only.
!
!-----------------------------------------------------------------------
!
  obsknt(1)=0.
  rejknt(1)=0.
  DO ista=1,ncolrad
    IF(irad(ista) /= 0) THEN
      jsrc=isrcrad(irad(ista))
      DO klev=1,nlevrad(ista)
        IF(qualrad(1,klev,ista) > 0 .AND. qualrad(2,klev,ista) > 0 ) THEN
          obsknt(1)=obsknt(1)+1.
          vrdiff=SQRT(                                                  &
                 odifrad(1,klev,ista)*odifrad(1,klev,ista)+             &
                 odifrad(2,klev,ista)*odifrad(2,klev,ista))
          IF(vrdiff > qcthrrad(2,jsrc) ) THEN
            WRITE(6,'(a,a,i5,a,i4)') ' Discarding radar Vr',            &
                ' at col ',ista,' klev =',klev
            WRITE(6,'(a,f8.0,a,f16.6,a,f16.6,a,f16.6)')                 &
                ' Hgt= ',hgtradc(klev,ista),                            &
                ' Ob= ',obsrad(2,klev,ista),                            &
                ' Diff= ',vrdiff,                                       &
                ' Thresh=',qcthrrad(2,jsrc)
            qualrad(1,klev,ista)=-199
            qualrad(2,klev,ista)=-199
            rejknt(1)=rejknt(1)+1.
          END IF
        END IF
      END DO
    END IF
  END DO
  WRITE(6,'(//a/a)') ' QC Statistics for radar data',                   &
                     ' Variable     Obs      Rejected    Percent'
  pctrej=0.
  IF(obsknt(1) > 0.) pctrej=100.*rejknt(1)/obsknt(1)
  WRITE(6,'(2x,a,i10,i10,f8.1)')                                        &
        'Vr',nint(obsknt(1)),nint(rejknt(1)),pctrej
  WRITE(6,'(/a)') ' '
!
!-----------------------------------------------------------------------
!
!    Check retrieval observation differences
!
!-----------------------------------------------------------------------
!
  DO ivar=1,nvar
    obsknt(ivar)=0.
    rejknt(ivar)=0.
  END DO
  DO ista=1,ncolret
    IF(iret(ista) /= 0) THEN
      jsrc=isrcret(iret(ista))
      DO klev=1,nlevret(ista)
        DO ivar=1,nvar-1
          IF(qualret(ivar,klev,ista) > 0) THEN
            obsknt(ivar)=obsknt(ivar)+1.
            IF(ABS(odifret(ivar,klev,ista)) >   qcthrret(ivar,jsrc) ) THEN
              WRITE(6,'(a,a,a,i5,a,i4)') ' Discarding retrieval ',      &
                  nam_var(ivar),' at col ',ista,' klev =',klev
              WRITE(6,'(a,f8.0,a,f16.6,a,f16.6,a,f16.6)')               &
                  ' Hgt= ',hgtretc(klev,ista),                          &
                  ' Ob= ',obsret(ivar,klev,ista),                       &
                  ' Diff= ',odifret(ivar,klev,ista),                    &
                  ' Thresh=',qcthrret(ivar,jsrc)
              qualret(ivar,klev,ista)=-199
              rejknt(ivar)=rejknt(ivar)+1.
            END IF
          END IF
        END DO
        IF(qualret(5,klev,ista) > 0) THEN
          obsknt(5)=obsknt(5)+1.
          tk=oanxret(4,klev,ista)*                                      &
                    ((oanxret(3,klev,ista)/p0)**rddcp)
          qvsat=f_qvsat(oanxret(3,klev,ista),tk)
          qcthrqv=qcthrret(5,jsrc)*qvsat
          IF(ABS(odifret(5,klev,ista)) > qcthrqv) THEN
            WRITE(6,'(a,a,a,i5,a,i4)') ' Discarding retrieval ',        &
                  nam_var(5),' at col ',ista,' klev =',klev
            WRITE(6,'(a,f8.0,a,f16.6,a,f16.6,a,f16.6)')                 &
                ' Hgt= ',hgtretc(klev,ista),                            &
                ' Ob= ',obsret(5,klev,ista),                            &
                ' Diff= ',odifret(5,klev,ista),                         &
                ' Thresh=',qcthrqv
            qualret(5,klev,ista)=-199
            rejknt(5)=rejknt(5)+1.
          END IF
        END IF
!
!-----------------------------------------------------------------------
!
!  Synchronize wind component flags
!
!-----------------------------------------------------------------------
!
        IF(qualret(1,klev,ista) == -199) qualret(2,klev,ista)=-199
        IF(qualret(2,klev,ista) == -199) qualret(1,klev,ista)=-199

      END DO
    END IF
  END DO
!
!-----------------------------------------------------------------------
!
!  Write statistics
!
!-----------------------------------------------------------------------
!
  WRITE(6,'(//a/a)') ' QC Statistics for retrieval data',               &
                     ' Variable     Obs      Rejected    Percent'
  DO ivar=1,nvar
    pctrej=0.
    IF(obsknt(ivar) > 0.) pctrej=100.*rejknt(ivar)/obsknt(ivar)
    WRITE(6,'(2x,a,i10,i10,f8.1)')                                      &
        nam_var(ivar),nint(obsknt(ivar)),nint(rejknt(ivar)),pctrej
  END DO
  WRITE(6,'(/a)') ' '
  RETURN
END SUBROUTINE qcdiff