!
!##################################################################
!##################################################################
!######                                                      ######
!######                SUBROUTINE RDNMCGRB                   ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!
SUBROUTINE rdnmcgrb(nx_ext,ny_ext,nz_ext,                               & 12,66
           gribfile,grbflen, gribtime,                                  &
           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,                         &
           rcdata,var_grb2d,var_grb3d,var_lev3d, 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.
!
!  1999/08/03 (Gene Bassett)
!  Excluded soil levels (grid types 111 & 112) from vertical level sorting.
!
!  2000/01/05 (Eric Kemp)
!  Fixed problem with century change over (ipds(21) runs from 1 to 100).
!
!  2002/09/04 (Kevin W. Thomas)
!  ETA soil temp and moisture data were never sorted, as they had flags
!  indicating "sigma vertical coordinates".  When CONDUIT (LDM) data is
!  the source, the data order isn't guaranteed, so it needs to be sorted.
!
!  Duplicated data reports that sometimes occur in CONDUIT data cause fatal
!  errors.  Duplicates are ignored.
!
!  2004/08/23 (Kevin W. Thomas)
!  Variable "grbunit" is now an allocatable character string.  It is
!  guaranteed to be the right size to hold a C file pointer.  This will
!  end the "segmentation violation" problems.
!
!-----------------------------------------------------------------------
!
!  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.
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
  INCLUDE 'gribcst.inc'      ! General GRIB definitions
  INCLUDE 'mp.inc'
  INTEGER :: nx_ext,ny_ext,nz_ext
  INTEGER :: grbflen, grbflen_new
  CHARACTER (LEN=*) :: gribfile
  CHARACTER (LEN=*) :: gribtime
  CHARACTER (LEN=128) :: gribfile_new
  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(nz_ext)  ! Vertical coordinate parameters
  INTEGER :: npeq         ! Number of lat circles from pole to equator
  INTEGER :: nit(nz_ext)  ! 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 :: stdio_size   ! Size of "struct file" (C code in gribio_c.c).
  INTEGER :: istatus      ! Return status
  CHARACTER(len=1), allocatable :: grbunit(:) ! C structure, size stdio_size
  !wdt RLC
  LOGICAL (KIND=1) :: ibms(nx_ext*ny_ext)    ! BMS logical array for data bit map
  REAL    :: rcdata(nx_ext*ny_ext)           ! temporary data array
  REAL    :: var_grb2d(nx_ext,ny_ext,n2dvs,n2dlvt)        ! GRIB 2-D variables
  REAL    :: var_grb3d(nx_ext,ny_ext,nz_ext,n3dvs,n3dlvt) ! GRIB 3-D variables
  INTEGER :: var_lev3d(nz_ext,n3dvs,n3dlvt)
                                       ! Levels (hybrid) for each 3-D variable
!
!-----------------------------------------------------------------------
!
!  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
  LOGICAL,           PARAMETER :: verbose = .FALSE.
  CHARACTER(LEN=11), PARAMETER :: cmd     = 'rdnmcgrib: '
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  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
!
!-----------------------------------------------------------------------
!
  IF (myproc == 0) THEN
    CALL findvartype
(iendn,itypec,wdlen)
    IF ( iendn == 2 ) THEN
      WRITE(6,'(a)') 'Unknown endian type. Stopped in rdnmcgrb'
      STOP
    END IF
    IF ( itypec == 2 ) THEN
      WRITE(6,'(a)') 'Unknown character set. Stopped in rdnmcgrb'
      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, nz_ext
    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,i3)') iyr,imo,iday,ihr,fhr
  myr = MOD( iyr, 100 )
  IF (myr == 0) THEN
    myr = 100
  END IF
  INQUIRE(FILE=gribfile(1:grbflen), EXIST = fexist )
  IF( fexist ) THEN
    gribfile_new = gribfile
    grbflen_new = grbflen
    GO TO 200
  ENDIF
  INQUIRE(FILE=trim(gribfile(1:grbflen))//'.Z', EXIST = fexist )
  IF( fexist ) THEN
    CALL unixcmd
( 'cp '//trim(gribfile(1:grbflen))//'.Z tem_ext_file.Z' )
    INQUIRE(FILE='tem_ext_file', EXIST = fexist )
    IF( fexist ) call unixcmd
( '/bin/rm tem_ext_file' ) 
    CALL uncmprs
( 'tem_ext_file.Z' )
    gribfile_new = 'tem_ext_file'
    grbflen_new = 12 
    GO TO 200
  END IF
  INQUIRE(FILE=trim(gribfile(1:grbflen))//'.gz', EXIST = fexist )
  IF( fexist ) THEN
    CALL unixcmd
( 'cp '//trim(gribfile(1:grbflen))//'.gz tem_ext_file.gz' )
    INQUIRE(FILE='tem_ext_file', EXIST = fexist )
    IF( fexist ) call unixcmd
( '/bin/rm tem_ext_file' ) 
    CALL uncmprs
( 'tem_ext_file.gz' )
    gribfile_new = 'tem_ext_file'
    grbflen_new = 12
    GO TO 200
  END IF
  WRITE(6,'(/1x,a,/1x,a/)') 
  WRITE(6,'(a)') 'GRIB file '//gribfile(1:grbflen)//                      &
      ' or its compressed version not found. Program stopped in RDNMCGRB.'
  STOP
  200 CONTINUE
  WRITE(6,'(8A)') cmd, 'Opening GRIB ', gribfile(1:grbflen)
  opnmod = 'r'
  CALL gsize ( stdio_size )
  ALLOCATE(grbunit(stdio_size), STAT = istatus)
  CALL check_alloc_status
(istatus, "grbunit")
  CALL gopen ( grbunit, gribfile_new, grbflen_new, opnmod, iret )
  IF  ( iret /= 0 )  THEN
    WRITE(6,'(a,a,/,a,i4)')                                             &
        'Error in opening file ',gribfile_new,                          &
        'C function gopen return status: ',iret
    DEALLOCATE(grbunit)
    RETURN
  END IF
!
!-----------------------------------------------------------------------
!
!  Get the size of the GRIB file
!
!-----------------------------------------------------------------------
!
  fsize = 0
  CALL gseek( grbunit, fsize, 2, iret )
  WRITE (6,'(2A,I10,A)') cmd, '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 RDNMCGRB. 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_new,                  &
        'Program stopped in RDNMCGRB.'
    CALL gclose( grbunit, iret )
    STOP
  END IF
!
!-----------------------------------------------------------------------
!
!  Read the GRIB file and fill in the variable arrays
!
!-----------------------------------------------------------------------
!
  IF( n2dvars > n2dvs .OR. n2dlvtps > n2dlvt ) THEN
    WRITE(6,'(a,i3,a,i3,a)')                                             &
    'Array var_nr2d(',n2dvs,',',n2dlvt,') declared in gribcst.inc too small.'
    WRITE(6,'(a,i3,a,i3,a)')                                             &
            'It needs to be at least ',n2dvars,'x',n2dlvtps,'.'
    write(6,'(a)') 'Program stopped in RDNMCGRB.'
    STOP
  ENDIF
  DO n=1,n2dvars
    DO m=1,n2dlvtps
      var_nr2d(n,m) = 0
    END DO
  END DO
  IF( n3dvars > n3dvs .OR. n3dlvtps > n3dlvt ) THEN
    write(6,'(a,i3,a,i3,a)')                                             &
    'Array var_nr3d(',n3dvs,',',n3dlvt,') declared in gribcst.inc too small.'
    write(6,'(a,i3,a,i3,a)')                                             &
    'It needs to be at least ',n3dvars,'x',n3dlvtps,'.'
    write(6,'(a)') 'Program stopped in RDNMCGRB.'
    STOP
  ENDIF
  DO m=1,n3dlvtps
    DO n=1,n3dvars
      var_nr3d(n,m) = 0
    END DO
  END DO
  grdflg = .false.
  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 )
    !print *,cmd, 'PDS#',L,ipds(3),ipds(5),ipds(6),ipds(7),rcdata(1)
    IF ( ipds(3) /= gridtyp ) THEN
      IF (verbose) &
        WRITE (6,'(/A,I5,2(A,I4))') 'Ignoring GRIB record', l, &
              ': Grid ID is ipds(3) =',ipds(3), ', expected gridtyp=',gridtyp
      CYCLE
    END IF
    mlvtp  = 0
    chklev = 0
    DO m=1,n3dlvtps
      IF ( ipds(6) == levtyp3d(m) ) THEN
        chklev = 1
        mlvtp  = m
        GO TO 30
      END IF
    END DO
    DO m=1,n2dlvtps
      IF ( ipds(6) == levtyp2d(m) ) THEN
        IF (levtyp2d(m) == 105) THEN  ! T_2m, QV_2m, U_10m, V_10m
          SELECT CASE (ipds(5))
          CASE (11, 51, 52)           ! Must at 2m
            IF (ipds(7) /= 2) EXIT 
          CASE (33, 34)               ! Must at 10m
            IF (ipds(7) /= 10) EXIT
          END SELECT
        END IF
        chklev = 2
        mlvtp  = m
        EXIT
      END IF
    END DO
    30      CONTINUE
    IF ( chklev == 0 ) THEN
      IF (verbose) &
        WRITE (6,'(/A,I5,A,I4)') 'Ignoring GRIB record', l, &
              ': Type of level not expected, ipds(6) =',ipds(6)
      CYCLE
    END IF
    IF(ipds(16) /= 0 .AND. ipds(16) /= 10) THEN
      IF (verbose) &
        WRITE(6,'(/A,I5,A)') 'Ignoring GRIB record', l, &
            ': average, accumulation, or time difference'
      CYCLE
    ELSE IF ( ipds(8)  /= myr  .OR. ipds(9)  /= imo .OR.                &
              ipds(10) /= iday .OR. ipds(11) /= ihr .OR.                &
              ipds(14) /= fhr ) THEN
      IF (verbose) &
        WRITE (6,'(/A,I5,A,5I2.2,"f",I3.3,3A)') &
            'Ignoring GRIB record', l, ': time of record (', &
            ipds(21)-1,(ipds(j),j=8,11),ipds(14), &
            ') does not match expected (', gribtime, ")"
      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,'(2A)') cmd, gridesc
      grdflg = .true.
    END IF
    IF ( igds(1) /= mproj_grb ) THEN
      IF (verbose) &
        WRITE(6,'(/A,I5,2(A,I4))') 'Ignoring GRIB record', l, &
                    ': Map projection is igds(1) =', igds(1), &
                    ', expected mproj_grb =', mproj_grb
      CYCLE
    END IF
    IF ( igds(2) /= nx_ext .OR. igds(3) /= ny_ext) THEN
      WRITE (6,'(a/a,i4,2x,a,i4/a,i4,2x,a,i4/a)')                       &
          'Horizontal dimension was not consistent,',                   &
          ' igds(2) = ', igds(2), ' igds(3) = ', igds(3),               &
          ' nx_ext  = ', nx_ext  , ' ny_ext  = ', ny_ext,               &
          'Program stopped in RDNMCGRB.'
      STOP
    END IF
    IF ( iscan == 0 ) THEN
      ileft  = 1
      iright = nx_ext
      iincr  = 1
    ELSE
      ileft  = nx_ext
      iright = 1
      iincr  = -1
    END IF
    IF ( jscan /= 0 ) THEN
      jleft  = 1
      jright = ny_ext
      jincr  = 1
    ELSE
      jleft  = ny_ext
      jright = 1
      jincr  = -1
    END IF
    IF ( kscan == 0 ) THEN
      ki = 1
      kj = nx_ext
    ELSE IF ( kscan == 1 ) THEN
      ki = ny_ext
      kj = 1
    ELSE
      IF (verbose) &
        WRITE(6,'(/A,I5,2(A,I4))') 'Ignoring GRIB record', l, &
                    'Unknown scanning mode, kscan = ', kscan
      CYCLE
    END IF
    IF (verbose) &
      WRITE (6,'(/A,I5,3(A,I5),$)') 'GRIB record', l, &
      ': param =', ipds(5), ', level type =', ipds(6), ', level =', ipds(7)
    IF ( chklev == 1 ) THEN           ! 3-D variable
      DO n=1,n3dvars
!        DO m=1,n3dlvtps   ! we already knew which level type it is, 
                           ! then why do this loop?
        IF ( ipds(5) == var_id3d(n,mlvtp) ) THEN
          IF (verbose) WRITE (6,'(A)') '  accept 3D.'
          var_nr3d(n,mlvtp) = var_nr3d(n,mlvtp) + 1
          IF (levtyp3d(mlvtp) == 111 .OR. levtyp3d(mlvtp) == 112) THEN
!
!-----------------------------------------------------------------------
!
!  Insert the level and data values into the var_lev3d and var_grb3d
!  in the order that they occur in the data file (e.g. below surface
!  coordinates).
!
!  This data must be sorted.  When input is CONDUIT (LDM), data isn't
!  guaranteed to be in the proper order in the file!
!
!-----------------------------------------------------------------------
!
!              ilev = var_nr3d(n,mlvtp)
              ilev= 0
              DO k=1,nz_ext
                IF ( ipds(7) == var_lev3d(k,n,mlvtp) ) THEN
                  WRITE(6,*) 'Duplicate report, non-pressure coordinates'
                  var_nr3d(n,mlvtp) = var_nr3d(n,mlvtp) - 1
                  GOTO 555
                ENDIF
                IF ( ipds(7) < var_lev3d(k,n,mlvtp) .OR.     &
                     var_lev3d(k,n,mlvtp) < 0.0) THEN
                  ilev = k
                  EXIT
                END IF
              END DO
              IF ( ilev == 0 ) THEN
                PRINT *, 'couldnt locate level ',ipds(7)
                PRINT *, 'for var ID#',var_id3d(n,mlvtp)
                PRINT *, ' n = ', n, ' m = ', mlvtp
                PRINT *, ' levtyp3d = ',levtyp3d(mlvtp)
                STOP
              END IF
            ELSE
!
!-----------------------------------------------------------------------
!
!  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,nz_ext
                IF ( ipds(7) == var_lev3d(k,n,mlvtp) ) then
                  WRITE(6,*) 'Duplicate report, pressure coordinates'
                  var_nr3d(n,mlvtp) = var_nr3d(n,mlvtp) - 1
                  GOTO 555
                ENDIF
                IF ( ipds(7) > var_lev3d(k,n,mlvtp) ) THEN
                  ilev = k
                  EXIT
                END IF
              END DO
              IF ( ilev == 0 ) THEN
                PRINT *, 'couldnt locate level ',ipds(7)
                PRINT *, 'for var ID#',var_id3d(n,mlvtp)
                PRINT *, ' n = ', n, ' m = ', mlvtp
                STOP
              END IF
            ENDIF
            ! slide all the following levels down one to make room
            DO k=nz_ext,ilev+1, -1
              var_lev3d(k,n,mlvtp)= var_lev3d(k-1,n,mlvtp)
              DO j=jleft,jright,jincr
                DO i=ileft,iright,iincr
                  var_grb3d(i,j,k,n,mlvtp)= var_grb3d(i,j,k-1,n,mlvtp)
                END DO
              END DO
            END DO
!
!   now insert the data at the appropriate level
!
            var_lev3d(ilev,n,mlvtp) = 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,mlvtp) = rcdata(ij)
              END DO
            END DO
          END IF
          555  CONTINUE
!        END DO
      END DO
    ELSE IF ( chklev == 2 ) THEN       ! 2-D variable
      IF(ipds(16) == 0 .OR. ipds(16) == 10) THEN
                                       ! Don't use average, accumulation,
                                       ! or time difference fields.
        DO n=1,n2dvars
!          DO m=1,n2dlvtps
            IF ( ipds(5) == var_id2d(n,mlvtp) ) THEN
              IF (verbose) WRITE (6,'(a)') '  accept 2D.'
              var_nr2d(n,mlvtp) = var_nr2d(n,mlvtp) + 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,mlvtp) = rcdata(ij)
                END DO
              END DO
            END IF
