Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision | |||
bufr.pm:bufrencode_source [2023-02-05 10:16:41] pals |
bufr.pm:bufrencode_source [2023-02-05 10:18:55] (current) pals |
||
---|---|---|---|
Line 34: | Line 34: | ||
use constant DEFAULT_TABLE_PATH_BUFRDC => '/ | use constant DEFAULT_TABLE_PATH_BUFRDC => '/ | ||
use constant DEFAULT_TABLE_PATH_ECCODES => '/ | use constant DEFAULT_TABLE_PATH_ECCODES => '/ | ||
- | # Ought to be your most up-to-date B table | ||
- | use constant DEFAULT_TABLE_BUFRDC => ' | ||
- | use constant DEFAULT_TABLE_ECCODES => ' | ||
# Parse command line options | # Parse command line options | ||
Line 43: | Line 40: | ||
GetOptions( | GetOptions( | ||
| | ||
- | ' | + | ' |
- | ' | + | ' |
- | ' | + | ' |
- | ' | + | ' |
- | ' | + | ' |
- | ' | + | ' |
- | # replication | + | ' |
- | ' | + | ' |
- | # descriptors on one line | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
) or pod2usage(-verbose => 0); | ) or pod2usage(-verbose => 0); | ||
- | |||
# User asked for help | # User asked for help | ||
pod2usage(-verbose => 1) if $option{help}; | pod2usage(-verbose => 1) if $option{help}; | ||
- | # No arguments if --code | + | # Data or metadata file not provided |
- | if (defined $option{code} or defined $option{flag}) { | + | pod2usage(-verbose => 0) if not $option{data} or not $option{metadata}; |
- | | + | |
- | } else { | + | |
- | pod2usage(-verbose => 0) if not @ARGV; | + | |
- | } | + | |
- | # If --flag is set, user must also provide code table | + | my $data_file |
- | pod2usage(-verbose | + | my $metadata_file = |
- | # All arguments must be integers | + | # Default is croak if (recoverable) error found in encoded BUFR format |
- | foreach | + | my $strict_checking = defined $option{strict_checking} |
- | | + | |
- | } | + | Geo:: |
- | if (defined $option{code} && $option{code} !~ /^\d+$/) { | + | |
- | | + | |
- | } | + | |
- | if (defined | + | |
- | pod2usage(" | + | |
- | } | + | |
- | + | ||
- | + | ||
- | # Set verbosity level for the BUFR module | + | |
- | my $verbose = $option{verbose} ? 1 : 0; | + | |
- | Geo:: | + | |
- | # From version 1.32 a descriptor sequence ending in e.g. 106000 031001 | + | # Set verbosity level |
- | # will be allowed unless strict checking is set, and we really want | + | Geo:: |
- | # bufrresolve.pl to complain in this case | + | |
- | Geo:: | + | |
# Set BUFR table format | # Set BUFR table format | ||
Line 111: | Line 86: | ||
} | } | ||
} | } | ||
- | |||
- | # BUFR table file to use | ||
- | my $table = $option{bufrtable} || | ||
- | ($tableformat eq ' | ||
my $bufr = Geo:: | my $bufr = Geo:: | ||
- | if (defined | + | # Read metadata into $bufr |
- | # Resolve flag value or dump code table | + | read_metadata($metadata_file, |
- | my $code_table | + | |
- | | + | # Load B and D tables (table version inferred from metadata) |
- | if ($option{flag} == 0) { | + | $bufr-> |
- | print "No bits are set\n"; | + | |
- | } else { | + | # Get the data |
- | | + | my ($data_refs, |
- | } | + | |
+ | $bufr-> | ||
+ | |||
+ | # Print the encoded BUFR message | ||
+ | my $buffer = $bufr-> | ||
+ | if ($option{outfile}) { | ||
+ | my $outfile | ||
+ | | ||
+ | binmode($fh); | ||
+ | print $fh $buffer; | ||
+ | } else { | ||
+ | binmode(STDOUT); | ||
+ | print $buffer; | ||
+ | } | ||
+ | |||
+ | # See OPTIONS section in pod for format of metadata file | ||
+ | sub read_metadata { | ||
+ | my ($file, $bufr) = @_; | ||
+ | |||
+ | # Read metadata from file into a hash | ||
+ | my %metadata; | ||
+ | open (my $fh, '<', | ||
+ | while ( < | ||
+ | | ||
+ | next if /^\s*$/; | ||
+ | s/^\s+//; | ||
+ | my ($key, $value) = split /\s+/, $_, 2; | ||
+ | $metadata{$key} = $value; | ||
+ | } | ||
+ | close $fh or die " | ||
+ | |||
+ | # Load the metadata into the BUFR object | ||
+ | my $m = \%metadata; | ||
+ | |||
+ | my $bufr_edition = $m-> | ||
+ | |||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | | ||
+ | | ||
+ | $bufr-> | ||
+ | $bufr->set_optional_section($m->{OPTIONAL_SECTION}); | ||
+ | | ||
+ | if ( $bufr_edition < 4 ) { | ||
+ | | ||
} else { | } else { | ||
- | | + | $bufr->set_int_data_subcategory($m-> |
+ | | ||
} | } | ||
- | } else { | + | |
- | # Resolve descriptor(s) | + | $bufr->set_local_table_version($m-> |
- | | + | |
- | | + | $bufr->set_year_of_century($m->{YEAR_OF_CENTURY}); |
- | print $bufr->resolve_descriptor(' | + | |
- | | + | |
- | | + | |
- | } elsif ($option{noexpand}) { | + | |
- | print $bufr-> | + | |
} else { | } else { | ||
- | | + | $bufr->set_year($m-> |
} | } | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | $bufr-> | ||
+ | |||
+ | return; | ||
+ | } | ||
+ | |||
+ | # See OPTIONS section in pod for format of data file | ||
+ | sub readdata { | ||
+ | my $file = shift; | ||
+ | open (my $fh, '<', | ||
+ | |||
+ | my ($data_refs, | ||
+ | my $subset = 0; | ||
+ | while ( <$fh> ) { | ||
+ | s/^\s+//; | ||
+ | # Lines not starting with a number are ignored | ||
+ | next if not /^\d/; | ||
+ | my ($n, $desc, $value) = split /\s+/, $_, 3; | ||
+ | $subset++ if $n == 1; | ||
+ | # Some operator descriptors are written on unnumbered lines | ||
+ | # without a value | ||
+ | if (!defined $desc || $desc !~ /^\d/) { | ||
+ | next unless $n >= 200000 && $n < 300000; # Better to die here? | ||
+ | $desc = $n; | ||
+ | $value = undef; | ||
+ | } else { | ||
+ | $value =~ s/\s+$//; | ||
+ | $value = undef if $value eq '' | ||
+ | } | ||
+ | push @{$data_refs-> | ||
+ | push @{$desc_refs-> | ||
+ | } | ||
+ | close $fh or die " | ||
+ | |||
+ | return ($data_refs, | ||
} | } | ||
Line 150: | Line 203: | ||
=head1 SYNOPSIS | =head1 SYNOPSIS | ||
- | | + | |
- | [--partial] | + | [--outfile |
- | | + | [--strict_checking |
- | | + | [--tableformat < |
- | | + | [--tablepath <path to BUFR tables> |
- | [--tableformat | + | [--verbose n] |
- | | + | [--help] |
- | | + | |
- | [--help] | + | |
- | + | ||
- | 2) bufrresolve.pl --code <code or flag table> | + | |
- | | + | |
- | [--tableformat < | + | |
- | | + | |
- | | + | |
- | + | ||
- | 3) bufrresolve.pl --flag < | + | |
- | [--bufrtable <name of BUFR table] | + | |
- | | + | |
- | | + | |
- | | + | |
=head1 DESCRIPTION | =head1 DESCRIPTION | ||
- | Utility program for fetching info from BUFR tables. | + | Encode a BUFR message, reading data and metadata |
+ | resulting | ||
+ | C< | ||
- | Execute without arguments for Usage, with option | + | Execute without arguments for Usage, with option --help for some |
additional info. See also L< | additional info. See also L< | ||
examples of use. | examples of use. | ||
- | The tables used can be selected by the user with options | + | =head1 OPTIONS |
- | C< | + | |
- | tableformat in Geo::BUFR is BUFRDC, while default tablepath in | + | |
- | bufrresolve.pl will be overridden if the environment variable | + | |
- | BUFR_TABLES is set. You should consider edit the source code of | + | |
- | bufrresolve.pl if you are not satisfied with the defaults chosen for | + | |
- | tablepath and bufrtable (search for ' | + | |
- | For tableformat ECCODES, see | + | |
- | L< | + | the same as consulting perldoc bufrencode.pl |
- | for more info on how to set C<--tablepath> | + | --outfile < |
+ | instead of STDOUT | ||
+ | | ||
+ | n=1 Issue warning if (recoverable) error in | ||
+ | | ||
+ | n=2 (default) Croak if (recoverable) error in BUFR format. | ||
+ | Nothing more in this message will be encoded. | ||
+ | --tableformat | ||
+ | | ||
+ | If used, will set path to BUFR tables. If not | ||
+ | | ||
+ | variable BUFR_TABLES, | ||
+ | will use DEFAULT_TABLE_PATH_<tableformat> | ||
+ | hard coded in source code. | ||
+ | --verbose n Set verbose level to n, 0< | ||
+ | Verbose output is sent to STDOUT, so ought to | ||
+ | be combined with option --outfile | ||
- | For the table name in C< | + | =head2 Required options |
- | table, e.g. B0000000000098013001.TXT. Replacing B with D or C, or | + | |
- | omitting this prefix altogether, or even omitting the trailing ' | + | |
- | (i.e. 0000000000098013001) will also work. | + | |
- | For the table name in C<--bufrtable> in ECCODES, use last significant part | + | =head4 |
- | of table location, e.g. ' | + | |
- | ' | + | |
- | up local sequence descriptors, | + | |
- | and the local table to get the full expansion, e.g. | + | |
- | ' | + | |
- | See also L</" | + | For the metadata file, use this as a prototype and change the values |
+ | as desired: | ||
- | =head1 OPTIONS | + | BUFR_EDITION |
+ | MASTER_TABLE | ||
+ | CENTRE | ||
+ | SUBCENTRE | ||
+ | UPDATE_SEQUENCE_NUMBER | ||
+ | OPTIONAL_SECTION | ||
+ | DATA_CATEGORY | ||
+ | INT_DATA_SUBCATEGORY | ||
+ | LOC_DATA_SUBCATEGORY | ||
+ | MASTER_TABLE_VERSION | ||
+ | LOCAL_TABLE_VERSION | ||
+ | YEAR 2008 | ||
+ | MONTH 9 | ||
+ | DAY 1 | ||
+ | HOUR 6 | ||
+ | MINUTE | ||
+ | SECOND | ||
+ | OBSERVED_DATA | ||
+ | COMPRESSED_DATA | ||
+ | DESCRIPTORS_UNEXPANDED | ||
- | | + | For BUFR edition < 4, replace the lines INT_DATA_SUBCATEGORY, |
- | --simple | + | LOC_DATA_SUBCATEGORY, YEAR and SECOND with new lines DATA_SUBCATEGORY |
- | descriptors on one line | + | and YEAR_OF_CENTURY (the order of lines doesn' |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | the same as consulting perldoc bufrresolve.pl | + | |
- | Usage 1): Resolves the given descriptor(s) fully into table B | + | =head4 |
- | descriptors, | + | |
- | bits) written on each line (except for --simple). --partial, --simple | + | |
- | and --noexpand are mutually exclusive (full expansion is default). | + | |
- | Usage 2): Prints | + | For the data file, use the same format as would result if you did run |
- | (named by the table B descriptor). | + | on the generated BUFR message |
- | Usage 3): Displays the bits set when the data value for the requested | + | bufrread.pl |
- | flag table is <value>. | + | |
- | Options may be abbreviated, | + | or if you use bufrread.pl with C<--width n>, replace 31 with n+16. |
+ | For example, the file might begin with | ||
- | =head1 CAVEAT | + | |
+ | | ||
+ | | ||
+ | | ||
+ | ... | ||
- | The C< | + | Every time a new line starting with the number 1 is met, a new subset |
- | is no guarantee that the same BUFR descriptor resolves the same way | + | will be generated in the BUFR message. Lines not starting with a |
- | for different BUFR tables. However, as soon as a new BUFR descriptor | + | number are ignored. |
- | is introduced in a BUFR table, it is extremely rare that the | + | |
- | descriptor is redefined in later versions. So for convenience, | + | For missing values, use ' |
- | bufrresolve.pl uses a default table (adding option C< | + | descriptor. |
- | show you the tables used). If this is the wrong table for your purpose | + | |
- | (most common case will be if the descriptor was added in a higher | + | Associated values should use BUFR descriptor 999999, and operator |
- | version than that of the default table), you should definitely use | + | descriptors 22[2345]000 and 23[2567]000 should not have a value, |
- | C<--bufrtable> with the appropriate table. | + | neither should this line be numbered, e.g. |
+ | |||
+ | | ||
+ | 222000 | ||
+ | | ||
+ | | ||
+ | ... | ||
+ | |||
+ | To encode a NIL subset, all delayed replication factors should | ||
+ | nonzero, and all other values set to missing except for the | ||
+ | descriptors defining | ||
+ | |||
+ | Options may be abbreviated, | ||
=head1 AUTHOR | =head1 AUTHOR |