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


SUBROUTINE rdnmcgrb2(gribfile,grbflen, gribtime,                        & 1,6
           gridesc, iproj_grb, gthin,                                   &
           ni_grb,nj_grb,np_grb, nk_grb,zk_grb, npeq,nit,               &
           pi_grb,pj_grb,ipole, di_grb,dj_grb,                          &
           latsw,lonsw, latne,lonne,                                    &
           latrot,lonrot,angrot,                                        &
           latstr,lonstr,facstr,                                        &
           lattru1,lattru2,lontrue,                                     &
           scanmode, iscan,jscan,kscan,                                 &
           ires,iearth,icomp,                                           &
           jpenta,kpenta,mpenta,ispect,icoeff,                          &
           xp_grb,yp_grb, xo_grb,yo_grb,zo_grb,                         &
           nxgrb,nygrb,nzgrb,var_lev3d,var_grb3d,                       &
           var_grb2d,ibms,rcdata, iret)

!-----------------------------------------------------------------------
!
!  PURPOSE:
!
!  This subroutine is to read and select given variables with GRIB
!  grid ID and level type from NMC GRIB files.
!
!  The decoder of GRIB is from NMC, ftp:nic.fb4.noaa.gov/pub
!
!-----------------------------------------------------------------------
!
!  AUTHOR: Yuhe Liu
!  01/02/1996 Initialized.
!
!  MODIFICATIONS:
!
!  09/24/1998 (Dennis A. Moon, Chief Scientist, SSESCO)
!  Added sorting in vertical levels to assure that the level changes
!  monotonically decreasing.
!
!  November 1999 (Eric Kemp)
!  Added several arguments to subroutine call.
!
!  9 January 2001 (Eric Kemp)
!  Added proper Y2K bug fix conforming with ARPS 5.0.
!
!-----------------------------------------------------------------------
!
!  INPUT:
!
!    gribfile      GRIB file name
!    grbflen       Length of GRIB file name
!    gribtime      Time of GRIB data
!
!  OUTPUT:
!
!    iproj_grb     Map projection number of GRIB data
!    trlon_grb     True longitude of GRIB data (degrees E)
!    latnot_grb(2) True latitude(s) of GRIB data (degrees N)
!    swlat_grb     Latitude  of first grid point at southwest conner
!    swlon_grb     Longitude of first grid point at southwest conner
!
!    dx_grb        x-direction grid length
!    dy_grb        y-direction grid length
!
!    iret          Return flag
!
!-----------------------------------------------------------------------
!
!  Variable Declarations.
!
!-----------------------------------------------------------------------

  USE gribcst2

  IMPLICIT NONE

  INTEGER :: nxgrb,nygrb,nzgrb
  INTEGER :: var_lev3d(nzgrb,n3dvs,n3dlvt)
     ! Levels (hybrid) for each 3-D variable
  REAL :: var_grb3d(nxgrb,nygrb,nzgrb,n3dvs,n3dlvt) ! GRIB 3-D variables
  REAL :: var_grb2d(nxgrb,nygrb,n2dvs,n2dlvt) ! GRIB variables
  LOGICAL :: ibms(nxgrb*nygrb)      ! BMS logical array for data bit map
  REAL :: rcdata(nxgrb*nygrb)      ! temporary data array

  INTEGER :: grbflen
  CHARACTER (LEN=80) :: gribfile
  CHARACTER (LEN=13) :: gribtime
  CHARACTER (LEN=1) :: opnmod