!          END DO
        END DO
      END IF
    END IF
  END DO
!
!-----------------------------------------------------------------------
!
!  Set good status
!
!-----------------------------------------------------------------------
!
  iret = 0
  CALL gclose( grbunit, iret )
  DEALLOCATE( grbunit )
  ENDIF         ! IF (myproc == 0)
  CALL mpupdatei
(iproj_grb,1)
  CALL mpupdatei
(gthin,1)
  CALL mpupdatei
(ni_grb,1)
  CALL mpupdatei
(nj_grb,1)
  CALL mpupdatei
(np_grb,1)
  CALL mpupdatei
(nk_grb,1)
  CALL mpupdater
(zk_grb,nz_ext)
  CALL mpupdatei
(npeq,1)
  CALL mpupdater
(nit,nz_ext)
  CALL mpupdater
(pi_grb,1)
  CALL mpupdater
(pj_grb,1)
  CALL mpupdatei
(ipole,1)
  CALL mpupdater
(di_grb,1)
  CALL mpupdater
(dj_grb,1)
  CALL mpupdater
(latsw,1)
  CALL mpupdater
(lonsw,1)
  CALL mpupdater
(latne,1)
  CALL mpupdater
(lonne,1)
  CALL mpupdater
(latrot,1)
  CALL mpupdater
