NCEP Home > NCO Home > Systems Integration Branch > Decoders > BUFRLIB > BUFRLIB Table of Contents > Other Useful Subroutines
Printer Friendly Version
Other Useful BUFRLIB Subroutines
First, we will discuss how to interface an application program with the BUFRLIB
software in a whole new way! Specifically, the reader may recall, from
our initial discussion, that the BUFRLIB software normally reads/writes BUFR
messages directly from/to a BUFR file that is physically stored on the local
system and interfaced to the software via logical unit number LUBFR.
However, it is also possible to read/write these same BUFR messages directly
from/to a memory array within the application program itself, in order to
provide users with greater flexibility from an input/output perspective:
CALL READERME ( IBFMSG, LUBFR, CSUBSET, IDATE, IRET )
Input argument:
IBFMSG INTEGER(*) BUFR message
LUBFR INTEGER Logical unit for BUFR file
Output arguments:
CSUBSET CHAR*(*) Table A mnemonic for IBFMSG
IDATE INTEGER Section 1 date-time for IBFMSG
IRET INTEGER Return code:
0 = normal return
-1 = could not read IBFMSG
This subroutine looks and behaves a lot like the already-familiar READMG,
except that here we have one additional input argument IBFMSG which
contains the BUFR message to be read by the software. As such, READERME
can be used in any context in which READMG might otherwise
be used, and, further, from that point on, the application program can
proceed with the usual calls to READSB (and, subsequently UFBINT, UFBREP, UFBSEQ, etc.),
just as though READMG had previously been used, so that there
is no further modification required within the application program in
order to use this input mechanism.
However, do note that, when using READERME, it is still necessary
for the application program to have previously called subroutine OPENBF
in order to associate a DX BUFR tables file with the messages that are being
input via IBFMSG, and it is still also necessary to
pass in the relevant LUBFR value as a call argument to READERME
even though, in this case, the software will not actually try to read from
the associated logical unit. Note also that, for READERME, the
meaning of the output argument IRET is subtly different than was
the case for READMG, in that a return value of -1 now simply
indicates that the particular input BUFR message in question could not be
successfully read for some reason but that the interface to the BUFRLIB
software remains open and, therefore, subsequent calls to READERME with new
input BUFR messages may still be attempted.
Now, for the opposite case where we wish to output encoded messages from the
BUFRLIB software back into the application program, we have:
CALL WRITSA ( LUBFR, MXIBFMSG, IBFMSG, LIBFMSG )
Input argument:
LUBFR INTEGER Logical unit for BUFR file
MXIBFMSG INTEGER Dimensioned size of IBFMSG array
Output arguments:
IBFMSG INTEGER(*) BUFR message
LIBFMSG INTEGER Length of IBFMSG
This subroutine is designed to be called in the same context as the
already-familiar WRITSB, in that it indicates to the BUFRLIB
software that all of the necessary data values for the current data
subset have been stored via appropriate preceding calls to UFBINT,
UFBREP, etc., and therefore the subset is ready to be
encoded and packed into the current message for the BUFR file associated
with logical unit LUBFR. However, in the case of WRITSA,
each completed BUFR message is passed back to the application program
within the array IBFMSG, and the second output argument
LIBFMSG indicates the number of array elements of
IBFMSG that are occupied by the message. Note that the
dimensioned size of IBFMSG (in INTEGER words!) must also
be passed in as input, in order to prevent the subroutine from possibly overflowing
this array.
When using WRITSA, it becomes important to realize that, since
the BUFRLIB software is designed to pack as many data subsets as
possible into each message, not every call to WRITSA will
result in a message being returned. In such cases, the second output
argument LIBFMSG will contain the value 0, indicating that
no message (or, more literally, a message of length 0!) was returned.
In other words, only when LIBFMSG contains a value greater
than 0 is there a BUFR message within array IBFMSG; otherwise,
the message into which the data subset was packed remains internally
within BUFRLIB so that future data subsets can be packed into it as well,
and the message will eventually be returned during some other future call
to WRITSA. This, however, leads to the question of what
to do if we have no more data subsets to store and thus were not planning
to make any more future calls to WRITSA from the application
program - how do we retrieve that last message that still
remains internally within BUFRLIB before we exit our program?
The answer is to call WRITSA one last time, but in a special
way. Specifically, if we call WRITSA with the input argument
LUBFR set to the additive inverse of its usual value
(i.e. (-1) * LUBFR), then this is a signal to WRITSA that we
are not storing a new data subset but, rather, wish to forcibly retrieve
the current internal BUFR message associated with logical unit LUBFR.
By doing this, we are assured that all BUFR message output has been returned
to the application program.
Note, however, that a similar special final
call is never required for WRITSB (i.e. which is
used when directing output BUFR messages to a file on the local system),
because, as was discussed earlier, the subsequent required call to CLOSBF
for logical unit LUBFR will ensure that all available BUFR
output is properly flushed to that logical unit before closing the
associated file. This brings up another important point,
which is to say that, even when we are using WRITSA instead
of WRITSB, and are therefore receiving the output BUFR messages
via a memory array within the application program, these messages are
nonetheless still also being written out to the file associated with
LUBFR, just like when we are using WRITSB!
This rather surprising fact is due solely to the overall design of the
BUFRLIB software; however, there is a way around this problem for the
user who does not want to allocate an actual file to hold this
extra copy of the BUFR output. Specifically, the solution is to use the
special input string of 'NUL' (rather than 'OUT') for the CIO call argument
to OPENBF when identifying this LUBFR to the BUFRLIB software.
That way, even though LUBFR must still contain a unique
integer value, the BUFRLIB software will never actually try to write
anything out to that logical unit number, and thus there is no need
for an actual file to be associated with that LUBFR value on
the local system!
As a final note, before we leave this overall discussion on interfacing BUFRLIB
with a memory array in an application program, the reader may have noticed
that, for both of the above subroutines, the IBFMSG call argument,
whereby the BUFR message is actually passed into or out of the BUFRLIB software
(depending on the case), is an INTEGER array rather than a CHARACTER array
as might be expected. This is due solely to the way that the BUFRLIB software
functions internally, but a user can easily overcome this issue, if necessary,
via an appropriate EQUIVALENCE between an array of each type within the
application program itself.
Now, here are some additional subroutines that might be of interest:
CALL DATELEN ( LEN )
Input argument:
LEN INTEGER Length of Section 1 date-time values to
be output by message-reading subroutines
such as READMG, READERME, etc.
8 = YYMMDDHH (i.e. 2-digit year)
10 = YYYYMMDDHH (i.e. 4-digit year)
This subroutine allows the user to specify the format for the IDATE output
argument that is returned by each subsequent call to any of the subroutines,
such as READMG or READERME, which read BUFR messages
from a BUFR file that is open for input. This subroutine may be called at
any time from the user's application program in order to set or reset this
date-time format accordingly, and in which case the new format will then
apply for all future calls to any of the message-reading subroutines (or
until it is changed again via a new call to DATELEN!). Alternatively,
if DATELEN is never called, then a default value of LEN = 8
(i.e. YYMMDDHH) applies.
Note that, in the case of a BUFR file that is open for output, there is no
need to ever call this subroutine, because the corresponding message-writing
subroutines such as OPENMB and OPENMG will automatically
accept the IDATE argument in either format (i.e. YYMMDDHH or
YYYYMMDDHH) without any special effort on the part of the application program.
CALL READNS ( LUBFR, CSUBSET, IDATE, IRET )
IRET = IREADNS ( LUBFR, CSUBSET, IDATE )
Input argument:
LUBFR INTEGER Logical unit for BUFR file
Output arguments:
CSUBSET CHAR*(*) Table A mnemonic for data subset
IDATE INTEGER Section 1 date-time for data subset
IRET INTEGER Return code:
0 = normal return
-1 = no more BUFR data subsets in LUBFR
Subroutine READNS (or its corresponding functional equivalent
IREADNS) provides a handy way to combine the functionalities
of READMG/IREADMG and READSB/IREADSB into one simple call.
The application program needs only to make the initial call to OPENBF
in order to define the BUFR file that is to be read, and then each
subsequent call to READNS (or IREADNS) will read the next
new BUFR data subset from that file, all the while automatically
opening and closing each new BUFR message as needed, so that subsequent
calls may be immediately made to the data values routines such as UFBINT,
UFBSEQ, etc.
At first, the concept of READNS/IREADNS may
seem somewhat puzzling, since the call sequence is identical to
that of READMG/IREADMG, which, as we've already seen,
functions at the BUFR message level rather than the BUFR data
subset level. However, the reader may also recall, from the
discussion of subroutines OPENMG and OPENMB, that every
BUFR data subset within a particular BUFR message must always
have identical CSUBSET and IDATE values, and, in that
context, it does make sense.
CALL UFBTAB ( LUBFR, R8ARR, MXMN, MXLV, NSUB, CMNSTR )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
CMNSTR CHAR*(*) String of blank-separated mnemonics
associated with R8ARR
MXMN INTEGER Size of first dimension of R8ARR
MXLV INTEGER Size of second dimension of R8ARR
Output arguments:
R8ARR(*,*) REAL*8 Data values read from BUFR file
NSUB INTEGER Number of data subsets in BUFR file
The call sequence for this subroutine looks similar to that of
UFBINT, UFBREP and UFBSEQ. However, its usage is quite different,
in that UFBTAB provides a mechanism whereby a user
can do a quick scan of the range of values corresponding to one
or more mnemnonics amongst all data subsets for an entire
BUFR file, whereas, as we have seen, UFBINT, UFBREP and
UFBSEQ only operate on one data subset at a time.
More specifically, UFBTAB opens the input BUFR file
connected to logical unit LUBFR (i.e. the application
does not itself even have to call subroutine OPENBF!),
reads through every BUFR message and data subset in the file, and,
for each data subset, decodes (into the next-available row of R8ARR)
the values corresponding to the mnemonics listed within CMNSTR,
so that, in the end, the number of rows of R8ARR that are filled
with data values is exactly the same as the number of data subsets
(i.e. NSUB) that were contained within the BUFR file!
The file itself is then automatically disconnected from the BUFRLIB
software via an internal call to subroutine CLOSBF; therefore,
UFBTAB serves as a convenient "all-in-one" subroutine call for
reading specified data values from every data subset within a BUFR file!
There are some caveats, however, so beware! First and foremost,
when using UFBTAB, the input value MXLV (and corresponding
second dimension of R8ARR!) must now be larger than is
normally the case for use with the UFBINT, UFBREP and UFBSEQ
subroutines, since it now must be greater than or equal to the number
of data subsets within the overall BUFR file, rather than just large
enough to hold the maximum number of replications of any particular
mnemonic within a single data subset. In addition, UFBTAB is
normally not very useful whenever CMNSTR contains any mnemonic
which is repeated or multiply-replicated within each data subset,
since, in such cases, only the value corresponding to the first occurrence
of that mnemonic will be returned. Finally, since the application program
does not itself directly call subroutine OPENBF, then
UFBTAB can only be used to read BUFR files which contain
embedded DX BUFR tables information, since there is no way to specify a
separate LUNDX value containing the equivalent information
in an ASCII text file!
CALL UFDUMP ( LUBFR, LUPRT )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
LUPRT INTEGER Logical unit for print output
This subroutine can be used to dump a verbose print listing of the contents of
a data subset from an input BUFR file. The file must already be opened for
input via a previous call to subroutine OPENBF, and a data subset
must have subsequently been read into the internal BUFRLIB arrays via calls
to READMG/IREADMG and READSB/IREADSB (or a single call to
READNS/IREADNS!), at which point a call to UFDUMP will
then dump a listing of the contents of that data subset to the file pointed to
by logical unit LUPRT. This listing contains each mnemonic in the
data subset, accompanied by its corresponding FXY number, definition, encoded
data value and other potentially useful information such the scale factor,
reference value and bit width that were used to encode the value. Therefore,
and especially for large BUFR files containing many data subsets, there is
the potential for a lot of print output to be generated, so be forewarned!
Nevertheless, UFDUMP can be a useful way to quickly look at all
of the data values within a subset, especially since, for mnemonics which
are replicated, it will list all of the occurrences of that mnemonic,
irrespective of the type of replication that was used. Furthermore, for
mnemonics whose units are "CCITT IA5", the subroutine will automatically
convert the corresponding values from REAL*8 to character and print them
as such, and it will even print the descriptive string "MISSING" for all
values which were encoded as missing within the corresponding subset.
CALL DXDUMP ( LUBFR, LDXOT )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
LDXOT INTEGER Logical unit for output BUFR tables file
This subroutine provides a handy way to view the DX BUFR tables information that
is embedded in the first few messages of a BUFR file. The user needs only to
have identified the file to the BUFRLIB software via a prior call to subroutine
OPENBF, and then a subsequent call to subroutine DXDUMP
will unpack the embedded tables information and write it out to the file pointed
to by logical unit LDXOT. The output file is written using the
same ASCII-text table format described within the document
Description and Format of DX BUFR Tables, so it is suitable
for use as subsequent input to subroutine OPENBF via the call
argument LUNDX. Subroutine DXDUMP can be most useful
for learning the contents of archive BUFR files.
IRET = IBFMS ( R8VAL )
Input argument:
R8VAL REAL*8 Data value read from previous call to UFBINT,
UFBREP, UFBSEQ, UFBTAB, etc.
Output arguments:
IRET INTEGER Return code:
0 = R8VAL is not "missing"
1 = R8VAL is "missing"
This function provides a handy way to test whether a data value returned from a previous
call to any of the subroutines UFBINT, UFBREP, UFBSEQ, UFBTAB, etc.
contains the value of 10.0E10, which denotes "missing" in the context of the BUFRLIB software.
As noted in a prior discussion, this means that the corresponding value was encoded as
"missing" (i.e. all bits set to 1) within the actual BUFR data subset.
Although this function may seem fairly trivial, it does test using a fuzziness threshold to
ensure that real numbers aren't tested for actual equality to each other. This in turn
resolves most floating point representation discrepancies between different hardware platforms.
From our earlier discussions, it was noted that data values are normally read from or written
to BUFR subsets using REAL*8 arrays, such as when the BUFRLIB subroutines
UFBINT, UFBREP or UFBSEQ are used. In other words, individual data
values are normally expected to fit within an 8-byte (i.e. 32-bit) variable. It was also noted
that character (i.e. CCITT IA5) values were read and written in the same way using a REAL*8
variable, with the conversion of such values to or from actual character values being handled
by the application program using a FORTRAN EQUIVALENCE or similar translation mechanism.
However, there are often character values longer than 8 bytes which need to be read from or
written into BUFR subsets, so the question then is how to handle such cases within the
BUFRLIB software. The following two subroutines provide the solution.
First we'll show how to write "long" (i.e. greater than 8 byte) character strings into
a BUFR data subset:
CALL WRITLC ( LUBFR, CHRSTR, CMNEM )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
CHRSTR CHAR*(*) Character value to be written into data subset
CMNEM CHAR*(*) Mnemonic corresponding to CHRSTR
This subroutine will store CHRSTR into the current data subset
as the value corresponding to mnemonic CMNEM. The actual length
of CHRSTR, and therefore the actual number of characters to be
stored, is determined automatically by the subroutine using the bit width for
CMNEM as defined within the DX BUFR tables file corresponding
to LUBFR.
When using this subroutine, there are a couple of caveats to be aware of. First of all,
unlike when using subroutines UFBINT, UFBREP or UFBSEQ, any
calls to subroutine WRITLC must be made
after the call to subroutine
WRITSB or WRITSA for the data subset
in question. While this may seem counterintuitive, it is merely due to the way in which
the BUFRLIB internally packs up subsets in 8-byte chunks by default. In either case,
a BUFR message that is output by either of these subroutines never contains the data
subset that was just packed during the call in question, so there is no danger that a
subset will ever be written out before we've had a chance to modify its contents with a
subsequent call to WRITLC!
Note also that the call sequence for WRITLC contains no
inherent way of storing multiple occurrences of long character strings corresponding to
the same mnemonic. So if the mnemonic CMNEM
is replicated or otherwise repeated within the overall data subset definition, how
can we store each successive CHRSTR into the proper location
within the subset? The answer is to do a separate call for each such string, but
modify CMNEM in each case to append the ordinal number of the
occurrence in question. For example, if there are five occurrences of mnemonic LSTID
within a given subset definition, then each successive occurrence can be stored by
calling WRITLC a total of five times, with each
respective CMNEM set to 'LSTID#1', 'LSTID#2', 'LSTID#3',
'LSTID#4' and 'LSTID#5'. Note that the first case is superfluous, since omitting
the ordinal number always defaults to the first occurrence of a particular string, so
we could just specify 'LSTID' instead of 'LSTID#1'.
Now that we know how to use WRITLC to write "long"
(i.e. greater than 8 byte) character strings into a BUFR data subset, we'll show how
to use its counterpart READLC for reading such strings from
a subset:
CALL READLC ( LUBFR, CHRSTR, CMNEM )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
CMNEM CHAR*(*) Mnemonic indicating value to be read from
data subset
Output argument:
CHRSTR CHAR*(*) Character value corresponding to CMNEM
The call sequence here is identical to that for WRITLC;
however, in this case CHRSTR is an output value, so
the user must allocate enough space for the resulting string within the
application program. Subroutine READLC can be called
at any time after the call to subroutine READSB, READNS
or equivalent for the data subset in question, and note that the same ordinal
notation used for WRITLC can also be used for mnemonics
when calling READLC, in order to handle any cases where
a particular mnemonic occurs multiple times within the overall subset definition.
For example, calling READLC with
CMNEM set to 'LSTID#4' will return the string
corresponding to the 4th occurrence of mnemonic 'LSTID' within the overall
subset definition.
CALL UFBEVN ( LUBFR, R8ARR, MXMN, MXLV, MXEV, NLV, CMNSTR )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
CMNSTR CHAR*(*) String of blank-separated mnemonics
associated with R8ARR
MXMN INTEGER Size of first dimension of R8ARR
MXLV INTEGER Size of second dimension of R8ARR
MXEV INTEGER Size of third dimension of R8ARR
Output argument:
R8ARR(*,*,*)REAL*8 Data values read from data subset
NLV INTEGER Number of levels of data values
read from data subset
This subroutine can be used to mimic the effect of a multiple-replication
sequence within another multiple-replication sequence, because here our
R8ARR array contains a third dimension, which allows for multiple
replications of each data value in the otherwise two-dimensional R8ARR
array that we looked at earlier during our previous discussion of UFBINT,
UFBREP, and UFBSEQ. As was the case with those subroutines,
the R8ARR array must be initially declared and dimensioned within
the application program, and the input string CMNSTR corresponds
to the values in the first dimension of R8ARR. However, there is
also an important difference, in that subroutine UFBEVN can only
be used when logical unit LUBFR points to a BUFR file that is open
for input (i.e. reading). Therefore, the call arguments MXMN,
MXLV and MXEV are always input arguments describing the actual
dimensions of R8ARR. Furthermore, and despite the addition of a
third dimension to the R8ARR array, note that there is no additional
corresponding output argument which definitively indicates the number of
third-dimension values that were read from the data subset; rather, this
information must be indirectly inferred by the application program via
direct inspection of the actual values returned within R8ARR.
In a DX BUFR tables file, the fact that a certain sequence of data values
contains three dimensions (and, thus, that UFBEVN may be used to
read them!) is indicated by enclosing the sequence within the special
indicator characters "[ ]". An example of this is included
within the sample program for decoding NCEP PREPBUFR files.
(integer value) = IUPBS01 ( IBFMSG, S01MNEM )
(integer value) = IUPVS01 ( LUBFR, S01MNEM )
Input argument:
IBFMSG INTEGER(*) BUFR message
LUBFR INTEGER Logical unit for BUFR file
S01MNEM CHAR*(*) Mnemonic describing value to be decoded from
within Section 0 or Section 1 of BUFR message:
'LENM' = Length (in bytes) of BUFR message
'LEN0' = Length (in bytes) of Section 0
'BEN' = BUFR edition number
'LEN1' = Length (in bytes) of Section 1
'BMT' = BUFR master table
'OGCE' = Originating center
'GSES' = Originating subcenter
'USN' = Update sequence number
'ISC2' = Flag indicating absence/presence of
(optional) Section 2 in BUFR message
0 = Section 2 absent
1 = Section 2 present
'MTYP' = Data category
'MSBT' = Data subcategory (local)
'MSBTI' = Data subcategory (international)
'MTV' = Version number of master table
'MTVL' = Version number of local tables
'YEAR' = Year (4-digit)
'MNTH' = Month
'DAYS' = Day
'HOUR' = Hour
'MINU' = Minute
'SECO' = Second
Output argument:
IUPBS1 INTEGER Decoded value
-1 = invalid S01MNEM input value
Either of these functions can be used to decode and return a specified value
from Section 0 or Section 1 of an input BUFR message; the difference is in how
the input BUFR message is provided to the function. In the case of IUPBS01,
the BUFR message is directly input to the function as an integer array, with
the start of the message aligned on the first 4 bytes of the array.
Alternatively, IUPVS01 always operates directly on the BUFR
message that was most recently read into the internal BUFRLIB arrays from
logical unit LUBFR via a call to one of the routines READMG,
IREADMG or READERME. In either case, the value to be decoded
is specified via the descriptive mnemonic S01MNEM, whose possible
values are listed above. Furthermore, either function will work correctly
on any BUFR message encoded according to BUFR edition 2, 3 or 4.
CALL PKVS01 ( S01MNEM, IVAL )
CALL PKBS1 ( IVAL, IBFMSG, S01MNEM )
Input argument:
IBFMSG INTEGER(*) BUFR message
IVAL INTEGER Value to be encoded within Section 0 or
Section 1 of BUFR message
S01MNEM CHAR*(*) Mnemonic describing value to be encoded
within Section 0 or Section 1 of BUFR message:
'BEN' = BUFR edition number
'BMT' = BUFR master table
'OGCE' = Originating center
'GSES' = Originating subcenter
'USN' = Update sequence number
'MTYP' = Data category
'MSBT' = Data subcategory (local)
'MSBTI' = Data subcategory (international)
'MTV' = Version number of master table
'MTVL' = Version number of local tables
'YEAR' = Year (4-digit)
'MNTH' = Month
'DAYS' = Day
'HOUR' = Hour
'MINU' = Minute
'SECO' = Second
These subroutines in essence function as the logical inverses of, respectively,
IUPVS01 and IUPBS01, in that they allow a user to directly
specify a value to be encoded into Section 0 or Section 1 of a BUFR message
for output, overriding the default value stored in that same location. As was
the case with IUPVS01 and IUPBS01, a descriptive mnemonic
S01MNEM is used to specify the value in question, and the choice of which
subroutine to use depends solely on whether the BUFR message to be written is passed directly as
a memory array (PKBS1) or stored internally within the BUFRLIB software (PKVS01). Either way, both subroutines
will work correctly on any BUFR message encoded using BUFR edition 2, 3 or 4.
However, note that the list of possible values that may be overwritten using these routines
(as shown above)
is somewhat shorter than the list of possible values that can be decoded using
the inverse routines IUPVS01 and IUPBS01.
Also, when using subroutine PKVS01, the new
value IVAL actually remains in effect for all future BUFR
messages output by any of the BUFRLIB subroutines such as WRITSB or
WRITSA that are subsequently called from within the same application
program! This means that a user can issue one call to PKVS01 at the
beginning of his or her application program and have it remain in effect
throughout the life of the application program (or until it is overridden
by a subsequent call to PKVS01 with the same S01MNEM value!).
Subroutine PKVS01 can even be called prior to the initial call
to subroutine OPENBF if it is desired for the new value to also
be included in any DX BUFR table information messages that are to be written
to the beginning of the output file!
(integer value) = IUPBS3 ( IBFMSG, S3MNEM )
Input argument:
IBFMSG INTEGER(*) BUFR message
S3MNEM CHAR*(*) Mnemonic describing value to be decoded from
within Section 3 of BUFR message:
'NSUB' = Number of data subsets in message
'IOBS' = Flag indicating whether message
contains observed data:
0 = no
1 = yes
'ICMP' = Flag indicating whether message
contains compressed data:
0 = no
1 = yes
Output argument:
IUPBS3 INTEGER Decoded value
-1 = invalid S3MNEM input value
This function can be used to decode and return a specified value
from Section 3 of an input BUFR message. The message is directly input to the
function as an integer array, with the start of the message aligned on the first
4 bytes of the array. The value to be decoded is specified via the descriptive
mnemonic S3MNEM, whose possible values are listed above.
The function will work correctly on any BUFR message encoded according to BUFR
edition 2, 3 or 4, but note that it cannot be used to determine the list of data
descriptors encoded within Section 3. Instead, for that we have the following
separate subroutine:
CALL UPDS3 ( IBFMSG, MXCDS3, CDS3, NDS3 )
Input argument:
IBFMSG INTEGER(*) BUFR message
MXCDS3 INTEGER Dimensioned size of CDS3 array
Output arguments:
CDS3 CHARACTER*6(*) Decoded sequence of data descriptors
from within Section 3 of IBFMSG
NDS3 INTEGER Number of data descriptors within CDS3
This subroutine decodes and returns the complete sequence of data descriptors
(i.e. FXY numbers) from Section 3 of the BUFR message contained within
IBFMSG, and as such
is especially useful in analyzing new or unfamiliar BUFR messages from unknown
or unfamiliar sources. Specifically, the information returned by a call to
UPDS3 can subsequently be used to generate a
DX BUFR tables file in the
ASCII text format required by the BUFRLIB software, and then the
software itself can subsequently be used to read/decode these messages.
However, it should be noted that UPDS3 does
not recursively
resolve FXY numbers that are themselves Table D (i.e. sequence) FXY numbers;
rather, what is returned is the exact sequence of FXY numbers as it appears
within Section 3. Note also that, as was the case with
IUPBS01, the beginning of the BUFR message must
be aligned on the first 4 bytes of the input array IBFMSG.
Finally, note that the dimensioned size of the CDS3 array
must be passed in as input, in order to prevent the subroutine from possibly
overflowing this array.
CALL NEMDEFS ( LUBFR, NEMO, CELEM, CUNIT, IRET )
Input argument:
LUBFR INTEGER Logical unit for BUFR file
NEMO CHAR*(*) Table B mnemonic
Output arguments:
CELEM CHARACTER*55 Element name associated with NEMO
CUNIT CHARACTER*24 Units associated with NEMO
IRET INTEGER Return code:
0 = Normal return
-1 = NEMO could not be found, or some
other error occurred
Given a Table B mnemonic defined in the table information associated with logical
unit LUBFR, this subroutine returns the element name and
units associated with that mnemonic. It can be called at any time in the application
program following the first call to BUFRLIB subroutine OPENBF.
CALL NEMSPECS ( LUBFR, NEMO, NNEMO, NSCL, NREF, NBTS, IRET )
Input argument:
LUBFR INTEGER Logical unit for BUFR file
NEMO CHAR*(*) Table B mnemonic
NNEMO INTEGER Ordinal ocurrence of NEMO for which
information is to be returned, counting
from the beginning of the overall subset
definition
Output arguments:
NSCL INTEGER Scale factor associated with NEMO
NREF INTEGER Reference value associated with NEMO
NBTS INTEGER Bit width associated with NEMO
IRET INTEGER Return code:
0 = Normal return
-1 = NEMO could not be found, or some
other error occurred
Given a Table B mnemonic defined in the table information associated with logical
unit LUBFR, this subroutine returns the scale factor, reference value
and bit width corresponding to the (NNEMO)th occurrence of that mnemonic within a subset
definition (counting from the beginning of the overall subset definition), and including
accounting for any Table C operators (e.g. 201YYY, 202YYY, 203YYY, 207YYY, 208YYY) which may be in
effect for that particular occurrence of the mnemonic. A subset definition must already be in
scope, either via a previous call to subroutine READSB or equivalent
(for reading/decoding BUFR data) or to subroutine OPENMB or equivalent
(for writing/encoding BUFR data).
CALL GETLENS ( IBFMSG, LL, LEN0, LEN1, LEN2, LEN3, LEN4, LEN5 )
Input argument:
IBFMSG INTEGER(*) BUFR message
LL INTEGER Number of last section whose length is to
be decoded
Output arguments:
LEN0 INTEGER Length of Section 0
LEN1 INTEGER Length of Section 1
LEN2 INTEGER Length of Section 2
LEN3 INTEGER Length of Section 3
LEN4 INTEGER Length of Section 4
LEN5 INTEGER Length of Section 5
This subroutine takes as input a BUFR message (the start of which,
as before, must be aligned on the first 4 bytes of the integer array
IBFMSG) and returns the lengths of each of the individual
sections of that message, up to a specified point as indicated via
the additional input variable LL. For example, setting LL to a value
of 3 means that all of the lengths up to and including Section 3
(i.e. Sections 0, 1, 2 and 3) will be decoded. The subroutine will
work correctly on any BUFR message encoded using BUFR edition 2, 3
or 4, and any section lengths that are not requested to be decoded
are returned with a default value of -1 for the corresponding output
argument.
In the main discussion, we described the use of subroutines
UFBINT, UFBREP and UFBSEQ
to read or write data values from a subset once a subset is in scope. We now describe
a few additional BUFRLIB subprograms which can be useful in certain
situations for extracting particular data values or other information from a subset.
CALL GETTAGPR ( LUBFR, TAGCH, NTAGCH, TAGPR, IRET )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
TAGCH CHAR*(*) Mnemonic
NTAGCH INTEGER Ordinal occurrence of TAGCH for which TAGPR is
to be returned, counting from the beginning of
the overall subset definition
Output arguments:
TAGPR CHAR*(*) Mnemonic corresponding to Table D parent sequence
of (NTAGCH)th occurrence of TAGCH
IRET INTEGER Return code:
0 = Normal return
-1 = Parent mnemonic could not be found, or some
other error occurred
This subroutine can be used to determine the Table D parent sequence of a specified
mnemonic within an overall subset definition. A subset must already be in
scope via a call to READSB or equivalent (for reading/decoding
BUFR data) or OPENMB or equivalent (for writing/encoding
BUFR data). If there is more than one occurrence of TAGCH
within the overall subset definition, the argument
NTAGCH can be used to specify which ordinal occurrence
of TAGCH we are interested in, counting from the beginning
of the overall subset definition.
CALL GETTAGRE ( LUBFR, TAGI, NTAGI, TAGRE, NTAGRE, IRET )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
TAGI CHAR*(*) Mnemonic
NTAGI INTEGER Ordinal occurrence of TAGI for which TAGRE is
to be returned, counting from the beginning of
the overall subset definition
Output arguments:
TAGRE CHAR*(*) Mnemonic referred to by TAGI via an internal bitmap
of (NTAGCH)th occurrence of TAGCH
NTAGRE INTEGER Ordinal occurrence of TAGRE referred to by (NTAGI)th
occurrence of TAGI, counting from the beginning of
the overall subset definition
IRET INTEGER Return code:
0 = Normal return
-1 = Could not find TAGRE, or some other error occurred
This subroutine can be used to determine whether a specified mnemonic references another
mnemonic within the same subset via an internal bitmap, and if so returns the referenced
mnemonic and its location within the subset. A subset must already be in
scope via a call to READSB or equivalent (for reading/decoding
BUFR data) or OPENMB or equivalent (for writing/encoding
BUFR data). If there is more than one occurrence of TAGI
within the overall subset definition, the argument
NTAGI can be used to specify which ordinal occurrence
of TAGI we are interested in, counting from the beginning
of the overall subset definition.
(real*8 value) = GETVALNB ( LUBFR, TAGPV, NTAGPV, TAGNB, NTAGNB )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
TAGPV CHAR*(*) Pivot mnemonic; the function will first search
for the (NTAGPV)th occurrence of TAGPV within
the subset, counting from the beginning of the
overall subset definition
NTAGPV INTEGER Ordinal occurrence of TAGPV within the subset
TAGNB CHAR*(*) Nearby mnemonic; assuming TAGPV is successfully
found, the function will then search nearby for
the (NTAGNB)th occurrence of TAGNB and return
the corresponding value
NTAGNB INTEGER Ordinal occurrence of TAGNB within the subset,
counting from the location of TAGPV. If NTAGNB is
positive, the function will search in a forward
direction from the location of TAGPV, or else if
NTAGNB is negative it will search in a backwards
direction.
Output arguments:
GETVALNB REAL*8 Data value corresponding to (NTAGNB)th occurrence
of TAGNB; if for any reason this value cannot be
found, then the current BUFRLIB "missing" value
is returned
This function also extracts specified information from a given subset in scope;
however, unlike for subroutines GETTAGPR
or GETTAGRE, this particular function should only
be called for a subset that is in scope
for reading/decoding via a previous call to subroutine READSB
or equivalent. Furthermore, this function returns the data value corresponding to a
mnemonic, rather than the mnemonic itself. The function is called with two input
mnemonics. The first mnemonic TAGPV is used as a pivot to establish
a specific reference point within the subset, with NTAGPV
used to differentiate between multiple occurrences in case there is more than one
occurrence of TAGPV within the overall subset definition.
The second mnemonic
TAGNB is the actual mnemonic whose corresponding value is to be
returned by the function and which can also be specified as an ordinal occurrence searching
forward (if NTAGNB is positive) or backward
(if NTAGNB is negative) from the pivot location specified by
TAGPV and NTAGPV.
CALL SETVALNB ( LUBFR, TAGPV, NTAGPV, TAGNB, NTAGNB, R8VAL, IRET )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
TAGPV CHAR*(*) Pivot mnemonic; the function will first search
for the (NTAGPV)th occurrence of TAGPV within
the subset, counting from the beginning of the
overall subset definition
NTAGPV INTEGER Ordinal occurrence of TAGPV within the subset
TAGNB CHAR*(*) Nearby mnemonic; assuming TAGPV is successfully
found, the function will then search nearby for
the (NTAGNB)th occurrence of TAGNB and store
R8VAL as the corresponding value
NTAGNB INTEGER Ordinal occurrence of TAGNB to search for, counting
from the location of TAGPV within the overall
subset definition. If NTAGNB is positive, the
function will search in a forward direction from
the location of TAGPV, or else if NTAGNB is
negative it will search in a backwards direction.
R8VAL REAL*8 Value to be stored corresponding to (NTAGNB)th
occurrence of TAGNB.
Output arguments:
IRET INTEGER Return code:
0 = Normal return
-1 = (NTAGNB)th occurrence of TAGNB could not
be found, or some other error occurred
This subroutine is the logical inverse of function GETVALNB, in
that it can be used to store a data value corresponding to a particular mnemonic within a
data subset. As such, it should only called for a subset that is in scope
for writing/encoding BUFR data via a previous call to subroutine
OPENMB or equivalent.
Just like for function GETVALNB, this subroutine is called with two
input mnemonics, with the first mnemonic TAGPV used as a pivot to
establish a specific reference point within the subset, and with
NTAGPV used to differentiate between multiple
occurrences in case there is more than one occurrence of TAGPV
within the overall subset definition. The second mnemonic
TAGNB is the actual mnemonic for which the value
R8VAL is to be stored, and again where NTAGNB
can be used to distinguish between multiple ordinal occurrences of this mnemonic, searching
forward (if NTAGNB is positive) or backward
(if NTAGNB is negative) from the pivot location specified by
TAGPV and NTAGPV.
CALL CNVED4 ( IBFMSG, LOBFMSG, OBFMSG )
Input argument:
IBFMSG INTEGER(*) BUFR message encoded using BUFR edition 3
LOBFMSG INTEGER Dimensioned size of OBFMSG array
Output arguments:
OBFMSG INTEGER(*) BUFR message encoded using BUFR edition 4
This subroutine reads an input BUFR message encoded using BUFR edition 3 and
then generates and outputs an equivalent BUFR message encoded using BUFR
edition 4. When using this subroutine, IBFMSG and OBFMSG must
be separate arrays, and the dimensioned size of OBFMSG
(in INTEGER words!) must also be passed in as input, in order to prevent the
subroutine from possibly overflowing this array.
Note that there's an easy way to internally activate this subroutine on BUFR
messages that are being generated for writing to an output file on the local
system.
Specifically, if subroutine PKVS01 is called with an input
S01MNEM value of 'BEN' (i.e. BUFR edition number) and a
corresponding input IVAL value of 4, then subroutine CNVED4
will be called internally for all future output BUFR messages written
via calls to subroutine WRITSB or WRITSA within
the same application program, meaning that all such output BUFR messages
will be automatically encoded using BUFR edition 4. This is often an easier
approach than directly calling CNVED4 from within the
application program.
As we touched upon briefly earlier, the BUFRLIB software has a default limit of
10000 bytes for the maximum size of any message that will be created and written
to a BUFR output file; however, it is very easy for a user to override this limit:
CALL MAXOUT ( MXMSIZ )
Input argument:
MXMSIZ INTEGER(*) New maximum message length (in bytes)
for all future output BUFR messages
0 = set to maximum value possible
This subroutine can be called at any time after the initial call to subroutine
OPENBF (which itself sets the default limit of 10000), and it
remains in effect for all future output BUFR messages associated with all
output BUFR files (i.e. logical unit LUBFR values) written by the BUFRLIB
software within the same application program. A user may repeatedly call
MAXOUT in order to repeatedly adjust the maximum
message length as desired, or a value of 0 may be passed in which is a signal
to the software to set the limit at whatever is the current maximum limit
allowed by the software. But either way, it is important to note that this
length is only ever just a maximum length and that some BUFR messages that are
generated may, in fact, end up being much shorter than this value.
For example, as we mentioned earlier during the discussion for subroutines
OPENMG and OPENMB,
the BUFRLIB software will in certain situations automatically close and
flush (to logical unit LUBFR) any existing BUFR message within the
internal arrays and initialize a new one. This behavior remains true for any
value of MXMSIZ, even if the length of the previous internal
message was still well below the maximum limit.
CALL BVERS ( CVERSTR )
Output argument:
CVERSTR CHAR*(*) String containing BUFRLIB version
This subroutine can be called by an application program to determine the version
of the BUFRLIB software currently in use.
The output string CVERSTR must be dimensioned at least 8 bytes
long in order to hold the resulting string.
CALL ERRWRT ( CSTR )
Input argument:
CSTR CHAR*(*) Error string or other diagnostic to be written
to user-specified destination
By default, when the BUFRLIB encounters an error or generates any type of diagnostic
during processing, a message to that effect is written to standard output. However,
if a user would like to direct such messages elsewhere, this can be done by providing
an inline version of subroutine ERRWRT, using the calling
sequence shown above, in order to override the default version of this subroutine
contained within the BUFRLIB source code distribution. The user does not need to
explicitly call this subroutine from within the application code, since the BUFRLIB
automatically issues a call to ERRWRT when needed.
Instead, the user simply needs to define his or her own subroutine with this same
name and include it within the compilation, and then the input string
CSTR can be logged or handled in any way of the user's
choosing. In any case, note that the amount and types of messages generated can also be
controlled by the user via a separate call to subroutine OPENBF
with the argument CIO='QUIET' and an appropriate verbosity
level indicator, as described earlier within the documentation.
CALL CMPMSG ( CF )
Input argument:
CF CHARACTER Flag indicating whether BUFR messages output
by future calls to subroutines WRITSB/WRITSA
are to be compressed:
'N' = no (the default)
'Y' = yes
This subroutine call provides an easy way to specify whether future BUFR
messages output via calls to subroutine WRITSB or WRITSA are
to be compressed using the algorithm for data subset compression prescribed
within the official WMO BUFR regulations. The default is 'N' (i.e. no) if
left unspecified, but this value can easily be toggled on ('Y') and off ('N')
for different calls to WRITSB or WRITSA for, e.g. different
output BUFR files connected to different LUBFR logical unit numbers
via separate prior calls to subroutine OPENBF. Either way,
once a value for CF is set via a call to subroutine CMPMSG,
it remains in effect for all messages written to all logical
units within the same application program, unless or until it is overridden by
a subsequent call to this same subroutine with the opposite value for CF.
Note that, from a high-level standpoint, it may seem reasonable to ask why one
wouldn't always want to compress BUFR output messages (and, therefore,
why the default value for CF isn't 'Y')? Without going into too
much detail here about the specifics of the WMO BUFR compression algorithm,
suffice it to say that compression only provides a real space-saving benefit
when the subsets to be compressed are devoid of any delayed replication and when
corresponding data values between different subsets within the same message
contain minimal variation. In other words, the use of compression is often
times not the best approach, and that's why it is built into the BUFRLIB
software as a user-specified option rather than as a default.
Now, before we cover the next two subroutines, a bit of historical
background is needed. Specifically, when the BUFRLIB software was originally
written, it was intended to be used to exchange BUFR data internally within
NCEP. Because of this, and owing also to the slower computer processing speeds
that were available at the time, certain non-standard "enhancements" were
written into the software to provide for faster encoding and decoding.
For instance, the software will normally, when writing/encoding a BUFR message,
insert byte counters in front of each Section 4 data subset in order to allow
subsequent reads of that same message to be faster and more efficient.
Also, liberal use is made of bit padding, and Section 3 is kept as short as
possible by representing the entire data subset via the use of the FXY number
that is associated with the top-level Table A mnemonic and, therefore, which is
itself almost invariably a local (i.e. non WMO-standard) FXY number. It should
be pointed out that all of these "enhancements" are entirely legal, since
local FXY numbers are permitted to be used in a BUFR message and, in fact,
are actually used by BUFRLIB to denote the existence of the
aforementioned byte counters and bit pads. However, and quite obviously,
any alternative BUFR decoding algorithm other than the NCEP BUFRLIB software
would not be able to cleanly decode such messages without prior knowledge of
the meaning of all such local FXY numbers and "enhancements", and, therefore,
it is strongly recommended to use one of the following additional subroutines
when writing/encoding BUFR messages that are intended to or could possibly be
read by persons using software other than the NCEP BUFRLIB software:
CALL STNDRD ( LUBFR, IBFMSG, LOBFMSG, OBFMSG )
CALL STDMSG ( CF )
Input arguments:
LUBFR INTEGER Logical unit for BUFR file
IBFMSG INTEGER(*) BUFR message
LOBFMSG INTEGER Dimensioned size of OBFMSG array
CF CHARACTER Flag indicating whether BUFR messages output
by future calls to subroutines WRITSB/WRITSA
are to be standardized:
'N' = no (the default)
'Y' = yes
Output arguments:
OBFMSG INTEGER(*) Standardized copy of IBFMSG
Subroutine STNDRD takes as input a BUFR message, such
as would have previously been output by, e.g. subroutine
WRITSA, and using the DX BUFR tables information associated
with logical unit LUBFR, outputs a standardized version of
this same
message within array OBFMSG, which must itself be a
separate array from IBFMSG. This "standardization"
involves removing all references to the aforementioned byte counters
and bit pads from Section 4 as well as replacing the Table A FXY number
from Section 3 of IBFMSG with an equivalent sequence
of lower-level Table B, Table C, Table D and/or replication FXY numbers
which directly constitute that Table A FXY number and which are themselves
all WMO-standard. The result is that the new message within OBFMSG
is now entirely and strictly standard according to the WMO BUFR regulations.
The alternative subroutine STDMSG provides an easy way to
standardize messages in an inline fashion, similar to how the aforementioned
subroutine CNVED4 can be called in an inline fashion via a
special call to subroutine PKVS01 (see above). Specifically,
if STDMSG is called with a value of 'Y', then subroutine
STNDRD will be called internally for all future output
BUFR messages written via calls to subroutine WRITSB or WRITSA
within the same application program, meaning that all such output BUFR messages
will already be automatically standardized without the user having to directly
call STNDRD on his/her own from within the application program!
Note however that, as was the case similarly with the aforementioned subroutine
CMPMSG for compression, any call to STDMSG will likewise
remain in effect for all future calls to WRITSB or WRITSA
within the same application program, unless or until it is superseded by a
subsequent call to STDMSG with the opposite value for CF.
Note that the above subroutines STNDRD, STDMSG, CNVED4 and
CMPMSG are only applicable when writing/encoding BUFR
messages for output. Alternatively, when reading/decoding BUFR messages that may
or may not contain standardization, compression and/or different editions of BUFR,
the BUFRLIB software, via the message-reading subroutines such as READMG,
READERME, etc. will automatically handle any such
variations or combinations thereof, all without any special additional effort
on the part of the user's application program!
During the earlier discussion of subroutine OPENBF,
we noted that the BUFRLIB software, by default, handles file input and output
via the use of this subroutine, and where the actual opening of the
underlying system file is handled at the application level where the
file is also associated with a FORTRAN logical unit number before issuing the
call to OPENBF. Having said that, it is possible to
read and write BUFR messages to or from system files using an alternative C
language interface. Each of the
following functions can be called from application programs written in either
FORTRAN or C, but for demonstration purposes we will use the FORTRAN syntax during
the remainder of the discussion.
In order to use this interface, we must first open the system file in question:
CALL COBFL ( BFL, IO )
Input arguments:
BFL CHAR*(*) System file to be opened
IO CHARACTER Flag indicating how BFL is to be opened:
'r' = reading (input)
'w' = writing (output)
This function opens the specified system file as either an input file (i.e. file
of existing BUFR messages to be decoded) or an output file (i.e. location where
BUFR messages will be written using the interface). The file name can be up to
120 characters and may include directory prefixes or any other notation allowed
by the underlying filesystem. Any errors will be automatically logged to
standard output or to an alternate location previously specified via the use of
subroutine ERRWRT. Note that, when using this interface,
it is only possible to have two system files open simultaneously (i.e. at most
one for input and at most one for output), whereas it was previously noted that
the FORTRAN OPENBF interface allows up to 32 simultaneous
open files with no limit on how many of these may be used for input or output.
Now, if we have opened a system file for input, we can use the following function
to read each successive BUFR message from the file:
CALL CRBMG ( MXMB, BMG, NMB, IRET )
Input arguments:
MXMB INTEGER Dimensioned size (in bytes) of BMG array
Output arguments:
BMG CHARACTER*1 (*) BUFR message
NMB INTEGER Size (in bytes) of BUFR message in BMG
IRET INTEGER Return code:
0 = normal return
1 = overflow of BMG array
2 = "7777" indicator not found in
expected location
-1 = end-of-file encountered while reading
-2 = I/O error encountered while reading
Likewise, if we have opened a system file for output, we can use the following
function to write each successive BUFR message to this file:
CALL CWBMG ( BMG, NMB, IRET )
Input arguments:
BMG CHARACTER*1 (*) BUFR message
NMB INTEGER Size (in bytes) of BUFR message in BMG
Output arguments:
IRET INTEGER Return code:
0 = normal return
-1 = I/O error encountered while writing
In either case, note that there is no need to explicitly specify which system file we
want to read to or write from, since this was already specified during the previous
call to COBFL and, as we noted, there is at most one
input file and one output file permitted to be open simultaneously when using this
interface; therefore, there is no danger of ambiguity. Note that when reading
BUFR messages using CRBMG, the dimensioned size (in
bytes) of the BMG array must be passed in as input, in
order to prevent the function from possibly overflowing this array.
Once we're done reading and/or writing BUFR messages, the system files themselves
can be closed and the interface disconnected via a final call to the following
function. Even if there is a file open for input and a separate one open for
output, only a single call to the following function is needed to close both of
them. There is no call argument required.
CALL CCBFL
Note that the above set of C language interface functions create a number of new
possibilities for overall application program design. For example, the above
interface could be used to easily read each complete BUFR message from a system file
using CRBMG, and then each such message could be passed as
input to subroutine READERME for subsequent processing via
READSB, UFBINT, UFBREP, etc. as discussed previously.
This is demonstrated in one of the example programs
included with the distribution.
Conversely, an application program could also be developed which uses the BUFRLIB to
generate BUFR messages for output and which passes them back to the application
program using subroutine WRITSA, so that each such message
could then be written out to a local system file using
CWBMG as shown above.
In version 10.1.0 and earlier versions of BUFRLIB, the writing out of BUFR messages
using subroutine WRITSB often meant that the messages were
written to disk with FORTRAN-blocking information surrounding them. This occurred
because the subroutine was using a FORTRAN "WRITE" command, and standard FORTRAN,
unlike certain other programming languages such as C and C++, does not have the
capability to read or write data to or from a system file as a pure binary stream of
bits. Some compilers did provide their own non-standard extensions to allow this,
but this was by no means standard across the many available UNIX platforms in
existence at the time. So for most users, the best available option was to use the
standard FORM='UNFORMATTED' access mode when opening an output file within their
application program, and then later
use the separate NCEP program cwordsh to remove the extraneous FORTRAN-blocking
information and thereby obtain a "pure" BUFR file.
Now however, with versions 10.2.x and later of BUFRLIB, the logic within
WRITSB has been internally rewritten to do a C-language
write of each BUFR message, so the resulting output file is now pure BUFR by default,
without the need to subsequently run cwordsh or use any special non-standard
extensions when opening the file within the application program! Likewise, the
subroutines READMG, IREADMG, READNS etc. have also been
updated to be able to read any type of BUFR file
(whether FORTRAN-blocked or not!) without any additional effort on the part of
the user! So there is no longer a need for the cwordsh program; however, any
users who wish to continue writing FORTRAN-blocked BUFR output files (e.g. for
consistency with historical archives) can continue to do so via the following new
subroutine:
CALL SETBLOCK ( IBLK )
Input arguments:
IBLK INTEGER Blocking indicator
-1 = little-endian blocking
0 = no blocking (i.e. "pure" BUFR)
1 = big-endian blocking
This new subroutine should be called immediately prior to the first call to
subroutine OPENBF, and then all writes to output files will
be done in accordance with the selected indicator, so
that users now have full control over the content of their resulting BUFR files and
can even specify output that is blocked with reverse-endianness to the native
platform. Note however that the default style is now "pure" BUFR for all output
files, so users who wish to retain any sort of FORTRAN-blocking must now call
subroutine SETBLOCK to specify it.
With versions 10.2.x and later of BUFRLIB, it is now also possible to specify a
custom "missing" value for writing and reading from BUFR files, rather
than using the BUFRLIB default value of 10.0E10:
CALL SETBMISS ( XMISS )
Input arguments:
XMISS REAL*8 Value to be used for "missing"
This new subroutine should be called immediately prior to the first call to
subroutine OPENBF, and the supplied value will then be
treated as "missing" for all future calls to subroutines
IBFMS, UFBINT, UFBREP, UFBSEQ, UFBTAB etc.
Correspondingly, a user can always check the value of "missing" that is
currently in use via a call to the following new function:
XMISS = GETBMISS()
Output arguments:
XMISS REAL*8 BUFRLIB "missing" value
Prior to version 11.0.0 of BUFRLIB, limits for values such as the maximum size of
a BUFR message, the maximum number of data values that could be written into a subset,
the maximum number of separate BUFR files that could be accessed for reading or
writing BUFR data at any one time by an application program, etc. were all set as parameters
within the source code and fixed at compile time, so the only way to adjust these
values was to manually edit the source code and then recompile the entire library.
Beginning with
version 11.0.0, many of these same values are now configurable at run time, with the
corresponding internal arrays dynamically allocated to allow much greater flexibility
for a variety of application program needs. This is done via the following function:
IRET = ISETPRM ( CPRMNM, IPVAL )
Input arguments:
CPRMNM CHAR*(*) BUFRLIB parameter to be modified from
default value:
'MXMSGL' = Maximum length (in bytes) of a BUFR
message
'MAXSS' = Maximum number of data values in an
uncompressed BUFR subset
'MXCDV' = Maximum number of data values that can
be written into a compressed BUFR subset
'MXLCC' = Maximum length (in bytes) of a character
string that can be written into a
compressed BUFR subset
'MXCSB' = Maximum number of subsets that can be
written into a compressed BUFR message
'NFILES' = Maximum number of BUFR files that can be
accessed for reading or writing at any
one time
'MAXTBA' = Maximum number of entries in internal BUFR
table A per BUFR file
'MAXTBB' = Maximum number of entries in internal BUFR
table B per BUFR file
'MAXTBD' = Maximum number of entries in internal BUFR
table D per BUFR file
'MAXMEM' = Maximum number of bytes that can be used
to store BUFR messages in internal memory
'MAXMSG' = Maximum number of BUFR messages that can
be stored in internal memory
'MXDXTS' = Maximum number of dictionary tables that
can be stored for use with BUFR messages
in internal memory
'MXMTBB' = Maximum number of master table B entries
'MXMTBD' = Maximum number of master table D entries
'MXMTBF' = Maximum number of master code/flag entries
'MAXCD' = Maximum number of child descriptors in a
table D descriptor sequence definition
'MAXJL' = Maximum number of entries in the internal
jump/link table
'MXS01V' = Maximum number of default Section 0 or
Section 1 values that can be overwritten
within an output BUFR message
'MXBTM' = Maximum number of bitmaps that can be
stored internally for a BUFR subset
'MXBTMSE' = Maximum number of entries that can be set
to a value of 0 (= "data present") within
each bitmap
'MXTAMC' = Maximum number of Table A mnemonics in the
internal jump/link table which contain at
least one Table C operator with X>=21 in
their subset definition
'MXTCO' = Maximum number of Table C operators with
X>=21 in the subset definition of any
Table A mnemonic
'MXNRV' = Maximum number of 2-03 reference values
in the internal jump/link table
'MXRST' = Maximum number of long character strings
that can be read from a compressed subset
IPVAL INTEGER New value for CPRMNM
Output arguments:
IRET INTEGER Return code:
0 = Normal return
-1 = Invalid or unknown CPRNMN parameter
A separate call to this function must be made for each parameter that is desired to
be changed from its default value, and all such calls must be made prior to the first
call to subroutine OPENBF within the application program,
because that is when all internal
arrays will be dynamically allocated based on the parameter values in effect at the
time. If the ISETPRM function is not called for a particular
parameter, then a default value for that parameter (as defined within an internal
FORTRAN module file) is used instead. To determine the value currently in effect for
any such parameter at run time, the following function can be used:
(integer value) = IGETPRM ( CPRMNM )
Input arguments:
CPRMNM CHAR*(*) BUFRLIB parameter from above list
Output arguments:
IGETPRM INTEGER Value assocated with CPRMNM
-1 = Invalid or unknown CPRNMN parameter
As mentioned above, all calls to function ISETPRM must be
made prior to the first call to subroutine OPENBF within the
application program, because that is when all internal arrays are dynamically allocated
based on the parameter values in effect at the time, and those sizes then remain in
effect for the remainder of the life of the application program. That said, if it is
later determined within the application program that one or more such values do need to be
changed, there is a way to do this via the use of the following subroutine call:
CALL EXITBUFR
This subroutine takes no input arguments and returns no output arguments. What it does
is to free all dynamically-allocated internal memory, close all logical units that are
currently open to the BUFRLIB, and reset the library to all of its original default
settings as though it had never been called. This allows an application program to
potentially reallocate memory all over again within the library via a new subsequent set
of one or more calls to function ISETPRM, followed by a new
call to subroutine OPENBF which will then be treated as though
it was the first call to this subroutine and allocate internal memory accordingly based
on the new settings.
Please note that, if and when subroutine EXITBUFR
is ever called, then there is no internal memory available within the BUFRLIB (and the entire
library is essentially unusable within the application program!), unless and until
subroutine OPENBF is once again called to reallocate memory
with the new settings. This may be a useful capability for application programs that
are finished with all calls to BUFRLIB and wish to move on to other unrelated tasks without
continuing to tie up all of the allocated memory space within the BUFRLIB. Otherwise, and
unless there's a need to change parameter sizes following the first call to
OPENBF, then there's no need to ever call
EXITBUFR within an application program, since all allocated
memory will automatically get freed anyway by the operating system once the application
program terminates!
|