This example shell script demonstrates how to use a Fortran program calling the BUFRDC library to decode a BUFR message.  The script:

  • retrieves observations in BUFR format from MARS
  • compiles and links a Fortran decoding program with gfortran
  • decodes and prints the contents of the BUFR message

#!/bin/bash
# **************************** LICENSE START ***********************************
#
# Copyright 2021 ECMWF. This software is distributed under the terms
# of the Apache License version 2.0. In applying this license, ECMWF does not
# waive the privileges and immunities granted to it by virtue of its status as
# an Intergovernmental Organization or submit itself to any jurisdiction.
#
# ***************************** LICENSE END ************************************
#
# Retrieve_decode_bufr      USER SERVICES  NOVEMBER 2021 - ECMWF
#
#
#       This shell-script:
#
#          - retrieves observations in BUFR format from MARS
#          - compiles and links a Fortran90 decoding program with gfortran 
#          - decodes and prints BUFR data
#
#       This shell script produces the standard output file 
#
#          retrieve_decode_bufr.<JOB-ID>.out
#
#       in the workdir directory, containing the log of job execution.    
#
#       For more information on BUFR format see
#
#       BUFR User's Guide  and
#       BUFR Reference Manual
#
#       at 
#
#       http://www.ecmwf.int/publications/technical_notes/
#
#
#-------------------------------
# setting options for SLURM
#-------------------------------
# Options that are specified within the script file should precede the
# first executable shell command in the file. 
# All options, which are case sensitive, are preceded by #SBATCH. 
# These lines become active only when the script is submitted
# using the "sbatch" command. 
# All job output is written to the workdir directory, by default. 

#SBATCH --qos=ef

        # Specifies that your job will run in the queue (Quality Of
        # Service) "ef".

#SBATCH --job-name=retrieve_decode_bufr

        # Assigns the specified name to the request

#SBATCH --output=retrieve_decode_bufr.%j.out

        # Specifies the name and location of STDOUT where %j is the job-id
        # The file will be # written in the workdir directory if it is a 
        # relative path. If not given, the default is slurm-%j.out in the
        # workdir.

#SBATCH --error=retrieve_decode_bufr.%j.out

        # Specifies the name and location of STDERR where %j is the job-id
        # The file will be # written in the workdir directory if it is a 
        # relative path. If not given, the default is slurm-%j.outin the
        # workdir.

#SBATCH --chdir=/scratch/...

        # Sets the working directory of the batch script before it is
        # executed.

#SBATCH --mail-type=FAIL
        
        # Specifies that an email should be sent in case the job fails.
        # Other options include BEGIN, END, REQUEUE and ALL (any state
        # change).

#SBATCH --time=00:05:00

        # Specifies that your job my run up to HH:MM:SS of wall clock
        # time. The job will be killed if it exceeds this limit. If
        # time is not defined, the default limit for the queue (qos)
        # will be used.


#-------------------------------
# setting environment variables
#-------------------------------

export PATH=$PATH:.             # Allows you to run any of your programs or
                                # scripts held in the current directory (not 
                                # required if already done in your .user_profile 
                                # or .user_kshrc)
set -ev

#-------------------------------
# commands to be executed
#-------------------------------

cd $SCRATCHDIR                  # All the files created in this directory will be
                                # deleted when the job terminates.


# cat is used to read the Fortran program from the input stream
# and to write it to the file 'bfdemo.f90'.
# cat reads line by line until it reaches a line which starts with EOF.
# If EOF is preceded by \, cat is done verbatim, otherways variables
# will be expanded.

cat > bfdemo.f90 <<EOF
      PROGRAM BFDEMO