(lonrot,1)
  CALL mpupdater
(angrot,1)
  CALL mpupdater
(latstr,1)
  CALL mpupdater
(lonstr,1)
  CALL mpupdater
(facstr,1)
  CALL mpupdater
(lattru1,1)
  CALL mpupdater
(lattru2,1)
  CALL mpupdater
(lontrue,1)
  CALL mpupdatei
(scanmode,1)
  CALL mpupdatei
(iscan,1)
  CALL mpupdatei
(jscan,1)
  CALL mpupdatei
(kscan,1)
  CALL mpupdatei
(ires,1)
  CALL mpupdatei
(iearth,1)
  CALL mpupdatei
(icomp,1)
  CALL mpupdatei
(jpenta,1)
  CALL mpupdatei
(kpenta,1)
  CALL mpupdatei
(mpenta,1)
  CALL mpupdatei
(ispect,1)
  CALL mpupdatei
(icoeff,1)
  CALL mpupdater
(xp_grb,1)
  CALL mpupdater
(yp_grb,1)
  CALL mpupdater
(xo_grb,1)
  CALL mpupdater
(yo_grb,1)
  CALL mpupdater
(zo_grb,1)
  CALL mpupdater
(rcdata,nx_ext*ny_ext)
  CALL mpupdater
(var_grb2d,nx_ext*ny_ext*n2dvs*n2dlvt)
  CALL mpupdater
