Skip Navigation Links weather.gov 
NOAA logo - Click to go to the NOAA homepage National Weather Service   NWS logo - Click to go to the NWS homepage
National Centers for Environmental Prediction
Navigation Bar Left Cap
Navigation Bar End Cap
 

NCEP Home > NCO Home > Systems Integration Branch > Decoders > BUFRLIB > BUFRLIB Table of Contents > General-purpose utility for decoding BUFR files
Printer image icon. Printer Friendly Version

Example Program: General purpose utility for decoding BUFR files

In this example, we show how various BUFRLIB subroutines and functions can be integrated within an application program to read and dump the contents of a file containing any types of valid BUFR messages, without the need to pre-define any DX BUFR tables. As discussed earlier within the documentation, this can be done via the use of appropriate Master BUFR tables, and by specifying IO='SEC3' when making the appropriate call to subroutine OPENBF for the file in question. Unlike in some of our other examples, the below program can be directly compiled and run "as is", without any additional code supplied by the user. The program consists of a main C-language program "debufr.c" which in turn calls a FORTRAN subroutine "fdebufr.f" as shown below.

 
--------------------------- main program "debufr.c" --------------------------
/*
** MAIN PROGRAM DOCUMENTATION BLOCK
**
** MAIN PROGRAM:  debufr
**   PRGMMR: J. Ator          ORG: NP12        DATE: 2009-07-01
**
** ABSTRACT: This program decodes a specified BUFR file and generates a
**   verbose listing of the contents.
**
** PROGRAM HISTORY LOG:
** 2009-07-01  J. Ator     Original author
**
** USAGE:
**   ./debufr [-b] [-o outfile] [-t tabledir] bufrfile
**
**   WHERE:
**     -b        specifies the "basic" option, whereby only information
**               from Sections 0-3 of each BUFR message in the bufrfile
**               is decoded, and no attempt is made to decode the data
**               in Section 4
**     outfile   [path/]name of file to contain verbose output listing;
**               the default is "debufr.out" in the local run directory
**     tabledir  directory containing BUFR master tables to be used for
**               decoding; the default is "/nwprod/fix"
**     bufrfile  [path/]name of BUFR file to be decoded
**
** REMARKS:
**   SUBPROGRAMS CALLED:
**     LOCAL      - fdebufr
**     BUFRLIB    - ccbfl    cobfl    crbmg    datelen  dxdump
**                  ireadsb  iupbs01  iupbs3   mtinfo   openbf
**                  readerme ufdump   upds3
**
**   FORTRAN logical unit numbers 51, 60, 90 and 91 are reserved for
**   use within the fdebufr subroutine.
**
** ATTRIBUTES:
**   LANGUAGE: C
**   MACHINE: Portable to all platforms
*/

#include 
#include 

#ifdef UNDERSCORE
#define cobfl cobfl_
#define ccbfl ccbfl_
#define fdebufr fdebufr_
#endif

int main( int argc, char *argv[ ] ) {

        int ch;
        int errflg;

        char basic = 'F';
        char io = 'r';
        char outfile[120] = "debufr.out";
        char tbldir[120] = "/nwprod/fix";

        /*
        **  Get the valid options from the command line:
        **      -b      "basic" option - only decodes information from Sections 0-3
        **              of each input message, with no decoding of Section 4 data
        **      -o      defines the output filename (default is "debufr.out")
        **      -t      defines the master table directory (default is "/nwprod/fix")
        */
        errflg = 0;
        while ( ( ch = getopt ( argc, argv, "bo:t:" ) ) != EOF ) {
            switch ( ch ) {
                case 'b':
                    basic = 'T';
                    break;
                case 'o':
                    strcpy ( outfile, optarg );
                    break;
                case 't':
                    strcpy ( tbldir, optarg );
                    break;
            }
        }

        /*
        **  There should be one remaining command line argument specifying the
        **  input BUFR file.
        */
        if ( (optind+1) != argc ) {
            printf( "\nUsage:  %s [options] BUFRfile\n\n", argv[0] );
            printf( "  where possible options are:\n" );
            printf( "    -b\n" );
            printf( "    -o [path/]filename of output file\n" );
            printf( "    -t [path/]filename of master table directory\n\n" );
            printf( "  and BUFRfile is [path/]filename of BUFR input file\n\n" );
            return -1;
        }

        /*
        **  Open the input BUFR file.
        */
        cobfl( argv[optind], &io );

        /*
        **  Read and decode each message from the input BUFR file.
        */
        fdebufr( outfile, tbldir, &basic,
                 strlen(outfile), strlen(tbldir) );

        /*
        **  Close the input BUFR file.
        */
        ccbfl( );

        return 0;
}
------------------------------------------------------------------------------


---------------------- FORTRAN subroutine "fdebufr.f" ------------------------

        SUBROUTINE FDEBUFR ( ofile, tbldir, basic )

