Exemple #1
0
def convert(f):
    factories = []
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    if \
            (f.lbtim.ia == 0) and \
            (f.lbtim.ib == 0) and \
            (f.lbtim.ic in [1, 2, 3, 4]) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        aux_coords_and_dims.append(
            (DimCoord(f.time_unit('hours').date2num(f.t1),
                      standard_name='time',
                      units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ia == 0) and \
            (f.lbtim.ib == 1) and \
            (f.lbtim.ic in [1, 2, 3, 4]) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        aux_coords_and_dims.append((DimCoord(f.time_unit('hours',
                                                         f.t2).date2num(f.t1),
                                             standard_name='forecast_period',
                                             units='hours'), None))
        aux_coords_and_dims.append(
            (DimCoord(f.time_unit('hours').date2num(f.t1),
                      standard_name='time',
                      units=f.time_unit('hours')), None))
        aux_coords_and_dims.append(
            (DimCoord(f.time_unit('hours').date2num(f.t2),
                      standard_name='forecast_reference_time',
                      units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        t_unit = f.time_unit('hours')
        t1_hours = t_unit.date2num(f.t1)
        t2_hours = t_unit.date2num(f.t2)
        period = t2_hours - t1_hours
        aux_coords_and_dims.append((DimCoord(standard_name='forecast_period',
                                             units='hours',
                                             points=f.lbft - 0.5 * period,
                                             bounds=[f.lbft - period,
                                                     f.lbft]), None))
        aux_coords_and_dims.append(
            (DimCoord(standard_name='time',
                      units=t_unit,
                      points=0.5 * (t1_hours + t2_hours),
                      bounds=[t1_hours, t2_hours]), None))
        aux_coords_and_dims.append(
            (DimCoord(f.time_unit('hours').date2num(f.t2) - f.lbft,
                      standard_name='forecast_reference_time',
                      units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        t_unit = f.time_unit('hours')
        t1_hours = t_unit.date2num(f.t1)
        t2_hours = t_unit.date2num(f.t2)
        period = t2_hours - t1_hours
        aux_coords_and_dims.append((DimCoord(standard_name='forecast_period',
                                             units='hours',
                                             points=f.lbft,
                                             bounds=[f.lbft - period,
                                                     f.lbft]), None))
        aux_coords_and_dims.append((DimCoord(standard_name='time',
                                             units=t_unit,
                                             points=t2_hours,
                                             bounds=[t1_hours,
                                                     t2_hours]), None))
        aux_coords_and_dims.append(
            (DimCoord(f.time_unit('hours').date2num(f.t2) - f.lbft,
                      standard_name='forecast_reference_time',
                      units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 12 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 3 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('djf',
                                             long_name='season',
                                             units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 3 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 6 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('mam',
                                             long_name='season',
                                             units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 6 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 9 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('jja',
                                             long_name='season',
                                             units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 9 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 12 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('son',
                                             long_name='season',
                                             units='no_unit'), None))

    if \
            (f.bdx != 0.0) and \
            (f.bdx != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system()), 1))

    if \
            (f.bdx != 0.0) and \
            (f.bdx != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system(),
                                   with_bounds=True), 1))

    if \
            (f.bdy != 0.0) and \
            (f.bdy != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy,
                                   f.bdy,
                                   f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()), 0))

    if \
            (f.bdy != 0.0) and \
            (f.bdy != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy,
                                   f.bdy,
                                   f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system(),
                                   with_bounds=True), 0))

    if \
            (f.bdy == 0.0 or f.bdy == f.bmdi) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.iy == 10)):
        dim_coords_and_dims.append(
            (DimCoord(f.y,
                      standard_name=f._y_coord_name(),
                      units='degrees',
                      bounds=f.y_bounds,
                      coord_system=f.coord_system()), 0))

    if \
            (f.bdx == 0.0 or f.bdx == f.bmdi) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix == 11)):
        dim_coords_and_dims.append(
            (DimCoord(f.x,
                      standard_name=f._x_coord_name(),
                      units='degrees',
                      bounds=f.x_bounds,
                      circular=(f.lbhem in [0, 4]),
                      coord_system=f.coord_system()), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.iy == 2) and \
            (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             standard_name='height',
                                             units='km',
                                             bounds=f.y_bounds,
                                             attributes={'positive':
                                                         'up'}), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.iy == 4):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             standard_name='depth',
                                             units='m',
                                             bounds=f.y_bounds,
                                             attributes={'positive':
                                                         'down'}), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.ix == 10) and \
            (f.bdx != 0) and \
            (f.bdx != f.bmdi):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.iy == 1) and \
            (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             long_name='pressure',
                                             units='hPa',
                                             bounds=f.y_bounds), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.ix == 1) and \
            (f.bdx == 0 or f.bdx == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.x,
                                             long_name='pressure',
                                             units='hPa',
                                             bounds=f.x_bounds), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.iy == 23):
        dim_coords_and_dims.append((DimCoord(
            f.y,
            standard_name='time',
            units=iris.unit.Unit('days since 0000-01-01 00:00:00',
                                 calendar=iris.unit.CALENDAR_360_DAY),
            bounds=f.y_bounds), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.ix == 23):
        dim_coords_and_dims.append((DimCoord(
            f.x,
            standard_name='time',
            units=iris.unit.Unit('days since 0000-01-01 00:00:00',
                                 calendar=iris.unit.CALENDAR_360_DAY),
            bounds=f.x_bounds), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.ix == 13) and \
            (f.bdx != 0):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   long_name='site_number',
                                   units='1'), 1))

    if \
            (len(f.lbcode) == 5) and \
            (13 in [f.lbcode.ix, f.lbcode.iy]) and \
            (11 not in [f.lbcode.ix, f.lbcode.iy]) and \
            (hasattr(f, 'lower_x_domain')) and \
            (hasattr(f, 'upper_x_domain')) and \
            (all(f.lower_x_domain != -1.e+30)) and \
            (all(f.upper_x_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord(
            (f.lower_x_domain + f.upper_x_domain) / 2.0,
            standard_name=f._x_coord_name(),
            units='degrees',
            bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T,
            coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    if \
            (len(f.lbcode) == 5) and \
            (13 in [f.lbcode.ix, f.lbcode.iy]) and \
            (10 not in [f.lbcode.ix, f.lbcode.iy]) and \
            (hasattr(f, 'lower_y_domain')) and \
            (hasattr(f, 'upper_y_domain')) and \
            (all(f.lower_y_domain != -1.e+30)) and \
            (all(f.upper_y_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord(
            (f.lower_y_domain + f.upper_y_domain) / 2.0,
            standard_name=f._y_coord_name(),
            units='degrees',
            bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T,
            coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(
            CellMethod("mean", coords="time",
                       intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 3):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib not in [2, 3]):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(
            CellMethod("minimum",
                       coords="time",
                       intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib != 2):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(
            CellMethod("maximum",
                       coords="time",
                       intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib != 2):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if f.lbproc not in [0, 128, 4096, 8192]:
        attributes["ukmo__process_flags"] = tuple(
            sorted([
                iris.fileformats.pp.lbproc_map[flag] for flag in f.lbproc.flags
            ]))

    if \
            (f.lbvc == 1) and \
            (not (str(f.stash) in ['m01s03i236', 'm01s03i237', 'm01s03i245', 'm01s03i247', 'm01s03i250'])) and \
            (f.blev != -1):
        aux_coords_and_dims.append((DimCoord(f.blev,
                                             standard_name='height',
                                             units='m',
                                             attributes={'positive':
                                                         'up'}), None))

    if str(f.stash) in [
            'm01s03i236', 'm01s03i237', 'm01s03i245', 'm01s03i247',
            'm01s03i250'
    ]:
        aux_coords_and_dims.append((DimCoord(1.5,
                                             standard_name='height',
                                             units='m',
                                             attributes={'positive':
                                                         'up'}), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 2):
        aux_coords_and_dims.append(
            (DimCoord(_model_level_number(f),
                      standard_name='model_level_number',
                      attributes={'positive': 'down'}), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 2) and \
            (f.brsvd[0] == f.brlev):
        aux_coords_and_dims.append((DimCoord(f.blev,
                                             standard_name='depth',
                                             units='m',
                                             attributes={'positive':
                                                         'down'}), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 2) and \
            (f.brsvd[0] != f.brlev):
        aux_coords_and_dims.append((DimCoord(f.blev,
                                             standard_name='depth',
                                             units='m',
                                             bounds=[f.brsvd[0], f.brlev],
                                             attributes={'positive':
                                                         'down'}), None))

    # soil level
    if len(f.lbcode) != 5 and f.lbvc == 6:
        aux_coords_and_dims.append(
            (DimCoord(_model_level_number(f),
                      long_name='soil_model_level_number',
                      attributes={'positive': 'down'}), None))

    if \
            (f.lbvc == 8) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and 1 not in [f.lbcode.ix, f.lbcode.iy])):
        aux_coords_and_dims.append((DimCoord(f.blev,
                                             long_name='pressure',
                                             units='hPa'), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 19):
        aux_coords_and_dims.append(
            (DimCoord(f.blev,
                      standard_name='air_potential_temperature',
                      units='K',
                      attributes={'positive': 'up'}), None))

    # Hybrid pressure coordinate
    if f.lbvc == 9:
        model_level_number = DimCoord(_model_level_number(f),
                                      standard_name='model_level_number',
                                      attributes={'positive': 'up'})
        # The following match the hybrid height scheme, but data has the
        # blev and bhlev values the other way around.
        #level_pressure = DimCoord(f.blev,
        #                          long_name='level_pressure',
        #                          units='Pa',
        #                          bounds=[f.brlev, f.brsvd[0]])
        #sigma = AuxCoord(f.bhlev,
        #                 long_name='sigma',
        #                 bounds=[f.bhrlev, f.brsvd[1]])
        level_pressure = DimCoord(f.bhlev,
                                  long_name='level_pressure',
                                  units='Pa',
                                  bounds=[f.bhrlev, f.brsvd[1]])
        sigma = AuxCoord(f.blev,
                         long_name='sigma',
                         bounds=[f.brlev, f.brsvd[0]])
        aux_coords_and_dims.extend([(model_level_number, None),
                                    (level_pressure, None), (sigma, None)])
        factories.append(
            Factory(HybridPressureFactory,
                    [{
                        'long_name': 'level_pressure'
                    }, {
                        'long_name': 'sigma'
                    },
                     Reference('surface_air_pressure')]))

    if f.lbvc == 65:
        aux_coords_and_dims.append(
            (DimCoord(_model_level_number(f),
                      standard_name='model_level_number',
                      attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append((DimCoord(f.blev,
                                             long_name='level_height',
                                             units='m',
                                             bounds=[f.brlev, f.brsvd[0]],
                                             attributes={'positive':
                                                         'up'}), None))
        aux_coords_and_dims.append((AuxCoord(f.bhlev,
                                             long_name='sigma',
                                             bounds=[f.bhrlev,
                                                     f.brsvd[1]]), None))
        factories.append(
            Factory(HybridHeightFactory, [{
                'long_name': 'level_height'
            }, {
                'long_name': 'sigma'
            },
                                          Reference('orography')]))

    if f.lbrsvd[3] != 0:
        aux_coords_and_dims.append(
            (DimCoord(f.lbrsvd[3], standard_name='realization'), None))

    if f.lbuser[4] != 0:
        aux_coords_and_dims.append((DimCoord(f.lbuser[4],
                                             long_name='pseudo_level',
                                             units='1'), None))

    if f.lbuser[6] == 1 and f.lbuser[3] == 5226:
        standard_name = "precipitation_amount"
        units = "kg m-2"

    if \
            (f.lbuser[6] == 2) and \
            (f.lbuser[3] == 101):
        standard_name = "sea_water_potential_temperature"
        units = "Celsius"

    if \
            ((f.lbsrce % 10000) == 1111) and \
            ((f.lbsrce / 10000) / 100.0 > 0):
        attributes['source'] = 'Data from Met Office Unified Model %4.2f' % (
            (f.lbsrce / 10000) / 100.0)

    if \
            ((f.lbsrce % 10000) == 1111) and \
            ((f.lbsrce / 10000) / 100.0 == 0):
        attributes['source'] = 'Data from Met Office Unified Model'

    if f.lbuser[6] != 0 or (f.lbuser[3] / 1000) != 0 or (f.lbuser[3] %
                                                         1000) != 0:
        attributes['STASH'] = f.stash

    if \
            (f.lbuser[6] == 1) and \
            (f.lbuser[3] == 4205):
        standard_name = "mass_fraction_of_cloud_ice_in_air"
        units = "1"

    if \
            (f.lbuser[6] == 1) and \
            (f.lbuser[3] == 4206):
        standard_name = "mass_fraction_of_cloud_liquid_water_in_air"
        units = "1"

    if \
            (f.lbuser[6] == 1) and \
            (f.lbuser[3] == 30204):
        standard_name = "air_temperature"
        units = "K"

    if \
            (f.lbuser[6] == 4) and \
            (f.lbuser[3] == 6001):
        standard_name = "sea_surface_wave_significant_height"
        units = "m"

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if \
            (not f.stash.is_valid) and \
            (f.lbfc in LBFC_TO_CF):
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    if f.lbuser[3] == 33:
        references.append(ReferenceTarget('orography', None))

    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget('surface_air_pressure', None))

    return (factories, references, standard_name, long_name, units, attributes,
            cell_methods, dim_coords_and_dims, aux_coords_and_dims)
Exemple #2
0
def _all_other_rules(f):
    """
    This deals with all the other rules that have not been factored into any of
    the other convert_scalar_coordinate functions above.

    """
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # Season coordinates (--> scalar coordinates)
    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4] and
            (len(f.lbcode) != 5 or
             (len(f.lbcode) == 5 and
              (f.lbcode.ix not in [20, 21, 22, 23] and
               f.lbcode.iy not in [20, 21, 22, 23]))) and
            f.lbmon == 12 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and
            f.lbmond == 3 and f.lbdatd == 1 and f.lbhrd == 0 and
            f.lbmind == 0):
        aux_coords_and_dims.append(
            (AuxCoord('djf', long_name='season', units='no_unit'),
             None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4] and
            ((len(f.lbcode) != 5) or
             (len(f.lbcode) == 5 and
              f.lbcode.ix not in [20, 21, 22, 23]
              and f.lbcode.iy not in [20, 21, 22, 23])) and
            f.lbmon == 3 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and
            f.lbmond == 6 and f.lbdatd == 1 and f.lbhrd == 0 and
            f.lbmind == 0):
        aux_coords_and_dims.append(
            (AuxCoord('mam', long_name='season', units='no_unit'),
             None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4] and
            ((len(f.lbcode) != 5) or
             (len(f.lbcode) == 5 and
              f.lbcode.ix not in [20, 21, 22, 23] and
              f.lbcode.iy not in [20, 21, 22, 23])) and
            f.lbmon == 6 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and
            f.lbmond == 9 and f.lbdatd == 1 and f.lbhrd == 0 and
            f.lbmind == 0):
        aux_coords_and_dims.append(
            (AuxCoord('jja', long_name='season', units='no_unit'),
             None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4] and
            ((len(f.lbcode) != 5) or
             (len(f.lbcode) == 5 and
              f.lbcode.ix not in [20, 21, 22, 23] and
              f.lbcode.iy not in [20, 21, 22, 23])) and
            f.lbmon == 9 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and
            f.lbmond == 12 and f.lbdatd == 1 and f.lbhrd == 0 and
            f.lbmind == 0):
        aux_coords_and_dims.append(
            (AuxCoord('son', long_name='season', units='no_unit'),
             None))

    # "Normal" (i.e. not cross-sectional) lats+lons (--> vector coordinates)
    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5 and
            f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system()),
             1))

    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5 and
            f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system(),
                                   with_bounds=True),
             1))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5 and
            f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy, f.bdy, f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()),
             0))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5 and
            f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy, f.bdy, f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system(),
                                   with_bounds=True),
             0))

    if ((f.bdy == 0.0 or f.bdy == f.bmdi) and
            (len(f.lbcode) != 5 or
             (len(f.lbcode) == 5 and f.lbcode.iy == 10))):
        dim_coords_and_dims.append(
            (DimCoord(f.y, standard_name=f._y_coord_name(), units='degrees',
                      bounds=f.y_bounds, coord_system=f.coord_system()),
             0))

    if ((f.bdx == 0.0 or f.bdx == f.bmdi) and
            (len(f.lbcode) != 5 or
             (len(f.lbcode) == 5 and f.lbcode.ix == 11))):
        dim_coords_and_dims.append(
            (DimCoord(f.x, standard_name=f._x_coord_name(),  units='degrees',
                      bounds=f.x_bounds, circular=(f.lbhem in [0, 4]),
                      coord_system=f.coord_system()),
             1))

    # Cross-sectional vertical level types (--> vector coordinates)
    if (len(f.lbcode) == 5 and f.lbcode.iy == 2 and
            (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append(
            (DimCoord(f.y, standard_name='height', units='km',
                      bounds=f.y_bounds, attributes={'positive': 'up'}),
             0))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 4):
        dim_coords_and_dims.append(
            (DimCoord(f.y, standard_name='depth', units='m',
                      bounds=f.y_bounds, attributes={'positive': 'down'}),
             0))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 10 and f.bdx != 0 and
            f.bdx != f.bmdi):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()),
             1))

    if (len(f.lbcode) == 5 and
            f.lbcode.iy == 1 and
            (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append(
            (DimCoord(f.y, long_name='pressure', units='hPa',
                      bounds=f.y_bounds),
             0))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 1 and
            (f.bdx == 0 or f.bdx == f.bmdi)):
        dim_coords_and_dims.append((DimCoord(f.x, long_name='pressure',
                                             units='hPa', bounds=f.x_bounds),
                                    1))

    # Cross-sectional time values (--> vector coordinates)
    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 23):
        dim_coords_and_dims.append(
            (DimCoord(
                f.y,
                standard_name='time',
                units=Unit('days since 0000-01-01 00:00:00',
                           calendar=iris.unit.CALENDAR_360_DAY),
                bounds=f.y_bounds),
             0))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 23):
        dim_coords_and_dims.append(
            (DimCoord(
                f.x,
                standard_name='time',
                units=Unit('days since 0000-01-01 00:00:00',
                           calendar=iris.unit.CALENDAR_360_DAY),
                bounds=f.x_bounds),
             1))

    # Site number (--> scalar coordinate)
    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 13 and
            f.bdx != 0):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt,
                                   long_name='site_number', units='1'),
             1))

    # Site number cross-sections (???)
    if (len(f.lbcode) == 5 and
            13 in [f.lbcode.ix, f.lbcode.iy] and
            11 not in [f.lbcode.ix, f.lbcode.iy] and
            hasattr(f, 'lower_x_domain') and
            hasattr(f, 'upper_x_domain') and
            all(f.lower_x_domain != -1.e+30) and
            all(f.upper_x_domain != -1.e+30)):
        aux_coords_and_dims.append(
            (AuxCoord((f.lower_x_domain + f.upper_x_domain) / 2.0,
                      standard_name=f._x_coord_name(), units='degrees',
                      bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T,
                      coord_system=f.coord_system()),
             1 if f.lbcode.ix == 13 else 0))

    if (len(f.lbcode) == 5 and
            13 in [f.lbcode.ix, f.lbcode.iy] and
            10 not in [f.lbcode.ix, f.lbcode.iy] and
            hasattr(f, 'lower_y_domain') and
            hasattr(f, 'upper_y_domain') and
            all(f.lower_y_domain != -1.e+30) and
            all(f.upper_y_domain != -1.e+30)):
        aux_coords_and_dims.append(
            (AuxCoord((f.lower_y_domain + f.upper_y_domain) / 2.0,
                      standard_name=f._y_coord_name(), units='degrees',
                      bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T,
                      coord_system=f.coord_system()),
             1 if f.lbcode.ix == 13 else 0))

    # LBPROC codings (--> cell methods + attributes)
    if f.lbproc == 128:
        method = 'mean'
    elif f.lbproc == 4096:
        method = 'minimum'
    elif f.lbproc == 8192:
        method = 'maximum'
    else:
        method = None

    if method is not None:
        if f.lbtim.ia != 0:
            intervals = '{} hour'.format(f.lbtim.ia)
        else:
            intervals = None

        if f.lbtim.ib == 2:
            # Aggregation over a period of time.
            cell_methods.append(CellMethod(method,
                                           coords='time',
                                           intervals=intervals))
        elif f.lbtim.ib == 3 and f.lbproc == 128:
            # Aggregation over a period of time within a year, over a number
            # of years.
            # Only mean (lbproc of 128) is handled as the min/max
            # interpretation is ambiguous e.g. decadal mean of daily max,
            # decadal max of daily mean, decadal mean of max daily mean etc.
            cell_methods.append(CellMethod('{} within years'.format(method),
                                           coords='time',
                                           intervals=intervals))
            cell_methods.append(CellMethod('{} over years'.format(method),
                                           coords='time'))
        else:
            # Generic cell method to indicate a time aggregation.
            cell_methods.append(CellMethod(method,
                                           coords='time'))

    if f.lbproc not in [0, 128, 4096, 8192]:
        attributes["ukmo__process_flags"] = tuple(sorted(
            [name for value, name in iris.fileformats.pp.lbproc_map.iteritems()
             if isinstance(value, int) and f.lbproc & value]))

    if (f.lbsrce % 10000) == 1111:
        attributes['source'] = 'Data from Met Office Unified Model'
        # Also define MO-netCDF compliant UM version.
        um_major = (f.lbsrce // 10000) // 100
        if um_major != 0:
            um_minor = (f.lbsrce // 10000) % 100
            attributes['um_version'] = '{:d}.{:d}'.format(um_major, um_minor)

    if (f.lbuser[6] != 0 or
            (f.lbuser[3] // 1000) != 0 or
            (f.lbuser[3] % 1000) != 0):
        attributes['STASH'] = f.stash

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if (not f.stash.is_valid and f.lbfc in LBFC_TO_CF):
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    # Orography reference field (--> reference target)
    if f.lbuser[3] == 33:
        references.append(ReferenceTarget('orography', None))

    # Surface pressure reference field (--> reference target)
    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget('surface_air_pressure', None))

    return (references, standard_name, long_name, units, attributes,
            cell_methods, dim_coords_and_dims, aux_coords_and_dims)
Exemple #3
0
def convert(f):
    factories = []
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    if \
            (f.lbtim.ia == 0) and \
            (f.lbtim.ib == 0) and \
            (f.lbtim.ic in [1, 2, 3, 4]) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        aux_coords_and_dims.append((DimCoord(f.time_unit('hours').date2num(f.t1), standard_name='time', units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ia == 0) and \
            (f.lbtim.ib == 1) and \
            (f.lbtim.ic in [1, 2, 3, 4]) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        aux_coords_and_dims.append((DimCoord(f.time_unit('hours', f.t2).date2num(f.t1), standard_name='forecast_period', units='hours'), None))
        aux_coords_and_dims.append((DimCoord(f.time_unit('hours').date2num(f.t1), standard_name='time', units=f.time_unit('hours')), None))
        aux_coords_and_dims.append((DimCoord(f.time_unit('hours').date2num(f.t2), standard_name='forecast_reference_time', units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        t_unit = f.time_unit('hours')
        t1_hours = t_unit.date2num(f.t1)
        t2_hours = t_unit.date2num(f.t2)
        period = t2_hours - t1_hours
        aux_coords_and_dims.append((
            DimCoord(standard_name='forecast_period', units='hours',
                     points=f.lbft - 0.5 * period,
                     bounds=[f.lbft - period, f.lbft]),
            None))
        aux_coords_and_dims.append((
            DimCoord(standard_name='time', units=t_unit,
                     points=0.5 * (t1_hours + t2_hours),
                     bounds=[t1_hours, t2_hours]),
            None))
        aux_coords_and_dims.append((DimCoord(f.time_unit('hours').date2num(f.t2) - f.lbft, standard_name='forecast_reference_time', units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])):
        t_unit = f.time_unit('hours')
        t1_hours = t_unit.date2num(f.t1)
        t2_hours = t_unit.date2num(f.t2)
        period = t2_hours - t1_hours
        aux_coords_and_dims.append((
            DimCoord(standard_name='forecast_period', units='hours',
                     points=f.lbft, bounds=[f.lbft - period, f.lbft]),
            None))
        aux_coords_and_dims.append((
            DimCoord(standard_name='time', units=t_unit,
                     points=t2_hours, bounds=[t1_hours, t2_hours]),
            None))
        aux_coords_and_dims.append((DimCoord(f.time_unit('hours').date2num(f.t2) - f.lbft, standard_name='forecast_reference_time', units=f.time_unit('hours')), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 12 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 3 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('djf', long_name='season', units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 3 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 6 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('mam', long_name='season', units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 6 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 9 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('jja', long_name='season', units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 9 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 12 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('son', long_name='season', units='no_unit'), None))

    if \
            (f.bdx != 0.0) and \
            (f.bdx != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 1):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, standard_name=f._x_coord_name(), units='degrees', circular=(f.lbhem in [0, 4]), coord_system=f.coord_system()), 1))

    if \
            (f.bdx != 0.0) and \
            (f.bdx != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 2):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, standard_name=f._x_coord_name(), units='degrees', circular=(f.lbhem in [0, 4]), coord_system=f.coord_system(), with_bounds=True), 1))

    if \
            (f.bdy != 0.0) and \
            (f.bdy != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 1):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzy, f.bdy, f.lbrow, standard_name=f._y_coord_name(), units='degrees', coord_system=f.coord_system()), 0))

    if \
            (f.bdy != 0.0) and \
            (f.bdy != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 2):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzy, f.bdy, f.lbrow, standard_name=f._y_coord_name(), units='degrees', coord_system=f.coord_system(), with_bounds=True), 0))

    if \
            (f.bdy == 0.0 or f.bdy == f.bmdi) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.iy == 10)):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name=f._y_coord_name(), units='degrees', bounds=f.y_bounds, coord_system=f.coord_system()), 0))

    if \
            (f.bdx == 0.0 or f.bdx == f.bmdi) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix == 11)):
        dim_coords_and_dims.append((DimCoord(f.x, standard_name=f._x_coord_name(),  units='degrees', bounds=f.x_bounds, circular=(f.lbhem in [0, 4]), coord_system=f.coord_system()), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.iy == 2) and \
            (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name='height', units='km', bounds=f.y_bounds, attributes={'positive': 'up'}), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.iy == 4):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name='depth', units='m', bounds=f.y_bounds, attributes={'positive': 'down'}), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.ix == 10) and \
            (f.bdx != 0) and \
            (f.bdx != f.bmdi):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, standard_name=f._y_coord_name(), units='degrees', coord_system=f.coord_system()), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.iy == 1) and \
            (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.y, long_name='pressure', units='hPa', bounds=f.y_bounds), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.ix == 1) and \
            (f.bdx == 0 or f.bdx == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.x, long_name='pressure', units='hPa', bounds=f.x_bounds), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.iy == 23):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name='time', units=iris.unit.Unit('days since 0000-01-01 00:00:00', calendar=iris.unit.CALENDAR_360_DAY), bounds=f.y_bounds), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.ix == 23):
        dim_coords_and_dims.append((DimCoord(f.x, standard_name='time', units=iris.unit.Unit('days since 0000-01-01 00:00:00', calendar=iris.unit.CALENDAR_360_DAY), bounds=f.x_bounds), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.ix == 13) and \
            (f.bdx != 0):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, long_name='site_number', units='1'), 1))

    if \
            (len(f.lbcode) == 5) and \
            (13 in [f.lbcode.ix, f.lbcode.iy]) and \
            (11 not in [f.lbcode.ix, f.lbcode.iy]) and \
            (hasattr(f, 'lower_x_domain')) and \
            (hasattr(f, 'upper_x_domain')) and \
            (all(f.lower_x_domain != -1.e+30)) and \
            (all(f.upper_x_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord((f.lower_x_domain + f.upper_x_domain) / 2.0, standard_name=f._x_coord_name(), units='degrees', bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T, coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    if \
            (len(f.lbcode) == 5) and \
            (13 in [f.lbcode.ix, f.lbcode.iy]) and \
            (10 not in [f.lbcode.ix, f.lbcode.iy]) and \
            (hasattr(f, 'lower_y_domain')) and \
            (hasattr(f, 'upper_y_domain')) and \
            (all(f.lower_y_domain != -1.e+30)) and \
            (all(f.upper_y_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord((f.lower_y_domain + f.upper_y_domain) / 2.0, standard_name=f._y_coord_name(), units='degrees', bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T, coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(CellMethod("mean", coords="time", intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 3):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib not in [2, 3]):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(CellMethod("minimum", coords="time", intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib != 2):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(CellMethod("maximum", coords="time", intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib != 2):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if f.lbproc not in [0, 128, 4096, 8192]:
        attributes["ukmo__process_flags"] = tuple(sorted([iris.fileformats.pp.lbproc_map[flag] for flag in f.lbproc.flags]))

    if \
            (f.lbvc == 1) and \
            (not (str(f.stash) in ['m01s03i236', 'm01s03i237', 'm01s03i245', 'm01s03i247', 'm01s03i250'])) and \
            (f.blev != -1):
        aux_coords_and_dims.append((DimCoord(f.blev, standard_name='height', units='m', attributes={'positive': 'up'}), None))

    if str(f.stash) in ['m01s03i236', 'm01s03i237', 'm01s03i245', 'm01s03i247', 'm01s03i250']:
        aux_coords_and_dims.append((DimCoord(1.5, standard_name='height', units='m', attributes={'positive': 'up'}), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 2):
        aux_coords_and_dims.append((DimCoord(_model_level_number(f), standard_name='model_level_number', attributes={'positive': 'down'}), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 2) and \
            (f.brsvd[0] == f.brlev):
        aux_coords_and_dims.append((DimCoord(f.blev, standard_name='depth', units='m', attributes={'positive': 'down'}), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 2) and \
            (f.brsvd[0] != f.brlev):
        aux_coords_and_dims.append((DimCoord(f.blev, standard_name='depth', units='m', bounds=[f.brsvd[0], f.brlev], attributes={'positive': 'down'}), None))

    # soil level
    if len(f.lbcode) != 5 and f.lbvc == 6:
        aux_coords_and_dims.append((DimCoord(_model_level_number(f), long_name='soil_model_level_number', attributes={'positive': 'down'}), None))

    if \
            (f.lbvc == 8) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and 1 not in [f.lbcode.ix, f.lbcode.iy])):
        aux_coords_and_dims.append((DimCoord(f.blev, long_name='pressure', units='hPa'), None))

    if \
            (len(f.lbcode) != 5) and \
            (f.lbvc == 19):
        aux_coords_and_dims.append((DimCoord(f.blev, standard_name='air_potential_temperature', units='K', attributes={'positive': 'up'}), None))

    # Hybrid pressure coordinate
    if f.lbvc == 9:
        model_level_number = DimCoord(_model_level_number(f),
                                      standard_name='model_level_number',
                                      attributes={'positive': 'up'})
        # The following match the hybrid height scheme, but data has the
        # blev and bhlev values the other way around.
        #level_pressure = DimCoord(f.blev,
        #                          long_name='level_pressure',
        #                          units='Pa',
        #                          bounds=[f.brlev, f.brsvd[0]])
        #sigma = AuxCoord(f.bhlev,
        #                 long_name='sigma',
        #                 bounds=[f.bhrlev, f.brsvd[1]])
        level_pressure = DimCoord(f.bhlev,
                                  long_name='level_pressure',
                                  units='Pa',
                                  bounds=[f.bhrlev, f.brsvd[1]])
        sigma = AuxCoord(f.blev,
                         long_name='sigma',
                         bounds=[f.brlev, f.brsvd[0]])
        aux_coords_and_dims.extend([(model_level_number, None),
                                    (level_pressure, None),
                                    (sigma, None)])
        factories.append(Factory(HybridPressureFactory,
                                 [{'long_name': 'level_pressure'},
                                  {'long_name': 'sigma'},
                                  Reference('surface_air_pressure')]))

    if f.lbvc == 65:
        aux_coords_and_dims.append((DimCoord(_model_level_number(f), standard_name='model_level_number', attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append((DimCoord(f.blev, long_name='level_height', units='m', bounds=[f.brlev, f.brsvd[0]], attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append((AuxCoord(f.bhlev, long_name='sigma', bounds=[f.bhrlev, f.brsvd[1]]), None))
        factories.append(Factory(HybridHeightFactory, [{'long_name': 'level_height'}, {'long_name': 'sigma'}, Reference('orography')]))

    if f.lbrsvd[3] != 0:
        aux_coords_and_dims.append((DimCoord(f.lbrsvd[3], standard_name='realization'), None))

    if f.lbuser[4] != 0:
        aux_coords_and_dims.append((DimCoord(f.lbuser[4], long_name='pseudo_level', units='1'), None))

    if f.lbuser[6] == 1 and f.lbuser[3] == 5226:
        standard_name = "precipitation_amount"
        units = "kg m-2"

    if \
            (f.lbuser[6] == 2) and \
            (f.lbuser[3] == 101):
        standard_name = "sea_water_potential_temperature"
        units = "Celsius"

    if \
            ((f.lbsrce % 10000) == 1111) and \
            ((f.lbsrce / 10000) / 100.0 > 0):
        attributes['source'] = 'Data from Met Office Unified Model %4.2f' % ((f.lbsrce / 10000) / 100.0)

    if \
            ((f.lbsrce % 10000) == 1111) and \
            ((f.lbsrce / 10000) / 100.0 == 0):
        attributes['source'] = 'Data from Met Office Unified Model'

    if f.lbuser[6] != 0 or (f.lbuser[3] / 1000) != 0 or (f.lbuser[3] % 1000) != 0:
        attributes['STASH'] = f.stash

    if \
            (f.lbuser[6] == 1) and \
            (f.lbuser[3] == 4205):
        standard_name = "mass_fraction_of_cloud_ice_in_air"
        units = "1"

    if \
            (f.lbuser[6] == 1) and \
            (f.lbuser[3] == 4206):
        standard_name = "mass_fraction_of_cloud_liquid_water_in_air"
        units = "1"

    if \
            (f.lbuser[6] == 1) and \
            (f.lbuser[3] == 30204):
        standard_name = "air_temperature"
        units = "K"

    if \
            (f.lbuser[6] == 4) and \
            (f.lbuser[3] == 6001):
        standard_name = "sea_surface_wave_significant_height"
        units = "m"

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if \
            (not f.stash.is_valid) and \
            (f.lbfc in LBFC_TO_CF):
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    if f.lbuser[3] == 33:
        references.append(ReferenceTarget('orography', None))

    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget('surface_air_pressure', None))

    return (factories, references, standard_name, long_name, units, attributes,
            cell_methods, dim_coords_and_dims, aux_coords_and_dims)
Exemple #4
0
def _all_other_rules(f):
    """
    This deals with all the other rules that have not been factored into any of
    the other convert_scalar_coordinate functions above.

    """
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # Season coordinates (--> scalar coordinates)
    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and (len(f.lbcode) != 5 or
                 (len(f.lbcode) == 5 and
                  (f.lbcode.ix not in [20, 21, 22, 23]
                   and f.lbcode.iy not in [20, 21, 22, 23]))) and f.lbmon == 12
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 3
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('djf',
                                             long_name='season',
                                             units='no_unit'), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 3
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 6
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('mam',
                                             long_name='season',
                                             units='no_unit'), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 6
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 9
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('jja',
                                             long_name='season',
                                             units='no_unit'), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 9
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0
            and f.lbmond == 12 and f.lbdatd == 1 and f.lbhrd == 0
            and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('son',
                                             long_name='season',
                                             units='no_unit'), None))

    # Special case where year is zero and months match.
    # Month coordinates (--> scalar coordinates)
    if (f.lbtim.ib == 2 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbyr == 0
            and f.lbyrd == 0 and f.lbmon == f.lbmond):
        aux_coords_and_dims.append((AuxCoord(f.lbmon,
                                             long_name='month_number'), None))
        aux_coords_and_dims.append((AuxCoord(calendar.month_abbr[f.lbmon],
                                             long_name='month',
                                             units='no_unit'), None))
        aux_coords_and_dims.append((DimCoord(points=f.lbft,
                                             standard_name='forecast_period',
                                             units='hours'), None))

    # "Normal" (i.e. not cross-sectional) lats+lons (--> vector coordinates)
    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system()), 1))

    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system(),
                                   with_bounds=True), 1))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy,
                                   f.bdy,
                                   f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()), 0))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy,
                                   f.bdy,
                                   f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system(),
                                   with_bounds=True), 0))

    if ((f.bdy == 0.0 or f.bdy == f.bmdi) and
        (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.iy == 10))):
        dim_coords_and_dims.append(
            (DimCoord(f.y,
                      standard_name=f._y_coord_name(),
                      units='degrees',
                      bounds=f.y_bounds,
                      coord_system=f.coord_system()), 0))

    if ((f.bdx == 0.0 or f.bdx == f.bmdi) and
        (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix == 11))):
        dim_coords_and_dims.append(
            (DimCoord(f.x,
                      standard_name=f._x_coord_name(),
                      units='degrees',
                      bounds=f.x_bounds,
                      circular=(f.lbhem in [0, 4]),
                      coord_system=f.coord_system()), 1))

    # Cross-sectional vertical level types (--> vector coordinates)
    if (len(f.lbcode) == 5 and f.lbcode.iy == 2
            and (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             standard_name='height',
                                             units='km',
                                             bounds=f.y_bounds,
                                             attributes={'positive':
                                                         'up'}), 0))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 4):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             standard_name='depth',
                                             units='m',
                                             bounds=f.y_bounds,
                                             attributes={'positive':
                                                         'down'}), 0))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 10 and f.bdx != 0
            and f.bdx != f.bmdi):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()), 1))

    if (len(f.lbcode) == 5 and f.lbcode.iy == 1
            and (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             long_name='pressure',
                                             units='hPa',
                                             bounds=f.y_bounds), 0))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 1
            and (f.bdx == 0 or f.bdx == f.bmdi)):
        dim_coords_and_dims.append((DimCoord(f.x,
                                             long_name='pressure',
                                             units='hPa',
                                             bounds=f.x_bounds), 1))

    # Cross-sectional time values (--> vector coordinates)
    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 23):
        dim_coords_and_dims.append(
            (DimCoord(f.y,
                      standard_name='time',
                      units=cf_units.Unit('days since 0000-01-01 00:00:00',
                                          calendar=cf_units.CALENDAR_360_DAY),
                      bounds=f.y_bounds), 0))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 23):
        dim_coords_and_dims.append(
            (DimCoord(f.x,
                      standard_name='time',
                      units=cf_units.Unit('days since 0000-01-01 00:00:00',
                                          calendar=cf_units.CALENDAR_360_DAY),
                      bounds=f.x_bounds), 1))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 3 and f.lbcode.iy == 23
            and f.lbtim.ib == 2 and f.lbtim.ic == 2):
        epoch_days_unit = cf_units.Unit('days since 0000-01-01 00:00:00',
                                        calendar=cf_units.CALENDAR_360_DAY)
        t1_epoch_days = epoch_days_unit.date2num(f.t1)
        t2_epoch_days = epoch_days_unit.date2num(f.t2)
        # The end time is exclusive, not inclusive.
        dim_coords_and_dims.append((DimCoord(np.linspace(t1_epoch_days,
                                                         t2_epoch_days,
                                                         f.lbrow,
                                                         endpoint=False),
                                             standard_name='time',
                                             units=epoch_days_unit,
                                             bounds=f.y_bounds), 0))

    # Site number (--> scalar coordinate)
    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 13
            and f.bdx != 0):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   long_name='site_number',
                                   units='1'), 1))

    # Site number cross-sections (???)
    if (len(f.lbcode) == 5 and 13 in [f.lbcode.ix, f.lbcode.iy]
            and 11 not in [f.lbcode.ix, f.lbcode.iy]
            and hasattr(f, 'lower_x_domain') and hasattr(f, 'upper_x_domain')
            and all(f.lower_x_domain != -1.e+30)
            and all(f.upper_x_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord(
            (f.lower_x_domain + f.upper_x_domain) / 2.0,
            standard_name=f._x_coord_name(),
            units='degrees',
            bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T,
            coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    if (len(f.lbcode) == 5 and 13 in [f.lbcode.ix, f.lbcode.iy]
            and 10 not in [f.lbcode.ix, f.lbcode.iy]
            and hasattr(f, 'lower_y_domain') and hasattr(f, 'upper_y_domain')
            and all(f.lower_y_domain != -1.e+30)
            and all(f.upper_y_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord(
            (f.lower_y_domain + f.upper_y_domain) / 2.0,
            standard_name=f._y_coord_name(),
            units='degrees',
            bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T,
            coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    # LBPROC codings (--> cell method + attributes)
    unhandled_lbproc = True
    zone_method = None
    time_method = None
    if f.lbproc == 0:
        unhandled_lbproc = False
    elif f.lbproc == 64:
        zone_method = 'mean'
    elif f.lbproc == 128:
        time_method = 'mean'
    elif f.lbproc == 4096:
        time_method = 'minimum'
    elif f.lbproc == 8192:
        time_method = 'maximum'
    elif f.lbproc == 192:
        time_method = 'mean'
        zone_method = 'mean'

    if time_method is not None:
        if f.lbtim.ia != 0:
            intervals = '{} hour'.format(f.lbtim.ia)
        else:
            intervals = None

        if f.lbtim.ib == 2:
            # Aggregation over a period of time.
            cell_methods.append(
                CellMethod(time_method, coords='time', intervals=intervals))
            unhandled_lbproc = False
        elif f.lbtim.ib == 3 and f.lbproc == 128:
            # Aggregation over a period of time within a year, over a number
            # of years.
            # Only mean (lbproc of 128) is handled as the min/max
            # interpretation is ambiguous e.g. decadal mean of daily max,
            # decadal max of daily mean, decadal mean of max daily mean etc.
            cell_methods.append(
                CellMethod('{} within years'.format(time_method),
                           coords='time',
                           intervals=intervals))
            cell_methods.append(
                CellMethod('{} over years'.format(time_method), coords='time'))
            unhandled_lbproc = False
        else:
            # Generic cell method to indicate a time aggregation.
            cell_methods.append(CellMethod(time_method, coords='time'))
            unhandled_lbproc = False

    if zone_method is not None:
        if f.lbcode == 1:
            cell_methods.append(CellMethod(zone_method, coords='longitude'))
            unhandled_lbproc = False
        elif f.lbcode == 101:
            cell_methods.append(
                CellMethod(zone_method, coords='grid_longitude'))
            unhandled_lbproc = False
        else:
            unhandled_lbproc = True

    if unhandled_lbproc:
        attributes["ukmo__process_flags"] = tuple(
            sorted([
                name for value, name in six.iteritems(
                    iris.fileformats.pp.lbproc_map)
                if isinstance(value, int) and f.lbproc & value
            ]))

    if (f.lbsrce % 10000) == 1111:
        attributes['source'] = 'Data from Met Office Unified Model'
        # Also define MO-netCDF compliant UM version.
        um_major = (f.lbsrce // 10000) // 100
        if um_major != 0:
            um_minor = (f.lbsrce // 10000) % 100
            attributes['um_version'] = '{:d}.{:d}'.format(um_major, um_minor)

    if (f.lbuser[6] != 0 or (f.lbuser[3] // 1000) != 0
            or (f.lbuser[3] % 1000) != 0):
        attributes['STASH'] = f.stash

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if (not f.stash.is_valid and f.lbfc in LBFC_TO_CF):
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    # Orography reference field (--> reference target)
    if f.lbuser[3] == 33:
        references.append(ReferenceTarget('orography', None))

    # Surface pressure reference field (--> reference target)
    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget('surface_air_pressure', None))

    return (references, standard_name, long_name, units, attributes,
            cell_methods, dim_coords_and_dims, aux_coords_and_dims)
Exemple #5
0
def convert(f):
    factories = []
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # "Normal" (non-cross-sectional) Time values (--> scalar coordinates)
    time_coords_and_dims = _convert_scalar_time_coords(
        lbcode=f.lbcode, lbtim=f.lbtim,
        epoch_hours_unit=f.time_unit('hours'),
        t1=f.t1, t2=f.t2, lbft=f.lbft)
    aux_coords_and_dims.extend(time_coords_and_dims)

    # Season coordinates (--> scalar coordinates)
    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 12 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 3 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('djf', long_name='season', units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 3 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 6 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('mam', long_name='season', units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 6 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 9 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('jja', long_name='season', units='no_unit'), None))

    if \
            (f.lbtim.ib == 3) and \
            (f.lbtim.ic in [1, 2, 4]) and \
            ((len(f.lbcode) != 5) or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])) and \
            (f.lbmon == 9 and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0) and \
            (f.lbmond == 12 and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('son', long_name='season', units='no_unit'), None))

    # "Normal" (i.e. not cross-sectional) lats+lons (--> vector coordinates)
    if \
            (f.bdx != 0.0) and \
            (f.bdx != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 1):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, standard_name=f._x_coord_name(), units='degrees', circular=(f.lbhem in [0, 4]), coord_system=f.coord_system()), 1))

    if \
            (f.bdx != 0.0) and \
            (f.bdx != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 2):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, standard_name=f._x_coord_name(), units='degrees', circular=(f.lbhem in [0, 4]), coord_system=f.coord_system(), with_bounds=True), 1))

    if \
            (f.bdy != 0.0) and \
            (f.bdy != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 1):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzy, f.bdy, f.lbrow, standard_name=f._y_coord_name(), units='degrees', coord_system=f.coord_system()), 0))

    if \
            (f.bdy != 0.0) and \
            (f.bdy != f.bmdi) and \
            (len(f.lbcode) != 5) and \
            (f.lbcode[0] == 2):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzy, f.bdy, f.lbrow, standard_name=f._y_coord_name(), units='degrees', coord_system=f.coord_system(), with_bounds=True), 0))

    if \
            (f.bdy == 0.0 or f.bdy == f.bmdi) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.iy == 10)):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name=f._y_coord_name(), units='degrees', bounds=f.y_bounds, coord_system=f.coord_system()), 0))

    if \
            (f.bdx == 0.0 or f.bdx == f.bmdi) and \
            (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix == 11)):
        dim_coords_and_dims.append((DimCoord(f.x, standard_name=f._x_coord_name(),  units='degrees', bounds=f.x_bounds, circular=(f.lbhem in [0, 4]), coord_system=f.coord_system()), 1))

    # Cross-sectional vertical level types (--> vector coordinates)
    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.iy == 2) and \
            (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name='height', units='km', bounds=f.y_bounds, attributes={'positive': 'up'}), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.iy == 4):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name='depth', units='m', bounds=f.y_bounds, attributes={'positive': 'down'}), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.ix == 10) and \
            (f.bdx != 0) and \
            (f.bdx != f.bmdi):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, standard_name=f._y_coord_name(), units='degrees', coord_system=f.coord_system()), 1))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.iy == 1) and \
            (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.y, long_name='pressure', units='hPa', bounds=f.y_bounds), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode.ix == 1) and \
            (f.bdx == 0 or f.bdx == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.x, long_name='pressure', units='hPa', bounds=f.x_bounds), 1))

    # Cross-sectional time values (--> vector coordinates)
    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.iy == 23):
        dim_coords_and_dims.append((DimCoord(f.y, standard_name='time', units=iris.unit.Unit('days since 0000-01-01 00:00:00', calendar=iris.unit.CALENDAR_360_DAY), bounds=f.y_bounds), 0))

    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.ix == 23):
        dim_coords_and_dims.append((DimCoord(f.x, standard_name='time', units=iris.unit.Unit('days since 0000-01-01 00:00:00', calendar=iris.unit.CALENDAR_360_DAY), bounds=f.x_bounds), 1))

    # Site number (--> scalar coordinate)
    if \
            (len(f.lbcode) == 5) and \
            (f.lbcode[-1] == 1) and \
            (f.lbcode.ix == 13) and \
            (f.bdx != 0):
        dim_coords_and_dims.append((DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, long_name='site_number', units='1'), 1))

    # Site number cross-sections (???)
    if \
            (len(f.lbcode) == 5) and \
            (13 in [f.lbcode.ix, f.lbcode.iy]) and \
            (11 not in [f.lbcode.ix, f.lbcode.iy]) and \
            (hasattr(f, 'lower_x_domain')) and \
            (hasattr(f, 'upper_x_domain')) and \
            (all(f.lower_x_domain != -1.e+30)) and \
            (all(f.upper_x_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord((f.lower_x_domain + f.upper_x_domain) / 2.0, standard_name=f._x_coord_name(), units='degrees', bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T, coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    if \
            (len(f.lbcode) == 5) and \
            (13 in [f.lbcode.ix, f.lbcode.iy]) and \
            (10 not in [f.lbcode.ix, f.lbcode.iy]) and \
            (hasattr(f, 'lower_y_domain')) and \
            (hasattr(f, 'upper_y_domain')) and \
            (all(f.lower_y_domain != -1.e+30)) and \
            (all(f.upper_y_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord((f.lower_y_domain + f.upper_y_domain) / 2.0, standard_name=f._y_coord_name(), units='degrees', bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T, coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    # LBPROC codings (--> cell methods + attributes)
    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(CellMethod("mean", coords="time", intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib == 3):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 128) and \
            (f.lbtim.ib not in [2, 3]):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(CellMethod("minimum", coords="time", intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 4096) and \
            (f.lbtim.ib != 2):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia == 0):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib == 2) and \
            (f.lbtim.ia != 0):
        cell_methods.append(CellMethod("maximum", coords="time", intervals="%d hour" % f.lbtim.ia))

    if \
            (f.lbproc == 8192) and \
            (f.lbtim.ib != 2):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if f.lbproc not in [0, 128, 4096, 8192]:
        attributes["ukmo__process_flags"] = tuple(sorted([iris.fileformats.pp.lbproc_map[flag] for flag in f.lbproc.flags]))

    # "Normal" (non-cross-sectional) Vertical levels
    #    (--> scalar coordinates and factories)
    vertical_coords_and_dims, vertical_factories = \
        _convert_scalar_vertical_coords(
            lbcode=f.lbcode,
            lbvc=f.lbvc,
            blev=f.blev,
            lblev=f.lblev,
            stash=f.stash,
            bhlev=f.bhlev,
            bhrlev=f.bhrlev,
            brsvd1=f.brsvd[0],
            brsvd2=f.brsvd[1],
            brlev=f.brlev)
    aux_coords_and_dims.extend(vertical_coords_and_dims)
    factories.extend(vertical_factories)

    # Realization (aka ensemble) (--> scalar coordinates)
    aux_coords_and_dims.extend(_convert_scalar_realization_coords(
        lbrsvd4=f.lbrsvd[3]))

    # Pseudo-level coordinate (--> scalar coordinates)
    aux_coords_and_dims.extend(_convert_scalar_pseudo_level_coords(
        lbuser5=f.lbuser[4]))

    if (f.lbsrce % 10000) == 1111:
        attributes['source'] = 'Data from Met Office Unified Model'
        # Also define MO-netCDF compliant UM version.
        um_major = (f.lbsrce / 10000) / 100
        if um_major != 0:
            um_minor = (f.lbsrce / 10000) % 100
            attributes['um_version'] = '{:d}.{:d}'.format(um_major, um_minor)

    if f.lbuser[6] != 0 or (f.lbuser[3] / 1000) != 0 or (f.lbuser[3] % 1000) != 0:
        attributes['STASH'] = f.stash

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if \
            (not f.stash.is_valid) and \
            (f.lbfc in LBFC_TO_CF):
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    # Orography reference field (--> reference target)
    if f.lbuser[3] == 33:
        references.append(ReferenceTarget('orography', None))

    # Surface pressure reference field (--> reference target)
    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget('surface_air_pressure', None))

    return (factories, references, standard_name, long_name, units, attributes,
            cell_methods, dim_coords_and_dims, aux_coords_and_dims)
Exemple #6
0
 def axis_coordinates(self):
     """Create iris DimCoord suitable for building a cube."""
     return DimCoord.from_regular(**self.__dict__)
Exemple #7
0
def _all_other_rules(f):
    """
    This deals with all the other rules that have not been factored into any of
    the other convert_scalar_coordinate functions above.

    """
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # Season coordinates (--> scalar coordinates)
    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            len(f.lbcode) != 5
            or (
                len(f.lbcode) == 5
                and (
                    f.lbcode.ix not in [20, 21, 22, 23]
                    and f.lbcode.iy not in [20, 21, 22, 23]
                )
            )
        )
        and f.lbmon == 12
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 3
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append(
            (AuxCoord("djf", long_name="season", units="no_unit"), None)
        )

    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (
                len(f.lbcode) == 5
                and f.lbcode.ix not in [20, 21, 22, 23]
                and f.lbcode.iy not in [20, 21, 22, 23]
            )
        )
        and f.lbmon == 3
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 6
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append(
            (AuxCoord("mam", long_name="season", units="no_unit"), None)
        )

    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (
                len(f.lbcode) == 5
                and f.lbcode.ix not in [20, 21, 22, 23]
                and f.lbcode.iy not in [20, 21, 22, 23]
            )
        )
        and f.lbmon == 6
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 9
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append(
            (AuxCoord("jja", long_name="season", units="no_unit"), None)
        )

    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (
                len(f.lbcode) == 5
                and f.lbcode.ix not in [20, 21, 22, 23]
                and f.lbcode.iy not in [20, 21, 22, 23]
            )
        )
        and f.lbmon == 9
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 12
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append(
            (AuxCoord("son", long_name="season", units="no_unit"), None)
        )

    # Special case where year is zero and months match.
    # Month coordinates (--> scalar coordinates)
    if (
        f.lbtim.ib == 2
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (
                len(f.lbcode) == 5
                and f.lbcode.ix not in [20, 21, 22, 23]
                and f.lbcode.iy not in [20, 21, 22, 23]
            )
        )
        and f.lbyr == 0
        and f.lbyrd == 0
        and f.lbmon == f.lbmond
    ):
        aux_coords_and_dims.append(
            (AuxCoord(f.lbmon, long_name="month_number"), None)
        )
        aux_coords_and_dims.append(
            (
                AuxCoord(
                    calendar.month_abbr[f.lbmon],
                    long_name="month",
                    units="no_unit",
                ),
                None,
            )
        )
        aux_coords_and_dims.append(
            (
                DimCoord(
                    points=f.lbft,
                    standard_name="forecast_period",
                    units="hours",
                ),
                None,
            )
        )

    # "Normal" (i.e. not cross-sectional) lats+lons (--> vector coordinates)
    if (
        f.bdx != 0.0
        and f.bdx != f.bmdi
        and len(f.lbcode) != 5
        and f.lbcode[0] == 1
    ):
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzx,
                    f.bdx,
                    f.lbnpt,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    circular=(f.lbhem in [0, 4]),
                    coord_system=f.coord_system(),
                ),
                1,
            )
        )

    if (
        f.bdx != 0.0
        and f.bdx != f.bmdi
        and len(f.lbcode) != 5
        and f.lbcode[0] == 2
    ):
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzx,
                    f.bdx,
                    f.lbnpt,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    circular=(f.lbhem in [0, 4]),
                    coord_system=f.coord_system(),
                    with_bounds=True,
                ),
                1,
            )
        )

    if (
        f.bdy != 0.0
        and f.bdy != f.bmdi
        and len(f.lbcode) != 5
        and f.lbcode[0] == 1
    ):
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzy,
                    f.bdy,
                    f.lbrow,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    coord_system=f.coord_system(),
                ),
                0,
            )
        )

    if (
        f.bdy != 0.0
        and f.bdy != f.bmdi
        and len(f.lbcode) != 5
        and f.lbcode[0] == 2
    ):
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzy,
                    f.bdy,
                    f.lbrow,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    coord_system=f.coord_system(),
                    with_bounds=True,
                ),
                0,
            )
        )

    if (f.bdy == 0.0 or f.bdy == f.bmdi) and (
        len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.iy == 10)
    ):
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.y,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    bounds=f.y_bounds,
                    coord_system=f.coord_system(),
                ),
                0,
            )
        )

    if (f.bdx == 0.0 or f.bdx == f.bmdi) and (
        len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix == 11)
    ):
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.x,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    bounds=f.x_bounds,
                    circular=(f.lbhem in [0, 4]),
                    coord_system=f.coord_system(),
                ),
                1,
            )
        )

    # Cross-sectional vertical level types (--> vector coordinates)
    if (
        len(f.lbcode) == 5
        and f.lbcode.iy == 2
        and (f.bdy == 0 or f.bdy == f.bmdi)
    ):
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.y,
                    standard_name="height",
                    units="km",
                    bounds=f.y_bounds,
                    attributes={"positive": "up"},
                ),
                0,
            )
        )

    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 4:
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.y,
                    standard_name="depth",
                    units="m",
                    bounds=f.y_bounds,
                    attributes={"positive": "down"},
                ),
                0,
            )
        )

    if (
        len(f.lbcode) == 5
        and f.lbcode.ix == 10
        and f.bdx != 0
        and f.bdx != f.bmdi
    ):
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzx,
                    f.bdx,
                    f.lbnpt,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    coord_system=f.coord_system(),
                ),
                1,
            )
        )

    if (
        len(f.lbcode) == 5
        and f.lbcode.iy == 1
        and (f.bdy == 0 or f.bdy == f.bmdi)
    ):
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.y, long_name="pressure", units="hPa", bounds=f.y_bounds
                ),
                0,
            )
        )

    if (
        len(f.lbcode) == 5
        and f.lbcode.ix == 1
        and (f.bdx == 0 or f.bdx == f.bmdi)
    ):
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.x, long_name="pressure", units="hPa", bounds=f.x_bounds
                ),
                1,
            )
        )

    # Cross-sectional time values (--> vector coordinates)
    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 23:
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.y,
                    standard_name="time",
                    units=cf_units.Unit(
                        "days since 0000-01-01 00:00:00",
                        calendar=cf_units.CALENDAR_360_DAY,
                    ),
                    bounds=f.y_bounds,
                ),
                0,
            )
        )

    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 23:
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.x,
                    standard_name="time",
                    units=cf_units.Unit(
                        "days since 0000-01-01 00:00:00",
                        calendar=cf_units.CALENDAR_360_DAY,
                    ),
                    bounds=f.x_bounds,
                ),
                1,
            )
        )

    if (
        len(f.lbcode) == 5
        and f.lbcode[-1] == 3
        and f.lbcode.iy == 23
        and f.lbtim.ib == 2
        and f.lbtim.ic == 2
    ):
        epoch_days_unit = cf_units.Unit(
            "days since 0000-01-01 00:00:00",
            calendar=cf_units.CALENDAR_360_DAY,
        )
        t1_epoch_days = epoch_days_unit.date2num(f.t1)
        t2_epoch_days = epoch_days_unit.date2num(f.t2)
        # The end time is exclusive, not inclusive.
        dim_coords_and_dims.append(
            (
                DimCoord(
                    np.linspace(
                        t1_epoch_days, t2_epoch_days, f.lbrow, endpoint=False
                    ),
                    standard_name="time",
                    units=epoch_days_unit,
                    bounds=f.y_bounds,
                ),
                0,
            )
        )

    # Site number (--> scalar coordinate)
    if (
        len(f.lbcode) == 5
        and f.lbcode[-1] == 1
        and f.lbcode.ix == 13
        and f.bdx != 0
    ):
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzx, f.bdx, f.lbnpt, long_name="site_number", units="1"
                ),
                1,
            )
        )

    # Site number cross-sections (???)
    if (
        len(f.lbcode) == 5
        and 13 in [f.lbcode.ix, f.lbcode.iy]
        and 11 not in [f.lbcode.ix, f.lbcode.iy]
        and hasattr(f, "lower_x_domain")
        and hasattr(f, "upper_x_domain")
        and all(f.lower_x_domain != -1.0e30)
        and all(f.upper_x_domain != -1.0e30)
    ):
        aux_coords_and_dims.append(
            (
                AuxCoord(
                    (f.lower_x_domain + f.upper_x_domain) / 2.0,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T,
                    coord_system=f.coord_system(),
                ),
                1 if f.lbcode.ix == 13 else 0,
            )
        )

    if (
        len(f.lbcode) == 5
        and 13 in [f.lbcode.ix, f.lbcode.iy]
        and 10 not in [f.lbcode.ix, f.lbcode.iy]
        and hasattr(f, "lower_y_domain")
        and hasattr(f, "upper_y_domain")
        and all(f.lower_y_domain != -1.0e30)
        and all(f.upper_y_domain != -1.0e30)
    ):
        aux_coords_and_dims.append(
            (
                AuxCoord(
                    (f.lower_y_domain + f.upper_y_domain) / 2.0,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T,
                    coord_system=f.coord_system(),
                ),
                1 if f.lbcode.ix == 13 else 0,
            )
        )

    # LBPROC codings (--> cell method + attributes)
    unhandled_lbproc = True
    zone_method = None
    time_method = None
    if f.lbproc == 0:
        unhandled_lbproc = False
    elif f.lbproc == 64:
        zone_method = "mean"
    elif f.lbproc == 128:
        time_method = "mean"
    elif f.lbproc == 4096:
        time_method = "minimum"
    elif f.lbproc == 8192:
        time_method = "maximum"
    elif f.lbproc == 192:
        time_method = "mean"
        zone_method = "mean"

    if time_method is not None:
        if f.lbtim.ia != 0:
            intervals = "{} hour".format(f.lbtim.ia)
        else:
            intervals = None

        if f.lbtim.ib == 2:
            # Aggregation over a period of time.
            cell_methods.append(
                CellMethod(time_method, coords="time", intervals=intervals)
            )
            unhandled_lbproc = False
        elif f.lbtim.ib == 3 and f.lbproc == 128:
            # Aggregation over a period of time within a year, over a number
            # of years.
            # Only mean (lbproc of 128) is handled as the min/max
            # interpretation is ambiguous e.g. decadal mean of daily max,
            # decadal max of daily mean, decadal mean of max daily mean etc.
            cell_methods.append(
                CellMethod(
                    "{} within years".format(time_method),
                    coords="time",
                    intervals=intervals,
                )
            )
            cell_methods.append(
                CellMethod("{} over years".format(time_method), coords="time")
            )
            unhandled_lbproc = False
        else:
            # Generic cell method to indicate a time aggregation.
            cell_methods.append(CellMethod(time_method, coords="time"))
            unhandled_lbproc = False

    if zone_method is not None:
        if f.lbcode == 1:
            cell_methods.append(CellMethod(zone_method, coords="longitude"))
            for coord, _dim in dim_coords_and_dims:
                if coord.standard_name == "longitude":
                    if len(coord.points) == 1:
                        coord.bounds = np.array([0.0, 360.0], dtype=np.float32)
                    else:
                        coord.guess_bounds()
            unhandled_lbproc = False
        elif f.lbcode == 101:
            cell_methods.append(
                CellMethod(zone_method, coords="grid_longitude")
            )
            for coord, _dim in dim_coords_and_dims:
                if coord.standard_name == "grid_longitude":
                    if len(coord.points) == 1:
                        coord.bounds = np.array([0.0, 360.0], dtype=np.float32)
                    else:
                        coord.guess_bounds()
            unhandled_lbproc = False
        else:
            unhandled_lbproc = True

    if unhandled_lbproc:
        attributes["ukmo__process_flags"] = tuple(
            sorted(
                [
                    name
                    for value, name in LBPROC_MAP.items()
                    if isinstance(value, int) and f.lbproc & value
                ]
            )
        )

    if (f.lbsrce % 10000) == 1111:
        attributes["source"] = "Data from Met Office Unified Model"
        # Also define MO-netCDF compliant UM version.
        um_major = (f.lbsrce // 10000) // 100
        if um_major != 0:
            um_minor = (f.lbsrce // 10000) % 100
            attributes["um_version"] = "{:d}.{:d}".format(um_major, um_minor)

    if (
        f.lbuser[6] != 0
        or (f.lbuser[3] // 1000) != 0
        or (f.lbuser[3] % 1000) != 0
    ):
        attributes["STASH"] = f.stash

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if not f.stash.is_valid and f.lbfc in LBFC_TO_CF:
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    # Orography reference field (--> reference target)
    if f.lbuser[3] == 33:
        references.append(ReferenceTarget("orography", None))

    # Surface pressure reference field (--> reference target)
    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget("surface_air_pressure", None))

    return (
        references,
        standard_name,
        long_name,
        units,
        attributes,
        cell_methods,
        dim_coords_and_dims,
        aux_coords_and_dims,
    )
Exemple #8
0
def _all_other_rules(f):
    """
    This deals with all the other rules that have not been factored into any of
    the other convert_scalar_coordinate functions above.

    """
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # Season coordinates (--> scalar coordinates)
    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            len(f.lbcode) != 5
            or (len(f.lbcode) == 5 and (f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23]))
        )
        and f.lbmon == 12
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 3
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append((AuxCoord("djf", long_name="season", units="no_unit"), None))

    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])
        )
        and f.lbmon == 3
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 6
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append((AuxCoord("mam", long_name="season", units="no_unit"), None))

    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])
        )
        and f.lbmon == 6
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 9
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append((AuxCoord("jja", long_name="season", units="no_unit"), None))

    if (
        f.lbtim.ib == 3
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])
        )
        and f.lbmon == 9
        and f.lbdat == 1
        and f.lbhr == 0
        and f.lbmin == 0
        and f.lbmond == 12
        and f.lbdatd == 1
        and f.lbhrd == 0
        and f.lbmind == 0
    ):
        aux_coords_and_dims.append((AuxCoord("son", long_name="season", units="no_unit"), None))

    # Special case where year is zero and months match.
    # Month coordinates (--> scalar coordinates)
    if (
        f.lbtim.ib == 2
        and f.lbtim.ic in [1, 2, 4]
        and (
            (len(f.lbcode) != 5)
            or (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23] and f.lbcode.iy not in [20, 21, 22, 23])
        )
        and f.lbyr == 0
        and f.lbyrd == 0
        and f.lbmon == f.lbmond
    ):
        aux_coords_and_dims.append((AuxCoord(f.lbmon, long_name="month_number"), None))
        aux_coords_and_dims.append((AuxCoord(calendar.month_abbr[f.lbmon], long_name="month", units="no_unit"), None))
        aux_coords_and_dims.append((DimCoord(points=f.lbft, standard_name="forecast_period", units="hours"), None))

    # "Normal" (i.e. not cross-sectional) lats+lons (--> vector coordinates)
    if f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5 and f.lbcode[0] == 1:
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzx,
                    f.bdx,
                    f.lbnpt,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    circular=(f.lbhem in [0, 4]),
                    coord_system=f.coord_system(),
                ),
                1,
            )
        )

    if f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5 and f.lbcode[0] == 2:
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzx,
                    f.bdx,
                    f.lbnpt,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    circular=(f.lbhem in [0, 4]),
                    coord_system=f.coord_system(),
                    with_bounds=True,
                ),
                1,
            )
        )

    if f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5 and f.lbcode[0] == 1:
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzy,
                    f.bdy,
                    f.lbrow,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    coord_system=f.coord_system(),
                ),
                0,
            )
        )

    if f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5 and f.lbcode[0] == 2:
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzy,
                    f.bdy,
                    f.lbrow,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    coord_system=f.coord_system(),
                    with_bounds=True,
                ),
                0,
            )
        )

    if (f.bdy == 0.0 or f.bdy == f.bmdi) and (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.iy == 10)):
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.y,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    bounds=f.y_bounds,
                    coord_system=f.coord_system(),
                ),
                0,
            )
        )

    if (f.bdx == 0.0 or f.bdx == f.bmdi) and (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix == 11)):
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.x,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    bounds=f.x_bounds,
                    circular=(f.lbhem in [0, 4]),
                    coord_system=f.coord_system(),
                ),
                1,
            )
        )

    # Cross-sectional vertical level types (--> vector coordinates)
    if len(f.lbcode) == 5 and f.lbcode.iy == 2 and (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append(
            (DimCoord(f.y, standard_name="height", units="km", bounds=f.y_bounds, attributes={"positive": "up"}), 0)
        )

    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 4:
        dim_coords_and_dims.append(
            (DimCoord(f.y, standard_name="depth", units="m", bounds=f.y_bounds, attributes={"positive": "down"}), 0)
        )

    if len(f.lbcode) == 5 and f.lbcode.ix == 10 and f.bdx != 0 and f.bdx != f.bmdi:
        dim_coords_and_dims.append(
            (
                DimCoord.from_regular(
                    f.bzx,
                    f.bdx,
                    f.lbnpt,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    coord_system=f.coord_system(),
                ),
                1,
            )
        )

    if len(f.lbcode) == 5 and f.lbcode.iy == 1 and (f.bdy == 0 or f.bdy == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.y, long_name="pressure", units="hPa", bounds=f.y_bounds), 0))

    if len(f.lbcode) == 5 and f.lbcode.ix == 1 and (f.bdx == 0 or f.bdx == f.bmdi):
        dim_coords_and_dims.append((DimCoord(f.x, long_name="pressure", units="hPa", bounds=f.x_bounds), 1))

    # Cross-sectional time values (--> vector coordinates)
    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 23:
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.y,
                    standard_name="time",
                    units=cf_units.Unit("days since 0000-01-01 00:00:00", calendar=cf_units.CALENDAR_360_DAY),
                    bounds=f.y_bounds,
                ),
                0,
            )
        )

    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 23:
        dim_coords_and_dims.append(
            (
                DimCoord(
                    f.x,
                    standard_name="time",
                    units=cf_units.Unit("days since 0000-01-01 00:00:00", calendar=cf_units.CALENDAR_360_DAY),
                    bounds=f.x_bounds,
                ),
                1,
            )
        )

    if len(f.lbcode) == 5 and f.lbcode[-1] == 3 and f.lbcode.iy == 23 and f.lbtim.ib == 2 and f.lbtim.ic == 2:
        epoch_days_unit = cf_units.Unit("days since 0000-01-01 00:00:00", calendar=cf_units.CALENDAR_360_DAY)
        t1_epoch_days = epoch_days_unit.date2num(f.t1)
        t2_epoch_days = epoch_days_unit.date2num(f.t2)
        # The end time is exclusive, not inclusive.
        dim_coords_and_dims.append(
            (
                DimCoord(
                    np.linspace(t1_epoch_days, t2_epoch_days, f.lbrow, endpoint=False),
                    standard_name="time",
                    units=epoch_days_unit,
                    bounds=f.y_bounds,
                ),
                0,
            )
        )

    # Site number (--> scalar coordinate)
    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 13 and f.bdx != 0:
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx, f.bdx, f.lbnpt, long_name="site_number", units="1"), 1)
        )

    # Site number cross-sections (???)
    if (
        len(f.lbcode) == 5
        and 13 in [f.lbcode.ix, f.lbcode.iy]
        and 11 not in [f.lbcode.ix, f.lbcode.iy]
        and hasattr(f, "lower_x_domain")
        and hasattr(f, "upper_x_domain")
        and all(f.lower_x_domain != -1.0e30)
        and all(f.upper_x_domain != -1.0e30)
    ):
        aux_coords_and_dims.append(
            (
                AuxCoord(
                    (f.lower_x_domain + f.upper_x_domain) / 2.0,
                    standard_name=f._x_coord_name(),
                    units="degrees",
                    bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T,
                    coord_system=f.coord_system(),
                ),
                1 if f.lbcode.ix == 13 else 0,
            )
        )

    if (
        len(f.lbcode) == 5
        and 13 in [f.lbcode.ix, f.lbcode.iy]
        and 10 not in [f.lbcode.ix, f.lbcode.iy]
        and hasattr(f, "lower_y_domain")
        and hasattr(f, "upper_y_domain")
        and all(f.lower_y_domain != -1.0e30)
        and all(f.upper_y_domain != -1.0e30)
    ):
        aux_coords_and_dims.append(
            (
                AuxCoord(
                    (f.lower_y_domain + f.upper_y_domain) / 2.0,
                    standard_name=f._y_coord_name(),
                    units="degrees",
                    bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T,
                    coord_system=f.coord_system(),
                ),
                1 if f.lbcode.ix == 13 else 0,
            )
        )

    # LBPROC codings (--> cell method + attributes)
    unhandled_lbproc = True
    zone_method = None
    time_method = None
    if f.lbproc == 0:
        unhandled_lbproc = False
    elif f.lbproc == 64:
        zone_method = "mean"
    elif f.lbproc == 128:
        time_method = "mean"
    elif f.lbproc == 4096:
        time_method = "minimum"
    elif f.lbproc == 8192:
        time_method = "maximum"
    elif f.lbproc == 192:
        time_method = "mean"
        zone_method = "mean"

    if time_method is not None:
        if f.lbtim.ia != 0:
            intervals = "{} hour".format(f.lbtim.ia)
        else:
            intervals = None

        if f.lbtim.ib == 2:
            # Aggregation over a period of time.
            cell_methods.append(CellMethod(time_method, coords="time", intervals=intervals))
            unhandled_lbproc = False
        elif f.lbtim.ib == 3 and f.lbproc == 128:
            # Aggregation over a period of time within a year, over a number
            # of years.
            # Only mean (lbproc of 128) is handled as the min/max
            # interpretation is ambiguous e.g. decadal mean of daily max,
            # decadal max of daily mean, decadal mean of max daily mean etc.
            cell_methods.append(CellMethod("{} within years".format(time_method), coords="time", intervals=intervals))
            cell_methods.append(CellMethod("{} over years".format(time_method), coords="time"))
            unhandled_lbproc = False
        else:
            # Generic cell method to indicate a time aggregation.
            cell_methods.append(CellMethod(time_method, coords="time"))
            unhandled_lbproc = False

    if zone_method is not None:
        if f.lbcode == 1:
            cell_methods.append(CellMethod(zone_method, coords="longitude"))
            unhandled_lbproc = False
        elif f.lbcode == 101:
            cell_methods.append(CellMethod(zone_method, coords="grid_longitude"))
            unhandled_lbproc = False
        else:
            unhandled_lbproc = True

    if unhandled_lbproc:
        attributes["ukmo__process_flags"] = tuple(
            sorted(
                [
                    name
                    for value, name in six.iteritems(iris.fileformats.pp.lbproc_map)
                    if isinstance(value, int) and f.lbproc & value
                ]
            )
        )

    if (f.lbsrce % 10000) == 1111:
        attributes["source"] = "Data from Met Office Unified Model"
        # Also define MO-netCDF compliant UM version.
        um_major = (f.lbsrce // 10000) // 100
        if um_major != 0:
            um_minor = (f.lbsrce // 10000) % 100
            attributes["um_version"] = "{:d}.{:d}".format(um_major, um_minor)

    if f.lbuser[6] != 0 or (f.lbuser[3] // 1000) != 0 or (f.lbuser[3] % 1000) != 0:
        attributes["STASH"] = f.stash

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if not f.stash.is_valid and f.lbfc in LBFC_TO_CF:
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    # Orography reference field (--> reference target)
    if f.lbuser[3] == 33:
        references.append(ReferenceTarget("orography", None))

    # Surface pressure reference field (--> reference target)
    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget("surface_air_pressure", None))

    return (
        references,
        standard_name,
        long_name,
        units,
        attributes,
        cell_methods,
        dim_coords_and_dims,
        aux_coords_and_dims,
    )
Exemple #9
0
    def test_apply_filter_with_safety_mask_enabled(self):
        # create cube with just one field and some QC flags
        latitude = DimCoord.from_regular(zeroth=-45.0,
                                         step=5.0,
                                         count=3,
                                         var_name='right_latitude',
                                         circular=False)
        longitude = DimCoord.from_regular(zeroth=-10.0,
                                          step=5.0,
                                          count=5,
                                          var_name='right_longitude',
                                          circular=False)
        axes_coordinates = [(latitude, 0), (longitude, 1)]
        fielddimensions = (len(latitude.points), len(longitude.points))

        # a set of data (all flagged as valid)
        zerodata = numpy.ma.masked_array(data=numpy.zeros(fielddimensions,
                                                          dtype=numpy.float32),
                                         mask=numpy.zeros(fielddimensions,
                                                          dtype=numpy.bool))

        # faulty coordinates with non overlapping mask
        wrong_latitude = numpy.array(
            [[0, ERRORVALUE, 3, 7, 2], [1, 0, ERRORVALUE, ERRORVALUE, 3],
             [7, 2, 6, 3, ERRORVALUE]], numpy.float32)

        wrong_longitude = numpy.array(
            [[ERRORVALUE, 1, 3, 7, ERRORVALUE], [1, 0, 8, 3, 3],
             [7, 2, 6, ERRORVALUE, 1]], numpy.float32)

        # example of QC flags
        qc = numpy.array([[0, 1, 3, 7, 2], [1, 0, 8, 3, 3], [7, 2, 6, 3, 1]],
                         numpy.int32)

        # build into cube
        cube = Cube(zerodata,
                    var_name='EXAMPLE',
                    dim_coords_and_dims=axes_coordinates)
        cube.add_aux_coord(AuxCoord(qc, var_name='QC'), data_dims=(0, 1))
        cube.add_aux_coord(AuxCoord(wrong_latitude, var_name='latitude'),
                           data_dims=(0, 1))
        cube.add_aux_coord(AuxCoord(wrong_longitude, var_name='longitude'),
                           data_dims=(0, 1))

        # copies of cube for tests
        collection_a = SatelliteCollection(
            TestSatelliteCollection.FieldNamesForTest(), cube.copy())
        collection_b = SatelliteCollection(
            TestSatelliteCollection.FieldNamesForTest(), cube.copy())
        collection_c = SatelliteCollection(
            TestSatelliteCollection.FieldNamesForTest(), cube.copy())

        # run with different filters
        collection_a.generate_safety_mask()
        collection_b.generate_safety_mask()
        collection_c.generate_safety_mask()

        collection_a.apply_filter(
            collection_a.get_filter_from_qc_flags(qc_mask=0xFFFF,
                                                  qc_filter=0x0008))
        numpy.testing.assert_equal(
            numpy.array([[True, True, True, True, True],
                         [True, True, True, True, True],
                         [True, True, True, True, True]]),
            collection_a.cube.data.mask)
        collection_b.apply_filter(
            collection_b.get_filter_from_qc_flags(qc_mask=0x0004,
                                                  qc_filter=0x0004))
        numpy.testing.assert_equal(
            numpy.array([[True, True, True, False, True],
                         [True, True, True, True, True],
                         [False, True, False, True, True]]),
            collection_b.cube.data.mask)

        collection_c.apply_filter(
            collection_c.get_filter_from_qc_flags(qc_mask=0x0003,
                                                  qc_filter=0x0002))
        numpy.testing.assert_equal(
            numpy.array([[True, True, True, True, True],
                         [True, True, True, True, True],
                         [True, False, False, True, True]]),
            collection_c.cube.data.mask)
Exemple #10
0
    def test_generate_safety_mask(self):

        # create cube with just one field and some QC flags
        latitude = DimCoord.from_regular(zeroth=-45.0,
                                         step=5.0,
                                         count=3,
                                         var_name='right_latitude',
                                         circular=False)
        longitude = DimCoord.from_regular(zeroth=-10.0,
                                          step=5.0,
                                          count=5,
                                          var_name='right_longitude',
                                          circular=False)
        axes_coordinates = [(latitude, 0), (longitude, 1)]
        fielddimensions = (len(latitude.points), len(longitude.points))

        # a set of data (all flagged as valid)
        zerodata = numpy.ma.masked_array(data=numpy.zeros(fielddimensions,
                                                          dtype=numpy.float32),
                                         mask=numpy.zeros(fielddimensions,
                                                          dtype=numpy.bool))

        # faulty coordinates with non overlapping mask
        wrong_latitude = numpy.array(
            [[0, ERRORVALUE, 3, 7, 2], [1, 0, ERRORVALUE, ERRORVALUE, 3],
             [7, 2, 6, 3, ERRORVALUE]], numpy.float32)

        wrong_longitude = numpy.array(
            [[ERRORVALUE, 1, 3, 7, ERRORVALUE], [1, 0, 8, 3, 3],
             [7, 2, 6, ERRORVALUE, 1]], numpy.float32)

        # build into cube
        cube = Cube(zerodata,
                    var_name='EXAMPLE',
                    dim_coords_and_dims=axes_coordinates)
        cube.add_aux_coord(AuxCoord(wrong_latitude, var_name='latitude'),
                           data_dims=(0, 1))
        cube.add_aux_coord(AuxCoord(wrong_longitude, var_name='longitude'),
                           data_dims=(0, 1))

        # copies of cube for tests
        collection = SatelliteCollection(
            TestSatelliteCollection.FieldNamesForTest(), cube.copy())

        # input coordinates with non overlapping masks

        collection.generate_safety_mask()
        numpy.testing.assert_equal(
            numpy.array([[True, True, False, False, True],
                         [False, False, True, True, False],
                         [False, False, False, True, True]]),
            collection.safety_mask)

        # faulty coordinates with overlapping mask

        wrong_latitude = numpy.array(
            [[ERRORVALUE, 1, 3, 7, ERRORVALUE], [1, 0, 2, 4, 3],
             [7, 2, 6, ERRORVALUE, 1]], numpy.float32)

        wrong_longitude = numpy.array(
            [[ERRORVALUE, 1, 3, 7, ERRORVALUE], [1, 0, 8, 3, 3],
             [7, 2, 6, ERRORVALUE, 1]], numpy.float32)

        # build into cube
        cube = Cube(zerodata,
                    var_name='EXAMPLE',
                    dim_coords_and_dims=axes_coordinates)
        cube.add_aux_coord(AuxCoord(wrong_latitude, var_name='latitude'),
                           data_dims=(0, 1))
        cube.add_aux_coord(AuxCoord(wrong_longitude, var_name='longitude'),
                           data_dims=(0, 1))

        # copies of cube for tests
        collection = SatelliteCollection(
            TestSatelliteCollection.FieldNamesForTest(), cube.copy())

        # input coordinates with non overlapping masks

        collection.generate_safety_mask()
        self.assertTrue(hasattr(collection, 'safety_mask'))
        numpy.testing.assert_equal(
            numpy.array([[True, False, False, False, True],
                         [False, False, False, False, False],
                         [False, False, False, True, False]]),
            collection.safety_mask)