def test_string_default(self): token = 'air temperature' # includes space result = CellMethod(self.method, coords=token) expected = '{}: unknown'.format(self.method) self.assertEqual(str(result), expected)
def process(self, cube_ens_wdir): """Create a cube containing the wind direction averaged over the ensemble realizations. Args: cube_ens_wdir (iris.cube.Cube): Cube containing wind direction from multiple ensemble realizations. Returns: iris.cube.Cube: Cube containing the wind direction averaged from the ensemble realizations. cube_r_vals (numpy.ndarray): 3D array - Radius taken from average complex wind direction angle. cube_confidence_measure (numpy.ndarray): 3D array - The average distance from mean normalised - used as a confidence value. Raises ------ TypeError: If cube_wdir is not a cube. """ if not isinstance(cube_ens_wdir, iris.cube.Cube): msg = "Wind direction input is not a cube, but {}" raise TypeError(msg.format(type(cube_ens_wdir))) try: cube_ens_wdir.convert_units("degrees") except ValueError as err: msg = "Input cube cannot be converted to degrees: {}".format(err) raise ValueError(msg) self.n_realizations = len(cube_ens_wdir.coord("realization").points) y_coord_name = cube_ens_wdir.coord(axis="y").name() x_coord_name = cube_ens_wdir.coord(axis="x").name() for wdir_slice in cube_ens_wdir.slices( ["realization", y_coord_name, x_coord_name] ): self._reset() # Extract wind direction data. self.wdir_complex = self.deg_to_complex(wdir_slice.data) (self.realization_axis,) = wdir_slice.coord_dims("realization") # Copies input cube and remove realization dimension to create # cubes for storing results. self.wdir_slice_mean = next(wdir_slice.slices_over("realization")) self.wdir_slice_mean.remove_coord("realization") # Derive average wind direction. self.calc_wind_dir_mean() # Find radius values for wind direction average. self.find_r_values() # Calculate the confidence measure based on the difference # between the complex average and the individual ensemble # realizations. self.calc_confidence_measure() # Finds any meaningless averages and substitute with # the wind direction taken from the first ensemble realization. # Mask True if r values below threshold. where_low_r = np.where(self.r_vals_slice.data < self.r_thresh, True, False) # If the any point in the array contains poor r-values, # trigger decider function. if where_low_r.any(): self.wind_dir_decider(where_low_r, wdir_slice) # Append to cubelists. self.wdir_cube_list.append(self.wdir_slice_mean) self.r_vals_cube_list.append(self.r_vals_slice) self.confidence_measure_cube_list.append(self.confidence_slice) # Combine cubelists into cube. cube_mean_wdir = self.wdir_cube_list.merge_cube() cube_r_vals = self.r_vals_cube_list.merge_cube() cube_confidence_measure = self.confidence_measure_cube_list.merge_cube() # Check that the dimensionality of coordinates of the output cube # matches the input cube. first_slice = next(cube_ens_wdir.slices_over(["realization"])) cube_mean_wdir = check_cube_coordinates(first_slice, cube_mean_wdir) # Change cube identifiers. cube_mean_wdir.add_cell_method(CellMethod("mean", coords="realization")) cube_r_vals.long_name = "radius_of_complex_average_wind_from_direction" cube_r_vals.units = None cube_confidence_measure.long_name = "confidence_measure_of_wind_from_direction" cube_confidence_measure.units = None return cube_mean_wdir, cube_r_vals, cube_confidence_measure
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", units="1"), 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 test_hours(self, mock_set): cell_method = CellMethod('sum', 'time', '25 hours') set_time_increment(cell_method, mock.sentinel.grib) mock_set.assert_any_call(mock.sentinel.grib, 'indicatorOfUnitForTimeIncrement', 1) mock_set.assert_any_call(mock.sentinel.grib, 'timeIncrement', 25)
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=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)) # 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 expected_cell_method(self, coords=('time',), method='mean', intervals=None): keys = dict(coords=coords, method=method, intervals=intervals) cell_method = CellMethod(**keys) return cell_method
def test_area(self, mock_set): cell_method = CellMethod('sum', 'area', '25 km') set_time_increment(cell_method, mock.sentinel.grib) mock_set.assert_any_call(mock.sentinel.grib, 'indicatorOfUnitForTimeIncrement', 255) mock_set.assert_any_call(mock.sentinel.grib, 'timeIncrement', 0)
def setUp(self): self.cube = stock.realistic_4d() cm = CellMethod('mean', 'time', '6hr') self.cube.add_cell_method(cm) self.representer = CubeRepresentation(self.cube) self.representer._get_bits(self.representer._get_lines())
def setUp(self): self.cube = stock.lat_lon_cube() # Rename cube to avoid warning about unknown discipline/parameter. self.cube.rename('air_temperature') cell_method = CellMethod(method='sum', coords=['time']) self.cube.add_cell_method(cell_method)
def test_error_wrong_accum_cell_method(precip_accum_cube, interpreter): """Test error when precipitation accumulation cube has the wrong cell method""" precip_accum_cube.cell_methods = [] precip_accum_cube.add_cell_method(CellMethod(method="mean", coords="time")) with pytest.raises(ValueError, match="Expected sum over time"): interpreter.run(precip_accum_cube)
def test_error_forbidden_weather_code_cell_method(wxcode_cube, interpreter): """Test error if special case cubes have a cell method that would usually be permitted""" wxcode_cube.add_cell_method(CellMethod(method="maximum", coords="time")) with pytest.raises(ValueError, match="Unexpected cell methods"): interpreter.run(wxcode_cube)
def test_error_ancillary_cell_method(landmask_cube, interpreter): """Test error raised when there's a cell method on a static ancillary""" landmask_cube.add_cell_method(CellMethod(method="maximum", coords="time")) with pytest.raises(ValueError, match="Unexpected cell methods"): interpreter.run(landmask_cube)
def test_mixture_default(self): token = 'air temperature' # includes space coord = Coord(1, long_name=token) result = CellMethod(self.method, coords=[coord, token]) expected = '{}: unknown, unknown'.format(self.method, token, token) self.assertEqual(str(result), expected)
def test_mixture(self): token = 'air_temperature' coord = Coord(1, standard_name=token) result = CellMethod(self.method, coords=[coord, token]) expected = '{}: {}, {}'.format(self.method, token, token) self.assertEqual(str(result), expected)
def test_maximum(self): self.cube.cell_methods = (CellMethod('maximum', 'time', '1 hour'),) lbproc = _lbproc_rules(self.cube, self.pp_field).lbproc self.assertEqual(lbproc, 8192)
def test_climatology_max(self): field = mock.MagicMock(lbproc=8192, lbtim=mock.Mock(ia=24, ib=3, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod('maximum', 'time')] self.assertEqual(res, expected)
def convert(grib): """ Converts a GRIB message into the corresponding items of Cube metadata. Args: * grib: A :class:`~iris.fileformats.grib.GribWrapper` object. Returns: A :class:`iris.fileformats.rules.ConversionMetadata` object. """ factories = [] references = [] standard_name = None long_name = None units = None attributes = {} cell_methods = [] dim_coords_and_dims = [] aux_coords_and_dims = [] # deprecation warning for this code path for edition 2 messages if grib.edition == 2: msg = ('This GRIB loader is deprecated and will be removed in ' 'a future release. Please consider using the new ' 'GRIB loader by setting the :class:`iris.Future` ' 'option `strict_grib_load` to True; e.g.:\n' 'iris.FUTURE.strict_grib_load = True\n' 'Please report issues you experience to:\n' 'https://groups.google.com/forum/#!topic/scitools-iris-dev/' 'lMsOusKNfaU') warnings.warn(msg) if \ (grib.gridType=="reduced_gg"): aux_coords_and_dims.append( (AuxCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) aux_coords_and_dims.append( (AuxCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 0)) if \ (grib.gridType=="regular_ll") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="regular_ll") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if \ (grib.gridType=="regular_gg") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="regular_gg") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if \ (grib.gridType=="rotated_ll") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="rotated_ll") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if grib.gridType in ["polar_stereographic", "lambert"]: dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units="m", coord_system=grib._coord_system), 0)) dim_coords_and_dims.append( (DimCoord(grib._x_points, grib._x_coord_name, units="m", coord_system=grib._coord_system), 1)) if \ (grib.edition == 1) and \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 11) and \ (grib._cf_data is None): standard_name = "air_temperature" units = "kelvin" if \ (grib.edition == 1) and \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 33) and \ (grib._cf_data is None): standard_name = "x_wind" units = "m s-1" if \ (grib.edition == 1) and \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 34) and \ (grib._cf_data is None): standard_name = "y_wind" units = "m s-1" if \ (grib.edition == 1) and \ (grib._cf_data is not None): standard_name = grib._cf_data.standard_name long_name = grib._cf_data.standard_name or grib._cf_data.long_name units = grib._cf_data.units if \ (grib.edition == 1) and \ (grib.table2Version >= 128) and \ (grib._cf_data is None): long_name = "UNKNOWN LOCAL PARAM " + str( grib.indicatorOfParameter) + "." + str(grib.table2Version) units = "???" if \ (grib.edition == 1) and \ (grib.table2Version == 1) and \ (grib.indicatorOfParameter >= 128): long_name = "UNKNOWN LOCAL PARAM " + str( grib.indicatorOfParameter) + "." + str(grib.table2Version) units = "???" if \ (grib.edition == 2) and \ (grib._cf_data is not None): standard_name = grib._cf_data.standard_name long_name = grib._cf_data.long_name units = grib._cf_data.units if \ (grib.edition == 1) and \ (grib._phenomenonDateTime != -1.0): aux_coords_and_dims.append( (DimCoord(points=grib.startStep, standard_name='forecast_period', units=grib._forecastTimeUnit), None)) aux_coords_and_dims.append( (DimCoord(points=grib.phenomenon_points('hours'), standard_name='time', units=Unit('hours since epoch', CALENDAR_GREGORIAN)), None)) def add_bounded_time_coords(aux_coords_and_dims, grib): t_bounds = grib.phenomenon_bounds('hours') period = Unit('hours').convert(t_bounds[1] - t_bounds[0], grib._forecastTimeUnit) aux_coords_and_dims.append( (DimCoord(standard_name='forecast_period', units=grib._forecastTimeUnit, points=grib._forecastTime + 0.5 * period, bounds=[grib._forecastTime, grib._forecastTime + period]), None)) aux_coords_and_dims.append( (DimCoord(standard_name='time', units=Unit('hours since epoch', CALENDAR_GREGORIAN), points=0.5 * (t_bounds[0] + t_bounds[1]), bounds=t_bounds), None)) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 2): add_bounded_time_coords(aux_coords_and_dims, grib) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 3): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 4): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 5): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("_difference", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 51): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 113): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 114): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 115): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 116): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 117): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 118): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("_covariance", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 123): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 124): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 125): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("standard_deviation", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 0): aux_coords_and_dims.append( (DimCoord(points=Unit(grib._forecastTimeUnit).convert( np.int32(grib._forecastTime), "hours"), standard_name='forecast_period', units="hours"), None)) aux_coords_and_dims.append( (DimCoord(points=grib.phenomenon_points('hours'), standard_name='time', units=Unit('hours since epoch', CALENDAR_GREGORIAN)), None)) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber in (8, 9)): add_bounded_time_coords(aux_coords_and_dims, grib) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 0): cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 1): cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 2): cell_methods.append(CellMethod("maximum", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 3): cell_methods.append(CellMethod("minimum", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 4): cell_methods.append(CellMethod("_difference", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 5): cell_methods.append(CellMethod("_root_mean_square", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 6): cell_methods.append(CellMethod("standard_deviation", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 7): cell_methods.append(CellMethod("_convariance", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 8): cell_methods.append(CellMethod("_difference", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 9): cell_methods.append(CellMethod("_ratio", coords="time")) if \ (grib.edition == 1) and \ (grib.levelType == 'pl'): aux_coords_and_dims.append((DimCoord(points=grib.level, long_name="pressure", units="hPa"), None)) if \ (grib.edition == 1) and \ (grib.levelType == 'sfc'): if (grib._cf_data is not None) and \ (grib._cf_data.set_height is not None): aux_coords_and_dims.append( (DimCoord(points=grib._cf_data.set_height, long_name="height", units="m", attributes={'positive': 'up'}), None)) elif grib.typeOfLevel == 'heightAboveGround': # required for NCAR aux_coords_and_dims.append((DimCoord(points=grib.level, long_name="height", units="m", attributes={'positive': 'up'}), None)) if \ (grib.edition == 1) and \ (grib.levelType == 'ml') and \ (hasattr(grib, 'pv')): aux_coords_and_dims.append( (AuxCoord(grib.level, standard_name='model_level_number', attributes={'positive': 'up'}), None)) aux_coords_and_dims.append((DimCoord(grib.pv[grib.level], long_name='level_pressure', units='Pa'), None)) aux_coords_and_dims.append((AuxCoord( grib.pv[grib.numberOfCoordinatesValues // 2 + grib.level], long_name='sigma'), None)) factories.append( Factory(HybridPressureFactory, [{ 'long_name': 'level_pressure' }, { 'long_name': 'sigma' }, Reference('surface_pressure')])) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface != grib.typeOfSecondFixedSurface): warnings.warn("Different vertical bound types not yet handled.") if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 103) and \ (grib.typeOfSecondFixedSurface == 255): aux_coords_and_dims.append( (DimCoord(points=grib.scaledValueOfFirstFixedSurface / (10.0**grib.scaleFactorOfFirstFixedSurface), standard_name="height", units="m"), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 103) and \ (grib.typeOfSecondFixedSurface != 255): aux_coords_and_dims.append((DimCoord( points=0.5 * (grib.scaledValueOfFirstFixedSurface / (10.0**grib.scaleFactorOfFirstFixedSurface) + grib.scaledValueOfSecondFixedSurface / (10.0**grib.scaleFactorOfSecondFixedSurface)), standard_name="height", units="m", bounds=[ grib.scaledValueOfFirstFixedSurface / (10.0**grib.scaleFactorOfFirstFixedSurface), grib.scaledValueOfSecondFixedSurface / (10.0**grib.scaleFactorOfSecondFixedSurface) ]), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 100) and \ (grib.typeOfSecondFixedSurface == 255): aux_coords_and_dims.append( (DimCoord(points=grib.scaledValueOfFirstFixedSurface / (10.0**grib.scaleFactorOfFirstFixedSurface), long_name="pressure", units="Pa"), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 100) and \ (grib.typeOfSecondFixedSurface != 255): aux_coords_and_dims.append((DimCoord( points=0.5 * (grib.scaledValueOfFirstFixedSurface / (10.0**grib.scaleFactorOfFirstFixedSurface) + grib.scaledValueOfSecondFixedSurface / (10.0**grib.scaleFactorOfSecondFixedSurface)), long_name="pressure", units="Pa", bounds=[ grib.scaledValueOfFirstFixedSurface / (10.0**grib.scaleFactorOfFirstFixedSurface), grib.scaledValueOfSecondFixedSurface / (10.0**grib.scaleFactorOfSecondFixedSurface) ]), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface in [105, 119]) and \ (grib.numberOfCoordinatesValues > 0): aux_coords_and_dims.append( (AuxCoord(grib.scaledValueOfFirstFixedSurface, standard_name='model_level_number', attributes={'positive': 'up'}), None)) aux_coords_and_dims.append( (DimCoord(grib.pv[grib.scaledValueOfFirstFixedSurface], long_name='level_pressure', units='Pa'), None)) aux_coords_and_dims.append( (AuxCoord(grib.pv[grib.numberOfCoordinatesValues // 2 + grib.scaledValueOfFirstFixedSurface], long_name='sigma'), None)) factories.append( Factory(HybridPressureFactory, [{ 'long_name': 'level_pressure' }, { 'long_name': 'sigma' }, Reference('surface_air_pressure')])) if grib._originatingCentre != 'unknown': aux_coords_and_dims.append((AuxCoord(points=grib._originatingCentre, long_name='originating_centre', units='no_unit'), None)) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 1): aux_coords_and_dims.append((DimCoord(points=grib.perturbationNumber, long_name='ensemble_member', units='no_unit'), None)) if \ (grib.edition == 2) and \ grib.productDefinitionTemplateNumber not in (0, 8): attributes["GRIB_LOAD_WARNING"] = ( "unsupported GRIB%d ProductDefinitionTemplate: #4.%d" % (grib.edition, grib.productDefinitionTemplateNumber)) if \ (grib.edition == 2) and \ (grib.centre == 'ecmf') and \ (grib.discipline == 0) and \ (grib.parameterCategory == 3) and \ (grib.parameterNumber == 25) and \ (grib.typeOfFirstFixedSurface == 105): references.append( ReferenceTarget( 'surface_air_pressure', lambda cube: { 'standard_name': 'surface_air_pressure', 'units': 'Pa', 'data': np.exp(cube.data) })) return ConversionMetadata(factories, references, standard_name, long_name, units, attributes, cell_methods, dim_coords_and_dims, aux_coords_and_dims)
def test_daily_mean(self): # lbtim.ia = 24 -> daily field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=24, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod('mean', 'time', '24 hour')] self.assertEqual(res, expected)
def setUp(self): self.cube = stock.simple_3d() cm = CellMethod("mean", "time", "6hr") self.cube.add_cell_method(cm) self.representer = CubeRepresentation(self.cube) self.representer._get_bits(self.representer._get_lines())
def test_other_lbtim_ib(self): # lbtim.ib = 5 -> non-specific aggregation field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=5, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("minimum", "time")] self.assertEqual(res, expected)
def test_multiple_intervals(self, mock_set): cell_method = CellMethod('sum', 'time', ('1 hour', '24 hour')) set_time_increment(cell_method, mock.sentinel.grib) mock_set.assert_any_call(mock.sentinel.grib, 'indicatorOfUnitForTimeIncrement', 255) mock_set.assert_any_call(mock.sentinel.grib, 'timeIncrement', 0)
def test_hourly_mean(self): # lbtim.ia = 1 -> hourly field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=1, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("mean", "time", "1 hour")] self.assertEqual(res, expected)
def fields(self, c_t=None, cft=None, ctp=None, c_h=None, c_p=None, phn=0, mmm=None, pse=None): # Return a list of 2d cubes representing raw PPFields, from args # specifying sequences of (scalar) coordinate values. # TODO? : add bounds somehow ? # # Arguments 'c<xx>' are either a single int value, making a scalar # coord, or a string of characters : '0'-'9' (index) or '-' (missing). # The indexes select point values from fixed list of possibles. # # Argument 'c_h' and 'c_p' represent height or pressure values, so # ought to be mutually exclusive -- these control LBVC. # # Argument 'phn' indexes phenomenon types. # # Argument 'mmm' denotes existence (or not) of a cell method of type # 'average' or 'min' or 'max' (values '012' respectively), applying to # the time values -- ultimately, this controls LBTIM. # # Argument 'pse' denotes pseudo-level numbers. # These translate into 'LBUSER5' values. # Get the number of result cubes, defined by the 'longest' arg. def arglen(arg): # Get the 'length' of a control argument. if arg is None: result = 0 elif isinstance(arg, six.string_types): result = len(arg) else: result = 1 return result n_flds = max(arglen(x) for x in (c_t, cft, ctp, c_h, c_p, mmm)) # Make basic anonymous test cubes. ny, nx = 3, 5 data = np.arange(n_flds * ny * nx, dtype=np.float32) data = data.reshape((n_flds, ny, nx)) cubes = [Cube(data[i]) for i in range(n_flds)] # Define test point values for making coordinates. time_unit = 'hours since 1970-01-01' period_unit = 'hours' height_unit = 'm' pressure_unit = 'hPa' time_values = 24.0 * np.arange(10) height_values = 100.0 * np.arange(1, 11) pressure_values = [ 100.0, 150.0, 200.0, 250.0, 300.0, 500.0, 850.0, 1000.0 ] pseudolevel_values = range(1, 11) # A valid value is >= 1. # Test phenomenon details. # NOTE: in order to write/readback as identical, these also contain a # canonical unit and matching STASH attribute. # Those could in principle be looked up, but it's a bit awkward. phenomenon_values = [ ('air_temperature', 'K', 'm01s01i004'), ('x_wind', 'm s-1', 'm01s00i002'), ('y_wind', 'm s-1', 'm01s00i003'), ('specific_humidity', 'kg kg-1', 'm01s00i010'), ] # Test cell-methods. # NOTE: if you add an *interval* to any of these cell-methods, it is # not saved into the PP file (?? or maybe not loaded back again ??). # This could be a PP save/load bug, or maybe just because no bounds ? cell_method_values = [ CellMethod('mean', 'time'), CellMethod('maximum', 'time'), CellMethod('minimum', 'time'), ] # Define helper to decode an argument as a list of test values. def arg_vals(arg, vals): # Decode an argument to a list of 'n_flds' coordinate point values. # (or 'None' where missing) # First get a list of value indices from the argument. # Can be: a single index value; a list of indices; or a string. if (isinstance(arg, Iterable) and not isinstance(arg, six.string_types)): # Can also just pass a simple iterable of values. inds = [int(val) for val in arg] else: n_vals = arglen(arg) if n_vals == 0: inds = [None] * n_flds elif n_vals == 1: inds = [int(arg)] * n_flds else: assert isinstance(arg, six.string_types) inds = [None if char == '-' else int(char) for char in arg] # Convert indices to selected point values. values = [None if ind is None else vals[int(ind)] for ind in inds] return values # Apply phenomenon_values definitions. phenomena = arg_vals(phn, phenomenon_values) for cube, (name, units, stash) in zip(cubes, phenomena): cube.rename(name) # NOTE: in order to get a cube that will write+readback the same, # the units must be the canonical one. cube.units = units # NOTE: in order to get a cube that will write+readback the same, # we must include a STASH attribute. cube.attributes['STASH'] = STASH.from_msi(stash) # Add x and y coords. cs = GeogCS(EARTH_RADIUS) xvals = np.linspace(0.0, 180.0, nx) co_x = DimCoord(np.array(xvals, dtype=np.float32), standard_name='longitude', units='degrees', coord_system=cs) yvals = np.linspace(-45.0, 45.0, ny) co_y = DimCoord(np.array(yvals, dtype=np.float32), standard_name='latitude', units='degrees', coord_system=cs) for cube in cubes: cube.add_dim_coord(co_y, 0) cube.add_dim_coord(co_x, 1) # Add multiple scalar coordinates as defined by the arguments. def arg_coords(arg, name, unit, vals=None): # Decode an argument to a list of scalar coordinates. if vals is None: vals = np.arange(n_flds + 2) # Note allowance vals = arg_vals(arg, vals) coords = [ None if val is None else DimCoord([val], units=unit) for val in vals ] # Apply names separately, as 'pressure' is not a standard name. for coord in coords: if coord: coord.rename(name) # Also fix heights to match what comes from a PP file. if name == 'height': coord.attributes['positive'] = 'up' return coords def add_arg_coords(arg, name, unit, vals=None): # Add scalar coordinates to each cube, for one argument. coords = arg_coords(arg, name, unit, vals) for cube, coord in zip(cubes, coords): if coord: cube.add_aux_coord(coord) add_arg_coords(c_t, 'time', time_unit, time_values) add_arg_coords(cft, 'forecast_reference_time', time_unit) add_arg_coords(ctp, 'forecast_period', period_unit, time_values) add_arg_coords(c_h, 'height', height_unit, height_values) add_arg_coords(c_p, 'pressure', pressure_unit, pressure_values) add_arg_coords(pse, 'pseudo_level', '1', pseudolevel_values) # Add cell methods as required. methods = arg_vals(mmm, cell_method_values) for cube, method in zip(cubes, methods): if method: cube.add_cell_method(method) return cubes
def test_custom_max(self): field = mock.MagicMock(lbproc=8192, lbtim=mock.Mock(ia=47, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("maximum", "time", "47 hour")] self.assertEqual(res, expected)
def convert(grib): factories = [] references = [] standard_name = None long_name = None units = None attributes = {} cell_methods = [] dim_coords_and_dims = [] aux_coords_and_dims = [] if \ (grib.gridType=="reduced_gg"): aux_coords_and_dims.append((AuxCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) aux_coords_and_dims.append((AuxCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 0)) if \ (grib.gridType=="regular_ll") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="regular_ll") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if \ (grib.gridType=="regular_gg") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="regular_gg") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if \ (grib.gridType=="rotated_ll") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="rotated_ll") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if grib.gridType in ["polar_stereographic", "lambert"]: dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units="m", coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units="m", coord_system=grib._coord_system), 1)) if \ (grib.edition == 1) and \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 11) and \ (grib._cf_data is None): standard_name = "air_temperature" units = "kelvin" if \ (grib.edition == 1) and \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 33) and \ (grib._cf_data is None): standard_name = "x_wind" units = "m s-1" if \ (grib.edition == 1) and \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 34) and \ (grib._cf_data is None): standard_name = "y_wind" units = "m s-1" if \ (grib.edition == 1) and \ (grib._cf_data is not None): standard_name = grib._cf_data.standard_name long_name = grib._cf_data.standard_name or grib._cf_data.long_name units = grib._cf_data.units if \ (grib.edition == 1) and \ (grib.table2Version >= 128) and \ (grib._cf_data is None): long_name = "UNKNOWN LOCAL PARAM " + str(grib.indicatorOfParameter) + "." + str(grib.table2Version) units = "???" if \ (grib.edition == 1) and \ (grib.table2Version == 1) and \ (grib.indicatorOfParameter >= 128): long_name = "UNKNOWN LOCAL PARAM " + str(grib.indicatorOfParameter) + "." + str(grib.table2Version) units = "???" if \ (grib.edition == 2) and \ (grib._cf_data is not None): standard_name = grib._cf_data.standard_name long_name = grib._cf_data.long_name units = grib._cf_data.units if \ (grib.edition == 1) and \ (grib._phenomenonDateTime != -1.0): aux_coords_and_dims.append((DimCoord(points=grib.startStep, standard_name='forecast_period', units=grib._forecastTimeUnit), None)) aux_coords_and_dims.append((DimCoord(points=grib.phenomenon_points('hours'), standard_name='time', units=Unit('hours since epoch', iris.unit.CALENDAR_GREGORIAN)), None)) def add_bounded_time_coords(aux_coords_and_dims, grib): t_bounds = grib.phenomenon_bounds('hours') period = Unit('hours').convert(t_bounds[1] - t_bounds[0], grib._forecastTimeUnit) aux_coords_and_dims.append(( DimCoord(standard_name='forecast_period', units=grib._forecastTimeUnit, points=grib._forecastTime + 0.5 * period, bounds=[grib._forecastTime, grib._forecastTime + period]), None)) aux_coords_and_dims.append(( DimCoord(standard_name='time', units=Unit('hours since epoch', iris.unit.CALENDAR_GREGORIAN), points=0.5 * (t_bounds[0] + t_bounds[1]), bounds=t_bounds), None)) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 3): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 4): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 5): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("_difference", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 51): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 113): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 114): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 115): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 116): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 117): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 118): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("_covariance", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 123): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 124): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 1) and \ (grib.timeRangeIndicator == 125): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("standard_deviation", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 0): aux_coords_and_dims.append((DimCoord(points=Unit(grib._forecastTimeUnit).convert(np.int32(grib._forecastTime), "hours"), standard_name='forecast_period', units="hours"), None)) aux_coords_and_dims.append((DimCoord(points=grib.phenomenon_points('hours'), standard_name='time', units=Unit('hours since epoch', iris.unit.CALENDAR_GREGORIAN)), None)) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber in (8, 9)): add_bounded_time_coords(aux_coords_and_dims, grib) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 0): cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 1): cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 2): cell_methods.append(CellMethod("maximum", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 3): cell_methods.append(CellMethod("minimum", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 4): cell_methods.append(CellMethod("_difference", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 5): cell_methods.append(CellMethod("_root_mean_square", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 6): cell_methods.append(CellMethod("standard_deviation", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 7): cell_methods.append(CellMethod("_convariance", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 8): cell_methods.append(CellMethod("_difference", coords="time")) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 8) and \ (grib.typeOfStatisticalProcessing == 9): cell_methods.append(CellMethod("_ratio", coords="time")) if \ (grib.edition == 1) and \ (grib.levelType == 'pl'): aux_coords_and_dims.append((DimCoord(points=grib.level, long_name="pressure", units="hPa"), None)) if \ (grib.edition == 1) and \ (grib.levelType == 'sfc') and \ (grib._cf_data is not None) and \ (grib._cf_data.set_height is not None): aux_coords_and_dims.append((DimCoord(points=grib._cf_data.set_height, long_name="height", units="m", attributes={'positive':'up'}), None)) if \ (grib.edition == 1) and \ (grib.levelType == 'ml') and \ (hasattr(grib, 'pv')): aux_coords_and_dims.append((AuxCoord(grib.level, standard_name='model_level_number', attributes={'positive': 'up'}), None)) aux_coords_and_dims.append((DimCoord(grib.pv[grib.level], long_name='level_pressure', units='Pa'), None)) aux_coords_and_dims.append((AuxCoord(grib.pv[grib.numberOfCoordinatesValues/2 + grib.level], long_name='sigma'), None)) factories.append(Factory(HybridPressureFactory, [{'long_name': 'level_pressure'}, {'long_name': 'sigma'}, Reference('surface_pressure')])) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface != grib.typeOfSecondFixedSurface): warnings.warn("Different vertical bound types not yet handled.") if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 103) and \ (grib.typeOfSecondFixedSurface == 255): aux_coords_and_dims.append((DimCoord(points=grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface), standard_name="height", units="m"), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 103) and \ (grib.typeOfSecondFixedSurface != 255): aux_coords_and_dims.append((DimCoord(points=0.5*(grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) + grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)), standard_name="height", units="m", bounds=[grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) , grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)]), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 100) and \ (grib.typeOfSecondFixedSurface == 255): aux_coords_and_dims.append((DimCoord(points=grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface), long_name="pressure", units="Pa"), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface == 100) and \ (grib.typeOfSecondFixedSurface != 255): aux_coords_and_dims.append((DimCoord(points=0.5*(grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) + grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)), long_name="pressure", units="Pa", bounds=[grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) , grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)]), None)) if \ (grib.edition == 2) and \ (grib.typeOfFirstFixedSurface in [105, 119]) and \ (grib.numberOfCoordinatesValues > 0): aux_coords_and_dims.append((AuxCoord(grib.scaledValueOfFirstFixedSurface, standard_name='model_level_number', attributes={'positive': 'up'}), None)) aux_coords_and_dims.append((DimCoord(grib.pv[grib.scaledValueOfFirstFixedSurface], long_name='level_pressure', units='Pa'), None)) aux_coords_and_dims.append((AuxCoord(grib.pv[grib.numberOfCoordinatesValues/2 + grib.scaledValueOfFirstFixedSurface], long_name='sigma'), None)) factories.append(Factory(HybridPressureFactory, [{'long_name': 'level_pressure'}, {'long_name': 'sigma'}, Reference('surface_air_pressure')])) if grib._originatingCentre != 'unknown': aux_coords_and_dims.append((AuxCoord(points=grib._originatingCentre, long_name='originating_centre', units='no_unit'), None)) if \ (grib.edition == 2) and \ (grib.productDefinitionTemplateNumber == 1): aux_coords_and_dims.append((DimCoord(points=grib.perturbationNumber, long_name='ensemble_member', units='no_unit'), None)) if grib.productDefinitionTemplateNumber not in (0, 8): attributes["GRIB_LOAD_WARNING"] = ("unsupported GRIB%d ProductDefinitionTemplate: #4.%d" % (grib.edition, grib.productDefinitionTemplateNumber)) if \ (grib.edition == 2) and \ (grib.centre == 'ecmf') and \ (grib.discipline == 0) and \ (grib.parameterCategory == 3) and \ (grib.parameterNumber == 25) and \ (grib.typeOfFirstFixedSurface == 105): references.append(ReferenceTarget('surface_air_pressure', lambda cube: {'standard_name': 'surface_air_pressure', 'units': 'Pa', 'data': np.exp(cube.data)})) return (factories, references, standard_name, long_name, units, attributes, cell_methods, dim_coords_and_dims, aux_coords_and_dims)
def test_daily_min(self): # lbproc = 4096 -> min field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=2, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("minimum", "time", "24 hour")] self.assertEqual(res, expected)
def test_maximum(self): self.cube.cell_methods = (CellMethod("maximum", "time", "1 hour"), ) lbproc = _lbproc_rules(self.cube, self.pp_field).lbproc self.assertEqual(lbproc, 8192)
def test_climatology_min(self): field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=3, ic=3)) res = _all_other_rules(field)[CELL_METHODS_INDEX] expected = [CellMethod("minimum", "time")] self.assertEqual(res, expected)
def grib1_convert(grib): """ Converts a GRIB1 message into the corresponding items of Cube metadata. Args: * grib: A :class:`~iris_grib.GribWrapper` object. Returns: A :class:`iris.fileformats.rules.ConversionMetadata` object. """ if grib.edition != 1: emsg = 'GRIB edition {} is not supported by {!r}.' raise TranslationError(emsg.format(grib.edition, type(grib).__name__)) factories = [] references = [] standard_name = None long_name = None units = None attributes = {} cell_methods = [] dim_coords_and_dims = [] aux_coords_and_dims = [] if \ (grib.gridType=="reduced_gg"): aux_coords_and_dims.append( (AuxCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) aux_coords_and_dims.append( (AuxCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 0)) if \ (grib.gridType=="regular_ll") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="regular_ll") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if \ (grib.gridType=="regular_gg") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="regular_gg") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if \ (grib.gridType=="rotated_ll") and \ (grib.jPointsAreConsecutive == 0): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1)) if \ (grib.gridType=="rotated_ll") and \ (grib.jPointsAreConsecutive == 1): dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1)) dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0)) if grib.gridType in ["polar_stereographic", "lambert"]: dim_coords_and_dims.append( (DimCoord(grib._y_points, grib._y_coord_name, units="m", coord_system=grib._coord_system), 0)) dim_coords_and_dims.append( (DimCoord(grib._x_points, grib._x_coord_name, units="m", coord_system=grib._coord_system), 1)) if \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 11) and \ (grib._cf_data is None): standard_name = "air_temperature" units = "kelvin" if \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 33) and \ (grib._cf_data is None): standard_name = "x_wind" units = "m s-1" if \ (grib.table2Version < 128) and \ (grib.indicatorOfParameter == 34) and \ (grib._cf_data is None): standard_name = "y_wind" units = "m s-1" if \ (grib._cf_data is not None): standard_name = grib._cf_data.standard_name long_name = grib._cf_data.standard_name or grib._cf_data.long_name units = grib._cf_data.units if \ (grib.table2Version >= 128) and \ (grib._cf_data is None): long_name = "UNKNOWN LOCAL PARAM " + str( grib.indicatorOfParameter) + "." + str(grib.table2Version) units = "???" if \ (grib.table2Version == 1) and \ (grib.indicatorOfParameter >= 128): long_name = "UNKNOWN LOCAL PARAM " + str( grib.indicatorOfParameter) + "." + str(grib.table2Version) units = "???" if \ (grib._phenomenonDateTime != -1.0): aux_coords_and_dims.append( (DimCoord(points=grib.startStep, standard_name='forecast_period', units=grib._forecastTimeUnit), None)) aux_coords_and_dims.append( (DimCoord(points=grib.phenomenon_points('hours'), standard_name='time', units=Unit('hours since epoch', CALENDAR_GREGORIAN)), None)) def add_bounded_time_coords(aux_coords_and_dims, grib): t_bounds = grib.phenomenon_bounds('hours') period = Unit('hours').convert(t_bounds[1] - t_bounds[0], grib._forecastTimeUnit) aux_coords_and_dims.append( (DimCoord(standard_name='forecast_period', units=grib._forecastTimeUnit, points=grib._forecastTime + 0.5 * period, bounds=[grib._forecastTime, grib._forecastTime + period]), None)) aux_coords_and_dims.append( (DimCoord(standard_name='time', units=Unit('hours since epoch', CALENDAR_GREGORIAN), points=0.5 * (t_bounds[0] + t_bounds[1]), bounds=t_bounds), None)) if \ (grib.timeRangeIndicator == 2): add_bounded_time_coords(aux_coords_and_dims, grib) if \ (grib.timeRangeIndicator == 3): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.timeRangeIndicator == 4): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.timeRangeIndicator == 5): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("_difference", coords="time")) if \ (grib.timeRangeIndicator == 51): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.timeRangeIndicator == 113): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.timeRangeIndicator == 114): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.timeRangeIndicator == 115): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.timeRangeIndicator == 116): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.timeRangeIndicator == 117): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.timeRangeIndicator == 118): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("_covariance", coords="time")) if \ (grib.timeRangeIndicator == 123): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("mean", coords="time")) if \ (grib.timeRangeIndicator == 124): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("sum", coords="time")) if \ (grib.timeRangeIndicator == 125): add_bounded_time_coords(aux_coords_and_dims, grib) cell_methods.append(CellMethod("standard_deviation", coords="time")) if \ (grib.levelType == 'pl'): aux_coords_and_dims.append((DimCoord(points=grib.level, long_name="pressure", units="hPa"), None)) if \ (grib.levelType == 'sfc'): if (grib._cf_data is not None) and \ (grib._cf_data.set_height is not None): aux_coords_and_dims.append( (DimCoord(points=grib._cf_data.set_height, long_name="height", units="m", attributes={'positive': 'up'}), None)) elif grib.typeOfLevel == 'heightAboveGround': # required for NCAR aux_coords_and_dims.append((DimCoord(points=grib.level, long_name="height", units="m", attributes={'positive': 'up'}), None)) if \ (grib.levelType == 'ml') and \ (hasattr(grib, 'pv')): aux_coords_and_dims.append( (AuxCoord(grib.level, standard_name='model_level_number', attributes={'positive': 'up'}), None)) aux_coords_and_dims.append((DimCoord(grib.pv[grib.level], long_name='level_pressure', units='Pa'), None)) aux_coords_and_dims.append((AuxCoord( grib.pv[grib.numberOfCoordinatesValues // 2 + grib.level], long_name='sigma'), None)) factories.append( Factory(HybridPressureFactory, [{ 'long_name': 'level_pressure' }, { 'long_name': 'sigma' }, Reference('surface_pressure')])) if grib._originatingCentre != 'unknown': aux_coords_and_dims.append((AuxCoord(points=grib._originatingCentre, long_name='originating_centre', units='no_unit'), None)) return ConversionMetadata(factories, references, standard_name, long_name, units, attributes, cell_methods, dim_coords_and_dims, aux_coords_and_dims)
def test_string(self): token = 'air_temperature' result = CellMethod(self.method, coords=token) expected = '{}: {}'.format(self.method, token) self.assertEqual(str(result), expected)