Esempio n. 1
0
    def messages(self):
        """
        Raises
        ------
        IOError:
            if a message cannot be unpacked after max_tries tries

        Returns
        -------
        data : yield results of messages
        """

        for i in np.arange(self.nr_messages) + 1:
            tries = 0

            ksup = np.zeros(self.size_ksup, dtype=np.int)
            ksec0 = np.zeros(self.size_ksec0, dtype=np.int)
            ksec1 = np.zeros(self.size_ksec1, dtype=np.int)
            ksec2 = np.zeros(self.size_ksec2, dtype=np.int)
            key = np.zeros(self.size_key, dtype=np.int)
            ksec3 = np.zeros(self.size_ksec3, dtype=np.int)
            ksec4 = np.zeros(self.size_ksec4, dtype=np.int)

            kerr = 0
            data = self.bufr.get_raw_bufr_msg(i)

            ecmwfbufr.bus012(
                data[0],  # input
                ksup,  # output
                ksec0,  # output
                ksec1,  # output
                ksec2,  # output
                kerr)  # output

            kelem = self.kelem_guess
            ksup_first = ksup[5]
            kvals = ksup_first * kelem
            max_kelem = 500000
            self.init_values = np.zeros(kvals, dtype=np.float64)
            self.cvals = np.zeros((kvals, 80), dtype=np.character)
            # try to expand bufr message with the first guess for
            # kelem
            increment_arraysize = True
            while increment_arraysize:
                cnames = np.zeros((kelem, 64), dtype='|S1')
                cunits = np.zeros((kelem, 24), dtype='|S1')
                ecmwfbufr.bufrex(
                    data[0],  # input
                    ksup,  # output
                    ksec0,  # output
                    ksec1,  # output
                    ksec2,  # output
                    ksec3,  # output
                    ksec4,  # output
                    cnames,  # output
                    cunits,  # output
                    self.init_values,  # output
                    self.cvals,  # output
                    kerr)  # output
                # no error - stop loop
                if kerr == 0 and ksec4[0] != 0:
                    increment_arraysize = False
                # error increase array size and try to unpack again
                else:
                    tries += 1
                    if tries >= self.max_tries:
                        raise IOError('This file seems corrupt')
                    kelem = kelem * 5
                    kvals = ksup_first * kelem

                    if kelem > max_kelem:
                        kelem = kvals / 2
                        max_kelem = kvals

                    self.init_values = np.zeros(kvals, dtype=np.float64)
                    self.cvals = np.zeros((kvals, 80), dtype=np.character)

            decoded_values = ksup[4]
            # set kelem_guess to decoded values of last message
            # only increases reading speed if all messages are the same
            # not sure if this is the best option
            self.kelem_guess = decoded_values
            decoded_msg = ksup[5]
            # calculate first dimension of 2D array
            factor = kvals / kelem

            # reshape and trim the array to the actual size of the data
            values = self.init_values.reshape((factor, kelem))
            values = values[:decoded_msg, :decoded_values]

            yield values