(var_grb3d,nx_ext*ny_ext*nz_ext*n3dvs*n3dlvt)
  CALL mpupdatei
(var_lev3d,nz_ext*n3dvs*n3dlvt)
  CALL mpupdatei
(iret,1)
  CALL mpupdatei
(n2dvars,1)
  CALL mpupdatei
(n2dlvtps,1)
  CALL mpupdatei
(var_nr2d,n2dvs*n2dlvt)
  CALL mpupdatei
(n3dvars,1)
  CALL mpupdatei
(var_nr3d,n3dvs*n3dlvt)
  RETURN
END SUBROUTINE rdnmcgrb
!
!##################################################################
!##################################################################
!######                                                      ######
!######                SUBROUTINE GRBSCAN                    ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!
SUBROUTINE grbscan(grbunit,fsize,nprods,                                & 3
           rcstart,rcbytes,nrecs)
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!
!  This subroutine is to scan the NMC GRIB files.
!
!-----------------------------------------------------------------------
!
!  AUTHOR: Yuhe Liu
!  01/03/1996 Initialized.
!
!  MODIFICATIONS:
!
!-----------------------------------------------------------------------
!
!  INPUT:
!
!    grbunit  Unit of GRIB file opened to scan for GRIB records
!    nprods   Maxmum record number
!    fsize    Size of the GRIB file
!
!  OUTPUT:
!
!    rcstart  Starting position (bytes) for each record
!    rcbytes  Record length in bytes
!    nrecs    Record number actually scanned
!    iret     Return flag
!
!-----------------------------------------------------------------------
!
!  Variable Declarations.
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
  INTEGER :: grbunit
  INTEGER :: fsize
  INTEGER :: nprods
  INTEGER :: rcbytes(nprods)  ! record length in bytes
  INTEGER :: rcstart(nprods)  ! record starting byte in a GRIB file
  INTEGER :: nrecs
  INTEGER :: iret
