def create_bufr_template():
    #  #[ create the template
    '''
    now use these definitions to create a BUFR template
    '''
    from pybufr_ecmwf.bufr_template import BufrTemplate

    variable3 = 0

    template = BufrTemplate()
    template.add_descriptor(D_301192) # 4 items
    template.add_descriptor(D_301193) # 6 items
    if USE_DELAYED_REPLICATION:
        max_nr = 5 # max. 5*1 items
        template.add_delayed_replic_descriptors(max_nr, [variable3,])
    return template
예제 #2
0
def create_bufr_template():
    #  #[ create the template
    '''
    now use these definitions to create a BUFR template
    '''
    from pybufr_ecmwf.bufr_template import BufrTemplate

    variable3 = 0

    template = BufrTemplate(verbose=True)
    template.add_descriptor(D_301192) # 4 items
    template.add_descriptor(D_301193) # 6 items
    if USE_DELAYED_REPLICATION:
        max_nr = 5 # max. 5*1 items
        template.add_delayed_replic_descriptors(max_nr, [variable3,])
    return template
print('='*50)
bufr_table_set.print_D_table()
print('='*50)

# define the table name without preceding 'B' or 'D' character
# (which will be prepended by the below write method)
table_name = '_test_table.txt'
bufr_table_set.write_tables(table_name)

# now use these definitions to create a BUFR template
max_nr_of_repeats = 5
num_subsets = 2
num_repetitions = [3, 5] # actual number to be used

template = BufrTemplate(verbose=True)
template.add_descriptor(D_363192) # 1 item
template.del_repl_max_nr_of_repeats_list = [max_nr_of_repeats,]*num_subsets

# and use this BUFR template to create a test BUFR message
bufr = BUFRInterfaceECMWF(verbose=True)

# fill sections 0, 1, 2 and 3
bufr.fill_sections_0123(bufr_code_centre=0,
                        bufr_obstype=0,
                        bufr_subtype=0,
                        bufr_table_local_version=0,
                        bufr_table_master=0,
                        bufr_table_master_version=0,
                        bufr_code_subcentre=0,
                        num_subsets=num_subsets,
                        bufr_compression_flag=0)