Esempio n. 2
0
def decoding_example(input_bufr_file):
    #  #[
    """
    wrap the example in a function to circumvent the pylint
    convention of requiring capitals for constants in the global
    scope (since most of these variables are not constants at all))
    """

    rbf = RawBUFRFile()
    rbf.open(input_bufr_file, 'rb')
    words = rbf.get_next_raw_bufr_msg()[0]
    rbf.close()

    # define the needed constants
    max_nr_descriptors = 20  # 300
    max_nr_expanded_descriptors = 140  # 160000
    max_nr_subsets = 361  # 25

    ktdlen = max_nr_descriptors
    # krdlen = max_nr_delayed_replication_factors
    kelem = max_nr_expanded_descriptors
    kvals = max_nr_expanded_descriptors * max_nr_subsets
    # jbufl  = max_bufr_msg_size
    # jsup   = length_ksup

    # handle BUFR tables
    print('------------------------------')

    # define our own location for storing (symlinks to) the BUFR tables
    private_bufr_tables_dir = os.path.abspath("./tmp_BUFR_TABLES")
    if not os.path.exists(private_bufr_tables_dir):
        os.mkdir(private_bufr_tables_dir)

    # make the needed symlinks to bufr tables

    # inspect the location of the ecmwfbufr.so file, and derive
    # from this the location of the BUFR tables that are delivered
    # with the ECMWF BUFR library software
    ecmwfbufr_path = os.path.split(ecmwfbufr.__file__)[0]
    path1 = os.path.join(ecmwfbufr_path, "ecmwf_bufrtables")
    path2 = os.path.join(ecmwfbufr_path, '..', "ecmwf_bufrtables")

    if os.path.exists(path1):
        ecmwf_bufr_tables_dir = path1
    elif os.path.exists(path2):
        ecmwf_bufr_tables_dir = path2
    else:
        print("Error: could not find BUFR tables directory")
        raise IOError

    # make sure the path is absolute, otherwise the ECMWF library
    # might fail when it attempts to use it ...
    ecmwf_bufr_tables_dir = os.path.abspath(ecmwf_bufr_tables_dir)

    needed_b_table = "B0000000000210000001.TXT"
    needed_d_table = "D0000000000210000001.TXT"
    available_b_table = "B0000000000098013001.TXT"
    available_d_table = "D0000000000098013001.TXT"

    source = os.path.join(ecmwf_bufr_tables_dir, available_b_table)
    destination = os.path.join(private_bufr_tables_dir, needed_b_table)
    ensure_symlink_exists(source, destination)

    source = os.path.join(ecmwf_bufr_tables_dir, available_d_table)
    destination = os.path.join(private_bufr_tables_dir, needed_d_table)
    ensure_symlink_exists(source, destination)

    # make sure the BUFR tables can be found
    # also, force a slash at the end, otherwise the library fails
    # to find the tables
    env = os.environ
    env["BUFR_TABLES"] = private_bufr_tables_dir + os.path.sep
    # print('private_bufr_tables_dir+os.path.sep=', \
    #        private_bufr_tables_dir+os.path.sep)

    # redirect all fortran stdout to fileunit 12, so the text
    # will end-up in a file called 'fort.12'
    # This is needed to get reproducible output for my unittests.
    # Without this trick the stdout stream from fortran and the stdout
    # stream from c/python may be mixed in inpredictable ways
    # (depending on the size of the buffer used to store the streams)
    os.environ['STD_OUT'] = '12'

    # suppres the default ECMWF welcome message which
    # is not yet redirected to the above defined fileunit
    os.environ['PRINT_TABLE_NAMES'] = 'FALSE'

    ksup = np.zeros(9, dtype=np.int)
    ksec0 = np.zeros(3, dtype=np.int)
    ksec1 = np.zeros(40, dtype=np.int)
    ksec2 = np.zeros(4096, dtype=np.int)
    kerr = 0

    print("calling: ecmwfbufr.bus012():")
    ecmwfbufr.bus012(words, ksup, ksec0, ksec1, ksec2, kerr)
    check_error_flag('ecmwfbufr.bus012', kerr)

    # convert the arrays to a list before printing, since
    # the standard print for numpy arrays is no longer reproducible
    # (old versions use spaces, new versions use commas as separator)
    print('ksup = ', ksup.tolist())
    print('------------------------------')
    print("printing content of section 0:")
    print("sec0 : ", ksec0.tolist())
    # print("sec0[hex] : ",[hex(i) for i in ksec0])
    ecmwfbufr.buprs0(ksec0)
    print('------------------------------')
    print("printing content of section 1:")
    print("sec1[:25] : ", ksec1[:25].tolist())
    # print("sec1[hex] : ",[hex(i) for i in ksec1])
    ecmwfbufr.buprs1(ksec1)
    key = np.zeros(46, dtype=np.int)
    sec2_len = ksec2[0]
    print('------------------------------')
    print("length of sec2: ", sec2_len)
    if sec2_len > 0:
        # buukey expands local ECMWF information from section 2 to the key array
        print('------------------------------')
        print("calling buukey")
        ecmwfbufr.buukey(ksec1, ksec2, key, ksup, kerr)
        print("sec2[:25] : ", ksec2[:25].tolist())
        print("printing content of section 2:")
        ecmwfbufr.buprs2(ksup, key)
    else:
        print('skipping section 2 [since it seems unused]')

    # these 4 are filled by the BUS012 call above
    # ksup   = np.zeros(         9, dtype = np.int)
    # ksec0  = np.zeros(         3, dtype = np.int)
    # ksec1  = np.zeros(        40, dtype = np.int)
    # ksec2  = np.zeros(      4096, dtype = np.int)

    print('------------------------------')
    ksec3 = np.zeros(4, dtype=np.int)
    ksec4 = np.zeros(2, dtype=np.int)
    cnames = np.zeros((kelem, 64), dtype=np.character)
    cunits = np.zeros((kelem, 24), dtype=np.character)
    values = np.zeros(kvals, dtype=np.float64)  # this is the default
    cvals = np.zeros((kvals, 80), dtype=np.character)
    kerr = 0

    print("calling: ecmwfbufr.bufrex():")
    ecmwfbufr.bufrex(words, ksup, ksec0, ksec1, ksec2, ksec3, ksec4, cnames,
                     cunits, values, cvals, kerr)
    check_error_flag('ecmwfbufr.bufrex', kerr)

    # print a selection of the decoded numbers
    print('------------------------------')
    print("Decoded BUFR message:")
    print("ksup : ", ksup.tolist())
    print("sec0 : ", ksec0.tolist())
    print("sec1[:25] : ", ksec1[:25].tolist())
    print("sec2[:25] : ", ksec2[:25].tolist())
    print("sec3 : ", ksec3.tolist())
    print("sec4 : ", ksec4.tolist())
    print("cnames [cunits] : ")
    for (i, cnm) in enumerate(cnames):
        cun = cunits[i]
        if python3:
            txtn = ''.join(c.decode() for c in cnm)
            txtu = ''.join(c.decode() for c in cun)
        else:
            txtn = ''.join(c for c in cnm)
            txtu = ''.join(c for c in cun)

        if txtn.strip() != '':
            print('[%3.3i]:%s [%s]' % (i, txtn, txtu))

    print("values[:25] : ", values[:25].tolist())
    print("values[-25:] : ", values[-25:].tolist())
    txt = ''.join(str(v) + ';' for v in values[:20] if v > 0.)
    print("values[:20] : ", txt)

    nsubsets = ksec3[2]  # 361 # number of subsets in this BUFR message

    #not yet used:
    #nelements = ksup[4] # 44 # size of one expanded subset

    lat = np.zeros(nsubsets)
    lon = np.zeros(nsubsets)
    for subs in range(nsubsets):
        # index_lat = nelements*(s-1)+24
        # index_lon = nelements*(s-1)+25
        index_lat = max_nr_expanded_descriptors * (subs - 1) + 24
        index_lon = max_nr_expanded_descriptors * (subs - 1) + 25
        lat[subs] = values[index_lat]
        lon[subs] = values[index_lon]
        if 30 * (subs // 30) == subs:
            print("subs = ", subs, "lat = ", lat[subs], " lon = ", lon[subs])
            print("min/max lat", min(lat), max(lat))
            print("min/max lon", min(lon), max(lon))

    print('------------------------------')
    # busel: fill the descriptor list arrays (only needed for printing)

    # warning: this routine has no inputs, and acts on data stored
    #          during previous library calls
    # Therefore it only produces correct results when either bus0123
    # or bufrex have been called previously on the same bufr message.....
    # However, it is not clear to me why it seems to correctly produce
    # the descriptor lists (both bare and expanded), but yet it does
    # not seem to fill the ktdlen and ktdexl values.

    ktdlen = 0
    ktdlst = np.zeros(max_nr_descriptors, dtype=np.int)
    ktdexl = 0
    ktdexp = np.zeros(max_nr_expanded_descriptors, dtype=np.int)
    kerr = 0

    print("calling: ecmwfbufr.busel():")
    ecmwfbufr.busel(
        ktdlen,  # actual number of data descriptors
        ktdlst,  # list of data descriptors
        ktdexl,  # actual number of expanded data descriptors
        ktdexp,  # list of expanded data descriptors
        kerr)  # error  message
    check_error_flag('ecmwfbufr.busel', kerr)

    print('busel result:')
    print("ktdlen = ", ktdlen)
    print("ktdexl = ", ktdexl)

    selection1 = np.where(ktdlst > 0)
    ktdlen = len(selection1[0])
    selection2 = np.where(ktdexp > 0)
    ktdexl = len(selection2[0])

    print('fixed lengths:')
    print("ktdlen = ", ktdlen)
    print("ktdexl = ", ktdexl)

    print('descriptor lists:')
    print("ktdlst = ", ktdlst[:ktdlen])
    print("ktdexp = ", ktdexp[:ktdexl])

    print('------------------------------')
    print("printing content of section 3:")
    print("sec3 : ", ksec3.tolist())
    ecmwfbufr.buprs3(ksec3, ktdlst, ktdexp, cnames)
Esempio n. 3
0
    def messages(self):
        """
        Raises
        ------
        IOError:
            if a message cannot be unpacked after max_tries tries

        Yields
        ------
        data : dict
            Dictionary of the data in the BUFR message.
            Keys are the names of the variables.
        units: dict
            The units of each data field in the data dictionary.
            Keys are the same as in the data dictionary.
        """

        for i in np.arange(self.nr_messages) + 1:
            tries = 0

            ksup = np.zeros(self.size_ksup, dtype=np.int)
            ksec0 = np.zeros(self.size_ksec0, dtype=np.int)
            ksec1 = np.zeros(self.size_ksec1, dtype=np.int)
            ksec2 = np.zeros(self.size_ksec2, dtype=np.int)
            ksec3 = np.zeros(self.size_ksec3, dtype=np.int)
            ksec4 = np.zeros(self.size_ksec4, dtype=np.int)

            kerr = 0
            data = self.bufr.get_raw_bufr_msg(i)

            ecmwfbufr.bus012(data[0],  # input
                             ksup,  # output
                             ksec0,  # output
                             ksec1,  # output
                             ksec2,  # output
                             kerr)  # output

            kelem = self.kelem_guess
            ksup_first = ksup[5]
            kvals = ksup_first * kelem
            max_kelem = 500000
            self.init_values = np.zeros(kvals, dtype=np.float64)
            self.cvals = np.zeros((kvals, 80), dtype=np.character)
            # try to expand bufr message with the first guess for
            # kelem
            increment_arraysize = True
            while increment_arraysize:
                cnames = np.zeros((kelem, 64), dtype='|S1')
                cunits = np.zeros((kelem, 24), dtype='|S1')
                ecmwfbufr.bufrex(data[0],  # input
                                 ksup,  # output
                                 ksec0,  # output
                                 ksec1,  # output
                                 ksec2,  # output
                                 ksec3,  # output
                                 ksec4,  # output
                                 cnames,  # output
                                 cunits,  # output
                                 self.init_values,  # output
                                 self.cvals,  # output
                                 kerr)  # output
                # no error - stop loop
                if kerr == 0 and ksec4[0] != 0:
                    increment_arraysize = False
                # error increase array size and try to unpack again
                else:
                    tries += 1
                    if tries >= self.max_tries:
                        raise IOError('This file seems corrupt')
                    kelem = kelem * 5
                    kvals = ksup_first * kelem

                    if kelem > max_kelem:
                        kelem = kvals / 2
                        max_kelem = kvals

                    self.init_values = np.zeros(kvals, dtype=np.float64)
                    self.cvals = np.zeros((kvals, 80), dtype=np.character)

            decoded_values = ksup[4]
            # set kelem_guess to decoded values of last message
            # only increases reading speed if all messages are the same
            # not sure if this is the best option
            self.kelem_guess = decoded_values
            decoded_msg = ksup[5]
            # calculate first dimension of 2D array
            factor = kvals / kelem

            # reshape and trim the array to the actual size of the data
            values = self.init_values.reshape((factor, kelem))
            values = values[:decoded_msg, :decoded_values]

            # reshape and format the cnames and cunits string attributes.
            cnames = [''.join(x).rstrip() for x in cnames[:decoded_values, :]]
            cunits = [''.join(x).rstrip() for x in cunits[:decoded_values, :]]

            data = {}
            units = {}
            for i, name in enumerate(cnames):
                data[name] = values[:, i]
                units[name] = cunits[i]

            yield data, units
Esempio n. 4
0
    def messages(self):
        """
        Raises
        ------
        IOError:
            if a message cannot be unpacked after max_tries tries

        Returns
        -------
        data : yield results of messages
        """
        count = 0
        for i in np.arange(self.nr_messages) + 1:
            tries = 0

            ksup = np.zeros(self.size_ksup, dtype=np.int)
            ksec0 = np.zeros(self.size_ksec0, dtype=np.int)
            ksec1 = np.zeros(self.size_ksec1, dtype=np.int)
            ksec2 = np.zeros(self.size_ksec2, dtype=np.int)
            ksec3 = np.zeros(self.size_ksec3, dtype=np.int)
            ksec4 = np.zeros(self.size_ksec4, dtype=np.int)

            kerr = 0
            data = self.bufr.get_raw_bufr_msg(i)

            ecmwfbufr.bus012(data[0],  # input
                             ksup,  # output
                             ksec0,  # output
                             ksec1,  # output
                             ksec2,  # output
                             kerr)  # output

            kelem = self.kelem_guess
            ksup_first = ksup[5]
            kvals = ksup_first * kelem
            max_kelem = 500000
            self.init_values = np.zeros(kvals, dtype=np.float64)
            self.cvals = np.zeros((kvals, 80), dtype=np.character)
            # try to expand bufr message with the first guess for
            # kelem
            increment_arraysize = True
            while increment_arraysize:
                cnames = np.zeros((kelem, 64), dtype='|S1')
                cunits = np.zeros((kelem, 24), dtype='|S1')

                with warnings.catch_warnings():
                    warnings.filterwarnings(
                        "ignore", category=DeprecationWarning)
                    ecmwfbufr.bufrex(data[0],  # input
                                     ksup,  # output
                                     ksec0,  # output
                                     ksec1,  # output
                                     ksec2,  # output
                                     ksec3,  # output
                                     ksec4,  # output
                                     cnames,  # output
                                     cunits,  # output
                                     self.init_values,  # output
                                     self.cvals,  # output
                                     kerr)  # output
                # no error - stop loop
                if kerr == 0 and ksec4[0] != 0:
                    increment_arraysize = False
                # error increase array size and try to unpack again
                else:
                    tries += 1
                    if tries >= self.max_tries:
                        raise IOError('This file seems corrupt')
                    kelem = kelem * 5
                    kvals = ksup_first * kelem

                    if kelem > max_kelem:
                        kelem = kvals / 2
                        max_kelem = kvals

                    self.init_values = np.zeros(kvals, dtype=np.float64)
                    self.cvals = np.zeros((kvals, 80), dtype=np.character)

            decoded_values = ksup[4]
            # set kelem_guess to decoded values of last message
            # only increases reading speed if all messages are the same
            # not sure if this is the best option
            self.kelem_guess = decoded_values
            decoded_msg = ksup[5]
            # calculate first dimension of 2D array
            factor = int(kvals / kelem)

            # reshape and trim the array to the actual size of the data
            values = self.init_values.reshape((factor, kelem))
            values = values[:decoded_msg, :decoded_values]
            count += values.shape[0]

            yield values
def decoding_example(input_bufr_file):
    #  #[
    """
    wrap the example in a function to circumvent the pylint
    convention of requiring capitals for constants in the global
    scope (since most of these variables are not constants at all))
    """

    rbf = RawBUFRFile()
    rbf.open(input_bufr_file, 'rb')
    words = rbf.get_next_raw_bufr_msg()[0]
    rbf.close()

    # define the needed constants
    max_nr_descriptors = 20 # 300
    max_nr_expanded_descriptors = 140 # 160000
    max_nr_subsets = 361 # 25

    ktdlen = max_nr_descriptors
    # krdlen = max_nr_delayed_replication_factors
    kelem = max_nr_expanded_descriptors
    kvals = max_nr_expanded_descriptors*max_nr_subsets
    # jbufl  = max_bufr_msg_size
    # jsup   = length_ksup

    # handle BUFR tables
    print('------------------------------')

    # define our own location for storing (symlinks to) the BUFR tables
    private_bufr_tables_dir = os.path.abspath("./tmp_BUFR_TABLES")
    if not os.path.exists(private_bufr_tables_dir):
        os.mkdir(private_bufr_tables_dir)

    # make the needed symlinks to bufr tables

    # inspect the location of the ecmwfbufr.so file, and derive
    # from this the location of the BUFR tables that are delivered
    # with the ECMWF BUFR library software
    ecmwfbufr_path = os.path.split(ecmwfbufr.__file__)[0]
    path1 = os.path.join(ecmwfbufr_path, "ecmwf_bufrtables")
    path2 = os.path.join(ecmwfbufr_path, '..', "ecmwf_bufrtables")

    if os.path.exists(path1):
        ecmwf_bufr_tables_dir = path1
    elif os.path.exists(path2):
        ecmwf_bufr_tables_dir = path2
    else:
        print("Error: could not find BUFR tables directory")
        raise IOError

    # make sure the path is absolute, otherwise the ECMWF library
    # might fail when it attempts to use it ...
    ecmwf_bufr_tables_dir = os.path.abspath(ecmwf_bufr_tables_dir)

    needed_b_table = "B0000000000210000001.TXT"
    needed_d_table = "D0000000000210000001.TXT"
    available_b_table = "B0000000000098013001.TXT"
    available_d_table = "D0000000000098013001.TXT"

    source = os.path.join(ecmwf_bufr_tables_dir, available_b_table)
    destination = os.path.join(private_bufr_tables_dir, needed_b_table)
    ensure_symlink_exists(source, destination)

    source = os.path.join(ecmwf_bufr_tables_dir, available_d_table)
    destination = os.path.join(private_bufr_tables_dir, needed_d_table)
    ensure_symlink_exists(source, destination)

    # make sure the BUFR tables can be found
    # also, force a slash at the end, otherwise the library fails
    # to find the tables
    env = os.environ
    env["BUFR_TABLES"] = private_bufr_tables_dir+os.path.sep
    # print('private_bufr_tables_dir+os.path.sep=', \
    #        private_bufr_tables_dir+os.path.sep)

    # redirect all fortran stdout to fileunit 12, so the text
    # will end-up in a file called 'fort.12'
    # This is needed to get reproducible output for my unittests.
    # Without this trick the stdout stream from fortran and the stdout
    # stream from c/python may be mixed in inpredictable ways
    # (depending on the size of the buffer used to store the streams)
    os.environ['STD_OUT'] = '12'

    # suppres the default ECMWF welcome message which
    # is not yet redirected to the above defined fileunit
    os.environ['PRINT_TABLE_NAMES'] = 'FALSE'

    ksup = np.zeros(9, dtype=np.int)
    ksec0 = np.zeros(3, dtype=np.int)
    ksec1 = np.zeros(40, dtype=np.int)
    ksec2 = np.zeros(4096, dtype=np.int)
    kerr = 0

    print("calling: ecmwfbufr.bus012():")
    ecmwfbufr.bus012(words, ksup, ksec0, ksec1, ksec2, kerr)
    check_error_flag('ecmwfbufr.bus012', kerr)

    # convert the arrays to a list before printing, since
    # the standard print for numpy arrays is no longer reproducible
    # (old versions use spaces, new versions use commas as separator)
    print('ksup = ', ksup.tolist())
    print('------------------------------')
    print("printing content of section 0:")
    print("sec0 : ", ksec0.tolist())
    # print("sec0[hex] : ",[hex(i) for i in ksec0])
    ecmwfbufr.buprs0(ksec0)
    print('------------------------------')
    print("printing content of section 1:")
    print("sec1[:25] : ", ksec1[:25].tolist())
    # print("sec1[hex] : ",[hex(i) for i in ksec1])
    ecmwfbufr.buprs1(ksec1)
    key = np.zeros(46, dtype=np.int)
    sec2_len = ksec2[0]
    print('------------------------------')
    print("length of sec2: ", sec2_len)
    if sec2_len > 0:
        # buukey expands local ECMWF information from section 2 to the key array
        print('------------------------------')
        print("calling buukey")
        ecmwfbufr.buukey(ksec1, ksec2, key, ksup, kerr)
        print("sec2[:25] : ", ksec2[:25].tolist())
        print("printing content of section 2:")
        ecmwfbufr.buprs2(ksup, key)
    else:
        print('skipping section 2 [since it seems unused]')

    # these 4 are filled by the BUS012 call above
    # ksup   = np.zeros(         9, dtype = np.int)
    # ksec0  = np.zeros(         3, dtype = np.int)
    # ksec1  = np.zeros(        40, dtype = np.int)
    # ksec2  = np.zeros(      4096, dtype = np.int)

    print('------------------------------')
    ksec3 = np.zeros(4, dtype=np.int)
    ksec4 = np.zeros(2, dtype=np.int)
    cnames = np.zeros((kelem, 64), dtype=np.character)
    cunits = np.zeros((kelem, 24), dtype=np.character)
    values = np.zeros(kvals, dtype=np.float64) # this is the default
    cvals = np.zeros((kvals, 80), dtype=np.character)
    kerr = 0

    print("calling: ecmwfbufr.bufrex():")
    ecmwfbufr.bufrex(words, ksup, ksec0, ksec1, ksec2, ksec3, ksec4,
                     cnames, cunits, values, cvals, kerr)
    check_error_flag('ecmwfbufr.bufrex', kerr)

    # print a selection of the decoded numbers
    print('------------------------------')
    print("Decoded BUFR message:")
    print("ksup : ", ksup.tolist())
    print("sec0 : ", ksec0.tolist())
    print("sec1[:25] : ", ksec1[:25].tolist())
    print("sec2[:25] : ", ksec2[:25].tolist())
    print("sec3 : ", ksec3.tolist())
    print("sec4 : ", ksec4.tolist())
    print("cnames [cunits] : ")
    for (i, cnm) in enumerate(cnames):
        cun = cunits[i]
        if python3:
            txtn = ''.join(c.decode() for c in cnm)
            txtu = ''.join(c.decode() for c in cun)
        else:
            txtn = ''.join(c for c in cnm)
            txtu = ''.join(c for c in cun)

        if txtn.strip() != '':
            print('[%3.3i]:%s [%s]' % (i, txtn, txtu))

    print("values[:25] : ", values[:25].tolist())
    print("values[-25:] : ", values[-25:].tolist())
    txt = ''.join(str(v)+';' for v in values[:20] if v > 0.)
    print("values[:20] : ", txt)

    nsubsets = ksec3[2] # 361 # number of subsets in this BUFR message

    #not yet used:
    #nelements = ksup[4] # 44 # size of one expanded subset

    lat = np.zeros(nsubsets)
    lon = np.zeros(nsubsets)
    for subs in range(nsubsets):
        # index_lat = nelements*(s-1)+24
        # index_lon = nelements*(s-1)+25
        index_lat = max_nr_expanded_descriptors*(subs-1)+24
        index_lon = max_nr_expanded_descriptors*(subs-1)+25
        lat[subs] = values[index_lat]
        lon[subs] = values[index_lon]
        if 30*(subs//30) == subs:
            print("subs = ", subs, "lat = ", lat[subs], " lon = ", lon[subs])
            print("min/max lat", min(lat), max(lat))
            print("min/max lon", min(lon), max(lon))

    print('------------------------------')
    # busel: fill the descriptor list arrays (only needed for printing)

    # warning: this routine has no inputs, and acts on data stored
    #          during previous library calls
    # Therefore it only produces correct results when either bus0123
    # or bufrex have been called previously on the same bufr message.....
    # However, it is not clear to me why it seems to correctly produce
    # the descriptor lists (both bare and expanded), but yet it does
    # not seem to fill the ktdlen and ktdexl values.

    ktdlen = 0
    ktdlst = np.zeros(max_nr_descriptors, dtype=np.int)
    ktdexl = 0
    ktdexp = np.zeros(max_nr_expanded_descriptors, dtype=np.int)
    kerr = 0

    print("calling: ecmwfbufr.busel():")
    ecmwfbufr.busel(ktdlen, # actual number of data descriptors
                    ktdlst, # list of data descriptors
                    ktdexl, # actual number of expanded data descriptors
                    ktdexp, # list of expanded data descriptors
                    kerr)   # error  message
    check_error_flag('ecmwfbufr.busel', kerr)

    print('busel result:')
    print("ktdlen = ", ktdlen)
    print("ktdexl = ", ktdexl)

    selection1 = np.where(ktdlst > 0)
    ktdlen = len(selection1[0])
    selection2 = np.where(ktdexp > 0)
    ktdexl = len(selection2[0])

    print('fixed lengths:')
    print("ktdlen = ", ktdlen)
    print("ktdexl = ", ktdexl)

    print('descriptor lists:')
    print("ktdlst = ", ktdlst[:ktdlen])
    print("ktdexp = ", ktdexp[:ktdexl])

    print('------------------------------')
    print("printing content of section 3:")
    print("sec3 : ", ksec3.tolist())
    ecmwfbufr.buprs3(ksec3, ktdlst, ktdexp, cnames)