def climatology_3d(): def jan_offset(day, year): dt = (datetime(year, 1, day) - datetime(1970, 1, 1)) return dt.total_seconds() / (24. * 3600) days = range(10, 15) years = [[year, year + 10] for year in [2001] * 4] days_since = [[jan_offset(day, yr1), jan_offset(day, yr2)] for (day, [yr1, yr2]) in zip(days, years)] time_bounds = np.array(days_since) time_points = time_bounds[..., 0] lon = np.linspace(-25, 25, 5) lat = np.linspace(0, 60, 3) time_dim = DimCoord(time_points, standard_name='time', bounds=time_bounds, units='days since 1970-01-01 00:00:00-00', climatological=True) lon_dim = DimCoord(lon, standard_name='longitude') lat_dim = DimCoord(lat, standard_name='latitude') data_shape = (len(time_points), len(lat), len(lon)) values = np.zeros(shape=data_shape, dtype=np.int8) cube = Cube(values) cube.add_dim_coord(time_dim, 0) cube.add_dim_coord(lat_dim, 1) cube.add_dim_coord(lon_dim, 2) cube.rename('climatology test') cube.units = 'Kelvin' cube.add_cell_method(CellMethod('mean over years', coords='time')) return cube
def test_unknown_method(self): cube = Cube([1, 2], long_name="odd_phenomenon") cube.add_cell_method(CellMethod(method="oddity", coords=("x",))) temp_dirpath = tempfile.mkdtemp() try: temp_filepath = os.path.join(temp_dirpath, "tmp.nc") iris.save(cube, temp_filepath) with warnings.catch_warnings(record=True) as warning_records: iris.load(temp_filepath) # Filter to get the warning we are interested in. warning_messages = [record.message for record in warning_records] warning_messages = [ warn for warn in warning_messages if isinstance(warn, UnknownCellMethodWarning) ] self.assertEqual(len(warning_messages), 1) message = warning_messages[0].args[0] msg = ( "NetCDF variable 'odd_phenomenon' contains unknown cell " "method 'oddity'" ) self.assertIn(msg, message) finally: shutil.rmtree(temp_dirpath)
def test_climatological_mean_single_year(self): cube = Cube(np.zeros((3, 4))) cube.add_aux_coord(AuxCoord(standard_name="forecast_period", units="hours", points=36, bounds=[24, 4 * 24])) cube.add_aux_coord( AuxCoord(standard_name="time", units="hours since epoch", points=240 + 36, bounds=[240 + 24, 240 + 4 * 24]) ) cube.add_aux_coord(AuxCoord(long_name="clim_season", points="DUMMY")) cube.add_cell_method(CellMethod("DUMMY", "clim_season")) field = self.convert_cube_to_field(cube) self.assertEqual(field.lbft, 4 * 24)
def create_difference_cube(cube, coord_name, diff_along_axis): """ Put the difference array into a cube with the appropriate metadata. Parameters ---------- cube : Iris.cube.Cube Cube from which the differences have been calculated. coord_name : String The name of the coordinate over which the difference have been calculated. diff_along_axis : numpy array Array containing the differences. Returns ------- diff_cube : Iris.cube.Cube Cube containing the differences calculated along the specified axis. """ points = cube.coord(coord_name).points mean_points = (points[1:] + points[:-1]) / 2 # Copy cube metadata and coordinates into a new cube. # Create a new coordinate for the coordinate along which the # difference has been calculated. metadata_dict = copy.deepcopy(cube.metadata._asdict()) diff_cube = Cube(diff_along_axis, **metadata_dict) for coord in cube.dim_coords: dims = cube.coord_dims(coord) if coord.name() in [coord_name]: coord = coord.copy(points=mean_points) diff_cube.add_dim_coord(coord.copy(), dims) for coord in cube.aux_coords: dims = cube.coord_dims(coord) diff_cube.add_aux_coord(coord.copy(), dims) for coord in cube.derived_coords: dims = cube.coord_dims(coord) diff_cube.add_aux_coord(coord.copy(), dims) # Add metadata to indicate that a difference has been calculated. # TODO: update this metadata when proper conventions have been # agreed upon. cell_method = CellMethod("difference", coords=[coord_name], intervals='1 grid length') diff_cube.add_cell_method(cell_method) diff_cube.attributes["form_of_difference"] = ("forward_difference") diff_cube.rename('difference_of_' + cube.name()) return diff_cube
def test_climatological_mean_single_year(self): cube = Cube(np.zeros((3, 4))) cube.add_aux_coord(AuxCoord(standard_name='forecast_period', units='hours', points=36, bounds=[24, 4 * 24])) cube.add_aux_coord(AuxCoord(standard_name='time', units='hours since epoch', points=240 + 36, bounds=[240 + 24, 240 + 4 * 24])) cube.add_aux_coord(AuxCoord(long_name='clim_season', points='DUMMY')) cube.add_cell_method(CellMethod('DUMMY', 'clim_season')) field = self.convert_cube_to_field(cube) self.assertEqual(field.lbft, 4 * 24)
def create_difference_cube(self, cube, coord_name, diff_along_axis): """ Put the difference array into a cube with the appropriate metadata. Args: cube (iris.cube.Cube): Cube from which the differences have been calculated. coord_name (str): The name of the coordinate over which the difference have been calculated. diff_along_axis (numpy.ndarray): Array containing the differences. Returns: iris.cube.Cube: Cube containing the differences calculated along the specified axis. """ points = cube.coord(coord_name).points mean_points = (points[1:] + points[:-1]) / 2 # Copy cube metadata and coordinates into a new cube. # Create a new coordinate for the coordinate along which the # difference has been calculated. metadata_dict = copy.deepcopy(cube.metadata._asdict()) diff_cube = Cube(diff_along_axis, **metadata_dict) for coord in cube.dim_coords: dims = cube.coord_dims(coord) if coord.name() in [coord_name]: coord = coord.copy(points=mean_points) diff_cube.add_dim_coord(coord.copy(), dims) for coord in cube.aux_coords: dims = cube.coord_dims(coord) diff_cube.add_aux_coord(coord.copy(), dims) for coord in cube.derived_coords: dims = cube.coord_dims(coord) diff_cube.add_aux_coord(coord.copy(), dims) # Add metadata to indicate that a difference has been calculated. # TODO: update metadata for difference and add metadata for gradient # when proper conventions have been agreed upon. if not self.is_gradient: cell_method = CellMethod("difference", coords=[coord_name], intervals="1 grid length") diff_cube.add_cell_method(cell_method) diff_cube.attributes["form_of_difference"] = "forward_difference" diff_cube.rename("difference_of_" + cube.name()) return diff_cube
def create_cube(self, fp_min, fp_mid, fp_max, ref_offset, season=None): cube = Cube(np.zeros((3, 4))) cube.add_aux_coord(AuxCoord(standard_name='forecast_period', units='hours', points=fp_mid, bounds=[fp_min, fp_max])) cube.add_aux_coord(AuxCoord(standard_name='time', units='hours since epoch', points=ref_offset + fp_mid, bounds=[ref_offset + fp_min, ref_offset + fp_max])) if season: cube.add_aux_coord(AuxCoord(long_name='clim_season', points=season)) cube.add_cell_method(CellMethod('DUMMY', 'clim_season')) return cube
def create_cube(self, fp_min, fp_mid, fp_max, ref_offset, season=None): cube = Cube(np.zeros((3, 4))) cube.add_aux_coord( AuxCoord(standard_name="forecast_period", units="hours", points=fp_mid, bounds=[fp_min, fp_max]) ) cube.add_aux_coord( AuxCoord( standard_name="time", units="hours since epoch", points=ref_offset + fp_mid, bounds=[ref_offset + fp_min, ref_offset + fp_max], ) ) if season: cube.add_aux_coord(AuxCoord(long_name="clim_season", points=season)) cube.add_cell_method(CellMethod("DUMMY", "clim_season")) return cube
def _update_metadata(diff_cube: Cube, coord_name: str, cube_name: str) -> None: """Rename cube, add attribute and cell method to describe difference. Args: diff_cube coord_name cube_name """ # Add metadata to indicate that a difference has been calculated. # TODO: update metadata for difference when # proper conventions have been agreed upon. cell_method = CellMethod( "difference", coords=[coord_name], intervals="1 grid length" ) diff_cube.add_cell_method(cell_method) diff_cube.attributes["form_of_difference"] = "forward_difference" diff_cube.rename("difference_of_" + cube_name)
def test_section_cell_methods(self): cube = Cube([0], long_name="name", units=1) cube.add_cell_method(CellMethod("stdev", "area")) cube.add_cell_method( CellMethod( method="mean", coords=["y", "time"], intervals=["10m", "3min"], comments=["vertical", "=duration"], )) rep = cube_replines(cube) # Note: not alphabetical -- provided order is significant expected = [ "name / (1) (-- : 1)", " Cell methods:", " stdev area", " mean y (10m, vertical), time (3min, =duration)", ] self.assertEqual(rep, expected)
def test_unknown_method(self): cube = Cube([1, 2], long_name='odd_phenomenon') cube.add_cell_method(CellMethod(method='oddity', coords=('x',))) temp_dirpath = tempfile.mkdtemp() try: temp_filepath = os.path.join(temp_dirpath, 'tmp.nc') iris.save(cube, temp_filepath) with warnings.catch_warnings(record=True) as warning_records: iris.load(temp_filepath) # Filter to get the warning we are interested in. warning_messages = [record.message for record in warning_records] warning_messages = [warn for warn in warning_messages if isinstance(warn, UnknownCellMethodWarning)] self.assertEqual(len(warning_messages), 1) message = warning_messages[0].args[0] msg = ("NetCDF variable 'odd_phenomenon' contains unknown cell " "method 'oddity'") self.assertIn(msg, message) finally: shutil.rmtree(temp_dirpath)
def test_climatological_mean_single_year(self): cube = Cube(np.zeros((3, 4))) cube.add_aux_coord( AuxCoord( standard_name="forecast_period", units="hours", points=36, bounds=[24, 4 * 24], )) cube.add_aux_coord( AuxCoord( standard_name="time", units="hours since epoch", points=240 + 36, bounds=[240 + 24, 240 + 4 * 24], )) cube.add_aux_coord(AuxCoord(long_name="clim_season", points="DUMMY")) cube.add_cell_method(CellMethod("DUMMY", "clim_season")) field = self.convert_cube_to_field(cube) self.assertEqual(field.lbft, 4 * 24)
def create_cube(self, fp_min, fp_mid, fp_max, ref_offset, season=None): cube = Cube(np.zeros((3, 4))) cube.add_aux_coord( AuxCoord( standard_name="forecast_period", units="hours", points=fp_mid, bounds=[fp_min, fp_max], )) cube.add_aux_coord( AuxCoord( standard_name="time", units="hours since epoch", points=ref_offset + fp_mid, bounds=[ref_offset + fp_min, ref_offset + fp_max], )) if season: cube.add_aux_coord(AuxCoord(long_name="clim_season", points=season)) cube.add_cell_method(CellMethod("DUMMY", "clim_season")) return cube