!                                                                       
!     BFDEMO - Program to demonstrate use of BUFREX routine.            
!                                                                       
!     Purpose.                                                          
!     --------                                                          
!                                                                       
!     Demonstrates use of BUFREX routine to unpack                      
!     BUFR coded data.                                                  
!                                                                       
!     Interface.                                                        
!     ----------                                                        
!                                                                       
!     File of BUFR coded data attached as 'input_datafile'              
!                                                                       
!     Method.                                                           
!     -------                                                           
!                                                                       
!     Read BUFR messages and print sections 0, 1, 2, 3 and 4.                 
!                                                                       
!                                                                       
!     Externals.                                                        
!     ----------     
!
!     PBOPEN
!     PBCLOSE
!     PBBUFR
!     BUS012
!     BUFREX
!     BUPRS0
!     BUPRS1
!     BUPRS2
!     BUPRS3
!     BUUKEY
!     BUSEL
!     BUPRT
!
!                                                                       
!     WMO Manual on Codes, Volume I, International Codes, PartB-Binary Codes  
!     WMO No. 306, FM 94-IX Ext BUFR.      
!                                                                       
!     Comments.                                                         
!     ---------                                                         
!                                                                       
!     BUFREX provides a number of packing/unpacking options.       
!     See documentation in routine BUFREX for details.                  
!                                                                       
!     Author.                                                           
!     -------                                                           
!                                                                       
!     M. Dragosavac                                 
!                                                                       
!     Modifications.                                                    
!     --------------
!     
!     U. Modigliani     ECMWF   08.97
!                       rewritten in Fortran 90
!
!-----------------------------------------------------------------
!                                         
      IMPLICIT NONE     
!
      EXTERNAL PBOPEN, PBCLOSE, PBBUFR, BUS012, BUFREX, BUPRS0, BUPRS1, &
               BUPRS2, BUPRS3, BUUKEY, BUSEL, BUPRT    
!                                                                       
!     This parameter holds the 'number of bytes per integer'    
!   
      INTEGER, PARAMETER :: I4B = SELECTED_INT_KIND(9)   
!
!     These parameters hold the 'number of bytes per single/double precision real'    
!   
      INTEGER(KIND=I4B), PARAMETER :: NBYTES_SP = KIND(1.0)           
!
      INTEGER(KIND=I4B), PARAMETER :: NBYTES_DP = KIND(1.0D0)
!
      INTEGER(KIND=I4B), PARAMETER :: JSUP = 9, JSEC0 = 3, JSEC1 = 40, &
                         JSEC2 = 4096, JSEC3 = 4, JSEC4 = 2, JKEY = 46

!     The default size of the Section 1 is 18 octets and 22 octets for
!     Bufr Edition 4, if there are no local entries.
!                                                                       
      INTEGER(KIND=I4B), PARAMETER :: & ! These paramters depend on the input data!
        KELEM =  80000,  &              ! expected number of expanded elements
        KVALS = 360000,  &              ! expected number of data values
        JBUFL =  20000                  ! length of bufr message (words)
!
      INTEGER(KIND=I4B), DIMENSION(JBUFL) :: KBUFF
!                                                                       
      CHARACTER(LEN=*), PARAMETER :: INPUT_FILE='input_datafile'
      CHARACTER(LEN=*), PARAMETER :: OPEN_MODE='r'
!
      CHARACTER(LEN=64), DIMENSION(KELEM)  :: CNAMES = ' '
      CHARACTER(LEN=24), DIMENSION(KELEM)  :: CUNITS = ' '
      CHARACTER(LEN=80), DIMENSION(KVALS)  :: CVALS = ' ' 
!                                                                       
      INTEGER(KIND=I4B), DIMENSION(JSUP)  :: KSUP 
      INTEGER(KIND=I4B), DIMENSION(JSEC0) :: KSEC0 
      INTEGER(KIND=I4B), DIMENSION(JSEC1) :: KSEC1 
      INTEGER(KIND=I4B), DIMENSION(JSEC2) :: KSEC2
      INTEGER(KIND=I4B), DIMENSION(JSEC3) :: KSEC3
      INTEGER(KIND=I4B), DIMENSION(JSEC4) :: KSEC4
       
      INTEGER(KIND=I4B), DIMENSION(JKEY) :: KEY 