!
!-----------------------------------------------------------------------
!
!  Misc local variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: nbytes
  CHARACTER (LEN=1) :: buffer(8)
!
!-----------------------------------------------------------------------
!
!  External function
!
!-----------------------------------------------------------------------
!
  INTEGER :: char2i
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
  nbytes = 0
  nrecs  = 0
  100   IF ( nbytes < fsize ) THEN
  CALL gseek( grbunit,nbytes,0,iret )
  IF ( iret /= 0 ) GO TO 200
  CALL gread( grbunit,buffer,8,iret )
  IF ( iret /= 8 ) GO TO 200
  IF ( char2i(buffer(1)) /= 71 .OR.     & ! test ASCII 'G'
       char2i(buffer(2)) /= 82 .OR.     & ! test ASCII 'R'
       char2i(buffer(3)) /= 73 .OR.     & ! test ASCII 'I'
       char2i(buffer(4)) /= 66 .OR.     & ! test ASCII 'B'
       char2i(buffer(8)) /= 1 )      THEN ! test Edition #, 1
    nbytes = nbytes + 1
    GO TO 100
  END IF
  nrecs = nrecs + 1
  IF ( nrecs <= nprods ) THEN
    rcstart(nrecs) = nbytes
    rcbytes(nrecs) = char2i(buffer(5))*65536                             &
                   + char2i(buffer(6))*256                               &
                   + char2i(buffer(7))
    nbytes = nbytes + rcbytes(nrecs)
  END IF
  GO TO 100
  END IF
  200   RETURN