!-----------------------------------------------------------------------
!
!  GRIB grid information
!
!-----------------------------------------------------------------------

  CHARACTER (LEN=42) :: gridesc ! Grid description

  INTEGER :: gdsflg       ! GDS indicator

  INTEGER :: iproj_grb    ! Map projection indicator
  INTEGER :: gthin        ! Indicator of whether the grid is "thinned"

  INTEGER :: ni_grb       ! Number of points along x-axis
  INTEGER :: nj_grb       ! Number of points along y-axis
  INTEGER :: np_grb       ! Total number of horizontal grid points

  INTEGER :: nk_grb       ! Number of vertical parameters
  REAL :: zk_grb(nzgrb)   ! Vertical coordinate parameters

  INTEGER :: npeq         ! Number of lat circles from pole to equator
  INTEGER :: nit(nzgrb)   ! Number of x-points for thinned grid

  REAL :: pi_grb          ! x-coordinate of pole point
  REAL :: pj_grb          ! y-coordinate of pole point
  INTEGER :: ipole        ! Projection center flag

  REAL :: di_grb          ! x-direction increment or grid length
  REAL :: dj_grb          ! y-direction increment or grid length

  REAL :: latsw           ! Latitude  of South West corner point
  REAL :: lonsw           ! Longitude of South West corner point
  REAL :: latne           ! Latitude  of North East corner point
  REAL :: lonne           ! Longitude of North East corner point

  REAL :: lattru1         ! Latitude (1st) at which projection is true
  REAL :: lattru2         ! Latitude (2nd) at which projection is true
  REAL :: lontrue         ! Longitude      at which projection is true

  REAL :: latrot          ! Latitude  of southern pole of rotation
  REAL :: lonrot          ! Longitude of southern pole of rotation
  REAL :: angrot          ! Angle of rotation

  REAL :: latstr          ! Latitude  of the pole of stretching
  REAL :: lonstr          ! Longitude of the pole of stretching
  REAL :: facstr          ! Stretching factor

  INTEGER :: scanmode     ! Scanning indicator
  INTEGER :: iscan        ! x-direction   scanning indicator
  INTEGER :: jscan        ! y-direction   scanning indicator
  INTEGER :: kscan        ! FORTRAN index scanning indicator

  INTEGER :: ires         ! Resolution direction increments indicator
  INTEGER :: iearth       ! Earth shape indicator: spherical or oblate?
  INTEGER :: icomp        ! (u,v) components decomposition indicator

  INTEGER :: jpenta       ! J-Pentagonal resolution parameter
  INTEGER :: kpenta       ! K-Pentagonal resolution parameter
  INTEGER :: mpenta       ! M-Pentagonal resolution parameter
  INTEGER :: ispect       ! Spectral representation type
  INTEGER :: icoeff       ! Spectral coefficient storage mode

  REAL :: xp_grb          ! X coordinate of sub-satellite point
  REAL :: yp_grb          ! Y coordinate of sub-satellite point
  REAL :: xo_grb          ! X coordinate of image sector origin
  REAL :: yo_grb          ! Y coordinate of image sector origin
  REAL :: zo_grb          ! Camera altitude from center of Earth

  INTEGER :: iret         ! Return flag

!-----------------------------------------------------------------------
!
!  Temporary arrays to read GRIB file
!
!-----------------------------------------------------------------------

  INTEGER :: nrecs        ! number of records

  INTEGER :: fsize        ! Size of GRIB file
  INTEGER :: grbunit      ! I/O unit of GRIB file

!-----------------------------------------------------------------------
!
!  Misc internal variables
!
!-----------------------------------------------------------------------

  INTEGER :: i,j,k,l,m,n, ij, ki, kj, ilev
  INTEGER :: iyr,imo,iday,ihr,fhr, myr

  INTEGER :: ileft, iright, iincr
  INTEGER :: jleft, jright, jincr

  INTEGER :: chklev, mlvtp
  INTEGER :: iendn,itypec,wdlen, nwrd

  LOGICAL :: grdflg           ! flag for grid information
  LOGICAL :: fexist