!                                                                       
!     The array VALUES (and the missing value indicator RVIND) are
!     declared as REAL*8 from emoslib version 370 onwards.
!
      REAL(KIND=NBYTES_DP), DIMENSION(KVALS)  :: VALUES
!      
      INTEGER(KIND=I4B), DIMENSION(KELEM) :: KTDLST, KTDEXP
!                                                                       
!     DATA CNAMES / KELEM * ' ' / , CUNITS / KELEM * ' ' / 
!                                                                       
!     Clear error counter.
!                                              
      INTEGER(KIND=I4B) :: NUMERR = 0    
!                                                                       
!     Set message counter.
!                                               
      INTEGER(KIND=I4B) :: NMESSAGE = 0   
      INTEGER(KIND=I4B) :: ISTATUS = 0 
      INTEGER(KIND=I4B) :: KUNIT, KBUFL, KEL, KTDLEN, KTDEXL  
!                                                                       
!     Open input file for reading.   
!                                    
      CALL PBOPEN (KUNIT, INPUT_FILE, OPEN_MODE, ISTATUS) 
!
!     Check return code.
!      
      WRITE ( * , * ) ' ' 
      WRITE ( * , * ) 'BFDEMO: After PBOPEN, status code   = ', ISTATUS 
      WRITE ( * , * ) ' ' 
      IF (ISTATUS .NE. 0) THEN 
          CALL PBCLOSE (KUNIT, ISTATUS)
          STOP 'BFDEMO: PBOPEN failed.'
      END IF       
!                                                                       
!     This is the beginning of a loop through BUFR records
!     reading one field at a time from the input datafile. 
!                                                                       
LOOP: DO WHILE (.TRUE.)     
!                                                               
         WRITE ( * , * ) '****************************************************' 
         WRITE ( * , * ) ' ' 
         CALL PBBUFR (KUNIT, KBUFF, JBUFL * NBYTES_SP, KBUFL, ISTATUS) 
         WRITE ( * , * ) 'BFDEMO: After PBBUFR, status code   = ', ISTATUS 
!                                                                       
         IF (ISTATUS .EQ. - 1) THEN
!
!        Exit the DO loop.
!
	        EXIT LOOP
         END IF
!        
!        It can be more specific: see PBBUFR error codes.
!                                                                      
         IF (ISTATUS .LT. - 1) THEN  
            CALL PBCLOSE (KUNIT, ISTATUS)
            STOP 'BFDEMO: Error reading file.' 
         END IF
!                                                                       
         NMESSAGE = NMESSAGE + 1 
!      
         WRITE ( * , * ) 'BFDEMO: BUFR message number         = ', NMESSAGE 
         WRITE ( * , * ) 'BFDEMO: Length of message           = ', KBUFL 
         WRITE ( * , * ) ' ' 
         WRITE ( * , * ) '****************************************************'
         WRITE ( * , * ) ' ' 
!                                                                       
         KBUFL = KBUFL / NBYTES_SP + 1 
!
!        Expands only section 0, 1 and 2 of Bufr message.
!                                                                  
         CALL BUS012 (KBUFL, KBUFF, KSUP, KSEC0, KSEC1, KSEC2, ISTATUS)       
!              
         IF(ISTATUS .NE. 0) THEN
            WRITE ( * , * ) 'Error in BUS012: ', ISTATUS
            CYCLE LOOP
         END IF
!
!        Decode Bufr message into fully expanded form; returning
!        information relevant for all Bufr sections, expanded values,
!        their names and units.
!      
         KEL=KELEM
         IF(KSUP(6).GT.1) THEN 
           KEL=KVALS/KSUP(6)
           IF (KEL.GT.KELEM) KEL=KELEM
         END IF
!
         CALL BUFREX (KBUFL, KBUFF, KSUP, KSEC0, KSEC1, KSEC2, KSEC3, KSEC4,   &
                      KEL, CNAMES, CUNITS, KVALS, VALUES, CVALS, ISTATUS)    