END SUBROUTINE grbscan
!
!##################################################################
!##################################################################
!######                                                      ######
!######                SUBROUTINE rdgrbdims                  ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!
SUBROUTINE rdgrbdims(dir_extd,extdname,extdopt,extdinit,extdfcst,       & 1,16
                     ni_grb,nj_grb,iret)
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!
!  This subroutine is to read dimension size from NMC GRIB #1 file.
!
!  The decoder of GRIB is from NMC, ftp:nic.fb4.noaa.gov/pub
!
!-----------------------------------------------------------------------
!
!  AUTHOR: Yunheng Wang
!  08/12/2005 Initialized.
!
!  MODIFICATIONS:
!
!-----------------------------------------------------------------------
!
!  INPUT:
!
!    gribfile      GRIB file name
!    grbflen       Length of GRIB file name
!
!  OUTPUT:
!
!    ni_grb        Grid size in west-east direction
!    nj_grb        Grid size in south-north direction
!
!    iret          Return flag
!
!-----------------------------------------------------------------------
!
!  Variable Declarations.
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
  CHARACTER(LEN=*)              :: dir_extd
  CHARACTER(LEN=*), INTENT(IN)  :: extdname
  CHARACTER(LEN=19),INTENT(IN)  :: extdinit
  CHARACTER(LEN=9)              :: extdfcst
  INTEGER,          INTENT(IN)  :: extdopt
  INTEGER,          INTENT(OUT) :: ni_grb       ! Number of points along x-axis
  INTEGER,          INTENT(OUT) :: nj_grb       ! Number of points along y-axis
  INTEGER,          INTENT(OUT) :: iret         ! Return flag
  INCLUDE 'gribcst.inc'
  INCLUDE 'mp.inc'
