NCEP Home > NCO Home > Systems Integration Branch > Decoders > BUFRLIB > BUFRLIB Table of Contents > Decoding wind profiler BUFR messages
Printer Friendly Version
Example Program: Decoding wind profiler BUFR messages
In this example, we will be decoding (i.e. reading) BUFR messages
that were encoded according to the "WIND PROFILER" format
listed within our sample DX BUFR tables file. In effect, this
means that we will be reading data subsets that are described by
the Table A mnemonic "NC002007". In doing so,
we will pass each BUFR message directly from the application program
to the BUFRLIB software via an array in memory, since this will allow
us to demonstrate the use of subroutine READERME in lieu
of subroutine READMG:
PARAMETER ( MXMN = 7 )
PARAMETER ( MXLV = 86 )
REAL*8 r8arr ( MXMN, MXLV )
PARAMETER ( MXBF = 16000 )
CHARACTER cbfmsg*(MXBF),
+ csubset*8
INTEGER ibfmsg ( MXBF / 4 )
EQUIVALENCE ( cbfmsg (1), ibfmsg (1) )
C*-----------------------------------------------------------------------
C* Open the BUFR messages file.
OPEN ( UNIT = 11, FILE = 'dummy' )
C* Open the BUFR tables file.
OPEN ( UNIT = 12, FILE = 'bufrtab.example' )
C* Associate the tables file with the messages file, and identify
C* the latter to the BUFRLIB software.
CALL OPENBF ( 11, 'IN', 12 )
C* Specify that we would like IDATE values returned using 10 digits
C* (i.e. YYYYMMDDHH ).
CALL DATELEN ( 10 )
DO WHILE ( .true. )
C* Read the next BUFR message.
( assume that there is code here to read the next BUFR message
from the local system into the character array cbfmsg )
IF ( there are no more messages ) THEN
CALL CLOSBF ( 11 )
( perform any other necessary local shutdown tasks )
STOP
END IF
msgok = .true.
C* Pass the BUFR message into the BUFRLIB software.
CALL READERME ( ibfmsg, 11, csubset, idate, ierrme )
IF ( ierrme .ne. 0 ) THEN
PRINT *, 'Error reading BUFR message within READERME'
msgok = .false.
ELSE IF ( csubset .ne. 'NC002007' ) THEN
PRINT *, 'BUFR message is not of type WIND PROFILER'
msgok = .false.
END IF
DO WHILE ( msgok )
C* Read the next data subset from the BUFR message.
IF ( IREADSB ( 11 ) .ne. 0 ) THEN
msgok = .false.
ELSE
C* At this point, we have a data subset within the
C* internal arrays of BUFRLIB, and we can now begin
C* reading actual data values:
C* Report identification.
CALL UFBINT ( 11, r8arr, MXMN, MXLV, nlv,
+ 'WMOB WMOS CLAT CLON SELV' )
PRINT *, ' WMO Block # = ', r8arr (1,1)
PRINT *, ' WMO Station # = ', r8arr (2,1)
PRINT *, ' Latitude = ', r8arr (3,1)
PRINT *, ' Longitude = ', r8arr (4,1)
PRINT *, 'Station Elevation = ', r8arr (5,1)
C* Report valid time.
CALL UFBINT ( 11, r8arr, MXMN, MXLV, nlv,
+ 'YEAR MNTH DAYS HOUR MINU' )
PRINT *, ' Year = ', r8arr (1,1)
PRINT *, ' Month = ', r8arr (2,1)
PRINT *, ' Day = ', r8arr (3,1)
PRINT *, ' Hour = ', r8arr (4,1)
PRINT *, ' Minute = ', r8arr (5,1)
C* Surface wind, temperature, humidity, etc.
CALL UFBINT ( 11, r8arr, MXMN, MXLV, nlv,
+ 'WDIR WSPD TMDBST REHU' )
PRINT *, ' Wind direction = ', r8arr (1,1)
PRINT *, ' Wind speed = ', r8arr (2,1)
PRINT *, ' Temperature (K) = ', r8arr (3,1)
PRINT *, 'Relative Humidity = ', r8arr (4,1)
C* Height increments.
CALL UFBREP ( 11, r8arr, MXMN, MXLV, nlv,
+ 'HINC' )
DO ii = 1, 3
PRINT *, ' Height increment #', ii, ' = ',
+ r8arr ( 1, ii )
END DO
C* Observation sequence (i.e. "OBSEQ" data).
CALL UFBREP ( 11, r8arr, MXMN, MXLV, nlv,
+ 'NPHL NPQC UCMP VCMP SDHS WCMP SDVS' )
DO ii = 1, 43
PRINT *, ' Profiler mode #', ii, ' = ',
+ r8arr ( 1, ii )
PRINT *, ' Profiler QC #', ii, ' = ',
+ r8arr ( 2, ii )
PRINT *, ' U Component #', ii, ' = ',
+ r8arr ( 3, ii )
PRINT *, ' V Component #', ii, ' = ',
+ r8arr ( 4, ii )
PRINT *, 'Stddev of Horiz wind #', ii, ' = ',
+ r8arr ( 5, ii )
PRINT *, ' W Component #', ii, ' = ',
+ r8arr ( 6, ii )
PRINT *, ' Stddev of Vert wind #', ii, ' = ',
+ r8arr ( 7, ii )
END DO
CALL UFBREP ( 11, r8arr, MXMN, MXLV, nlv,
+ 'ACAV' )
C* Total number of values
C* (with respect to accumulation or average)
DO ii = 1, 86
PRINT *, ' ACAV value #', ii, ' = ',
+ r8arr ( 1, ii )
END DO
END IF
END DO
END DO
END
In the above program example, the first thing that is done is to
associate logical unit numbers with our BUFR messages and tables
files via the FORTRAN OPEN statement. Note that the messages file
is an empty "dummy" file for this program, since we will be
using subroutine READERME (instead of READMG), and, therefore,
the BUFRLIB software will never actually try to read BUFR messages
(or, for that matter, anything else) from logical unit #11.
However, the call to OPENBF is still necessary in order
to associate our sample DX BUFR tables file (as local file
"bufrtab.example") with this logical unit #11, which will itself
then be passed as the second (i.e. LUBFR) argument to READERME.
Then, following the call to OPENBF, a looping mechanism
is set up to continuously read each new BUFR message (in some
unspecified manner from the local system) into the character array
cbfmsg, until there are no more messages to read, at which
time subroutine CLOSBF is called and the program stops.
Otherwise, the message is passed into subroutine READERME
via the integer array ibfmsg, which is EQUIVALENCED to
cbfmsg. Upon return from each call to READERME,
we check that the read was successful and also that the message
contains the type of data subset (i.e. "NC002007") that we
are interested in. In fact, this latter check could actually be
accomplished prior to even calling READERME, as in:
IF ( ( IUPBS01 ( ibfmsg, 'MTYP' ) .eq. '2' ) .and.
+ ( IUPBS01 ( ibfmsg, 'MSBT' ) .eq. '7' ) ) THEN
msgok = .true.
ELSE
msgok = .false.
END IF
Or, alternatively, we could even call UPDS3 in order to
confirm that the sequence of FXY numbers in Section 3 of the BUFR
message matches what was defined for "NC002007" within our
"bufrtab.example" tables file! At any rate, once we have an actual "NC002007"
message internally within BUFRLIB, a second (i.e. inner) loop reads
each data subset from that message via successive calls to function
IREADSB, until a non-zero return code indicates that there
are no more data subsets and that, therefore, we need to go back to
the first (i.e. outer) loop to read and pass the next BUFR message into
READERME. Otherwise, successive calls to UFBINT, UFBREP,
etc. return the desired actual data values, in the units listed for
the respective mnemonics within the associated BUFR tables file.
In particular, note how the order in which the mnemonics are listed
within the final (i.e. CMNSTR) call argument defines the
order in which their respective values are stored within the output
array r8arr, and note that any such values which are
"missing" for a particular data subset will be returned as 10.0E10.
Note also that the use of UFBREP is required for reading
the levels of observation sequence data, since that data was replicated
via regular (i.e. non-delayed) replication with a fixed replication
factor of ( 36 + 7 = 43 ). In fact, the use of UFBREP is also
required for the repeated mnemonics "HINC" and "ACAV", the latter
of which occurs twice within each observation sequence level and which
therefore is replicated ( 43 * 2 = 86 ) total times within each data
subset. This, it is worth noting, is why we set the parameter MXLV = 86,
recalling that is the responsibility of the application program to
ensure that the r8arr array is dimensioned at least as
large enough to hold all of the possible data values that could be
returned by any call of UFBINT, UFBREP , etc. in which it is used!
Further, and for that very same reason, if the observation sequence
data had been, say, 8-bit delayed replicated instead of regularly
replicated with a fixed (i.e. previously known) replication factor of 43,
then we would have been wise to set MXLV = 510 ( = 255 * 2 ),
since 255 is the maximum number of levels that could possibly be returned
by UFBINT when using 8-bit delayed replication, and, in such
a case, we would have to inspect the output value nlv in order
to know how many levels were actually returned for each data subset!
|