!                    
!        Check return code.
!                                                                       
         IF (ISTATUS .GT. 0) THEN
!
!           Increase the number of errors' counter.
! 
            NUMERR = NUMERR + 1 
            CYCLE LOOP
         END IF       
!
!        Print section 0 of Bufr message.
!            
         CALL BUPRS0 (KSEC0)      
!
!        Print section 1 of Bufr message.
!       
         CALL BUPRS1 (KSEC1) 
!
!        Expands local ECMWF information from section 2.
!    
         CALL BUUKEY (KSEC1, KSEC2, KEY, KSUP, ISTATUS) 
!
!        Print section 2 of Bufr message (expanded RDB key).
!
         CALL BUPRS2 (KSUP, KEY) 
!     
!        Returns list of Data Descriptors as in Section 3  of Bufr
!        message and total/requested list of elements.
!
         CALL BUSEL (KTDLEN, KTDLST, KTDEXL, KTDEXP, ISTATUS) 
!
!        Print section 3 of Bufr message.
!  
         CALL BUPRS3 (KSEC3, KTDLEN, KTDLST, KTDEXL, KTDEXP, KELEM, CNAMES) 
!                                                                       
!        Print expanded Bufr message.
!                                                                  
         CALL BUPRT (0, 1, KSUP(6), KEL, CNAMES, CUNITS, CVALS, KVALS, VALUES,&
                     KSUP, KSEC1, ISTATUS) 
!                                                                       
!        Loop back for next BUFR record.                                   
!                                                                       
      END DO LOOP
!                                                                       
!     End-of-file on input.                                             
!
      WRITE ( * , * ) 'BFDEMO: End-of-file on input.'  
      WRITE ( * , * ) ' ' 
      WRITE ( * , * ) '****************************************************' 
      WRITE ( * , * ) ' ' 
      WRITE ( * , * ) 'BFDEMO: Number of records processed = ', NMESSAGE 
      WRITE ( * , * ) 'BFDEMO: Number of decoding errors   = ', NUMERR 
      WRITE ( * , * ) ' ' 
      WRITE ( * , * ) '****************************************************'
! 
      CALL PBCLOSE (KUNIT, ISTATUS)
!                         
	  STOP 'BFDEMO: Terminated'
!                                       
      END PROGRAM BFDEMO                            
EOF


#--------------------
# MARS  request
#--------------------

mars<<EOF              # Retrieve the data from MARS to the 
                       # target file "bufr_file".
retrieve,
        date    = -3,
        type    = obs,
        obstype = s,
        #ident   = 03955/03957,
        time    = 09:00,
        range   = 180,
        target  = "bufr_file"
EOF


if [ $? != 0 ]                          # Check MARS exit code
then
      echo " The MARS request failed."
      exit 1
fi


module load prgenv/gnu    # Or module load pg
module load bufrdc

#-------------------------------
# compile and link libraries
#-------------------------------

ln -s bufr_file input_datafile        # Connect target file to data file.

echo was gfortran -march=native -O3 -o bfdemo bfdemo.f90 $EMOSLIB       
gfortran -march=native -O3 -o bfdemo bfdemo.f90 $BUFRDC_LIB

# Use gfortran -o to create the bfdemo executable.  
# The compiler options -march=native -O3 provide some basic
# optimisation.  The $EMOSLIB options are passed to the linker.

./bfdemo > $SCRATCH/decoded_data        # execute bfdemo and redirect 
                                        # the output to your $SCRATCH 
                                        # directory

#-------------------------------
# tidy up by deleting unwanted files
#-------------------------------
# Don't forget to delete $SCRATCH/decoded_data if not needed any longer! 
# Tidying up in $SCRATCHDIR is done automatically. 

exit 0
 
# End of example job 'Retrieve_decode_bufr'               Copyright ECMWF 2021