bufr.pm:bufrencode_source

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
bufr.pm:bufrencode_source [2010-02-24 12:50:40]
pals created
bufr.pm:bufrencode_source [2023-02-05 10:18:55] (current)
pals
Line 1: Line 1:
-<code> +<code perl
-#!/usr/bin/perl -w+#!/usr/bin/perl
  
-# (C) Copyright 2010, met.no+# (C) Copyright 2010-2023 MET Norway
 # #
 # This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
Line 19: Line 19:
 # 02110-1301, USA. # 02110-1301, USA.
  
-Encode a BUFR message, reading data and metadata from files. +pod included at end of file
- +
-# Author: P. Sannes met.no 2010 +
  
 use strict; use strict;
 +use warnings;
 use Getopt::Long; use Getopt::Long;
 +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 'ECCODES' if preferred 
 +use constant DEFAULT_TABLE_FORMAT => 'BUFRDC';
  
-use constant DEFAULT_TABLE_PATH => '/usr/local/lib/emos/bufrtables';+# Will be used if neither --tablepath nor $ENV{BUFR_TABLES} is set 
 +use constant DEFAULT_TABLE_PATH_BUFRDC => '/usr/local/lib/bufrtables'; 
 +use constant DEFAULT_TABLE_PATH_ECCODES => '/usr/local/share/eccodes/definitions/bufr/tables';
  
 # Parse command line options # Parse command line options
Line 41: Line 44:
            'metadata=s',            'metadata=s',
            'outfile=s',            'outfile=s',
 +           'strict_checking=i',
 +           'tableformat=s',
            'tablepath=s',            'tablepath=s',
            'verbose=i',            'verbose=i',
-       ) or die "Wrong option(s), execute $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};
  
 # Data or metadata file not provided # Data or metadata file not provided
-usage() if not $option{data} or not $option{metadata};+pod2usage(-verbose => 0) if not $option{data} or not $option{metadata};
  
 my $data_file      $option{data}; my $data_file      $option{data};
 my $metadata_file =  $option{metadata}; my $metadata_file =  $option{metadata};
  
-my $verbose = $option{verbose} ? $option{verbose} : 0;+# Default is croak if (recoverable) error found in encoded BUFR format 
 +my $strict_checking defined $option{strict_checking} 
 +    ? $option{strict_checking} : 2; 
 +Geo::BUFR->set_strict_checking($strict_checking);
  
-# Set verbosity level for the BUFR module. Must be set also for each +# Set verbosity level 
-# BUFR object generated +Geo::BUFR->set_verbose($option{verbose}) if $option{verbose}; 
-BUFR->set_verbose($verbose);+ 
 +Set BUFR table format 
 +my $tableformat = (defined $option{tableformat}) ? uc $option{tableformat} : DEFAULT_TABLE_FORMAT; 
 +Geo::BUFR->set_tableformat($tableformat);
  
 # 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->set_tablepath($option{tablepath});+    Geo::BUFR->set_tablepath($option{tablepath});
 } 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->set_tablepath($ENV{BUFR_TABLES});+    Geo::BUFR->set_tablepath($ENV{BUFR_TABLES});
 } else { } else {
-    # If all else fails, use the libemos bufrtables +    # If all else fails, use the default tablepath in BUFRDC/ECCODES 
-    BUFR->set_tablepath(DEFAULT_TABLE_PATH);+    if ($tableformat eq 'BUFRDC') { 
 +        Geo::BUFR->set_tablepath(DEFAULT_TABLE_PATH_BUFRDC); 
 +    } elsif ($tableformat eq 'ECCODES'
 +        Geo::BUFR->set_tablepath(DEFAULT_TABLE_PATH_ECCODES); 
 +    }
 } }
  
-# Read in metadata +my $bufr Geo::BUFR->new();
-my $metadata read_metadata($metadata_file);+
  
-my $bufr = BUFR->new(); +Read metadata into $bufr 
- +read_metadata($metadata_file, $bufr);
-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};+
  
 +# Load B and D tables (table version inferred from metadata)
 $bufr->load_BDtables(); $bufr->load_BDtables();
  
