!
!##################################################################
!##################################################################
!###### ######
!###### SUBROUTINE RDNMCGRB ######
!###### ######
!###### Developed by ######
!###### Center for Analysis and Prediction of Storms ######
!###### University of Oklahoma ######
!###### ######
!##################################################################
!##################################################################
!
SUBROUTINE rdnmcgrb(nx_ext,ny_ext,nz_ext, & 8,5
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).
!
!-----------------------------------------------------------------------
!
! 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
INTEGER :: nx_ext,ny_ext,nz_ext
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(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 :: grbunit ! I/O unit of GRIB file
LOGICAL :: 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 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
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! 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 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,i2)') 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 ( .NOT.fexist ) THEN
WRITE(6,'(a)') 'GRIB file '//gribfile(1:grbflen)// &
' not found. Program stopped in RDNMCGRB.'
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 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, &
'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 *,'PDS#',L,ipds(3),ipds(5),ipds(6),ipds(7),rcdata(1)
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
WRITE (6,'(a,i6,a/a,4i2.2,i2.2/a)') &
'Time of record, ',l, &
'was inconsistant with expected,', &
' pds time = ',(ipds(j),j=8,11),ipds(14), &
' gribtime = ',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,'(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) /= 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 consistant,', &
' 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
! 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) .AND. ipds(6) == levtyp3d(m) ) THEN
var_nr3d(n,m) = var_nr3d(n,m) + 1
! print '(5(a,i6))',
! : 'ipds(7) = ', ipds(7),' var = ',var_id3d(n,m),
! : ' var_nr3d = ',var_nr3d(n,m),' n = ', n, ' m = ', m
!
IF (levtyp3d(m) == 111 .OR. levtyp3d(m) == 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).
!
!-----------------------------------------------------------------------
!
ilev = var_nr3d(n,m)
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,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)
PRINT *, ' n = ', n, ' m = ', m
STOP
END IF
! slide all the following levels down one to make room
DO k=nz_ext,ilev+1, -1
var_lev3d(k,n,m)= var_lev3d(k-1,n,m)
DO j=jleft,jright,jincr
DO i=ileft,iright,iincr
var_grb3d(i,j,k,n,m)= var_grb3d(i,j,k-1,n,m)
END DO
END DO
END DO
END IF
!
! 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
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,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 IF
END DO
!
!-----------------------------------------------------------------------
!
! Set good status
!
!-----------------------------------------------------------------------
!
iret = 0
CALL gclose( grbunit, iret )
RETURN
END SUBROUTINE rdnmcgrb
!
!##################################################################
!##################################################################
!###### ######
!###### SUBROUTINE GRBSCAN ######
!###### ######
!###### Developed by ######
!###### Center for Analysis and Prediction of Storms ######
!###### University of Oklahoma ######
!###### ######
!##################################################################
!##################################################################
!
SUBROUTINE grbscan(grbunit,fsize,nprods, & 1
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)
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! 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 ( ICHAR(buffer(1)) /= 71 .OR. & ! test ASCII 'G'
ICHAR(buffer(2)) /= 82 .OR. & ! test ASCII 'R'
ICHAR(buffer(3)) /= 73 .OR. & ! test ASCII 'I'
ICHAR(buffer(4)) /= 66 .OR. & ! test ASCII 'B'
ICHAR(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) = ICHAR(buffer(5))*65536 &
+ ICHAR(buffer(6))*256 &
+ ICHAR(buffer(7))
nbytes = nbytes + rcbytes(nrecs)
END IF
GO TO 100
END IF
200 RETURN
END SUBROUTINE grbscan