!
!-----------------------------------------------------------------------
!
!  Temporary arrays to read GRIB file
!
!-----------------------------------------------------------------------
!
  INTEGER :: nrecs        ! number of records
  INTEGER :: iproj        ! Map projection indicator
  INTEGER :: fsize        ! Size of GRIB file
  INTEGER :: stdio_size   ! Size of "struct file" (C code in gribio_c.c).
  CHARACTER(LEN=1), ALLOCATABLE :: grbunit(:) ! C structure, size stdio_size
  LOGICAL (KIND=1), ALLOCATABLE :: ibms(:)    ! BMS logical array for data bit map
  REAL,             ALLOCATABLE :: rcdata(:)  ! temporary data array
!
!-----------------------------------------------------------------------
!
!  Misc. Local variables
!
!-----------------------------------------------------------------------
!
  CHARACTER(LEN=128) :: gribfile
  CHARACTER(LEN=14)  :: gribtime
  INTEGER            :: lenrun, grbflen
  CHARACTER (LEN=128) :: gribfile_new
  CHARACTER (LEN=1)   :: opnmod
  INTEGER             :: grbflen_new
  INTEGER             :: iendn,itypec,wdlen, nwrd
  INTEGER             :: l, i
  LOGICAL             :: fexist
  INTEGER             :: iyr,imo,iday,ihr,imin,isec
  INTEGER             :: ifhr
  LOGICAL,           PARAMETER :: verbose = .FALSE.
  CHARACTER(LEN=11), PARAMETER :: cmd     = 'rdgrbdims: '
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
  ALLOCATE(ibms(nbufsz/4),   STAT = iret)
  CALL check_alloc_status
(iret, 'rdgrbdims:ibms')
  ALLOCATE(rcdata(nbufsz/4), STAT = iret)
  CALL check_alloc_status
(iret, 'rdgrbdims:rcdata')
!-----------------------------------------------------------------------
!
! Construct the grib file name
!
!-----------------------------------------------------------------------
  READ (extdinit,'(i4,1x,i2,1x,i2,1x,i2,1x,i2,1x,i2)')                  &
                                             iyr,imo,iday,ihr,imin,isec
  ifhr = 0
  IF(extdfcst == '         ') extdfcst='000:00:00'
  READ(extdfcst,'(i3)') ifhr
  WRITE (gribtime,'(i4.4,i2.2,i2.2,i2.2,a1,i2.2)')                      &
                                              iyr,imo,iday,ihr,'f',ifhr
  lenrun   = LEN(dir_extd)
  grbflen  = LEN_TRIM(dir_extd)
  IF( grbflen == 0 .OR. dir_extd(1:grbflen) == ' ' ) THEN
    dir_extd = '.'
    grbflen=1
  END IF
  IF( dir_extd(grbflen:grbflen) /= '/' .AND. grbflen < lenrun ) THEN
    grbflen = grbflen+1
    dir_extd(grbflen:grbflen) = '/'
  END IF
  gribfile = dir_extd(1:grbflen)//TRIM(extdname)//'.'//TRIM(gribtime)
  grbflen = LEN_TRIM(gribfile)
!
!-----------------------------------------------------------------------
!
!  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 findvartype
(iendn,itypec,wdlen)
  IF ( iendn == 2 ) THEN
    WRITE(6,'(a)') 'Unknown endian type. Stopped in rdnmcgrb'
    iret = -1
    GOTO 999
  END IF
  IF ( itypec == 2 ) THEN
    WRITE(6,'(a)') 'Unknown character set. Stopped in rdnmcgrb'
    iret = -1
    GOTO 999
  END IF
  IF (myproc == 0) THEN