-Read in the data (descriptors and values)+Get the data
 my ($data_refs, $desc_refs, $num_subsets) = readdata($data_file); my ($data_refs, $desc_refs, $num_subsets) = readdata($data_file);
  
Line 120: Line 101:
  
 # Print the encoded BUFR message # Print the encoded BUFR message
 +my $buffer = $bufr->encode_message($data_refs, $desc_refs);
 if ($option{outfile}) { if ($option{outfile}) {
-    open(my $OUT, '>',$option{outfile}) +    my $outfile = $option{outfile}; 
-        or die "Cannot open $option{outfile} for writing: $!"; +    open my $fh, '>', $outfile or die "Can'open $outfile: $!"; 
-    print $OUT $bufr->encode_message($data_refs, $desc_refs); +    binmode($fh); 
-    close $OUT or die "Cannot close $option{outfile}: $!";+    print $fh $buffer;
 } else { } else {
-    print $bufr->encode_message($data_refs, $desc_refs);+    binmode(STDOUT); 
 +    print $buffer;
 } }
  
 +# See OPTIONS section in pod for format of metadata file
 sub read_metadata { sub read_metadata {
-    my $file = shift; +    my ($file, $bufr= @_;
-    open (my $fh, '<', $fileor die "Cannot open $file: $!";+
  
 +    # Read metadata from file into a hash
     my %metadata;     my %metadata;
 +    open (my $fh, '<', $file) or die "Cannot open $file: $!";
     while ( <$fh> ) {     while ( <$fh> ) {
         chomp;         chomp;
         next if /^\s*$/;         next if /^\s*$/;
 +        s/^\s+//;
         my ($key, $value) = split /\s+/, $_, 2;         my ($key, $value) = split /\s+/, $_, 2;
         $metadata{$key} = $value;         $metadata{$key} = $value;
     }     }
-    close $fh;+    close $fh or die "Cannot close $file: $!"; 
 + 
 +    # Load the metadata into the BUFR object 
 +    my $m = \%metadata; 
 + 
 +    my $bufr_edition = $m->{BUFR_EDITION}; 
 + 
 +    $bufr->set_bufr_edition($bufr_edition); 
 +    $bufr->set_master_table($m->{MASTER_TABLE}); 
 +    $bufr->set_centre($m->{CENTRE}); 
 +    $bufr->set_subcentre($m->{SUBCENTRE}); 
 +    $bufr->set_update_sequence_number($m->{UPDATE_SEQUENCE_NUMBER}); 
 +    $bufr->set_optional_section($m->{OPTIONAL_SECTION}); 
 +    $bufr->set_data_category($m->{DATA_CATEGORY}); 
 +    if ( $bufr_edition < 4 ) { 
 +        $bufr->set_data_subcategory($m->{DATA_SUBCATEGORY}); 
 +    } else { 
 +        $bufr->set_int_data_subcategory($m->{INT_DATA_SUBCATEGORY}); 
 +        $bufr->set_loc_data_subcategory($m->{LOC_DATA_SUBCATEGORY}); 
 +    } 
 +    $bufr->set_master_table_version($m->{MASTER_TABLE_VERSION}); 
 +    $bufr->set_local_table_version($m->{LOCAL_TABLE_VERSION}); 
 +    if ( $bufr_edition < 4 ) { 
 +        $bufr->set_year_of_century($m->{YEAR_OF_CENTURY}); 
 +    } else { 
 +        $bufr->set_year($m->{YEAR}); 
 +    } 
 +    $bufr->set_month($m->{MONTH}); 
 +    $bufr->set_day($m->{DAY}); 
 +    $bufr->set_hour($m->{HOUR}); 
 +    $bufr->set_minute($m->{MINUTE}); 
 +    $bufr->set_second($m->{SECOND}) if $bufr_edition >= 4; 
 +    $bufr->set_observed_data($m->{OBSERVED_DATA}); 
 +    $bufr->set_compressed_data($m->{COMPRESSED_DATA}); 
 +    $bufr->set_descriptors_unexpanded($m->{DESCRIPTORS_UNEXPANDED}); 
 +    $bufr->set_local_use($m->{LOCAL_USE}) if exists $m->{LOCAL_USE};
  
-    return \%metadata;+    return;
 } }
  
 +# See OPTIONS section in pod for format of data file
 sub readdata { sub readdata {
     my $file = shift;     my $file = shift;
Line 154: Line 175:
     while ( <$fh> ) {     while ( <$fh> ) {
         s/^\s+//;         s/^\s+//;
 +        # Lines not starting with a number are ignored
         next if not /^\d/;         next if not /^\d/;
         my ($n, $desc, $value) = split /\s+/, $_, 3;         my ($n, $desc, $value) = split /\s+/, $_, 3;
         $subset++ if $n == 1;         $subset++ if $n == 1;
-        $value =~ s/\s+$//; +        # Some operator descriptors are written on unnumbered lines 
-        $value = undef if $value eq '' or $value eq 'missing'; +        # without a value 
-        $data_refs->[$subset]->[$n-1] = $value; +        if (!defined $desc || $desc !~ /^\d/) { 
-        $desc_refs->[$subset]->[$n-1] = $desc;+            next unless $n >= 200000 && $n < 300000; # Better to die here? 
 +            $desc = $n; 
 +            $value = undef; 
 +        } else { 
 +            $value =~ s/\s+$//; 
 +            $value = undef if $value eq '' or $value eq 'missing'; 
 +        
 +        push @{$data_refs->[$subset]}, $value; 
 +        push @{$desc_refs->[$subset]}, $desc;
     }     }
-    close $fh;+    close $fh or die "Cannot close $file: $!";
  
     return ($data_refs, $desc_refs, $subset);     return ($data_refs, $desc_refs, $subset);
 } }
  
-sub usage { +=pod
-    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 { +=encoding utf8
-    print <<"EOF";+
  
-Will create a BUFR message printed to STDOUT based on data and metadata +=head1 SYNOPSIS
-in files <data file> and <metadata file> respectively.+
  
-Usage: $0 -<data file> -<metadata file> +  bufrencode.pl --data <data file> --metadata <metadata file> 
-or     $0 --data <data file> --metadata <metadata file>+      [--outfile <file to print encoded BUFR message to>
 +      [--strict_checking n] 
 +      [--tableformat <BUFRDC|ECCODES>
 +      [--tablepath <path to BUFR tables>
 +      [--verbose n] 
 +      [--help]
  
-Options: +=head1 DESCRIPTION
-      --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 fileuse this as prototype and change the values as desired:+Encode a BUFR messagereading data and metadata from files. The 
 +resulting BUFR message will be printed to STDOUT unless option 
 +C<--outfile> is set.
  
-BUFR_EDITION +Execute without arguments for Usage, with option --help for some 
-MASTER_TABLE +additional info. See also L<https://wiki.met.no/bufr.pm/start> for 
-CENTRE  98 +examples of use. 
-SUBCENTRE + 
-UPDATE_NUMBER  0 +=head1 OPTIONS 
-OPTIONAL_SECTION + 
-DATA_CATEGORY +   --help               Display Usage and explain the options. Almost 
-INT_DATA_SUBCATEGORY  0 +                        the same as consulting perldoc bufrencode.pl 
-LOC_DATA_SUBCATEGORY  255 +   --outfile <filename> Will print the encoded BUFR message to <filename> 
-MASTER_TABLE_VERSION  13 +                        instead of STDOUT 
-LOCAL_TABLE_VERSION  1 +   --strict_checking n  n=0 Disable strict checking of BUFR format 
-YEAR  2008 +                        n=1 Issue warning if (recoverable) error in 
-MONTH  9 +                            BUFR format 
-DAY  1 +                        n=2 (default) Croak if (recoverable) error in BUFR format. 
-HOUR  6 +                            Nothing more in this message will be encoded. 
-MINUTE +   --tableformat        Currently supported are BUFRDC and ECCODES (default is BUFRDC) 
-SECOND +   --tablepath <path to BUFR tables> 
-OBSERVED_DATA +                        If used, will set path to BUFR tables. If not 
-COMPRESSED_DATA +                        set, will fetch tables from the environment 
-DESCRIPTORS_UNEXPANDED  308004 012005 002002+                        variable BUFR_TABLES, or if this is not set: 
 +                        will use DEFAULT_TABLE_PATH_<tableformat> 
 +                        hard coded in source code. 
 +   --verbose n          Set verbose level to n, 0<=n<=6 (default 0). 
 +                        Verbose output is sent to STDOUT, so ought to 
 +                        be combined with option --outfile 
 + 
 +=head2 Required options 
 + 
 +=head4 --metadata <metadata file> 
 + 
 +For the metadata file, use this as a prototype and change the values 
 +as desired: 
 + 
 +  BUFR_EDITION 
 +  MASTER_TABLE 
 +  CENTRE  88 
 +  SUBCENTRE 
 +  UPDATE_SEQUENCE_NUMBER  0 
 +  OPTIONAL_SECTION 
 +  DATA_CATEGORY 
 +  INT_DATA_SUBCATEGORY  2 
 +  LOC_DATA_SUBCATEGORY  255 
 +  MASTER_TABLE_VERSION  14 
 +  LOCAL_TABLE_VERSION  0 
 +  YEAR  2008 
 +  MONTH  9 
 +  DAY  1 
 +  HOUR  6 
 +  MINUTE 
 +  SECOND 
 +  OBSERVED_DATA 
 +  COMPRESSED_DATA 
 +  DESCRIPTORS_UNEXPANDED  308004 012005 002002
  
 For BUFR edition < 4, replace the lines INT_DATA_SUBCATEGORY, For BUFR edition < 4, replace the lines INT_DATA_SUBCATEGORY,
 LOC_DATA_SUBCATEGORY, YEAR and SECOND with new lines DATA_SUBCATEGORY LOC_DATA_SUBCATEGORY, YEAR and SECOND with new lines DATA_SUBCATEGORY
 and YEAR_OF_CENTURY (the order of lines doesn't matter). and YEAR_OF_CENTURY (the order of lines doesn't matter).
 +
 +=head4 --data <data file>
  
 For the data file, use the same format as would result if you did run For the data file, use the same format as would result if you did run
 on the generated BUFR message on the generated BUFR message
 +
     bufrread.pl <bufr file> --data_only | cut -c -31     bufrread.pl <bufr file> --data_only | cut -c -31
-(or if you use bufrread.pl with --width n, replace 31 with n+16).+ 
 +or if you use bufrread.pl with C<--width n>, replace 31 with n+16.
 For example, the file might begin with For example, the file might begin with
  
Line 242: Line 291:
 ... ...
  
-Every time a new line starting with the number 1 is met, a new subset will be +Every time a new line starting with the number 1 is met, a new subset 
-generated in the BUFR message. Lines not starting with a number are ignored.+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.+For missing values, use 'missing' or stop the line after the BUFR 
 +descriptor.
  
-Associated values should use BUFR descriptor 999999.+Associated values should use BUFR descriptor 999999, and operator 
 +descriptors 22[2345]000 and 23[2567]000 should not have a value, 
 +neither should this line be numbered, e.g.
  
-To encode a NIL subset, all delayed replication factors should be set to 1, and +   160  011002          missing 
-all other values set to missing except for the descriptors defining the station.+        222000 
 +   161  031002              160 
 +   162  031031                0 
 +...
  
-EOF +To encode a NIL subset, all delayed replication factors should be 
-    exit 0; +nonzero, and all other values set to missing except for the 
-}+descriptors defining the station. 
 + 
 +Options may be abbreviated, e.g. C<--h> or C<-h> for C<--help> 
 + 
 +=head1 AUTHOR 
 + 
 +Pål Sannes E<lt>pal.sannes@met.noE<gt> 
 + 
 +=head1 COPYRIGHT 
 + 
 +Copyright (C) 2010-2023 MET Norway 
 + 
 +=cut
 </code> </code>
  • bufr.pm/bufrencode_source.1267015840.txt.gz
  • Last modified: 2022-05-31 09:23:11
  • (external edit)