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, ec_rec_len)
71 integer :: debug_level, ec_rec_len
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, ec_rec_len)
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,ec_rec_len)
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. 125) then
204 map%source = 'NOAA GSD Rapid Refresh'
205 else if (iprocess .eq. 105) then
206 map%source = 'NOAA GSD'
208 print *,'Unknown GSD source'
211 else if (icenter .eq. 60) then
213 else if (icenter .eq. 98) then
215 else if (icenter .eq. 74 .or. icenter .eq. 75 ) then
218 map%source = 'unknown model and orig center'
221 IPARM=KSEC1(7) ! Indicator of parameter
222 KTYPE=KSEC1(8) ! Indicator of type of level
224 ! print *,' IPARM, KTYPE, KSEC1(9)', iparm,ktype,ksec1(9)
229 ELSEIF(KTYPE.EQ.100) THEN
230 LVL1=FLOAT(KSEC1(9)) * 100.
232 ELSEIF(KTYPE.EQ.101) THEN
235 ELSEIF(KTYPE.EQ.102) THEN
238 ELSEIF(KTYPE.EQ.103) THEN
241 ELSEIF(KTYPE.EQ.105) THEN
244 ELSEIF(KTYPE.EQ.107) THEN
247 ELSEIF(KTYPE.EQ.109) THEN
250 ELSEIF(KTYPE.EQ.111) THEN
253 ELSEIF(KTYPE.EQ.112) THEN ! Layer between two depths below surface
256 ELSEIF(KTYPE.EQ.113) THEN
259 ELSEIF(KTYPE.EQ.115) THEN
262 ELSEIF(KTYPE.EQ.117) THEN
265 ELSEIF(KTYPE.EQ.119) THEN
268 ELSEIF(KTYPE.EQ.125) THEN
271 ELSEIF(KTYPE.EQ.160) THEN
274 ELSEIF(KTYPE.EQ.200) THEN
277 ELSEIF(KTYPE.EQ.201) THEN
285 ! Check to see that the combination of iparm, ktype, lvl1, and lvl2
286 ! match what has been requested in the Vtable. If not, set the field
287 ! name to NULL, meaning that we do not want to process this one.
291 if (gcode(i).eq.iparm) then
292 if (lcode(i).eq.ktype) then
293 if ((level1(i).eq.lvl1) .or. (level1(i) == splatcode) ) then
294 if (level2(i).eq.lvl2) then
297 if (ktype.eq.100) then ! Pressure-level
299 elseif (ktype.eq.102) then
301 elseif ((ktype.eq.116.and.lvl1.le.50.and.lvl2.eq.0) .or. &
302 (ktype.eq.105).or.(ktype.eq.1) .or. &
303 (ktype.eq.111).or.(ktype.eq.112) ) then
305 level = float(200000+iprty(i))
306 elseif (ktype.eq.109 .or. ktype.eq.107) then ! hybrid or sigma levels
308 elseif (ktype.eq. 6 ) then ! max wind
310 elseif (ktype.eq. 7 ) then ! trop
312 elseif (ktype .eq. 160 ) then ! depth below sea-surface (m)
314 elseif (ktype .eq. 237 .or. ktype .eq. 238 ) then ! depth of ocean layer
316 elseif (ktype .eq. 200 ) then !column variable (TCDC,PWAT,etc.)
319 if (level .lt. -998. ) then
320 write(6,*) 'Could not find a level for this Vtable entry'
321 write(6,*) 'iparm = ',iparm,' ktype = ',ktype,' lvl1 = ',lvl1,' lvl2 = ',lvl2
322 write(6,*) 'Fix the Vtable or modify rd_grib1.F'
331 if (field .eq. 'NULL') then
336 if ((field.eq.'WEASD').or.(field.eq.'SNOW')) then
337 level = level + ksec1(19)+1
340 ! Build the 19-character date string, based on GRIB header date and time
341 ! information, including forecast time information:
343 ICC=KSEC1(22) ! CENTURY OF THE DATA
344 IYY=KSEC1(11) ! (TWO-DIGIT) YEAR OF THE DATA
345 MONTH=KSEC1(12) ! MONTH OF THE DATA
346 DAY=KSEC1(13) ! DAY OF THE DATA
347 HOUR=KSEC1(14) ! HOUR OF THE DATA
348 MINUTE=KSEC1(15) ! MINUTE OF THE DATA
350 if (ksec1(19) == 3) then
351 FCST = (KSEC1(17) + KSEC1(18))/2
353 ! elseif (ksec1(19) == 4 .or. ksec1(19) == 5) then
354 elseif (ksec1(19) == 4 .or. ksec1(19) == 5 .or. ksec1(19) == 7) then
359 ! convert the fcst units to hours if necessary
360 if (ksec1(16) .eq. 254 ) then
362 elseif (ksec1(16) .eq. 0 ) then
369 YEAR = (ICC-1)*100 + IYY
373 call build_hdate(hdate,year,month,day,hour,minute,second)
375 call geth_newdate(hdate,hdate,3600*fcst)
377 ! Store information about the grid on which the data is.
378 ! This stuff gets stored in the MAP variable, as defined in module GRIDINFO
380 map%startloc = 'SWCORNER'
381 map%grid_wind = .true.
382 ! NCEP's grib1 messages (in GDS Octet 17, the Resolution and Component Flags)
383 ! all have '0' for the earth radius flag which the documentation (written by NCEP)
384 ! says is 6367.47, but they really use 6371.229. Hardcode it.
385 ! It's not clear what ECMWF uses. One place says 6367.47 and another 6371.229.
386 if ( index(map%source,'NCEP') .ne. 0 ) then
387 map%r_earth = 6371.229
389 map%r_earth = 6367.47
392 if (ksec2(4).eq.0) then ! Lat/Lon grid
400 ! If this is global data, then the dx and dy are more accurately
401 ! computed by the number of points than the 3 digits grib permits.
402 if ( ABS(map%nx * map%dx - 360.) .lt. 1 ) then
403 if ( ABS ( map%dx - (360./real(map%nx)) ) .gt. 0.00001 ) then
404 !print *,'old dx = ',ginfo(8)
405 map%dx = 360./real(map%nx)
406 !print *,'new dx = ',map%dx
409 if ( ABS((map%ny-1) * map%dy - 2.*abs(map%lat1)) .lt. 1. ) then
410 if ( ABS ( map%dy - (2.*abs(map%lat1)/real(map%ny-1)) ) .gt. 0.00001 ) then
411 !print *,'old dy = ',ginfo(9)
412 map%dy = 2.*abs(map%lat1)/real(map%ny-1)
413 !print *,'new dy = ',map%dy
416 write(tmp8,'(b8.8)') infogrid(5)
417 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
418 if (icenter .eq. 7 .and. KSEC1(5) .eq. 173 ) then ! correction for ncep grid 173
421 map%dx = 0.083333333 * sign(1.0,map%dx)
422 map%dy = 0.083333333 * sign(1.0,map%dy)
424 ! correction for ncep grid 229 added 5/3/07 JFB
425 if (icenter .eq. 7 .and. KSEC1(5) .eq. 229 ) then
426 if (ginfo(3) .gt. 89. .and. ginfo(9) .gt. 0.) then
427 map%dy = -1. * map%dy
431 ! print *, "CE map stuff", map%igrid, map%nx, map%ny, map%dx, &
432 ! map%dy, map%lat1, map%lon1
434 elseif (ksec2(4).eq.1) then ! Mercator Grid
438 map%dx = ginfo(8) ! km
440 map%truelat1 = ginfo(5)
445 write(tmp8,'(b8.8)') infogrid(5)
446 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
448 elseif (ksec2(4).eq.3) then ! Lambert Conformal Grid
453 map%truelat1 = ginfo(11)
454 map%truelat2 = ginfo(12)
459 write(tmp8,'(b8.8)') infogrid(5)
460 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
461 ! if (tmp8(2:2) .eq. '0') map%r_earth = 6367.47
463 elseif(ksec2(4).eq.4) then ! Gaussian Grid
469 map%dy = real (infogrid(9))
472 write(tmp8,'(b8.8)') infogrid(5)
473 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
474 ! If this is global data, then the dx and dy are more accurately
475 ! computed by the number of points than the 3 digits grib permits.
476 if ( ABS(map%nx * map%dx - 360.) .lt. 1. ) then
477 if ( ABS ( map%dx - (360./real(map%nx)) ) .gt. 0.00001 ) then
478 ! print *,'old dx = ',ginfo(8)
479 map%dx = 360./real(map%nx)
480 ! print *,'new dx = ',map%dx
485 elseif (ksec2(4).eq.5) then ! Polar-Stereographic Grid.
496 write(tmp8,'(b8.8)') infogrid(5)
497 if (tmp8(5:5) .eq. '0') map%grid_wind = .false.
500 print*, 'Unknown Data Representation Type, ksec2(4)= ', ksec2(4)
504 111 format(' igrid : ', i3, /, &
505 ' nx, ny : ', 2I4, /, &
506 ' truelat1, 2: ', 2F10.4, /, &
507 ' Center Lon : ', F10.4, /, &
508 ' LatLon(1,1): ', 2F10.4, /, &
509 ' DX, DY : ', F10.4, F10.4)
511 ! Special for NCEP/NCAR Reanalysis Project:
512 ! Throw out PSFC on lat/lon grid (save gaussian version)
513 if ((icenter.eq.7).and.(iprocess.eq.80)) then ! Careful! This combination may refer
514 ! to other products as well.
515 if ((field.eq.'PSFC').and.(ksec2(4).eq.0)) then
522 if (allocated(rdatarray)) deallocate(rdatarray)
523 allocate(rdatarray(map%nx * map%ny))
525 ! If nx=65535, assume the grid is a thinned grid.
526 ! Process only the NCEP grid IDs is 37 to 44.
527 if (map%nx.eq.65535) then
528 if ( (icenter .ne. 7) .or. (KSEC1(5).lt.37) .or. (KSEC1(5).gt.44) ) then
529 write(*,*) 'Originating center is ',icenter
530 write(*,*) 'Grid ID is ',KSEC1(5),' Only WAFS grids 37-44 are supported'
531 write(*,'(" ***** STOP in Subroutine RD_GRIB1.",//)')
541 ! Unpack the 2D slab from the GRIB record, and put it in array rdatarray
544 if (allocated(thinnedDataArray)) deallocate(thinnedDataArray)
545 allocate(thinnedDataArray(map%nx * map%ny))
546 call gribdata(thinnedDataArray,3447)
548 ! Calculate how many points for each latitude, and accumulate into array
549 if ((KSEC1(5).ge.37).and.(KSEC1(5).le.40)) then
550 ! Northern hemisphere:
554 np = int(2.0+(90.0/1.25)*cos(i*1.25*3.1415926/180.0))
555 npoints_acc(i+2)=npoints_acc(i+1)+np
558 ! Southern Hemisphere:
563 np = int(2.0+(90.0/1.25)*cos(ii*1.25*3.1415926/180.0))
564 npoints_acc(i+2)=npoints_acc(i+1)+np
566 npoints_acc(74) = npoints_acc(73) + 73
569 ! for row number i (where i=1 is the southern edge of the grid)
570 ! npoints_acc(i+1)-npoints_acc(i) = number of points in this line
571 ! npoints_acc(i)+1 = index into thinned array for first point of line
574 np = npoints_acc(ny+1)-npoints_acc(ny) ! Number of points in this line.
576 ! Calulate the x index (mj) of thinned array (real value)
577 mj = (nx-1.0)*(np-1.0)/(72.0)
579 if (abs(mj - int(mj)) < 1.E-10) then
580 rdatarray((ny-1)*73+nx) = thinnedDataArray(npoints_acc(ny)+1+int(mj))
582 ! Get the 2 closest values from thinned array
583 Vb = thinnedDataArray(npoints_acc(ny)+1+int(mj))
584 Vc = thinnedDataArray(npoints_acc(ny)+1+int(mj)+1)
585 ! Get the next two closest, if available:
589 Va = thinnedDataArray(npoints_acc(ny)+1+int(mj)-1)
592 Vd = thinnedDataArray(npoints_acc(ny)+1+int(mj)+2)
595 if ((Va < -999998.) .or. (Vd < -999998.)) then
596 ! Use 2-point linear interpolation.
597 rdatarray((ny-1)*73+nx) = Vb*(int(mj)+1.0-mj) + Vc*(mj-int(mj))
599 ! Use 4-point overlapping parabolic interpolation.
600 xmj = mj - float(int(mj))
601 rdatarray((ny-1)*73+nx) = oned(xmj,Va,Vb,Vc,Vd)
607 call gribdata(rdatarray,map%nx*map%ny)
610 ! Some grids are broken and need to be reordered (e.g. NCEP-II in 1997).
611 ! WPS assumes that the grids are ordered consistently with the start location.
613 call mprintf(.true.,DEBUG, &
614 "RD_GRIB1 icenter = %i , iprocess = %i , grid = %i",i1=icenter,i2=iprocess,i3=KSEC1(5))
615 if (icenter .eq. 7 .and. iprocess .eq. 0 .and. KSEC1(5) .eq. 2 ) then
616 call mprintf(.true.,DEBUG, &
617 "resetting NCEP2 dx and dy. If this is not NCEP2 data you must modify rd_grib1.f90")
618 call mprintf(.true.,DEBUG, &
619 "field = %s , dx = %f , dy = %f , i10 = %i",s1=field,f1=map%dx,f2=map%dy,i1=infogrid(10))
622 ! call reorder_it (rdatarray, map%nx, map%ny, map%dx, map%dy, infogrid(10))
625 ! Deallocate a couple of arrays that may have been allocated by the
626 ! GRIB decoding routines.
630 END subroutine rd_grib1
632 real function oned(x, a, b, c, d) Result (Answer)
634 real :: x ! Proportion of the way between B and C. Between 0.0 and 1.0
637 if (abs(x) < 1.E-10) then
641 IF(abs(x-1.) < 1.E-10) then
645 Answer = (1.0-X)*(B+X*(0.5*(C-A)+X*(0.5*(C+A)-B)))+X*(C+(1.0-X)*(0.5 &
646 *(B-D)+(1.0-X)*(0.5*(B+D)-C)))