!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!-----------------------------------------------------------------------
!
!  Find the type of endian, type of character set and length of
!  machine word
!
!  iendn     -  Integer for big-endian or little-endian
!               = 0   big-endian
!               = 1   little-endian
!               = 2   cannot compute
!  itypec    -  Integer for type of character set
!               = 0   ascii  character set
!               = 1   ebcdic character set
!               = 2   not ascii or ebcdic
!  wdlen     -  Integer for words size of computer in bytes
!               = 4   for 32 bit (4 bytes) computers
!               = 8   for 64 bit (8 bytes) computers
!
!-----------------------------------------------------------------------

  CALL w3fi04(iendn,itypec,wdlen)
  IF ( iendn == 2 ) THEN
    WRITE(6,'(a)') 'Unknown endian type. Stopped in rdnmcgrb2'
    STOP
  END IF

  IF ( itypec == 2 ) THEN
    WRITE(6,'(a)') 'Unknown character set. Stopped in rdnmcgrb2'
    STOP
  END IF

!-----------------------------------------------------------------------
!
!   initialize the var_lev3d array so we can sort the records by
!   level values as we read them. We can't assume monotonic ordering
!   of the levels
!
!-----------------------------------------------------------------------

  DO k=1, nzgrb
    DO n=1, n3dvs
      DO m=1, n3dlvt
        var_lev3d(k,n,m)= -999999
      END DO
    END DO
  END DO

!-----------------------------------------------------------------------
!
!  Open the GRIB file
!
!-----------------------------------------------------------------------

  READ (gribtime,'(i4,3i2,1x,i2)') iyr,imo,iday,ihr,fhr

!  myr = iyr - 1900
!arpscntl Y2K RLC per GMB/Donghai
! myr = MOD( iyr, 100 )

!EMK...Proper Y2K bug fix found in ARPS 5.0 package
  myr = MOD( iyr, 100 )   
  IF (myr == 0) THEN
    myr = 100
  END IF


  INQUIRE(FILE=gribfile(1:grbflen), EXIST = fexist )
  IF ( .NOT.fexist ) THEN
    WRITE(6,'(a)') 'GRIB file '//gribfile(1:grbflen)//                  &
        ' not found. Program stopped in RDNMCGRB2.'
    STOP
  END IF

  PRINT *, ' Opening GRIB file, gribfile= ',gribfile
  opnmod = 'r'
  CALL gopen  ( grbunit, gribfile, grbflen, opnmod, iret )
  IF  ( iret /= 0 )  THEN
    WRITE(6,'(a,a,/,a,i4)')                                             &
        'Error in opening file ',gribfile,                              &
        'C function gopen return status: ',iret
    RETURN
  END IF

!-----------------------------------------------------------------------
!
!  Get the size of the GRIB file
!
!-----------------------------------------------------------------------

  fsize = 0
  CALL gseek( grbunit, fsize, 2, iret )
  WRITE (6,'(a,i16,a)') 'The size of GRIB file is ',fsize,' bytes'

!-----------------------------------------------------------------------
!
!  Scan the GRIB file to count records
!
!-----------------------------------------------------------------------

  nrecs = 0
  CALL grbscan( grbunit, fsize, nprods, rcstart, rcbytes, nrecs )
  IF ( nrecs > nprods ) THEN
    WRITE (6,'(a/a,i6,a,i6/a/a)')                                       &
        'The actual number of products exceeded the expected number.',  &
        'Number of assumed products: ', nprods,                         &
        'Number of actual products: ', nrecs,                           &
        'Program stopped in RDNMCGRB2. Please change NPRODS in ',       &
        'file gribcst.inc and re-run the program.'
    CALL gclose( grbunit, iret )
    STOP
  ELSE IF ( nrecs <= 0 ) THEN
    WRITE (6,'(a,a,a)')                                                 &
        'No GRIB message found in file ',gribfile,                      &
        'Program stopped in RDNMCGRB2.'
    CALL gclose( grbunit, iret )
    STOP
  END IF

