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