C$$$  SUBPROGRAM DOCUMENTATION BLOCK
C
C SUBPROGRAM:    fdebufr
C   PRGMMR: J. Ator          ORG: NP12       DATE: 2009-07-01
C
C ABSTRACT: This subroutine reads every BUFR message from within the
C   input file that was specified on the command line.  Each such
C   message is decoded and the results are written as output to ofile.
C   No DX dictionary files or messages are necessary; rather, only
C   BUFR master tables are required and must exist in the directory
C   specified by tbldir.
C
C PROGRAM HISTORY LOG:
C 2009-07-01  J. Ator     Original author
C
C USAGE:    call fdebufr ( ofile, tbldir, basic )
C   INPUT ARGUMENT LIST:
C     ofile    - character*(*): file to contain verbose output
C                listing for each decoded BUFR message
C     tbldir   - character*(*): directory containing BUFR master
C                tables to be used for decoding
C     basic    - character: indicator as to whether the "basic"
C                option was specified on the command line:
C                  'Y' = yes
C                  'N' = no
C
C REMARKS:
C   FORTRAN logical unit numbers 51, 60, 90 and 91 are reserved for
C   use within this subroutine.
C
C ATTRIBUTES:
C   LANGUAGE: FORTRAN 77
C   MACHINE:  Portable to all platforms
C
C$$$

        PARAMETER ( MXBF = 950000 )
        PARAMETER ( MXBFD4 = MXBF/4 )
        PARAMETER ( MXDS3 = 500 )

        CHARACTER*(*)   ofile, tbldir
        CHARACTER       basic

        CHARACTER*8     cmgtag
        CHARACTER*6     cds3 ( MXDS3 )

        CHARACTER*1     bfmg ( MXBF )

        INTEGER         ibfmg ( MXBFD4 )

        EQUIVALENCE     ( bfmg (1), ibfmg (1) )

C----------- End of declarations --------------

C       Open the output file.

        OPEN ( UNIT = 51, FILE = ofile )

C       Note that in the below OPEN statement we just need to specify
C       a dummy placeholder file.

        lunit = 60
        OPEN ( UNIT = lunit, FILE = '/dev/null' )
        CALL OPENBF ( lunit, 'SEC3', lunit )

        CALL MTINFO ( tbldir, 90, 91 )

        CALL DATELEN ( 10 )

        nmsg = 0

        nsubt = 0

        DO WHILE ( .true. )

C           Get the next message from the input BUFR file.

            CALL CRBMG ( bfmg, MXBF, nbyt, ierr )
            IF ( ierr .ne. 0 )  THEN
                IF ( ierr .eq. -1 ) THEN
                    WRITE  ( UNIT = 51, FMT = '( /, 2A, I7, A, I9, A )')
     +                'Reached end of BUFR file; it contained a total ',
     +                'of', nmsg, ' messages and', nsubt, ' subsets'
                ELSE
                    WRITE  ( UNIT = 51, FMT = '( /, 2A, I4 )' )
     +                'Error while reading BUFR file; the return code ',
     +                'from CRBMG = ', IERR
                ENDIF
                IF ( basic .eq. 'F' ) THEN
                    WRITE (51, FMT = '( /, A, / )' )
     +                  'Here is the DX table that was generated:'
                    CALL DXDUMP ( lunit, 51 )
                ENDIF

C               Close the output file.

                CLOSE ( 51 )

                RETURN
            ENDIF

            nmsg = nmsg + 1

            WRITE  ( UNIT = 51, FMT = '( /, A, I7 )' )
     +          'Found BUFR message #', nmsg

            WRITE (51,*) ' '

            WRITE (51,*) '       Message length:', IUPBS01(ibfmg,'LENM')
            WRITE (51,*) '     Section 0 length:', IUPBS01(ibfmg,'LEN0')
            WRITE (51,*) '         BUFR edition:', IUPBS01(ibfmg,'BEN')

            WRITE (51,*) ' '

            WRITE (51,*) '     Section 1 length:', IUPBS01(ibfmg,'LEN1')
            WRITE (51,*) '         Master table:', IUPBS01(ibfmg,'BMT')
            WRITE (51,*) '   Originating center:', IUPBS01(ibfmg,'OGCE')
            WRITE (51,*) 'Originating subcenter:', IUPBS01(ibfmg,'GSES')
            WRITE (51,*) 'Update sequence numbr:', IUPBS01(ibfmg,'USN')

            IF ( IUPBS01(ibfmg,'ISC2') .eq. 1 ) THEN
                WRITE (51,*) '   Section 2 present?: Yes'
            ELSE
                WRITE (51,*) '   Section 2 present?: No'
            ENDIF

            WRITE (51,*) '        Data category:', IUPBS01(ibfmg,'MTYP')
            WRITE (51,*) '    Local subcategory:', IUPBS01(ibfmg,'MSBT')
            WRITE (51,*) 'Internatl subcategory:',
     +                                  IUPBS01(ibfmg,'MSBTI')
            WRITE (51,*) ' Master table version:', IUPBS01(ibfmg,'MTV')
            WRITE (51,*) '  Local table version:', IUPBS01(ibfmg,'MTVL')
            WRITE (51,*) '                 Year:', IUPBS01(ibfmg,'YEAR')
            WRITE (51,*) '                Month:', IUPBS01(ibfmg,'MNTH')
            WRITE (51,*) '                  Day:', IUPBS01(ibfmg,'DAYS')
            WRITE (51,*) '                 Hour:', IUPBS01(ibfmg,'HOUR')
            WRITE (51,*) '               Minute:', IUPBS01(ibfmg,'MINU')
            WRITE (51,*) '               Second:', IUPBS01(ibfmg,'SECO')

            WRITE (51,*) ' '

            nsub = IUPBS3(ibfmg,'NSUB')
            WRITE (51,*) 'Number of data subsets:', nsub
            nsubt = nsubt + nsub

            IF ( IUPBS3(ibfmg,'IOBS') .eq. 1 ) THEN
                WRITE (51,*) '    Data are observed?: Yes'
            ELSE
                WRITE (51,*) '    Data are observed?: No'
            ENDIF

            IF ( IUPBS3(ibfmg,'ICMP') .eq. 1 ) THEN
                WRITE (51,*) '  Data are compressed?: Yes'
            ELSE
                WRITE (51,*) '  Data are compressed?: No'
            ENDIF

            CALL UPDS3 ( ibfmg, MXDS3, cds3, nds3 )
            WRITE (51,*) ' Number of descriptors:', nds3
            DO jj = 1, nds3
                WRITE ( 51, FMT = '( 5X, I4, A, A6)' )
     +              jj, ": ", cds3 ( jj )
            END DO

            IF ( basic .eq. 'F' ) THEN

