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)
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)
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)
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)
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)
def axis_coordinates(self): """Create iris DimCoord suitable for building a cube.""" return DimCoord.from_regular(**self.__dict__)
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, )
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, )
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)
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)