Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
bufr.pm:bufrread.pl [2010-02-10 09:45:53] pals |
bufr.pm:bufrread.pl [2025-11-05 09:22:06] (current) pals |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | < | + | < |
| - | # | + | # |
| - | # (C) Copyright 2010, met.no | + | # (C) Copyright 2010-2025 MET Norway |
| # | # | ||
| - | # Project Info: https:// | + | # This program is free software; you can redistribute it and/or modify |
| - | # | + | # it under the terms of the GNU General Public License as published by |
| - | # This program is free software; you can redistribute it and/or modify | + | # the Free Software Foundation; either version 2 of the License, or |
| - | # under the terms of the GNU Lesser | + | |
| - | # the Free Software Foundation; either version 2.1 of the License, or | + | |
| # (at your option) any later version. | # (at your option) any later version. | ||
| # | # | ||
| # This program is distributed in the hope that it will be useful, but | # This program is distributed in the hope that it will be useful, but | ||
| - | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | + | # WITHOUT ANY WARRANTY; without even the implied warranty of |
| - | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | + | # MERCHANTABILITY |
| - | # License for more details. | + | # General Public |
| # | # | ||
| - | # You should have received a copy of the GNU Lesser | + | # You should have received a copy of the GNU General Public |
| - | # License | + | # along with this program; if not, write to the Free Software |
| - | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | + | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| - | # USA. | + | # 02110-1301, USA. |
| - | + | # pod included at end of file | |
| - | # Usage: bufrread < | + | |
| - | + | ||
| - | # Extract Bufr messages from bufr file(s) and decode them. | + | |
| - | # See subroutine usage_verbose for explanation of the options. | + | |
| - | + | ||
| - | # Author: P.Sannes met.no 2010 | + | |
| use strict; | use strict; | ||
| + | use warnings; | ||
| use Getopt:: | use Getopt:: | ||
| + | use Pod::Usage qw(pod2usage); | ||
| + | use Geo::BUFR; | ||
| - | # metno module | + | # This is actually default in BUFR.pm, but provided here to make it |
| - | use BUFR; | + | # easier for users to change to ' |
| + | use constant DEFAULT_TABLE_FORMAT => ' | ||
| - | my $DEFAULT_TABLE_PATH | + | # Will be used if neither --tablepath nor $ENV{BUFR_TABLES} is set |
| + | use constant DEFAULT_TABLE_PATH_BUFRDC | ||
| + | use constant DEFAULT_TABLE_PATH_ECCODES => '/ | ||
| # Parse command line options | # Parse command line options | ||
| Line 41: | Line 39: | ||
| GetOptions( | GetOptions( | ||
| | | ||
| - | ' | + | ' |
| - | ' | + | ' |
| + | # | ||
| + | ' | ||
| ' | ' | ||
| ' | ' | ||
| ' | ' | ||
| ' | ' | ||
| + | ' | ||
| ' | ' | ||
| + | ' | ||
| ' | ' | ||
| ' | ' | ||
| ' | ' | ||
| ' | ' | ||
| + | ' | ||
| ' | ' | ||
| - | ' | + | ' |
| ' | ' | ||
| - | ) or die "Wrong option(s), execute $0 without arguments for Usage\n" | + | ) or pod2usage(-verbose => 0); |
| # User asked for help | # User asked for help | ||
| - | usage_verbose() if $option{help}; | + | pod2usage(-verbose => 1) if $option{help}; |
| # Make sure there is at least one input file | # Make sure there is at least one input file | ||
| - | usage() unless @ARGV; | + | pod2usage(-verbose => 0) unless @ARGV; |
| + | |||
| + | # Set verbosity level | ||
| + | Geo:: | ||
| - | my $verbose = $option{verbose} ? $option{verbose} : 0; | + | # Set whether section 4 should be decoded for the BUFR module |
| + | Geo:: | ||
| - | # Set verbosity level for the BUFR module. Must be set also for each | + | # Set whether quality information should be decoded |
| - | # BUFR object generated | + | Geo::BUFR->set_noqc() if ($option{noqc}); |
| - | BUFR->set_verbose($verbose); | + | |
| - | # Set whether quality information should be decoded for the BUFR | + | Geo::BUFR->set_strict_checking($option{strict_checking}) if defined |
| - | # module | + | |
| - | BUFR->set_noqc() if ($option{noqc}); | + | |
| - | BUFR->set_strict_checking($option{strict_checking}) if defined $option{strict_checking}; | + | Geo::BUFR->set_show_all_operators($option{all_operators}) if defined $option{all_operators}; |
| - | BUFR-> | + | # Set BUFR table format |
| + | my $tableformat = (defined | ||
| + | Geo:: | ||
| # Set BUFR table path | # Set BUFR table path | ||
| if ($option{tablepath}) { | if ($option{tablepath}) { | ||
| # Command line option --tablepath overrides all | # Command line option --tablepath overrides all | ||
| - | BUFR-> | + | |
| } elsif ($ENV{BUFR_TABLES}) { | } elsif ($ENV{BUFR_TABLES}) { | ||
| # If no --tablepath option, use the BUFR_TABLES environment variable | # If no --tablepath option, use the BUFR_TABLES environment variable | ||
| - | BUFR-> | + | |
| } else { | } else { | ||
| - | # If all else fails, use the libemos bufrtables | + | # If all else fails, use the default tablepath in BUFRDC/ |
| - | BUFR-> | + | |
| + | Geo::BUFR-> | ||
| + | } elsif ($tableformat eq ' | ||
| + | Geo:: | ||
| + | } | ||
| + | } | ||
| + | |||
| + | my $ahl_regexp; | ||
| + | if ($option{ahl}) { | ||
| + | eval { $ahl_regexp = qr/ | ||
| + | die " | ||
| } | } | ||
| Line 92: | Line 108: | ||
| my $OUT; | my $OUT; | ||
| if ($option{outfile}) { | if ($option{outfile}) { | ||
| - | open($OUT, '>', | + | open($OUT, '>', |
| or die " | or die " | ||
| } else { | } else { | ||
| Line 104: | Line 120: | ||
| # Arrays over filter criteria, used if option --filter is set | # Arrays over filter criteria, used if option --filter is set | ||
| - | my @fid; # Filter descriptors, | + | my @fid; # Filter descriptors, |
| my @fiv; # Filter values, e.g. $fiv[1] = [ [ 3, 895 ], [ 6 252 ] ] | my @fiv; # Filter values, e.g. $fiv[1] = [ [ 3, 895 ], [ 6 252 ] ] | ||
| my @num_desc; # Number of filter descriptors for each criterion, e.g. $num_desc[1] = 2 | my @num_desc; # Number of filter descriptors for each criterion, e.g. $num_desc[1] = 2 | ||
| Line 122: | Line 138: | ||
| # Loop for processing of BUFR input files | # Loop for processing of BUFR input files | ||
| foreach my $inputfname ( @ARGV ) { | foreach my $inputfname ( @ARGV ) { | ||
| - | my $bufr = BUFR-> | + | my $bufr = Geo::BUFR-> |
| - | + | $bufr->set_filter_cb(\& | |
| - | # This sets object verbose level equal to class verbose level | + | |
| - | $bufr->set_verbose($verbose); | + | |
| - | + | ||
| - | | + | |
| - | # Load C table (all C-tables we have are linked to this single one) | + | |
| - | $bufr-> | + | |
| - | or die " | + | |
| - | } | + | |
| # Open BUFR file | # Open BUFR file | ||
| Line 142: | Line 150: | ||
| - | # Extract data from BUFR file. | + | # Extract data from BUFR file. Print AHL for first message in each GTS |
| - | # Print WMO ahl for first message in each WMO bulletin, print | + | # bulletin, print message number for each new message, print subset |
| - | # message number for each new message, print subset | + | # number for each subset. |
| - | # if message contains more than one subset | + | |
| sub decode { | sub decode { | ||
| - | my $bufr = shift; # BUFR object | + | my $bufr = shift; |
| my ($message_header, | my ($message_header, | ||
| Line 154: | Line 161: | ||
| # option has been used | # option has been used | ||
| READLOOP: | READLOOP: | ||
| - | while (not $bufr->feof()) { | + | while (not $bufr->eof()) { |
| - | # Read next observation. If an error is encountered during | + | |
| - | # decoding, skip this observation while printing the error | + | # decoding, skip this observation while printing the error |
| - | # message to STDERR, also displaying ahl of bulletin if found. | + | # message to STDERR, also displaying ahl of bulletin if found |
| + | # (but skip error message if the message should be skipped on | ||
| + | # --ahl anyway). | ||
| my ($data, $descriptors); | my ($data, $descriptors); | ||
| - | eval { | + | |
| ($data, $descriptors) = $bufr-> | ($data, $descriptors) = $bufr-> | ||
| }; | }; | ||
| if ($@) { | if ($@) { | ||
| + | $current_ahl = $bufr-> | ||
| + | next READLOOP if $option{ahl} && $current_ahl !~ $ahl_regexp; | ||
| + | |||
| warn $@; | warn $@; | ||
| # Try to extract message number and ahl of the bulletin | # Try to extract message number and ahl of the bulletin | ||
| # where the error occurred | # where the error occurred | ||
| - | | + | $current_message_number = $bufr-> |
| - | | + | if (defined |
| - | $current_ahl = $bufr-> | + | my $error_msg = "In message $current_message_number"; |
| - | my $error_msg; | + | |
| - | | + | |
| - | if $current_message_number; | + | |
| $error_msg .= " contained in bulletin with ahl $current_ahl\n" | $error_msg .= " contained in bulletin with ahl $current_ahl\n" | ||
| if $current_ahl; | if $current_ahl; | ||
| warn $error_msg if $error_msg; | warn $error_msg if $error_msg; | ||
| - | }; | + | |
| + | exit(1) if $option{on_error_stop}; | ||
| next READLOOP; | next READLOOP; | ||
| } | } | ||
| - | if ($option{param}) { | + | |
| - | # Reduce data and descritors | + | |
| - | ($data, $descriptors) | + | |
| - | | + | # Load C table, trying first to use same table version as |
| + | | ||
| + | # this C table file does not exist, loads C table for latest | ||
| + | # master table in table path found instead. | ||
| + | my $table_version = $bufr-> | ||
| + | my $tableformat = Geo:: | ||
| + | if ($tableformat eq ' | ||
| + | | ||
| + | } elsif ($tableformat eq ' | ||
| + | $bufr-> | ||
| + | } | ||
| } | } | ||
| my $current_subset_number = $bufr-> | my $current_subset_number = $bufr-> | ||
| - | | + | |
| + | # should have been set to at least 1 (even in a 0 subset message) | ||
| + | last READLOOP if $current_subset_number == 0; | ||
| - | if ($current_subset_number == 1) { | + | if ($current_subset_number == 1 || $option{nodata}) { |
| $current_message_number = $bufr-> | $current_message_number = $bufr-> | ||
| $current_ahl = $bufr-> | $current_ahl = $bufr-> | ||
| Line 197: | Line 219: | ||
| $section013_dumped = 0; | $section013_dumped = 0; | ||
| - | next READLOOP if $option{filter} | + | next READLOOP if ($option{filter} |
| - | | + | |
| print $OUT $message_header; | print $OUT $message_header; | ||
| Line 210: | Line 232: | ||
| $section013_dumped = 1; | $section013_dumped = 1; | ||
| } | } | ||
| + | next READLOOP if $option{nodata}; | ||
| } else { # subset number > 1 | } else { # subset number > 1 | ||
| - | next READLOOP if $option{filter} | + | next READLOOP if ($option{filter} |
| - | | + | |
| # If subset 1 was filtered away, section 0-3 might not | # If subset 1 was filtered away, section 0-3 might not | ||
| Line 227: | Line 250: | ||
| } | } | ||
| - | if ($nsubsets > 1) { | + | if ($option{param}) { |
| - | | + | |
| + | ($data, $descriptors) | ||
| + | = param($data, | ||
| } | } | ||
| - | | + | |
| - | print $OUT $bufr-> | + | printf $OUT " |
| + | |||
| + | # If an error is encountered during dumping of section 4, skip | ||
| + | # this subset while printing the error message to STDERR, also | ||
| + | # displaying ahl of bulletin | ||
| + | my $dump; | ||
| + | eval { | ||
| + | $dump = ( $option{bitmap} ) | ||
| + | ? | ||
| + | | ||
| + | : $bufr-> | ||
| + | }; | ||
| + | if ($@) { | ||
| + | warn $@; | ||
| + | my $error_msg = "In message $current_message_number" | ||
| + | . " and subset $current_subset_number"; | ||
| + | $error_msg .= " contained in bulletin with ahl $current_ahl\n" | ||
| + | if $current_ahl; | ||
| + | warn $error_msg; | ||
| + | exit(1) if $option{on_error_stop}; | ||
| + | next READLOOP; | ||
| } else { | } else { | ||
| - | print $OUT $bufr-> | + | print $OUT $dump; |
| } | } | ||
| } | } | ||
| Line 248: | Line 293: | ||
| push @requested_desc, | push @requested_desc, | ||
| } | } | ||
| + | close $fh or die " | ||
| return @requested_desc; | return @requested_desc; | ||
| } | } | ||
| # Reduce the data to those corresponding to the requested descriptors | # Reduce the data to those corresponding to the requested descriptors | ||
| - | # only | + | # only. |
| sub param { | sub param { | ||
| my ($data, $descriptors, | my ($data, $descriptors, | ||
| Line 268: | Line 314: | ||
| } | } | ||
| - | sub usage { | ||
| - | print <<" | ||
| - | Usage: $0 <bufr file(s)> | ||
| - | [--codetables] | ||
| - | [--data_only] | ||
| - | [--param < | ||
| - | [--filter <filter file>] | ||
| - | [--bitmap] | ||
| - | [--noqc] | ||
| - | [--outfile < | ||
| - | [--optional_section] | ||
| - | [--width n] | ||
| - | [--strict_checking n] | ||
| - | [--all_operators] | ||
| - | [--tablepath <path to BUFR tables>] | ||
| - | [--verbose n] | ||
| - | [--help] | ||
| - | Try ' | ||
| - | EOF | ||
| - | exit 0; | ||
| - | } | ||
| - | |||
| - | |||
| - | sub usage_verbose { | ||
| - | print <<" | ||
| - | |||
| - | Usage: $0 <bufr file(s)> [options] | ||
| - | |||
| - | Will print section 0-4 in BUFR messages in <bufr file(s)> | ||
| - | Options (may be abbreviated, | ||
| - | |||
| - | --codetables | ||
| - | is [CODE TABLE] or [FLAG TABLE] | ||
| - | --data_only | ||
| - | --param < | ||
| - | Decode parameters with descriptors in < | ||
| - | --filter <filter file> | ||
| - | Decode observations meeting criteria in <filter file> only | ||
| - | --bitmap | ||
| - | --noqc | ||
| - | (or any descriptors following 222000) | ||
| - | --outfile < | ||
| - | Will print to < | ||
| - | --optional_section | ||
| - | Display a hex dump of optional section if present | ||
| - | --width n Set width of field used for data values to n characters | ||
| - | (default is 15) | ||
| - | --strict_checking n n=0 (default) Disable strict checking of BUFR format | ||
| - | n=1 Issue warning if (recoverable) error in | ||
| - | BUFR format | ||
| - | n=2 Croak if (recoverable) error in BUFR format. | ||
| - | Nothing more in this message will be decoded. | ||
| - | --all_operators Show all operator descriptors when printing section 4 | ||
| - | --tablepath <path to BUFR tables> | ||
| - | Set path to BUFR tables (overrides ENV{BUFR_TABLES}) | ||
| - | --verbose n Set verbose level to n, 0< | ||
| - | --help | ||
| - | |||
| - | You should probably set | ||
| - | export BUFR_TABLES=$DEFAULT_TABLE_PATH | ||
| - | or use the --tablepath option. | ||
| - | |||
| - | Each line in < | ||
| - | Rest of line will be ignored. bufrread will extract values for these descriptors | ||
| - | only. If used together with --filter, < | ||
| - | in <filter file>. | ||
| - | |||
| - | Using --filter will decode only those observations that meet one of the criteria in | ||
| - | <filter file> (and all of those criteria marked D!). Comments (starting with #) are | ||
| - | ignored. An example of a filter file is | ||
| - | |||
| - | # All stations in WMO block 01 | ||
| - | D: 001001 | ||
| - | 1 | ||
| - | D: 001001 001002 | ||
| - | 3 895 | ||
| - | 6 252 | ||
| - | D: 001011 | ||
| - | LF5U # Ekofisk | ||
| - | D!: 004004 | ||
| - | 6 | ||
| - | 7 | ||
| - | |||
| - | which decodes all observations with block number 01, two other specific wmo stations | ||
| - | and one specific ship, all of which having hour (004004) equal to 6 or 7. | ||
| - | If there is no value line after a descriptor line, it is enough that the observation | ||
| - | contains the descriptor(s), | ||
| - | from a BUFR synop file, the filter file should contain this single line only: | ||
| - | |||
| - | D: 001011 | ||
| - | |||
| - | If an error occurs during decoding (typically because the required BUFR table is | ||
| - | missing or message is corrupt) the message is skipped, and the number of errors | ||
| - | is reported at end of output. | ||
| - | |||
| - | EOF | ||
| - | exit 0; | ||
| - | } | ||
| ################################################################################### | ################################################################################### | ||
| Line 371: | Line 319: | ||
| # Filter routines | # Filter routines | ||
| - | # Read in content | + | sub filter_on_ahl { |
| + | my $obj = shift; | ||
| + | my $ahl_regexp = shift; | ||
| + | my $ahl = $obj-> | ||
| + | return $ahl =~ $ahl_regexp ? 0 : 1; | ||
| + | } | ||
| + | |||
| + | # Read in contents | ||
| # @num_desc, @num_val and $num_criteria, | # @num_desc, @num_val and $num_criteria, | ||
| + | # Note that index 0 of the arrays is not used. | ||
| sub read_filter_file { | sub read_filter_file { | ||
| my $filter_file = shift; | my $filter_file = shift; | ||
| Line 379: | Line 335: | ||
| or die " | or die " | ||
| while (< | while (< | ||
| - | # Remove comments | + | # Remove comments |
| s/#.*//; | s/#.*//; | ||
| - | next if /^$/; | + | next if /^\s*$/; |
| if (s/ | if (s/ | ||
| my @desc = split; | my @desc = split; | ||
| + | # Check that all descriptors are numbers | ||
| + | foreach my $desc (@desc) { | ||
| + | die "' | ||
| + | if $desc !~/^\d+$/; | ||
| + | } | ||
| + | # Save the criterium | ||
| $num_desc[++$num_criteria] = @desc; | $num_desc[++$num_criteria] = @desc; | ||
| $num_val[$num_criteria] = 0; | $num_val[$num_criteria] = 0; | ||
| Line 392: | Line 354: | ||
| } else { | } else { | ||
| my @values = split; | my @values = split; | ||
| + | # Check that value line contains correct number of values | ||
| + | die " | ||
| + | . " for line $. in filter file ' | ||
| + | if scalar @values != scalar @{$fid[$num_criteria]}; | ||
| + | # Remove leading 0's in numerical values (to prepare for string comparison) | ||
| + | for $_ (@values) { s/ | ||
| $fiv[$num_criteria]-> | $fiv[$num_criteria]-> | ||
| } | } | ||
| } | } | ||
| + | close $fh or die " | ||
| return; | return; | ||
| } | } | ||
| Line 400: | Line 369: | ||
| # Return true (observations should be filtered) if the observation | # Return true (observations should be filtered) if the observation | ||
| # does not meet all of the D! criteria (if exists) and does not meet | # does not meet all of the D! criteria (if exists) and does not meet | ||
| - | # any one of the other criteria (if exists) in filter file | + | # any one of the other criteria (if exists) in filter file. |
| sub filter_observation { | sub filter_observation { | ||
| my $bufr = shift; | my $bufr = shift; | ||
| die "Error in filter_observation: | die "Error in filter_observation: | ||
| - | unless ref($bufr) eq ' | + | unless ref($bufr) eq 'Geo::BUFR'; |
| my ($data, $descriptors) = @_; | my ($data, $descriptors) = @_; | ||
| - | my $num_ordinary_criteria = @fid - $num_required_criteria; | + | my $num_ordinary_criteria = $#fid - $num_required_criteria; |
| my $num_success_req_criteria = 0; # Number of required criteria successfully fulfilled | my $num_success_req_criteria = 0; # Number of required criteria successfully fulfilled | ||
| my $num_success_ord_criteria = 0; # Number of ordinary criteria successfully fulfilled | my $num_success_ord_criteria = 0; # Number of ordinary criteria successfully fulfilled | ||
| Line 452: | Line 421: | ||
| for (my $j = 0; $j < @{$descriptors}; | for (my $j = 0; $j < @{$descriptors}; | ||
| if ($descriptors-> | if ($descriptors-> | ||
| + | next DESC if !defined $data-> | ||
| (my $val = $data-> | (my $val = $data-> | ||
| if ($val eq $fiv[$filter_criterion]-> | if ($val eq $fiv[$filter_criterion]-> | ||
| Line 464: | Line 434: | ||
| or $num_success_ord_criteria > 0)) { | or $num_success_ord_criteria > 0)) { | ||
| return 0; # Don't filter this observation | return 0; # Don't filter this observation | ||
| + | } else { | ||
| + | next DESC; | ||
| } | } | ||
| } else { | } else { | ||
| Line 490: | Line 462: | ||
| return 1; | return 1; | ||
| } | } | ||
| + | |||
| + | =pod | ||
| + | |||
| + | =encoding utf8 | ||
| + | |||
| + | =head1 SYNOPSIS | ||
| + | |||
| + | bufrread.pl <bufr file(s)> | ||
| + | [--ahl < | ||
| + | [--all_operators] | ||
| + | [--bitmap] | ||
| + | [--codetables] | ||
| + | [--data_only] | ||
| + | [--filter <filter file>] | ||
| + | [--help] | ||
| + | [--nodata] | ||
| + | [--noqc] | ||
| + | [--on_error_stop] | ||
| + | [--optional_section] | ||
| + | [--outfile < | ||
| + | [--param < | ||
| + | [--strict_checking n] | ||
| + | [--tableformat < | ||
| + | [--tablepath <path to BUFR tables>] | ||
| + | [--verbose n] | ||
| + | [--width n] | ||
| + | |||
| + | =head1 DESCRIPTION | ||
| + | |||
| + | Extract BUFR messages from BUFR file(s) and print the decoded content | ||
| + | to screen, including AHL (Abbreviated Header Line) if present. | ||
| + | |||
| + | Execute without arguments for Usage, with option C< | ||
| + | additional info. See also L< | ||
| + | examples of use. | ||
| + | |||
| + | |||
| + | =head1 OPTIONS | ||
| + | |||
| + | --ahl < | ||
| + | | ||
| + | | ||
| + | when printing section 4 | ||
| + | | ||
| + | | ||
| + | is [CODE TABLE] or [FLAG TABLE] | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | more info you might prefer to consult perldoc bufrread.pl | ||
| + | | ||
| + | | ||
| + | (or any descriptors following 222000) | ||
| + | | ||
| + | | ||
| + | Will print to < | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | n=1 Issue warning if (recoverable) error in | ||
| + | BUFR format | ||
| + | n=2 Croak if (recoverable) error in BUFR format. | ||
| + | | ||
| + | | ||
| + | | ||
| + | Set path to BUFR tables (overrides ENV{BUFR_TABLES}) | ||
| + | | ||
| + | show the tables loaded. | ||
| + | | ||
| + | | ||
| + | |||
| + | Options may be abbreviated, | ||
| + | |||
| + | To avoid having to use the C< | ||
| + | set the environment variable BUFR_TABLES to the directory where your | ||
| + | BUFR tables are located (unless the default path provided by | ||
| + | bufrread.pl works for you). For tableformat ECCODES, se | ||
| + | L< | ||
| + | for more info on how to set C< | ||
| + | |||
| + | For option C< | ||
| + | expression. E.g. C<--ahl " | ||
| + | (ISS) from CCCC=ENMI. This is the only case where a little knowledge | ||
| + | of Perl might possibly be required when using the utility programs | ||
| + | included in Geo::BUFR. | ||
| + | |||
| + | For option C< | ||
| + | a BUFR descriptor (6 digits). | ||
| + | bufrread.pl will display values for these descriptors only. | ||
| + | |||
| + | Using C< | ||
| + | the criteria in <filter file> marked D: and all of those criteria | ||
| + | marked D!:. Comments (starting with #) are ignored. An example of a | ||
| + | filter file is | ||
| + | |||
| + | D: 001001 | ||
| + | 1 | ||
| + | D: 001001 001002 | ||
| + | 3 895 | ||
| + | 6 252 | ||
| + | D: 001011 | ||
| + | LF5U # Ekofisk | ||
| + | D!: 004004 | ||
| + | 6 | ||
| + | 7 | ||
| + | |||
| + | which decodes all observations with block number 01, two other | ||
| + | specific WMO stations and one specific ship, all of which having hour | ||
| + | (004004) equal to 6 or 7. If there is no value line after a | ||
| + | descriptor line, it is enough that the observation contains the | ||
| + | descriptor(s), | ||
| + | messages from a BUFR file, the filter file should contain this single | ||
| + | line only: | ||
| + | |||
| + | D: 001011 | ||
| + | |||
| + | If an error occurs during decoding (typically because the required | ||
| + | BUFR table is missing or message is corrupt), the BUFR message is | ||
| + | skipped with an error message printed to STDERR, and processing then | ||
| + | continues with the next BUFR message. You can change this default | ||
| + | behaviour, however, by setting C< | ||
| + | |||
| + | =head1 CAVEAT | ||
| + | |||
| + | Option C< | ||
| + | Namely, when the first bit-map is encountered, | ||
| + | their descriptors) will be displayed unless they refer to the | ||
| + | preceding data values by a bit-map. And output is not to be trusted | ||
| + | if a bit-map refers to another bit-map or the bit-mapped values are | ||
| + | combined with 204YYY (add associated field operator). | ||
| + | |||
| + | =head1 AUTHOR | ||
| + | |||
| + | Pål Sannes E< | ||
| + | |||
| + | =head1 COPYRIGHT | ||
| + | |||
| + | Copyright (C) 2010-2025 MET Norway | ||
| + | |||
| + | =cut | ||
| </ | </ | ||