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