예제 #4
0
class BUFRMessage_W:
    #  #[ bufr msg class for writing
    """
    a class that implements iteration over the data in
    a given bufr message for reading
    """
    def __init__(self,
                 parent,
                 num_subsets=1,
                 verbose=False,
                 do_range_check=False):
        #  #[ initialise a message for writing
        self.parent = parent
        self.num_subsets = num_subsets
        self.verbose = verbose
        self.do_range_check = do_range_check
        self._bufr_obj = BUFRInterfaceECMWF(verbose=verbose)
        # fill sections 0, 1, 2 and 3 with default values
        self._bufr_obj.fill_sections_0123(
            bufr_code_centre=0,  # use official WMO tables
            bufr_obstype=3,  # sounding
            bufr_subtype=253,  # L2B
            bufr_table_local_version=0,  # dont use local tables
            bufr_table_master=0,
            bufr_table_master_version=26,  # use latest WMO version
            bufr_code_subcentre=0,  # L2B processing facility
            num_subsets=num_subsets,
            bufr_compression_flag=64)
        # 64=compression/0=no compression

        #table_name = 'default'
        # self._bufr_obj.setup_tables(table_b_to_use='B'+table_name,
        #                            table_d_to_use='D'+table_name)

        # use information from sections 0123 to construct the BUFR table
        # names expected by the ECMWF BUFR library
        self._bufr_obj.setup_tables()

        # init to None
        self.template = None
        self.values = None
        self.cvals = None
        #  #]
    def set_template(self, *args, **kwargs):
        #  #[ set the template
        self.template = BufrTemplate()

        # todo: see if it is possible to also allow
        # a bufr_template instance as input
        for descr in args:
            # inputs may be integer, string or a Descriptor instance
            # print('adding descriptor: ', descr, ' of type ', type(descr))
            self.template.add_descriptor(descr)

        if 'max_repl' in kwargs:
            #print('max_repl = ', kwargs['max_repl'])
            self.template.del_repl_max_nr_of_repeats_list = kwargs['max_repl']

        self._bufr_obj.register_and_expand_descriptors(self.template)

        # retrieve the length of the expanded descriptor list
        exp_descr_list_length = self._bufr_obj.ktdexl
        if self.verbose:
            print("exp_descr_list_length = ", exp_descr_list_length)
        # ensure zeros at the end are removed, so explicitely
        # define the end of the slice
        exp_descr_list = self._bufr_obj.ktdexp[:exp_descr_list_length]
        if self.verbose:
            print("exp_descr_list = ", self._bufr_obj.ktdexp)
        self.num_fields = exp_descr_list_length

        # ensure all descriptors are instances of bufr_table.Descriptor
        self.normalised_descriptor_list = \
            self._bufr_obj.bt.normalise_descriptor_list(exp_descr_list)

        # allocate the needed values and cvalues arrays

        self.num_values = self.num_subsets * self.num_fields
        self.values = numpy.zeros(self.num_values, dtype=numpy.float64)
        # note: float64 is the default but it doesnt hurt to be explicit
        if self.verbose:
            print("self.num_values = ", self.num_values)

        # note: these two must be identical for now, otherwise the
        # python to fortran interface breaks down. This also ofcourse is the
        # cause of the huge memory use of cvals in case num_values is large.
        self.num_cvalues = self.num_values
        self.cvals = numpy.zeros((self.num_cvalues, 80), dtype=numpy.character)
        self.cvals_index = 0

        # dont use this, it is not compatible to python 2.6:
        # from collections import OrderedDict

        # since I cannot use an orderddict due to missing compatibility
        # to python 2.6, I'll use an additional (ordered) list of keys

        # fill an ordered dict with field properties for convenience
        self.field_properties = {}
        self.field_properties_keys = []
        for idx, descr in enumerate(self.normalised_descriptor_list):
            if descr.unit == 'CCITTIA5':
                (min_allowed_num_chars, max_allowed_num_chars,
                 dummy_var) = descr.get_min_max_step()
                p = {
                    'index': idx,
                    'name': descr.name,
                    'min_allowed_num_chars': min_allowed_num_chars,
                    'max_allowed_num_chars': max_allowed_num_chars
                }
            else:
                (min_allowed_value, max_allowed_value,
                 step) = descr.get_min_max_step()
                p = {
                    'index': idx,
                    'name': descr.name,
                    'min_allowed_value': min_allowed_value,
                    'max_allowed_value': max_allowed_value,
                    'step': step
                }
            self.field_properties[descr.reference] = p
            self.field_properties_keys.append(descr.reference)
        #  #]
    def copy_template_from_bufr_msg(self, msg):
        pass

    def get_field_names(self):
        #  #[ request field names
        names = []
        for key in self.field_properties_keys:
            p = self.field_properties[key]
            names.append(p['name'])
        return names
        #  #]
    def add_subset_data(self, data):
        pass

    def write_msg_to_file(self):
        #  #[ write out the current message
        # do the encoding to binary format
        self._bufr_obj.encode_data(self.values, self.cvals)

        # check if file was properly opened
        if not self.parent.is_open:
            errtxt = 'please open the bufr file before writing data to it!'
            raise IncorrectUsageError(errtxt)

        # write the encoded BUFR message
        self.parent.raw_bf.write_raw_bufr_msg(self._bufr_obj.encoded_message)
        #  #]
    def str_get_index_to_use(self, this_key):
        #  #[ convert string input for key to index in exp. descr. list
        # see if an index is provided
        index = -1
        if '[' in this_key:
            parts = this_key.split('[')
            this_key = parts[0]
            index_str = parts[1][:-1]
            index = int(index_str)

        possible_matches = []
        names_of_possible_matches = []
        try:
            reference = int(this_key)
            p = self.field_properties[reference]
            descr_name = p['name']
        except:
            # this appears to be not an integer number, so assume
            # (part of) the name is given
            descr_name = this_key

        for key in self.field_properties_keys:
            p = self.field_properties[key]
            if descr_name in p['name']:
                possible_matches.append(key)
                names_of_possible_matches.append(p['name'])

        # print('possible matches for key: ', possible_matches)
        if len(possible_matches) == 1:
            #  ok, proper location found
            key = possible_matches[0]
            p = self.field_properties[key]
            index_to_use = p['index']
            # print('filling row:', p)
        elif len(possible_matches) == 0:
            errtxt = ('ERROR: the current BUFRmessage does not contain any ' +
                      'fields that have [{}] in their name.'.format(this_key))
            raise IncorrectUsageError(errtxt)
        elif index >= 0:
            #  ok, proper location found since an index was supplied
            try:
                key = possible_matches[index]
            except:
                # invalid index
                errtxt = ('ERROR: the index on the requested descriptor ' +
                          'is out of the possible range. ' +
                          'Only {0} '.format(len(possible_matches)) +
                          'possible matches are present in this template. ' +
                          'while the requested index was {} '.format(index) +
                          'for key {0}.'.format(this_key))
                raise IncorrectUsageError(errtxt)

            p = self.field_properties[key]
            index_to_use = p['index']
            # print('filling row:', p)
        else:
            errtxt = ('ERROR: the current BUFRmessage has multiple ' +
                      'fields that have [{}] in their name.'.format(this_key) +
                      ' Please add an index to indicate which ' +
                      'field should be used. Key [{}] matches with {}.'.format(
                          this_key, names_of_possible_matches))
            raise IncorrectUsageError(errtxt)

        return index_to_use, p
        #  #]
    def num_get_index_to_use(self, this_key):
        #  #[ get properties for direct index
        # print('self.field_properties_keys = ', self.field_properties_keys)
        # print('self.field_properties = ', self.field_properties)
        index_to_use = this_key
        reference = self.field_properties_keys[this_key]
        p = self.field_properties[reference]
        return index_to_use, p
        #  #]
    def fill(self, values):
        #  #[ fill all elements for all subsets using a 2d array

        np_values = numpy.array(values)

        # check array shape
        nfields_data, nsubsets_data = numpy.shape(np_values)
        if ((nsubsets_data != self.num_subsets)
                or (nfields_data != self.num_fields)):
            errtxt = (
                'input values array has wrong shape! ' +
                'values shape: {0}:{1} '.format(nsubsets_data, nfields_data) +
                'but expected shape is: {0}:{1}'.format(
                    self.num_subsets, self.num_fields))
            raise IncorrectUsageError(errtxt)

        # fill the requested row with data
        for subset in range(self.num_subsets):
            i = subset * self.num_fields
            for j in range(self.num_fields):
                self.values[i + j] = np_values[j, subset]

        #  #]
    def fill_subset(self, isubset, values):
        #  #[ fill all elements for a given subset

        np_values = numpy.array(values)

        # check subset index
        nfields_data = len(np_values)
        if ((isubset < 0) or (isubset >= self.num_subsets)):
            errtxt = ('incorrect subset number: {0} '.format(isubset) +
                      'The subset index must be between {0} and {1}.'.format(
                          0, self.num_subsets - 1))
            raise IncorrectUsageError(errtxt)

        # check array length
        if (nfields_data != self.num_fields):
            errtxt = ('input values array has wrong length! ' +
                      'values length: {0} '.format(nfields_data) +
                      'but expected length is: {0}'.format(self.num_fields))
            raise IncorrectUsageError(errtxt)

        # fill the requested row with data
        i = isubset * self.num_fields
        for j in range(self.num_fields):
            self.values[i + j] = np_values[j]

        #  #]
    def check_and_assign_val(self, this_value, p, j):
        #  #[ chack range and assign
        if self.do_range_check:
            # optional, since this may make the code slower
            check_range(p, this_value)

        self.values[j] = this_value
        #  #]
    def check_and_assign_ascii_val(self, this_value, p, j):
        #  #[ check length of input string and assign to cvals array
        # no need to check this one I guess
        #p['min_allowed_num_chars']
        max_len = p['max_allowed_num_chars']
        if len(this_value) > max_len:
            print('WARNING: string is too long and will be truncated',
                  file=sys.stderr)
            print('during encoding of: [{0}]'.format(this_value),
                  file=sys.stderr)
            print(
                'Maximum allowed lenght in the current template is: {}'.format(
                    max_len),
                file=sys.stderr)
            print('but this string has length: {}'.format(len(this_value)),
                  file=sys.stderr)

            # truncate string
            this_value = this_value[:max_len]

        # ensure input string has correct length
        # and is left aligned
        # (if optional right alignment is needed, change < in >)
        this_value = '{0:<{width}s}'.format(this_value, width=max_len)

        self.cvals[self.cvals_index, :] = ' '  # init with spaces
        for ic, c in enumerate(this_value):
            self.cvals[self.cvals_index, ic] = c  # copy characters
        # store the cvals_index for the cvals array in the values
        # array, this is needed so the software can find the the
        # text string
        self.values[j] = ((self.cvals_index + 1) * 1000 + len(this_value))
        self.cvals_index = self.cvals_index + 1
        #  #]
    def __setitem__(self, this_key, this_value):
        #  #[ allow addition of date with dict like interface
        # print('searching for: ', this_key)

        if type(this_key) is int:
            # a direct index to the expanded list of descriptors
            # should be given in this case
            index_to_use, p = self.num_get_index_to_use(this_key)
        elif type(this_key) is str:
            index_to_use, p = self.str_get_index_to_use(this_key)
        else:
            errtxt = 'key has unknown type: {}'.format(type(this_key))
            raise IncorrectUsageError(errtxt)

        # check if input value is character string
        input_is_ccittia5 = False
        if type(this_value) is str:
            input_is_ccittia5 = True
            n = 1
        else:
            # check length of input (scalar or array?)
            try:
                n = len(this_value)
                try:
                    if type(this_value[0]) is str:
                        input_is_ccittia5 = True
                except IndexError:
                    pass
            except TypeError:
                n = 1

        if n != 1:
            if n != self.num_subsets:
                errtxt = ('Please provide an array of size num_subsets! ' +
                          'Current array has size {0} '.format(n) +
                          'but num_subsets is {0}'.format(self.num_subsets))
                raise IncorrectUsageError(errtxt)

        # fill the requested row with data
        for subset in range(self.num_subsets):
            i = subset * self.num_fields
            j = i + index_to_use
            if not input_is_ccittia5:
                if n == 1:
                    self.check_and_assign_val(this_value, p, j)
                else:
                    self.check_and_assign_val(this_value[subset], p, j)
            else:
                # special case for character strings
                if n == 1:
                    self.check_and_assign_ascii_val(this_value, p, j)
                else:
                    self.check_and_assign_ascii_val(this_value[subset], p, j)
