This is an old revision of the document!
#!/usr/bin/perl -w # (C) Copyright 2010, met.no # # 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # 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, USA. # Encode a BUFR message, reading data and metadata from files. # Author: P. Sannes met.no 2010 use strict; use Getopt::Long; # metno module use BUFR; use constant DEFAULT_TABLE_PATH => '/usr/local/lib/emos/bufrtables'; # Parse command line options my %option = (); GetOptions( \%option, 'data=s', 'help', 'metadata=s', 'outfile=s', 'tablepath=s', 'verbose=i', ) or die "Wrong option(s), execute $0 without arguments for Usage\n"; # User asked for help usage_verbose() if $option{help}; # Data or metadata file not provided usage() if not $option{data} or not $option{metadata}; my $data_file = $option{data}; my $metadata_file = $option{metadata}; my $verbose = $option{verbose} ? $option{verbose} : 0; # Set verbosity level for the BUFR module. Must be set also for each # BUFR object generated BUFR->set_verbose($verbose); # Set BUFR table path if ($option{tablepath}) { # Command line option --tablepath overrides all BUFR->set_tablepath($option{tablepath}); } elsif ($ENV{BUFR_TABLES}) { # If no --tablepath option, use the BUFR_TABLES environment variable BUFR->set_tablepath($ENV{BUFR_TABLES}); } else { # If all else fails, use the libemos bufrtables BUFR->set_tablepath(DEFAULT_TABLE_PATH); } # Read in metadata my $metadata = read_metadata($metadata_file); my $bufr = BUFR->new(); # This sets object verbose level equal to class verbose level $bufr->set_verbose($verbose); my $bufr_edition = $metadata->{BUFR_EDITION}; $bufr->set_bufr_edition($bufr_edition); $bufr->set_master_table($metadata->{MASTER_TABLE}); $bufr->set_centre($metadata->{CENTRE}); $bufr->set_subcentre($metadata->{SUBCENTRE}); $bufr->set_update_sequence_number($metadata->{UPDATE_NUMBER}); $bufr->set_optional_section($metadata->{OPTIONAL_SECTION}); $bufr->set_data_category($metadata->{DATA_CATEGORY}); if ( $bufr_edition < 4 ) { $bufr->set_data_subcategory($metadata->{DATA_SUBCATEGORY}); } else { $bufr->set_int_data_subcategory($metadata->{INT_DATA_SUBCATEGORY}); $bufr->set_loc_data_subcategory($metadata->{LOC_DATA_SUBCATEGORY}); } $bufr->set_master_table_version($metadata->{MASTER_TABLE_VERSION}); $bufr->set_local_table_version($metadata->{LOCAL_TABLE_VERSION}); if ( $bufr_edition < 4 ) { $bufr->set_year_of_century($metadata->{YEAR_OF_CENTURY}); } else { $bufr->set_year($metadata->{YEAR}); } $bufr->set_month($metadata->{MONTH}); $bufr->set_day($metadata->{DAY}); $bufr->set_hour($metadata->{HOUR}); $bufr->set_minute($metadata->{MINUTE}); $bufr->set_second($metadata->{SECOND}) if $bufr_edition >= 4; $bufr->set_observed_data($metadata->{OBSERVED_DATA}); $bufr->set_compressed_data($metadata->{COMPRESSED_DATA}); $bufr->set_descriptors_unexpanded($metadata->{DESCRIPTORS_UNEXPANDED}); $bufr->set_local_use($metadata->{LOCAL_USE}) if exists $metadata->{LOCAL_USE}; $bufr->load_BDtables(); # Read in the data (descriptors and values) my ($data_refs, $desc_refs, $num_subsets) = readdata($data_file); $bufr->set_number_of_subsets($num_subsets); # Print the encoded BUFR message if ($option{outfile}) { open(my $OUT, '>',$option{outfile}) or die "Cannot open $option{outfile} for writing: $!"; print $OUT $bufr->encode_message($data_refs, $desc_refs); close $OUT or die "Cannot close $option{outfile}: $!"; } else { print $bufr->encode_message($data_refs, $desc_refs); } sub read_metadata { my $file = shift; open (my $fh, '<', $file) or die "Cannot open $file: $!"; my %metadata; while ( <$fh> ) { chomp; next if /^\s*$/; my ($key, $value) = split /\s+/, $_, 2; $metadata{$key} = $value; } close $fh; return \%metadata; } sub readdata { my $file = shift; open (my $fh, '<', $file) or die "Cannot open $file: $!"; my ($data_refs, $desc_refs); my $subset = 0; while ( <$fh> ) { s/^\s+//; next if not /^\d/; my ($n, $desc, $value) = split /\s+/, $_, 3; $subset++ if $n == 1; $value =~ s/\s+$//; $value = undef if $value eq '' or $value eq 'missing'; $data_refs->[$subset]->[$n-1] = $value; $desc_refs->[$subset]->[$n-1] = $desc; } close $fh; return ($data_refs, $desc_refs, $subset); } sub usage { print <<"EOF"; Usage: $0 --data <data file> --metadata <metadata file> [--tablepath <path to BUFR tables>] [--outfile <file to print encoded BUFR message(s) to>] [--verbose n] [--help] Try '$0 --help' for more information. EOF exit 0; } sub usage_verbose { print <<"EOF"; Will create a BUFR message printed to STDOUT based on data and metadata in files <data file> and <metadata file> respectively. Usage: $0 -d <data file> -m <metadata file> or $0 --data <data file> --metadata <metadata file> Options: --help Will print this help message and then exit --outfile <filename> Will print encoded BUFR messages to <filename> instead of STDOUT --verbose n Set verbose level to n, 0<=n<=3 (default 0). Verbose output is sent STDOUT, so ought to be combined with option --outfile --tablepath <path to BUFR tables> If used, will set path to BUFR tables. If not set, will fetch tables from the environment variable BUFR_TABLES, or if this is not set: will use /usr/local/lib/emos/bufrtables/ For the metadata file, use this as prototype and change the values as desired: BUFR_EDITION 4 MASTER_TABLE 0 CENTRE 98 SUBCENTRE 0 UPDATE_NUMBER 0 OPTIONAL_SECTION 0 DATA_CATEGORY 0 INT_DATA_SUBCATEGORY 0 LOC_DATA_SUBCATEGORY 255 MASTER_TABLE_VERSION 13 LOCAL_TABLE_VERSION 1 YEAR 2008 MONTH 9 DAY 1 HOUR 6 MINUTE 0 SECOND 0 OBSERVED_DATA 1 COMPRESSED_DATA 0 DESCRIPTORS_UNEXPANDED 308004 012005 002002 For BUFR edition < 4, replace the lines INT_DATA_SUBCATEGORY, LOC_DATA_SUBCATEGORY, YEAR and SECOND with new lines DATA_SUBCATEGORY and YEAR_OF_CENTURY (the order of lines doesn't matter). For the data file, use the same format as would result if you did run on the generated BUFR message bufrread.pl <bufr file> --data_only | cut -c -31 (or if you use bufrread.pl with --width n, replace 31 with n+16). For example, the file might begin with 1 001195 Newport 2 005002 51.55 3 006002 -2.99 4 004001 2008 ... Every time a new line starting with the number 1 is met, a new subset will be generated in the BUFR message. Lines not starting with a number are ignored. For missing values, use 'missing' or stop the line after the BUFR descriptor. Associated values should use BUFR descriptor 999999. To encode a NIL subset, all delayed replication factors should be set to 1, and all other values set to missing except for the descriptors defining the station. EOF exit 0; }