!-----------------------------------------------------------------------
!
!  Read the GRIB file and fill in the variable arrays
!
!-----------------------------------------------------------------------

  DO n=1,n2dvars
    DO m=1,n2dlvtps
      var_nr2d(n,m) = 0
    END DO
  END DO

  DO m=1,n3dlvtps
    DO n=1,n3dvars
      var_nr3d(n,m) = 0
    END DO
  END DO

  grdflg = .false.

  WRITE(6,*)'Unpacking ',nrecs,' records...'
  DO l=1,nrecs
    DO i=1,ipdsz
      ipds(i) = 0
    END DO
    DO i=1,igdsz
      igds(i) = 0
    END DO

    CALL gseek( grbunit, rcstart(l), 0, iret )
    CALL gread( grbunit, mgrib, rcbytes(l), iret )

    IF ( iendn == 1 ) THEN     ! little endian machine
      nwrd = (rcbytes(l)+3)/4
      CALL swap4byte( mgrib, nwrd )
    END IF

    CALL w3fi63( mgrib, ipds, igds, ibms, rcdata, mptrs, iret )

    IF ( ipds(3) /= gridtyp ) THEN
!      write (6,'(a,i6,a/a,i6,a,i6)') 'Grid id of record, ',L,
!    :    'was inconsistant with expected,',
!    :    'ipds(3)=',ipds(3), ' gridtyp=',gridtyp
      CYCLE
    END IF

    DO m=1,n3dlvtps
      IF ( ipds(6) == levtyp3d(m) ) THEN
        chklev = 1
        mlvtp  = m
        GO TO 30
      ELSE
        chklev = 0
      END IF
    END DO

    DO m=1,n2dlvtps
      IF ( ipds(6) == levtyp2d(m) ) THEN
        chklev = 2
        mlvtp  = m
        EXIT
      ELSE
        chklev = 0
      END IF
    END DO

    30      CONTINUE

    IF ( chklev == 0 ) THEN
!      write (6,'(a,i4,a/a,i4)')
!    :    'Type of level of record, ',L,
!    :    ' was inconsistant with expected,',
!    :    ' ipds(6) =',ipds(6)
      CYCLE
    END IF

    IF ( ipds(8) /= myr .OR.ipds(9) /= imo.OR.                          &
           ipds(10) /= iday.OR.ipds(11) /= ihr.OR.                      &
           ipds(14) /= fhr ) THEN
!arpscntl RLC format
      WRITE (6,'(a,i6,a/a,I3.2,3i2.2,i2.2/2a)')                         &
          'Time of record, ',l, 'was inconsistant with expected,',      &
          ' pds time = ',(ipds(j),j=8,11),ipds(14),                     &
          ' gribtime = ', TRIM(gribtime)
      WRITE (6,'(A,I3.2,3i2.2,i2.2)') "Gribtime: ", myr, imo, iday, ihr, fhr
      CYCLE
    END IF

    gdsflg = IAND(ipds(4),128)/128
    IF ( .NOT. grdflg ) THEN
      CALL grbgrid(gridtyp, gdsflg, igds,                               &
                   gridesc, iproj_grb, gthin,                           &
                   ni_grb,nj_grb,np_grb, nk_grb,zk_grb, npeq,nit,       &
                   pi_grb,pj_grb,ipole, di_grb,dj_grb,                  &
                   latsw,lonsw, latne,lonne,                            &
                   latrot,lonrot,angrot,                                &
                   latstr,lonstr,facstr,                                &
                   lattru1,lattru2,lontrue,                             &
                   scanmode, iscan,jscan,kscan,                         &
                   ires,iearth,icomp,                                   &
                   jpenta,kpenta,mpenta,ispect,icoeff,                  &
                   xp_grb,yp_grb, xo_grb,yo_grb,zo_grb)

      WRITE (6,'(a)') gridesc

      grdflg = .true.
    END IF

    IF ( igds(1) /= mproj_grb ) THEN