!
!-----------------------------------------------------------------------
!
!  Open the GRIB file
!
!-----------------------------------------------------------------------
!
    INQUIRE(FILE=gribfile(1:grbflen), EXIST = fexist )
    IF( fexist ) THEN
      gribfile_new = gribfile
      grbflen_new = grbflen
      GO TO 200
    ENDIF
    INQUIRE(FILE=trim(gribfile(1:grbflen))//'.Z', EXIST = fexist )
    IF( fexist ) THEN
      CALL unixcmd
( 'cp '//trim(gribfile(1:grbflen))//'.Z tem_ext_file.Z' )
      INQUIRE(FILE='tem_ext_file', EXIST = fexist )
      IF( fexist ) call unixcmd
( '/bin/rm tem_ext_file' ) 
      CALL uncmprs
( 'tem_ext_file.Z' )
      gribfile_new = 'tem_ext_file'
      grbflen_new = 12 
      GO TO 200
    END IF
    INQUIRE(FILE=trim(gribfile(1:grbflen))//'.gz', EXIST = fexist )
    IF( fexist ) THEN
      CALL unixcmd
( 'cp '//trim(gribfile(1:grbflen))//'.gz tem_ext_file.gz' )
      INQUIRE(FILE='tem_ext_file', EXIST = fexist )
      IF( fexist ) call unixcmd
( '/bin/rm tem_ext_file' ) 
      CALL uncmprs
( 'tem_ext_file.gz' )
      gribfile_new = 'tem_ext_file'
      grbflen_new = 12
      GO TO 200
    END IF
    WRITE(6,'(/1x,a/)') 'GRIB file '//gribfile(1:grbflen)//                      &
        ' or its compressed version not found. Program stopped in RDGRBDIMS.'
    iret = -2
    GOTO 999
    200 CONTINUE
    WRITE(6,'(8A)') cmd, 'Opening GRIB ', TRIM(gribfile)
    opnmod = 'r'
    CALL gsize ( stdio_size )
    ALLOCATE(grbunit(stdio_size), STAT = iret)
    CALL check_alloc_status
(iret, "rdgrbdim:grbunit")
    CALL gopen ( grbunit, gribfile_new, grbflen_new, opnmod, iret )
    IF  ( iret /= 0 )  THEN
      WRITE(6,'(a,a,/,a,i4)') 'Error in opening file ',gribfile_new,    &
                              'C function gopen return status: ',iret
      DEALLOCATE(grbunit)
      GOTO 999
    END IF
!
!-----------------------------------------------------------------------
!
!  Get the size of the GRIB file
!
!-----------------------------------------------------------------------
!
    fsize = 0
    CALL gseek( grbunit, fsize, 2, iret )
    WRITE (6,'(2A,I10,A)') cmd, '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 RDNMCGRB. Please change NPRODS in ',        &
        'file gribcst.inc and re-run the program.'
      CALL gclose( grbunit, iret )
      iret = -3
      GOTO 999
    ELSE IF ( nrecs <= 0 ) THEN
      WRITE (6,'(a,a,a)')                                               &
        'No GRIB message found in file ',gribfile_new,                  &
        'Program stopped in RDNMCGRB.'
      CALL gclose( grbunit, iret )
      iret = -3
      GOTO 999
    END IF
!
!-----------------------------------------------------------------------
!
!  Read the first record in GRIB file
!
!-----------------------------------------------------------------------
!
    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 )
      iproj = IABS(igds(1))
      IF (iproj ==  0 .OR. iproj == 3) THEN
        ni_grb = igds(2)
        nj_grb = igds(3)
      ELSE 
        WRITE(6,'()') 'Unknow map projection: ',iproj
        iret = -5 
        EXIT
      END IF
      iret = 0  ! set good status
      EXIT 
    END DO
!
!-----------------------------------------------------------------------
!
!  close grib file
!
!-----------------------------------------------------------------------
!
    CALL gclose( grbunit, iret )
    DEALLOCATE( grbunit )
  END IF         ! IF (myproc == 0)
  999 CONTINUE
  DEALLOCATE(ibms,rcdata)
  CALL mpupdatei
(ni_grb,1)
  CALL mpupdatei
(nj_grb,1)
  CALL mpupdatei
(iret, 1)
  RETURN
END SUBROUTINE rdgrbdims