1 !*****************************************************************************!
2 ! Subroutine RD_GRIB1 !
5 ! Read one record from the input GRIB file. Based on the information in !
6 ! the GRIB header and the user-defined Vtable, decide whether the field in !
7 ! the GRIB record is one to process or to skip. If the field is one we !
8 ! want to keep, extract the data from the GRIB record, and pass the data !
9 ! back to the calling routine. !
13 ! IUNIT : "Unit Number" to open and read from. Not really a Fortran !
14 ! unit number, since we do not do Fortran I/O for the GRIB !
15 ! files. Nor is it a UNIX File Descriptor returned from a C !
16 ! OPEN statement. It is really just an array index to the !
17 ! array (IUARR) where the UNIX File Descriptor values are !
19 ! GRIBFLNM: File name to open, if it is not already open. !
20 ! IUARR : Array to hold UNIX File descriptors retured from a C open !
21 ! statement. If the value of IUARR(IUNIT) is zero, then the !
22 ! file GRIBFLNM must be opened, and the value of IUARR(IUNIT) !
23 ! becomes the UNIX File descriptor to read from. !
24 ! DEBUG_LEVEL Integer for various amounts of printout. !
27 ! LEVEL : The pressure-level (Pa) of the field to process. !
28 ! FIELD : The field name of the field to process. NULL is returned !
29 ! if we do not want to process the field we read. !
30 ! HDATE : The 19-character date of the field to process. !
31 ! IERR : Error flag: 0 - no error on read from GRIB file. !
32 ! 1 - Hit the end of the GRIB file. !
33 ! 2 - The file GRIBFLNM we tried to open does !
39 ! Subroutine DEALLOGRIB !
40 ! Subroutine GRIBGET !
41 ! Subroutine GRIBHEADER !
42 ! Subroutine GET_SEC1 !
43 ! Subroutine GET_SEC2 !
44 ! Subroutine GET_GRIDINFO !
45 ! Subroutine BUILD_HDATE !
46 ! Subroutine GETH_NEWDATE !
47 ! Subroutine GRIBDATA !
50 ! File GRIBFLNM is opened, as necessary !
52 ! Variable MAP from module GRIDINFO is filled in. !
54 ! Numerous side effects from the GRIB-processing routines. !
58 ! Summer, 1998, and continuing !
61 !*****************************************************************************!
62 SUBROUTINE rd_grib1(IUNIT, gribflnm, level, field, hdate, &
63 ierr, iuarr, debug_level)
71 integer :: debug_level
72 integer :: iunit ! Array number in IUARR assigned to the C read pointer.
73 integer, dimension(100) :: KSEC1
74 integer, dimension(10) :: KSEC2
75 integer, dimension(40) :: infogrid
76 real, dimension(40) :: ginfo
78 !-----------------------------------------------------------------------
79 integer :: iparm, ktype
82 integer :: icenter, iprocess, iscan, ii, isb
83 integer year, month, day, hour, minute, second, icc, iyy
86 character(LEN=*) :: field
87 character(LEN=132) :: gribflnm
88 character(LEN=8) :: tmp8
89 integer, dimension(255) :: iuarr
90 integer :: ierr, iostat, nunit
91 integer :: i, lvl2, lvl1
92 character(LEN=19) :: hdate
95 ! Variables for thinned grids:
96 logical :: lthinned = .FALSE.
97 real, allocatable, dimension(:) :: thinnedDataArray
98 integer, dimension(74) :: npoints_acc
100 integer :: np, ny, nx
101 real :: Va, Vb, Vc, Vd
102 real, external :: oned
106 ! If the file GRIBFLNM has not been opened, then IUARR(IUNIT) should be Zero.
107 ! In this case, open the file GRIBFLNM, and store the UNIX File descriptor
108 ! in to IUARR(IUNIT). This way, we will know what UNIX File descriptor to use
109 ! next time we call this RD_GRIB subroutine.
111 if (iuarr(iunit).eq.0) then
112 if (debug_level.gt.0) then
113 call c_open(iunit, nunit, gribflnm, 1, ierr, 1)
115 call c_open(iunit, nunit, gribflnm, 1, ierr, -1)
125 ! Read a single GRIB record, but do no unpacking now:
127 call gribget(iuarr(iunit), ierr)
130 call mprintf(.true.,DEBUG,"RD_GRIB1 gribget read error, ierr = %i",i1=ierr)
135 ! Unpack the header information:
137 call gribheader(debug_level,igherr)
138 if (igherr /= 0) then
144 ! Copy header information to arrays KSEC1, KSEC2, INFOGRID, and GRIDINFO
148 call get_gridinfo(infogrid, ginfo)
150 icenter = KSEC1(3) ! Indicator of the source (center) of the data.
151 iprocess = KSEC1(4) ! Indicator of model (or whatever) which generated the data.
153 if (icenter.eq.7) then
154 if (iprocess.eq.83 .or. iprocess.eq.84) then
155 map%source = 'NCEP MESO NAM Model'
156 elseif (iprocess.eq.81) then
157 map%source = 'NCEP GFS Analysis'
158 elseif (iprocess.eq.82) then
159 map%source = 'NCEP GFS GDAS/FNL'
160 elseif (iprocess.eq.89) then
161 map%source = 'NCEP NMM '
162 elseif (iprocess.eq.96) then
163 map%source = 'NCEP GFS Model'
164 elseif (iprocess.eq.107) then
165 map%source = 'NCEP GEFS'
166 elseif (iprocess.eq.109) then
167 map%source = 'NCEP RTMA'
168 elseif (iprocess.eq.86 .or. iprocess.eq.100) then
169 map%source = 'NCEP RUC Model' ! 60 km
170 elseif (iprocess.eq.101) then
171 map%source = 'NCEP RUC Model' ! 40 km
172 elseif (iprocess.eq.105) then
173 map%source = 'NCEP RUC Model' ! 20 km
174 elseif (iprocess.eq.140) then
175 map%source = 'NCEP NARR'
176 elseif (iprocess.eq.195) then
177 map%source = 'NCEP CDAS2'
178 elseif (iprocess.eq.44) then
179 map%source = 'NCEP SST Analysis'
180 elseif (iprocess.eq.70) then
181 map%source = 'GFDL Hurricane Model'
182 elseif (iprocess.eq.129) then
183 map%source = 'NCEP GODAS'
184 elseif (iprocess.eq.25) then
185 map%source = 'NCEP SNOW COVER ANALYSIS'
187 map%source = 'unknown model from NCEP'
189 ! grid numbers only set for NCEP and AFWA models
190 write(tmp8,'("GRID ",i3)') KSEC1(5)
191 map%source(25:32) = tmp8
192 else if (icenter .eq. 57) then
193 if (iprocess .eq. 87) then
194 map%source = 'AFWA AGRMET'
198 write(tmp8,'("GRID ",i3)') KSEC1(5)
199 map%source(25:32) = tmp8
200 else if (icenter .eq. 58) then
201 map%source = 'US Navy FNOC'
202 else if (icenter .eq. 59) then
203 if (iprocess .eq. 120) then
204 map%source = 'NOAA GSD Rapid Refresh'
206 map%source = 'NOAA GSD'
208 else if (icenter .eq. 60) then
210 else if (icenter .eq. 98) then
212 else if (icenter .eq. 74 .or. icenter .eq. 75 ) then
215 map%source = 'unknown model and orig center'
218 IPARM=KSEC1(7) ! Indicator of parameter
219 KTYPE=KSEC1(8) ! Indicator of type of level
221 ! print *,' IPARM, KTYPE, KSEC1(9)', iparm,ktype,ksec1(9)
226 ELSEIF(KTYPE.EQ.100) THEN
227 LVL1=FLOAT(KSEC1(9)) * 100.
229 ELSEIF(KTYPE.EQ.101) THEN
232 ELSEIF(KTYPE.EQ.102) THEN
235 ELSEIF(KTYPE.EQ.103) THEN
238 ELSEIF(KTYPE.EQ.105) THEN
241 ELSEIF(KTYPE.EQ.107) THEN
244 ELSEIF(KTYPE.EQ.109) THEN
247 ELSEIF(KTYPE.EQ.111) THEN
250 ELSEIF(KTYPE.EQ.112) THEN ! Layer between two depths below surface
253 ELSEIF(KTYPE.EQ.113) THEN
256 ELSEIF(KTYPE.EQ.115) THEN
259 ELSEIF(KTYPE.EQ.117) THEN
262 ELSEIF(KTYPE.EQ.119) THEN
265 ELSEIF(KTYPE.EQ.125) THEN
268 ELSEIF(KTYPE.EQ.160) THEN
271 ELSEIF(KTYPE.EQ.200) THEN
274 ELSEIF(KTYPE.EQ.201) THEN
282 ! Check to see that the combination of iparm, ktype, lvl1, and lvl2
283 ! match what has been requested in the Vtable. If not, set the field
284 ! name to NULL, meaning that we do not want to process this one.
288 if (gcode(i).eq.iparm) then
289 if (lcode(i).eq.ktype) then
290 if ((level1(i).eq.lvl1) .or. (level1(i) == splatcode) ) then
291 if (level2(i).eq.lvl2) then
294 if (ktype.eq.100) then ! Pressure-level
296 elseif (ktype.eq.102) then
298 elseif ((ktype.eq.116.and.lvl1.le.50.and.lvl2.eq.0) .or. &
299 (ktype.eq.105).or.(ktype.eq.1) .or. &
300 (ktype.eq.111).or.(ktype.eq.112) ) then
302 level = float(200000+iprty(i))
303 elseif (ktype.eq.109 .or. ktype.eq.107) then ! hybrid or sigma levels
305 elseif (ktype.eq. 6 ) then ! max wind
307 elseif (ktype.eq. 7 ) then ! trop
309 elseif (ktype .eq. 160 ) then ! depth below sea-surface (m)
311 elseif (ktype .eq. 237 .or. ktype .eq. 238 ) then ! depth of ocean layer
313 elseif (ktype .eq. 200 ) then !column variable (TCDC,PWAT,etc.)
316 if (level .lt. -998. ) then
317 write(6,*) 'Could not find a level for this Vtable entry'
318 write(6,*) 'iparm = ',iparm,' ktype = ',ktype,' lvl1 = ',lvl1,' lvl2 = ',lvl2
319 write(6,*) 'Fix the Vtable or modify rd_grib1.F'
328 if (field .eq. 'NULL') then
333 if ((field.eq.'WEASD').or.(field.eq.'SNOW')) then
334 level = level + ksec1(19)+1
337 ! Build the 19-character date string, based on GRIB header date and time
338 ! information, including forecast time information:
340 ICC=KSEC1(22) ! CENTURY OF THE DATA
341 IYY=KSEC1(11) ! (TWO-DIGIT) YEAR OF THE DATA
342 MONTH=KSEC1(12) ! MONTH OF THE DATA
343 DAY=KSEC1(13) ! DAY OF THE DATA
344 HOUR=KSEC1(14) ! HOUR OF THE DATA
345 MINUTE=KSEC1(15) ! MINUTE OF THE DATA
347 if (ksec1(19) == 3) then
348 FCST = (KSEC1(17) + KSEC1(18))/2
350 ! elseif (ksec1(19) == 4 .or. ksec1(19) == 5) then
351 elseif (ksec1(19) == 4 .or. ksec1(19) == 5 .or. ksec1(19) == 7) then
360 YEAR = (ICC-1)*100 + IYY
364 call build_hdate(hdate,year,month,day,hour,minute,second)
366 call geth_newdate(hdate,hdate,3600*fcst)
368 ! Store information about the grid on which the data is.
369 ! This stuff gets stored in the MAP variable, as defined in module GRIDINFO
371 map%startloc = 'SWCORNER'
372 map%grid_wind = .true.
373 ! NCEP's grib1 messages (in GDS Octet 17, the Resolution and Component Flags)
374 ! all have '0' for the earth radius flag which the documentation (written by NCEP)
375 ! says is 6367.47, but they really use 6371.229. Hardcode it.
376 ! It's not clear what ECMWF uses. One place says 6367.47 and another 6371.229.
377 if ( index(map%source,'NCEP') .ne. 0 ) then
378 map%r_earth = 6371.229
380 map%r_earth = 6367.47
383 if (ksec2(4).eq.0) then ! Lat/Lon grid
391 ! If this is global data, then the dx and dy are more accurately
392 ! computed by the number of points than the 3 digits grib permits.
393 if ( ABS(map%nx * map%dx - 360.) .lt. 1 ) then
394 if ( ABS ( map%dx - (360./real(map%nx)) ) .gt. 0.00001 ) then
395 !print *,'old dx = ',ginfo(8)
396 map%dx = 360./real(map%nx)
397 !print *,'new dx = ',map%dx
400 if ( ABS((map%ny-1) * map%dy - 2.*abs(map%lat1)) .lt. 1 ) then
401 if ( ABS ( map%dy - (2.*abs(map%lat1)/real(map%ny-1)) ) .gt. 0.00001 ) then
402 !print *,'old dy = ',ginfo(9)
403 map%dy = 2.*abs(map%lat1)/real(map%ny-1)
404 !print *,'new dy = ',map%dy
407 write(tmp8,'(b8.8)') infogrid(5)
408 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
409 if (icenter .eq. 7 .and. KSEC1(5) .eq. 173 ) then ! correction for ncep grid 173
412 map%dx = 0.083333333 * sign(1.0,map%dx)
413 map%dy = 0.083333333 * sign(1.0,map%dy)
415 ! correction for ncep grid 229 added 5/3/07 JFB
416 if (icenter .eq. 7 .and. KSEC1(5) .eq. 229 ) then
417 if (ginfo(3) .gt. 89. .and. ginfo(9) .gt. 0.) then
418 map%dy = -1. * map%dy
422 ! print *, "CE map stuff", map%igrid, map%nx, map%ny, map%dx, &
423 ! map%dy, map%lat1, map%lon1
425 elseif (ksec2(4).eq.1) then ! Mercator Grid
429 map%dx = ginfo(8) ! km
431 map%truelat1 = ginfo(5)
436 write(tmp8,'(b8.8)') infogrid(5)
437 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
439 elseif (ksec2(4).eq.3) then ! Lambert Conformal Grid
444 map%truelat1 = ginfo(11)
445 map%truelat2 = ginfo(12)
450 write(tmp8,'(b8.8)') infogrid(5)
451 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
452 ! if (tmp8(2:2) .eq. '0') map%r_earth = 6367.47
454 elseif(ksec2(4).eq.4) then ! Gaussian Grid
460 map%dy = real (infogrid(9))
463 write(tmp8,'(b8.8)') infogrid(5)
464 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
466 elseif (ksec2(4).eq.5) then ! Polar-Stereographic Grid.
477 write(tmp8,'(b8.8)') infogrid(5)
478 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
481 print*, 'Unknown Data Representation Type, ksec2(4)= ', ksec2(4)
485 111 format(' igrid : ', i3, /, &
486 ' nx, ny : ', 2I4, /, &
487 ' truelat1, 2: ', 2F10.4, /, &
488 ' Center Lon : ', F10.4, /, &
489 ' LatLon(1,1): ', 2F10.4, /, &
490 ' DX, DY : ', F10.4, F10.4)
492 ! Special for NCEP/NCAR Reanalysis Project:
493 ! Throw out PSFC on lat/lon grid (save gaussian version)
494 if ((icenter.eq.7).and.(iprocess.eq.80)) then ! Careful! This combination may refer
495 ! to other products as well.
496 if ((field.eq.'PSFC').and.(ksec2(4).eq.0)) then
503 if (allocated(rdatarray)) deallocate(rdatarray)
504 allocate(rdatarray(map%nx * map%ny))
506 ! If nx=65535, assume the grid is a thinned grid.
507 ! Process only the NCEP grid IDs is 37 to 44.
508 if (map%nx.eq.65535) then
509 if ( (icenter .ne. 7) .or. (KSEC1(5).lt.37) .or. (KSEC1(5).gt.44) ) then
510 write(*,*) 'Originating center is ',icenter
511 write(*,*) 'Grid ID is ',KSEC1(5),' Only WAFS grids 37-44 are supported'
512 write(*,'(" ***** STOP in Subroutine RD_GRIB1.",//)')
522 ! Unpack the 2D slab from the GRIB record, and put it in array rdatarray
525 if (allocated(thinnedDataArray)) deallocate(thinnedDataArray)
526 allocate(thinnedDataArray(map%nx * map%ny))
527 call gribdata(thinnedDataArray,3447)
529 ! Calculate how many points for each latitude, and accumulate into array
530 if ((KSEC1(5).ge.37).and.(KSEC1(5).le.40)) then
531 ! Northern hemisphere:
535 np = int(2.0+(90.0/1.25)*cos(i*1.25*3.1415926/180.0))
536 npoints_acc(i+2)=npoints_acc(i+1)+np
539 ! Southern Hemisphere:
544 np = int(2.0+(90.0/1.25)*cos(ii*1.25*3.1415926/180.0))
545 npoints_acc(i+2)=npoints_acc(i+1)+np
547 npoints_acc(74) = npoints_acc(73) + 73
550 ! for row number i (where i=1 is the southern edge of the grid)
551 ! npoints_acc(i+1)-npoints_acc(i) = number of points in this line
552 ! npoints_acc(i)+1 = index into thinned array for first point of line
555 np = npoints_acc(ny+1)-npoints_acc(ny) ! Number of points in this line.
557 ! Calulate the x index (mj) of thinned array (real value)
558 mj = (nx-1.0)*(np-1.0)/(72.0)
560 if (abs(mj - int(mj)) < 1.E-10) then
561 rdatarray((ny-1)*73+nx) = thinnedDataArray(npoints_acc(ny)+1+int(mj))
563 ! Get the 2 closest values from thinned array
564 Vb = thinnedDataArray(npoints_acc(ny)+1+int(mj))
565 Vc = thinnedDataArray(npoints_acc(ny)+1+int(mj)+1)
566 ! Get the next two closest, if available:
570 Va = thinnedDataArray(npoints_acc(ny)+1+int(mj)-1)
573 Vd = thinnedDataArray(npoints_acc(ny)+1+int(mj)+2)
576 if ((Va < -999998.) .or. (Vd < -999998.)) then
577 ! Use 2-point linear interpolation.
578 rdatarray((ny-1)*73+nx) = Vb*(int(mj)+1.0-mj) + Vc*(mj-int(mj))
580 ! Use 4-point overlapping parabolic interpolation.
581 xmj = mj - float(int(mj))
582 rdatarray((ny-1)*73+nx) = oned(xmj,Va,Vb,Vc,Vd)
588 call gribdata(rdatarray,map%nx*map%ny)
591 ! Some grids are broken and need to be reordered (e.g. NCEP-II in 1997).
592 ! WPS assumes that the grids are ordered consistently with the start location.
594 call mprintf(.true.,DEBUG, &
595 "RD_GRIB1 icenter = %i , iprocess = %i , grid = %i",i1=icenter,i2=iprocess,i3=KSEC1(5))
596 if (icenter .eq. 7 .and. iprocess .eq. 0 .and. KSEC1(5) .eq. 2 ) then
597 call mprintf(.true.,DEBUG, &
598 "resetting NCEP2 dx and dy. If this is not NCEP2 data you must modify rd_grib1.f90")
599 call mprintf(.true.,DEBUG, &
600 "field = %s , dx = %f , dy = %f , i10 = %i",s1=field,f1=map%dx,f2=map%dy,i1=infogrid(10))
603 ! call reorder_it (rdatarray, map%nx, map%ny, map%dx, map%dy, infogrid(10))
606 ! Deallocate a couple of arrays that may have been allocated by the
607 ! GRIB decoding routines.
611 END subroutine rd_grib1
613 real function oned(x, a, b, c, d) Result (Answer)
615 real :: x ! Proportion of the way between B and C. Between 0.0 and 1.0
618 if (abs(x) < 1.E-10) then
622 IF(abs(x-1.) < 1.E-10) then
626 Answer = (1.0-X)*(B+X*(0.5*(C-A)+X*(0.5*(C+A)-B)))+X*(C+(1.0-X)*(0.5 &
627 *(B-D)+(1.0-X)*(0.5*(B+D)-C)))