예제 #5
0
table_name = '_test_table.txt'
bufr_table_set.write_tables(table_name)

# now use these definitions to create a BUFR template
max_nr_of_replications = 3
num_subsets = 3
num_replications1 = [1, 2, 3]
num_replications2 = [[
    1,
], [
    2,
    2,
], [3, 3, 3]]

template = BufrTemplate(verbose=True)
template.add_descriptor(D_363192)  # 1 item
template.del_repl_max_nr_of_repeats_list = ([
    max_nr_of_replications,
] * max_nr_of_replications * num_subsets)

# and use this BUFR template to create a test BUFR message
bufr = BUFRInterfaceECMWF(verbose=True)

# fill sections 0, 1, 2 and 3
bufr.fill_sections_0123(bufr_code_centre=0,
                        bufr_obstype=0,
                        bufr_subtype=0,
                        bufr_table_local_version=0,
                        bufr_table_master=0,
                        bufr_table_master_version=0,
                        bufr_code_subcentre=0,
예제 #6
0
bufr_table_set.print_B_table()
print('='*50)
print("D-table:")
print('='*50)
bufr_table_set.print_D_table()
print('='*50)

# define the table name without preceding 'B' or 'D' character
# (which will be prepended by the below write method)
table_name = '_test_table.txt'
bufr_table_set.write_tables(table_name)

# now use these definitions to create a BUFR template
max_nr_of_repeats = 5
template = BufrTemplate(verbose=True)
template.add_descriptor(var1) # 1 item
template.add_delayed_replic_descriptors(max_nr_of_repeats,
                                        D_363192) # max. 1 + 5*5 items

# and use this BUFR template to create a test BUFR message
bufr = BUFRInterfaceECMWF(verbose=True)

# fill sections 0, 1, 2 and 3
num_subsets = 3
bufr.fill_sections_0123(bufr_code_centre=0,
                        bufr_obstype=0,
                        bufr_subtype=0,
                        bufr_table_local_version=0,
                        bufr_table_master=0,
                        bufr_table_master_version=0,
                        bufr_code_subcentre=0,