!      write (6,'(a,i3)')
!    :    'Map projection was not consistant, igds(1) = ', igds(1)
      CYCLE
    END IF

    IF ( igds(2) /= nxgrb .OR. igds(3) /= nygrb ) THEN
      WRITE (6,'(a/a,i4,2x,a,i4/a,i4,2x,a,i4/a)')                       &
          'Horizontal dimension was not consistant,',                   &
          ' igds(2) = ', igds(2), ' igds(3) = ', igds(3),               &
          ' nxgrb   = ', nxgrb  , ' nygrb   = ', nygrb,                 &
          'Program stopped in RDNMCGRB2.'
      STOP
    END IF

    IF ( iscan == 0 ) THEN
      ileft  = 1
      iright = nxgrb
      iincr  = 1
    ELSE
      ileft  = nxgrb
      iright = 1
      iincr  = -1
    END IF

    IF ( jscan /= 0 ) THEN
      jleft  = 1
      jright = nygrb
      jincr  = 1
    ELSE
      jleft  = nygrb
      jright = 1
      jincr  = -1
    END IF

    IF ( kscan == 0 ) THEN
      ki = 1
      kj = nxgrb
    ELSE IF ( kscan == 1 ) THEN
      ki = nygrb
      kj = 1
    ELSE
!      write (6,'(a,i3,a,i6)')
!    :    'Unknown scanning mode, kScan = ', kScan
      CYCLE
    END IF

    IF ( chklev == 1 ) THEN           ! 3-D variable
      DO n=1,n3dvars
        DO m=1,n3dlvtps

          IF ( ipds(5) == var_id3d(n,m) ) THEN
            var_nr3d(n,m) = var_nr3d(n,m) + 1

!-----------------------------------------------------------------------
!
!  Insert the level and data values into the var_lev3d and var_grb3d
!  arrays in order of decreasing level value,
!
!  For example if the level type is pressure levels the levels
!  will be sorted in order of decreasing pressure
!
!  ilev is the level at which to insert the current data
!
!-----------------------------------------------------------------------

            ilev= 0
            DO k=1,nzgrb
              IF ( ipds(7) > var_lev3d(k,n,m) ) THEN
                ilev = k
                EXIT
              END IF
            END DO

            120           CONTINUE

            IF ( ilev == 0 ) THEN
              PRINT*,'couldnt locate level ',ipds(7)
              PRINT*,'for var ID#',var_id3d(n,m)
              STOP
            END IF

!   slide all the following levels down one to make room

            DO k=nzgrb, ilev+1, -1
              var_lev3d(k,n,m)= var_lev3d(k-1,n,m)
              DO j=jleft,jright,jincr
                DO i=ileft,iright,iincr
                  ij = ki*iincr*(i-ileft) + kj*jincr*(j-jleft) + 1
                  var_grb3d(i,j,k,n,m)= var_grb3d(i,j,k-1,n,m)
                END DO
              END DO
            END DO

!   now insert the data at the appropriate level

            var_lev3d(ilev,n,m) = ipds(7)
            DO j=jleft,jright,jincr
              DO i=ileft,iright,iincr
                ij = ki*iincr*(i-ileft) + kj*jincr*(j-jleft) + 1
                var_grb3d(i,j,ilev,n,m) = rcdata(ij)
              END DO
            END DO
          END IF
        END DO
      END DO
    ELSE IF ( chklev == 2 ) THEN       ! 2-D variable
      DO n=1,n2dvars
        DO m=1,n2dlvtps
          IF ( ipds(5) == var_id2d(n,m) ) THEN
            var_nr2d(n,m) = var_nr2d(n,m) + 1
            DO i=ileft,iright,iincr
              DO j=jleft,jright,jincr
                ij = ki*iincr*(i-ileft) + kj*jincr*(j-jleft) + 1
                var_grb2d(i,j,n,m) = rcdata(ij)
              END DO
            END DO
          END IF
        END DO
      END DO
    END IF

  END DO

!-----------------------------------------------------------------------
!
!  Set good status
!
!-----------------------------------------------------------------------

  iret = 0

  CALL gclose( grbunit, iret )

  RETURN
END SUBROUTINE rdnmcgrb2