C               Decode and output the data from Section 4.

                CALL READERME ( ibfmg, lunit, cmgtag, imgdt, ierme )
                IF ( ierme .ge. 0 ) THEN
                    WRITE  ( UNIT = 51,
     +                       FMT = '( /, A, I7, 3A, I10, A, I6, A )' )
     +                  'BUFR message #', nmsg, ' of type ', cmgtag,
     +                  ' and date ', imgdt, ' contains ', nsub,
     +                  ' subsets:'
                    DO WHILE ( IREADSB ( lunit ) .eq. 0 )
                        CALL UFDUMP ( lunit, 51 )
                    ENDDO
                ENDIF
            ENDIF

            WRITE  ( UNIT = 51, FMT = '( /, A, I7 )' )
     +          'End of BUFR message #', nmsg
            WRITE  ( UNIT = 51, FMT = '( /, 120("-"))' )

        ENDDO

        RETURN
        END
------------------------------------------------------------------------------

As shown above, this particular application program is designed to be run as a UNIX shell command, with the BUFR file to be decoded as the lone argument. The output file where decoded information is to be printed can be specified via the option -o; otherwise the file "debufr.out" is created in the same directory. Similarly, and since the program will need access to master BUFR tables, an option -t is also provided where the directory containing these master tables is located. Note that this same directory name is eventually passed in as an argument to subroutine MTINFO within the FORTRAN code, in order to indicate the location of these master tables to the BUFRLIB software. Finally, note that an additional -b option is also provided in case the user just wants a basic listing of the contents of Sections 0 through 3 of each BUFR message without a full-blown listing of all of the data values in Section 4. For further details see the "USAGE:" section within the documentation block of the above C code. Otherwise, before moving into the FORTRAN code, note that this C code also does a call to COBFL, since we will be demonstrating the use of BUFRLIB's C language interface to read each BUFR message from the specified input file.

Now, within the FORTRAN code, note that we make an initial call to OPENBF, despite the fact that we will be using CRBMG to actually read the BUFR messages from the specified input file. This call to OPENBF is nonetheless needed in order to associate a FORTRAN logical unit number that can later be passed into subroutine READERME, and also to let the BUFRLIB software know (via the use of IO='SEC3') that we want messages decoded according to their Section 3 data description section once we pass them in via READERME later on in the code.

At this point, and after the aforementioned required call to subroutine MTINFO is made, the main loop is entered to read each BUFR message in turn from the specified file using CRBMG, print the basic information from Sections 0 through 3 using multiple successive calls to IUPBS01, IUPBS3 and UPDS3, and then (unless the -b option was specified on the command line), pass the message into subroutine READERME, where each data subset can then be read using IREADSB and subsequently printed to the specified output file using subroutine UFDUMP. Finally, after all such BUFR messages have been read and decoded from the file, the program makes a call to subroutine DXDUMP to print a copy of the internal DX table that was automatically generated by the BUFRLIB during processing of the file. Control is then passed back to the above C code, where the final call to CCBFL is made and then the program exits.



NOAA/ National Weather Service
National Centers for Environmental Prediction
5830 University Research Court
College Park, MD 20740
NCEP Internet Services Team
Disclaimer
Credits
Glossary
Privacy Policy
About Us
Career Opportunities
Page last modified: Thursday, 10-Jun-2010 13:08:08 UTC