User Tools

Site Tools


bufr.pm:bufrencode_source

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;
}
bufr.pm/bufrencode_source.1267015840.txt.gz · Last modified: (external edit)