Example #1
0
 def test_set_lazy(self):
     # Setting new lazy bounds realises them.
     coord = DimCoord(self.pts_real, bounds=self.bds_lazy)
     new_bounds = self.bds_lazy + 102.3
     coord.bounds = new_bounds
     result = coord.core_bounds()
     self.assertEqualRealArraysAndDtypes(result, new_bounds.compute())
Example #2
0
 def test_real_points(self):
     # Getting real points returns a copy
     coord = DimCoord(self.pts_real)
     result = coord.core_points()
     self.assertArraysDoNotShareData(
         result, self.pts_real,
         'Points are the same array as the provided data.')
Example #3
0
 def test_set_lazy(self):
     # Setting new lazy points realises them.
     coord = DimCoord(self.pts_real)
     new_pts = self.pts_lazy + 102.3
     coord.points = new_pts
     result = coord.core_points()
     self.assertEqualRealArraysAndDtypes(result, new_pts.compute())
Example #4
0
 def test_real_points(self):
     # Getting real points does not change or copy them.
     coord = DimCoord(self.pts_real)
     result = coord.core_points()
     self.assertArraysShareData(
         result, self.pts_real,
         'Points are not the same array as the provided data.')
Example #5
0
 def test_real_points(self):
     data = self.pts_real
     coord = DimCoord(data)
     result = coord.core_points()
     self.assertArraysShareData(
         result, self.pts_real,
         'core_points() are not the same data as the internal array.')
Example #6
0
 def test_short_time_interval(self):
     coord = DimCoord([5], standard_name='time',
                      units='days since 1970-01-01')
     expected = ("DimCoord([1970-01-06 00:00:00], standard_name='time', "
                 "calendar='gregorian')")
     result = coord.__str__()
     self.assertEqual(expected, result)
Example #7
0
 def test_fail_not_monotonic(self):
     # Setting real bounds requires that they are monotonic.
     coord = DimCoord(self.pts_real, bounds=self.bds_real)
     msg = 'strictly monotonic'
     with self.assertRaisesRegexp(ValueError, msg):
         coord.bounds = np.array([[3.0, 2.0], [1.0, 0.0], [2.0, 1.0]])
     self.assertArrayEqual(coord.bounds, self.bds_real)
Example #8
0
 def test_fail_bad_shape(self):
     # Setting real points requires matching shape.
     coord = DimCoord(self.pts_real, bounds=self.bds_real)
     msg = 'The shape of the bounds array should be'
     with self.assertRaisesRegexp(ValueError, msg):
         coord.bounds = np.array([1.0, 2.0, 3.0])
     self.assertArrayEqual(coord.bounds, self.bds_real)
Example #9
0
 def _make_partially_collapsed_coord(self, coord, grid, guessed_axis):
     """
     Make a new DimCoord which represents a partially collapsed (aggregated into bins) coordinate.
     This dimcoord will have a grid
     :type coord: data_io.Coord.Coord
     :param coord: Coordinate to partially collapse
     :type grid: aggregation.aggregation_grid.AggregationGrid
     :param grid: grid on which this coordinate will aggregate
     :type guessed_axis: str
     :param guessed_axis: String identifier of the axis to which this coordinate belongs (e.g. 'T', 'X')
     :return: DimCoord
     """
     if grid.is_time or guessed_axis == 'T':
         # Ensure that the limits are date/times.
         dt = parse_datetime.convert_datetime_components_to_datetime(grid.start, True)
         grid_start = Subset._convert_datetime_to_coord_unit(coord, dt)
         dt = parse_datetime.convert_datetime_components_to_datetime(grid.end, False)
         grid_end = Subset._convert_datetime_to_coord_unit(coord, dt)
         grid_delta = grid.delta
     else:
         # Assume to be a non-time axis
         (grid_start, grid_end) = Subset._fix_non_circular_limits(float(grid.start), float(grid.end))
         grid_delta = float(grid.delta)
     new_coordinate_grid = aggregation_grid_array(grid_start, grid_end, grid_delta, grid.is_time, coord)
     new_coord = DimCoord(new_coordinate_grid, var_name=coord.name(), standard_name=coord.standard_name,
                          units=coord.units)
     if len(new_coord.points) == 1:
         new_coord.bounds = [[grid_start, grid_end]]
     else:
         new_coord.guess_bounds()
     return new_coord
Example #10
0
 def test_long_time_interval__bounded(self):
     coord = DimCoord([5, 6], standard_name='time',
                      units='years since 1970-01-01')
     coord.guess_bounds()
     expected = ("DimCoord([5 6], bounds=[[4.5 5.5]\n [5.5 6.5]], "
                 "standard_name='time', calendar='gregorian')")
     result = coord.__str__()
     self.assertEqual(expected, result)
Example #11
0
 def test_fail_bad_shape(self):
     # Setting real points requires matching shape.
     points = [1.0, 2.0]
     coord = DimCoord(points)
     msg = 'Require data with shape \(2,\), got \(3,\)'
     with self.assertRaisesRegexp(ValueError, msg):
         coord.points = np.array([1.0, 2.0, 3.0])
     self.assertArrayEqual(coord.points, points)
Example #12
0
 def test_set_real(self):
     # Setting points does not copy, but makes a readonly view.
     coord = DimCoord(self.pts_real)
     new_pts = self.pts_real + 102.3
     coord.points = new_pts
     result = coord.core_points()
     self.assertArraysShareData(
         result, new_pts,
         'Points are not the same data as the assigned array.')
Example #13
0
 def test_1d_coord_no_bounds_warning(self):
     coord = DimCoord([0, 1, 2], standard_name='latitude')
     msg = "Coordinate 'latitude' is not bounded, guessing contiguous " \
           "bounds."
     with warnings.catch_warnings():
         # Cause all warnings to raise Exceptions
         warnings.simplefilter("error")
         with self.assertRaisesRegexp(Warning, msg):
             coord.contiguous_bounds()
Example #14
0
 def test_set_real(self):
     # Setting points copies the data
     coord = DimCoord(self.pts_real)
     new_pts = self.pts_real + 102.3
     coord.points = new_pts
     result = coord.core_points()
     self.assertArraysDoNotShareData(
         result, new_pts,
         'Points are the same data as the assigned array.')
Example #15
0
 def test_set_real(self):
     # Setting bounds does not copy, but makes a readonly view.
     coord = DimCoord(self.pts_real, bounds=self.bds_real)
     new_bounds = self.bds_real + 102.3
     coord.bounds = new_bounds
     result = coord.core_bounds()
     self.assertArraysShareData(
         result, new_bounds,
         'Bounds are not the same data as the assigned array.')
Example #16
0
 def test_short_time_interval__bounded(self):
     coord = DimCoord([5, 6], standard_name='time',
                      units='days since 1970-01-01')
     coord.guess_bounds()
     expected = ("DimCoord([1970-01-06 00:00:00, 1970-01-07 00:00:00], "
                 "bounds=[[1970-01-05 12:00:00, 1970-01-06 12:00:00],\n"
                 "       [1970-01-06 12:00:00, 1970-01-07 12:00:00]], "
                 "standard_name='time', calendar='gregorian')")
     result = coord.__str__()
     self.assertEqual(expected, result)
Example #17
0
 def setUp(self):
     self.sigma = DimCoord(np.arange(5, dtype=np.float) * 10, long_name="sigma", units="1")
     self.eta = AuxCoord(np.arange(4, dtype=np.float).reshape(2, 2), long_name="eta", units="m")
     self.depth = AuxCoord(np.arange(4, dtype=np.float).reshape(2, 2) * 10, long_name="depth", units="m")
     self.depth_c = AuxCoord([15], long_name="depth_c", units="m")
     self.nsigma = AuxCoord([3], long_name="nsigma")
     self.zlev = DimCoord(np.arange(5, dtype=np.float) * 10, long_name="zlev", units="m")
     self.kwargs = dict(
         sigma=self.sigma, eta=self.eta, depth=self.depth, depth_c=self.depth_c, nsigma=self.nsigma, zlev=self.zlev
     )
Example #18
0
 def test__discontiguity_in_bounds_call(self):
     # Check that :meth:`iris.coords.Coord._discontiguity_in_bounds` is
     # called.
     coord = DimCoord([1, 3], bounds=[[0, 2], [2, 4]])
     with mock.patch('iris.coords.Coord._discontiguity_in_bounds'
                     ) as discontiguity_check:
         # Discontiguity returns two objects that are unpacked in
         # `coord.is_contiguous`.
         discontiguity_check.return_value = [None, None]
         coord.is_contiguous(rtol=1e-1, atol=1e-3)
     discontiguity_check.assert_called_with(rtol=1e-1, atol=1e-3)
Example #19
0
 def test_dim_1d(self):
     # Numeric coords should not be serialised.
     coord = DimCoord(points=np.array([2, 4, 6, 8]),
                      bounds=np.array([[1, 3], [3, 5], [5, 7], [7, 9]]))
     for units in ['unknown', 'no_unit', 1, 'K']:
         coord.units = units
         collapsed_coord = coord.collapsed()
         self.assertArrayEqual(collapsed_coord.points,
                               np.mean(coord.points))
         self.assertArrayEqual(collapsed_coord.bounds,
                               [[coord.bounds.min(), coord.bounds.max()]])
Example #20
0
 def test_formula_terms_p0_bounded(self):
     coord_a = DimCoord(range(5))
     coord_p0 = DimCoord(1, bounds=[0, 2], var_name='p0')
     self.provides['coordinates'].extend([(coord_a, 'a'), (coord_p0, 'p0')])
     self.requires['formula_terms'] = dict(a='a', b='b', ps='ps', p0='p0')
     with warnings.catch_warnings(record=True) as warn:
         warnings.simplefilter('always')
         _load_aux_factory(self.engine, self.cube)
         self.assertEqual(len(warn), 1)
         msg = 'Ignoring atmosphere hybrid sigma pressure scalar ' \
             'coordinate {!r} bounds.'.format(coord_p0.name())
         self.assertEqual(msg, warn[0].message.message)
Example #21
0
 def test_longitude_0_360_one_degree(self):
     x = np.arange(0.5, 360.5, 1)
     y = np.array([50.5, 51.5])
     values = np.arange(len(y) * len(x)).reshape((len(y), len(x)))
     latitude = DimCoord(y, standard_name='latitude', units='degrees')
     longitude = DimCoord(x, standard_name='longitude', units='degrees')
     data = make_from_cube(Cube(values, dim_coords_and_dims=[(latitude, 0), (longitude, 1)]))
     out_values, out_x, out_y= Generic2DPlot._cube_manipulation(data, longitude.contiguous_bounds(),
                                                                latitude.contiguous_bounds())
     x_bounds = np.arange(0, 361, 1)
     y_bounds = np.array([50, 51, 52])
     assert_arrays_equal(out_x, x_bounds)
     assert_arrays_equal(out_y, y_bounds)
 def setUp(self):
     self.sigma = DimCoord(np.arange(5, dtype=np.float) * 10,
                           long_name='sigma', units='1')
     self.eta = AuxCoord(np.arange(4, dtype=np.float).reshape(2, 2),
                         long_name='eta', units='m')
     self.depth = AuxCoord(np.arange(4, dtype=np.float).reshape(2, 2) * 10,
                           long_name='depth', units='m')
     self.depth_c = AuxCoord([15], long_name='depth_c', units='m')
     self.nsigma = AuxCoord([3], long_name='nsigma')
     self.zlev = DimCoord(np.arange(5, dtype=np.float) * 10,
                          long_name='zlev', units='m')
     self.kwargs = dict(sigma=self.sigma, eta=self.eta, depth=self.depth,
                        depth_c=self.depth_c, nsigma=self.nsigma,
                        zlev=self.zlev)
Example #23
0
class Test_nearest_neighbour_index__descending(tests.IrisTest):
    def setUp(self):
        points = [270., 180., 90., 0.]
        self.coord = DimCoord(points, circular=False,
                              units='degrees')

    def _test_nearest_neighbour_index(self, target, bounds=False,
                                      circular=False):
        _bounds = [[340, 260], [260, 100], [100, 10], [10, -20]]
        ext_pnts = [-70, -10, 110, 275, 370]
        if bounds:
            self.coord.bounds = _bounds
        self.coord.circular = circular
        results = [self.coord.nearest_neighbour_index(ind) for ind in ext_pnts]
        self.assertEqual(results, target)

    def test_nobounds(self):
        target = [3, 3, 2, 0, 0]
        self._test_nearest_neighbour_index(target)

    def test_nobounds_circular(self):
        target = [0, 3, 2, 0, 3]
        self._test_nearest_neighbour_index(target, circular=True)

    def test_bounded(self):
        target = [3, 3, 1, 0, 0]
        self._test_nearest_neighbour_index(target, bounds=True)

    def test_bounded_circular(self):
        target = [0, 3, 1, 0, 3]
        self._test_nearest_neighbour_index(target, bounds=True, circular=True)
Example #24
0
 def test_lat_lon_decreasing_no_bounds(self):
     x = np.array([0.5, -0.5])
     y = np.array([51.5, 50.5])
     values = np.array([[1, 2], [3, 4]])
     latitude = DimCoord(y, standard_name='latitude', units='degrees')
     longitude = DimCoord(x, standard_name='longitude', units='degrees')
     data = make_from_cube(Cube(values, dim_coords_and_dims=[(latitude, 0), (longitude, 1)]))
     out_values, out_x, out_y= Generic2DPlot._cube_manipulation(data, longitude.contiguous_bounds(),
                                                                latitude.contiguous_bounds())
     expected_x = np.array([1, 0, -1])
     expected_y = np.array([52, 51, 50])
     expected_v = np.array([[1, 2],
                            [3, 4]])
     assert_arrays_equal(out_x, expected_x)
     assert_arrays_equal(out_y, expected_y)
     assert_arrays_equal(out_values, expected_v)
Example #25
0
    def test_writable_points(self):
        coord1 = DimCoord(np.arange(5),
                          bounds=[[0, 1], [1, 2], [2, 3], [3, 4], [4, 5]])
        coord2 = coord1.copy()
        msg = 'destination is read-only'

        with self.assertRaisesRegexp(ValueError, msg):
            coord1.points[:] = 0

        with self.assertRaisesRegexp(ValueError, msg):
            coord2.points[:] = 0

        with self.assertRaisesRegexp(ValueError, msg):
            coord1.bounds[:] = 0

        with self.assertRaisesRegexp(ValueError, msg):
            coord2.bounds[:] = 0
Example #26
0
 def test_formula_terms_p0_bounded(self):
     coord_a = DimCoord(np.arange(5))
     coord_p0 = DimCoord(1, bounds=[0, 2], var_name="p0")
     self.provides["coordinates"].extend([(coord_a, "a"), (coord_p0, "p0")])
     self.requires["formula_terms"] = dict(a="a", b="b", ps="ps", p0="p0")
     with warnings.catch_warnings(record=True) as warn:
         warnings.simplefilter("always")
         _load_aux_factory(self.engine, self.cube)
         self.assertEqual(len(warn), 1)
         msg = "Ignoring atmosphere hybrid sigma pressure scalar " "coordinate {!r} bounds.".format(coord_p0.name())
         self.assertEqual(msg, warn[0].message.message)
Example #27
0
def _add_iris_coord(cube, name, points, dim, calendar=None):
    """
    Add a Coord to a Cube from a Pandas index or columns array.

    If no calendar is specified for a time series, Gregorian is assumed.

    """
    units = Unit("unknown")
    if calendar is None:
        calendar = iris.unit.CALENDAR_GREGORIAN

    # Convert pandas datetime objects to python datetime obejcts.
    if isinstance(points, pandas.tseries.index.DatetimeIndex):
        points = np.array([i.to_datetime() for i in points])

    # Convert datetime objects to Iris' current datetime representation.
    if points.dtype == object:
        dt_types = (datetime.datetime, netcdftime.datetime)
        if all([isinstance(i, dt_types) for i in points]):
            units = Unit("hours since epoch", calendar=calendar)
            points = units.date2num(points)

    points = np.array(points)
    if (np.issubdtype(points.dtype, np.number) and
            iris.util.monotonic(points, strict=True)):
                coord = DimCoord(points, units=units)
                coord.rename(name)
                cube.add_dim_coord(coord, dim)
    else:
        coord = AuxCoord(points, units=units)
        coord.rename(name)
        cube.add_aux_coord(coord, dim)
Example #28
0
def uv_cubes(x=None, y=None):
    """Return u, v cubes with a grid in a rotated pole CRS."""
    cs = iris.coord_systems.RotatedGeogCS(grid_north_pole_latitude=37.5,
                                          grid_north_pole_longitude=177.5)
    if x is None:
        x = np.linspace(311.9, 391.1, 6)
    if y is None:
        y = np.linspace(-23.6, 24.8, 5)

    x2d, y2d = np.meshgrid(x, y)
    u = 10 * (2 * np.cos(2 * np.deg2rad(x2d) + 3 * np.deg2rad(y2d + 30)) ** 2)
    v = 20 * np.cos(6 * np.deg2rad(x2d))
    lon = DimCoord(x, standard_name='grid_longitude', units='degrees',
                   coord_system=cs)
    lat = DimCoord(y, standard_name='grid_latitude', units='degrees',
                   coord_system=cs)
    u_cube = Cube(u, standard_name='x_wind', units='m/s')
    v_cube = Cube(v, standard_name='y_wind', units='m/s')
    for cube in (u_cube, v_cube):
        cube.add_dim_coord(lat.copy(), 0)
        cube.add_dim_coord(lon.copy(), 1)
    return u_cube, v_cube
Example #29
0
class Test_guess_bounds(tests.IrisTest):
    def setUp(self):
        self.coord = DimCoord(np.array([-160, -120, 0, 30, 150, 170]),
                              units='degree', standard_name='longitude',
                              circular=True)

    def test_non_circular(self):
        self.coord.circular = False
        self.coord.guess_bounds()
        target = np.array([[-180., -140.], [-140., -60.], [-60., 15.],
                           [15., 90.], [90., 160.], [160., 180.]])
        self.assertArrayEqual(target, self.coord.bounds)

    def test_circular_increasing(self):
        self.coord.guess_bounds()
        target = np.array([[-175., -140.], [-140., -60.], [-60., 15.],
                           [15., 90.], [90., 160.], [160., 185.]])
        self.assertArrayEqual(target, self.coord.bounds)

    def test_circular_decreasing(self):
        self.coord.points = self.coord.points[::-1]
        self.coord.guess_bounds()
        target = np.array([[185., 160.], [160., 90.], [90., 15.],
                           [15., -60.], [-60., -140.], [-140., -175.]])
        self.assertArrayEqual(target, self.coord.bounds)

    def test_circular_increasing_alt_range(self):
        self.coord.points = np.array([10, 30, 90, 150, 210, 220])
        self.coord.guess_bounds()
        target = np.array([[-65., 20.], [20., 60.], [60., 120.],
                           [120., 180.], [180., 215.], [215., 295.]])
        self.assertArrayEqual(target, self.coord.bounds)

    def test_circular_decreasing_alt_range(self):
        self.coord.points = np.array([10, 30, 90, 150, 210, 220])[::-1]
        self.coord.guess_bounds()
        target = np.array([[295, 215], [215, 180], [180, 120], [120, 60],
                           [60, 20], [20, -65]])
        self.assertArrayEqual(target, self.coord.bounds)
Example #30
0
def uv_cubes_3d(ref_cube, n_realization=3):
    """
    Return 3d u, v cubes with a grid in a rotated pole CRS taken from
    the provided 2d cube, by adding a realization dimension
    coordinate bound to teh zeroth dimension.

    """
    lat = ref_cube.coord('grid_latitude')
    lon = ref_cube.coord('grid_longitude')
    x2d, y2d = np.meshgrid(lon.points, lat.points)
    u = 10 * (2 * np.cos(2 * np.deg2rad(x2d) + 3 * np.deg2rad(y2d + 30)) ** 2)
    v = 20 * np.cos(6 * np.deg2rad(x2d))
    # Multiply slices by factor to give variation over 0th dim.
    factor = np.arange(1, n_realization + 1).reshape(n_realization, 1, 1)
    u = factor * u
    v = factor * v
    realization = DimCoord(np.arange(n_realization), 'realization')
    u_cube = Cube(u, standard_name='x_wind', units='m/s')
    v_cube = Cube(v, standard_name='y_wind', units='m/s')
    for cube in (u_cube, v_cube):
        cube.add_dim_coord(realization.copy(), 0)
        cube.add_dim_coord(lat.copy(), 1)
        cube.add_dim_coord(lon.copy(), 2)
    return u_cube, v_cube
Example #31
0
 def test_real_bounds(self):
     coord = DimCoord(self.pts_real, bounds=self.bds_real)
     result = coord.core_bounds()
     self.assertArraysDoNotShareData(
         result, self.bds_real,
         'core_bounds() are the same data as the internal array.')
Example #32
0
    def create_data_object(self, filenames, variable, index_offset=1):
        from cis.data_io.hdf_vd import get_data
        from cis.data_io.hdf_vd import VDS
        from pyhdf.error import HDF4Error
        from cis.data_io import hdf_sd
        from iris.coords import DimCoord, AuxCoord
        from iris.cube import Cube
        from cis.data_io.gridded_data import GriddedData
        from cis.time_util import cis_standard_time_unit

        logging.debug("Creating data object for variable " + variable)

        variables = ['Latitude', 'Longitude', "Profile_Time", "Pressure"]
        logging.info("Listing coordinates: " + str(variables))

        variables.append(variable)

        # reading data from files
        sdata = {}
        for filename in filenames:
            try:
                sds_dict = hdf_sd.read(filename, variables)
            except HDF4Error as e:
                raise IOError(str(e))

            for var in list(sds_dict.keys()):
                utils.add_element_to_list_in_dict(sdata, var, sds_dict[var])

        alt_name = "altitude"
        logging.info("Additional coordinates: '" + alt_name + "'")

        # work out size of data arrays
        # the coordinate variables will be reshaped to match that.
        # NOTE: This assumes that all Caliop_L1 files have the same altitudes.
        #       If this is not the case, then the following line will need to be changed
        #       to concatenate the data from all the files and not just arbitrarily pick
        #       the altitudes from the first file.
        alt_data = get_data(VDS(filenames[0], "Lidar_Data_Altitudes"), True)

        alt_coord = DimCoord(alt_data, standard_name='altitude', units='km')
        alt_coord.convert_units('m')

        lat_data = hdf.read_data(sdata['Latitude'],
                                 self._get_calipso_data)[:, index_offset]
        lat_coord = AuxCoord(lat_data, standard_name='latitude')

        pres_data = hdf.read_data(sdata['Pressure'], self._get_calipso_data)
        pres_coord = AuxCoord(pres_data,
                              standard_name='air_pressure',
                              units='hPa')

        # longitude
        lon = sdata['Longitude']
        lon_data = hdf.read_data(lon, self._get_calipso_data)[:, index_offset]
        lon_coord = AuxCoord(lon_data, standard_name='longitude')

        # profile time, x
        time = sdata['Profile_Time']
        time_data = hdf.read_data(time, self._get_calipso_data)[:,
                                                                index_offset]
        time_coord = DimCoord(time_data,
                              long_name='Profile_Time',
                              standard_name='time',
                              units="seconds since 1993-01-01 00:00:00")
        time_coord.convert_units(cis_standard_time_unit)

        # retrieve data + its metadata
        var = sdata[variable]
        metadata = hdf.read_metadata(var, "SD")

        if variable in MIXED_RESOLUTION_VARIABLES:
            logging.warning(
                "Using Level 2 resolution profile for mixed resolution variable {}. See CALIPSO "
                "documentation for more details".format(variable))
            data = hdf.read_data(var, self._get_mixed_resolution_calipso_data)
        else:
            data = hdf.read_data(var, self._get_calipso_data)

        cube = Cube(data,
                    long_name=metadata.long_name,
                    units=self.clean_units(metadata.units),
                    dim_coords_and_dims=[(alt_coord, 1), (time_coord, 0)],
                    aux_coords_and_dims=[(lat_coord, (0, )),
                                         (lon_coord, (0, )),
                                         (pres_coord, (0, 1))])
        gd = GriddedData.make_from_cube(cube)
        return gd
Example #33
0
 def test_valid(self):
     coords_and_dims = _convert_scalar_realization_coords(lbrsvd4=21)
     self.assertEqual(coords_and_dims,
                      [(DimCoord([21], standard_name='realization'), None)])
Example #34
0
 def setUp(self):
     self.cube_a = Cube([[1, 2, 3], [4, 5, 6]], long_name='a')
     self.x_coord = DimCoord([11, 12, 13], long_name='x')
     self.y_coord = DimCoord([21, 22], long_name='y')
     self.cube_a.add_dim_coord(self.x_coord, 1)
     self.cube_a.add_dim_coord(self.y_coord, 0)
Example #35
0
 def test_dup(self):
     c1 = self.ref_co_1d
     c2 = DimCoord([1, 2])
     self._coords_eq(c1, c2)
Example #36
0
    print experiment_id
    sys.stdout.flush()

    cube = iris.load_cube(fu, glob_tc)

    #pdb.set_trace()

    mean_list = []
    for pressure_cube in (cube.slices(
        ['time', 'grid_latitude', 'grid_longitude'])):

        time_coords = pressure_cube.coord('time')
        add_hour_of_day(pressure_cube, time_coords)

        pc_time_merge = pressure_cube.aggregated_by('hour', iris.analysis.MEAN)
        pc_time_merge.add_dim_coord(DimCoord(points=pc_time_merge.coords('time')[0].bounds[:,0].flatten(),\
                                           long_name='time', standard_name='time',units=pc_time_merge.coords('time')[0].units),0)

        mean_list.extend(iris.cube.CubeList([pc_time_merge]))

    #pdb.set_trace()

    mean = iris.cube.CubeList(mean_list).merge_cube()

    mean.coord('grid_latitude').guess_bounds()
    mean.coord('grid_longitude').guess_bounds()

    if dm == 'temp':
        mean.rename('potential_temperature')
        mean.units = iris.unit.Unit('K')
    if dm == 'sp_hum':
        mean.rename('specific_humidity')
def build_spotdata_cube(
    data,
    name,
    units,
    altitude,
    latitude,
    longitude,
    wmo_id,
    scalar_coords=None,
    neighbour_methods=None,
    grid_attributes=None,
    additional_dims=None,
):
    """
    Function to build a spotdata cube with expected dimension and auxiliary
    coordinate structure.

    It can be used to create spot data cubes. In this case the data is the
    spot data values at each site, and the coordinates that describe each site.

    It can also be used to create cubes which describe the grid points that are
    used to extract each site from a gridded field, for different selection
    method. The selection methods are specified by the neighbour_methods
    coordinate. The grid_attribute coordinate encapsulates information required
    to extract data, for example the x/y indices that identify the grid point
    neighbour.

    .. See the documentation for examples of these cubes.
    .. include:: extended_documentation/spotdata/build_spotdata_cube/
       build_spotdata_cube_examples.rst

    Args:
        data (float or numpy.ndarray):
            Float spot data or array of data points from several sites.
            The spot index should be the last dimension if the array is
            multi-dimensional (see optional additional dimensions below).
        name (str):
            Cube name (eg 'air_temperature')
        units (str):
            Cube units (eg 'K')
        altitude (float or numpy.ndarray):
            Float or 1d array of site altitudes in metres
        latitude (float or numpy.ndarray):
            Float or 1d array of site latitudes in degrees
        longitude (float or numpy.ndarray):
            Float or 1d array of site longitudes in degrees
        wmo_id (str or list of str):
            String or list of site 5-digit WMO identifiers
        scalar_coords (list of iris.coords.AuxCoord):
            Optional list of iris.coords.AuxCoord instances
        neighbour_methods (list of str):
            Optional list of neighbour method names, e.g. 'nearest'
        grid_attributes (list of str):
            Optional list of grid attribute names, e.g. x-index, y-index
        additional_dims (list of iris.coords.DimCoord):
            Optional list of additional dimensions to preceed the spot data dimension.

    Returns:
        iris.cube.Cube:
            A cube containing the extracted spot data with spot data being the final dimension.
    """

    # construct auxiliary coordinates
    alt_coord = AuxCoord(altitude, "altitude", units="m")
    lat_coord = AuxCoord(latitude, "latitude", units="degrees")
    lon_coord = AuxCoord(longitude, "longitude", units="degrees")
    id_coord = AuxCoord(wmo_id, long_name="wmo_id", units="no_unit")

    aux_coords_and_dims = []

    # append scalar coordinates
    if scalar_coords is not None:
        for coord in scalar_coords:
            aux_coords_and_dims.append((coord, None))

    # construct dimension coordinates
    if np.isscalar(data):
        data = np.array([data])
    spot_index = DimCoord(
        np.arange(data.shape[-1], dtype=np.int32), long_name="spot_index", units="1"
    )

    dim_coords_and_dims = []
    current_dim = 0

    if neighbour_methods is not None:
        neighbour_methods_coord = DimCoord(
            np.arange(len(neighbour_methods), dtype=np.int32),
            long_name="neighbour_selection_method",
            units="1",
        )
        neighbour_methods_key = AuxCoord(
            neighbour_methods,
            long_name="neighbour_selection_method_name",
            units="no_unit",
        )

        dim_coords_and_dims.append((neighbour_methods_coord, current_dim))
        aux_coords_and_dims.append((neighbour_methods_key, current_dim))
        current_dim += 1

    if grid_attributes is not None:
        grid_attributes_coord = DimCoord(
            np.arange(len(grid_attributes), dtype=np.int32),
            long_name="grid_attributes",
            units="1",
        )
        grid_attributes_key = AuxCoord(
            grid_attributes, long_name="grid_attributes_key", units="no_unit"
        )

        dim_coords_and_dims.append((grid_attributes_coord, current_dim))
        aux_coords_and_dims.append((grid_attributes_key, current_dim))
        current_dim += 1

    if additional_dims is not None:
        for coord in additional_dims:
            dim_coords_and_dims.append((coord, current_dim))
            current_dim += 1

    dim_coords_and_dims.append((spot_index, current_dim))
    for coord in [alt_coord, lat_coord, lon_coord, id_coord]:
        aux_coords_and_dims.append((coord, current_dim))

    # create output cube
    spot_cube = iris.cube.Cube(
        data,
        long_name=name,
        units=units,
        dim_coords_and_dims=dim_coords_and_dims,
        aux_coords_and_dims=aux_coords_and_dims,
    )
    # rename to force a standard name to be set if name is valid
    spot_cube.rename(name)

    return spot_cube
Example #38
0
def add_coordinate(
    incube,
    coord_points,
    coord_name,
    coord_units=None,
    dtype=np.float32,
    order=None,
    is_datetime=False,
    attributes=None,
):
    """
    Function to duplicate a sample cube with an additional coordinate to create
    a cubelist. The cubelist is merged to create a single cube, which can be
    reordered to place the new coordinate in the required position.

    Args:
        incube (iris.cube.Cube):
            Cube to be duplicated.
        coord_points (list or numpy.ndarray):
            Values for the coordinate.
        coord_name (str):
            Long name of the coordinate to be added.
        coord_units (str):
            Coordinate unit required.
        dtype (type):
            Datatype for coordinate points.
        order (list):
            Optional list of integers to reorder the dimensions on the new
            merged cube.  For example, if the new coordinate is required to
            be in position 1 on a 4D cube, use order=[1, 0, 2, 3] to swap the
            new coordinate position with that of the original leading
            coordinate.
        is_datetime (bool):
            If "true", the leading coordinate points have been given as a
            list of datetime objects and need converting.  In this case the
            "coord_units" argument is overridden and the time points provided
            in seconds.  The "dtype" argument is overridden and set to int64.
        attributes (dict):
            Optional coordinate attributes.

    Returns:
        iris.cube.Cube:
            Cube containing an additional dimension coordinate.
    """
    # if the coordinate already exists as a scalar coordinate, remove it
    cube = incube.copy()
    try:
        cube.remove_coord(coord_name)
    except CoordinateNotFoundError:
        pass

    # if new coordinate points are provided as datetimes, convert to seconds
    if is_datetime:
        coord_units = TIME_COORDS["time"].units
        dtype = TIME_COORDS["time"].dtype
        new_coord_points = [_create_time_point(val) for val in coord_points]
        coord_points = new_coord_points

    cubes = iris.cube.CubeList([])
    for val in coord_points:
        temp_cube = cube.copy()
        temp_cube.add_aux_coord(
            DimCoord(
                np.array([val], dtype=dtype),
                long_name=coord_name,
                units=coord_units,
                attributes=attributes,
            ))

        # recalculate forecast period if time or frt have been updated
        if ("time" in coord_name and coord_units is not None
                and Unit(coord_units).is_time_reference()):
            forecast_period = forecast_period_coord(
                temp_cube, force_lead_time_calculation=True)
            try:
                temp_cube.replace_coord(forecast_period)
            except CoordinateNotFoundError:
                temp_cube.add_aux_coord(forecast_period)

        cubes.append(temp_cube)

    new_cube = cubes.merge_cube()
    if order is not None:
        new_cube.transpose(order)

    return new_cube
Example #39
0
def set_up_variable_cube(
    data,
    name="air_temperature",
    units="K",
    spatial_grid="latlon",
    time=datetime(2017, 11, 10, 4, 0),
    time_bounds=None,
    frt=datetime(2017, 11, 10, 0, 0),
    realizations=None,
    include_scalar_coords=None,
    attributes=None,
    standard_grid_metadata=None,
):
    """
    Set up a cube containing a single variable field with:
    - x/y spatial dimensions (equal area or lat / lon)
    - optional leading "realization" dimension
    - "time", "forecast_reference_time" and "forecast_period" scalar coords
    - option to specify additional scalar coordinates
    - configurable attributes

    Args:
        data (numpy.ndarray):
            2D (y-x ordered) or 3D (realization-y-x ordered) array of data
            to put into the cube.
        name (str):
            Variable name (standard / long)
        units (str):
            Variable units
        spatial_grid (str):
            What type of x/y coordinate values to use.  Permitted values are
            "latlon" or "equalarea".
        time (datetime.datetime):
            Single cube validity time
        time_bounds (tuple or list of datetime.datetime instances):
            Lower and upper bound on time point, if required
        frt (datetime.datetime):
            Single cube forecast reference time
        realizations (list or numpy.ndarray):
            List of forecast realizations.  If not present, taken from the
            leading dimension of the input data array (if 3D).
        include_scalar_coords (list):
            List of iris.coords.DimCoord or AuxCoord instances of length 1.
        attributes (dict):
            Optional cube attributes.
        standard_grid_metadata (str):
            Recognised mosg__model_configuration for which to set up Met
            Office standard grid attributes.  Should be 'uk_det', 'uk_ens',
            'gl_det' or 'gl_ens'.
    """
    # construct spatial dimension coordimates
    ypoints = data.shape[-2]
    xpoints = data.shape[-1]
    y_coord, x_coord = construct_xy_coords(ypoints, xpoints, spatial_grid)

    # construct realization dimension for 3D data, and dim_coords list
    ndims = len(data.shape)
    if ndims == 3:
        if realizations is not None:
            if len(realizations) != data.shape[0]:
                raise ValueError(
                    "Cannot generate {} realizations from data of shape "
                    "{}".format(len(realizations), data.shape))
            realizations = np.array(realizations)
            if issubclass(realizations.dtype.type, np.integer):
                # expect integer realizations
                realizations = realizations.astype(np.int32)
            else:
                # option needed for percentile & probability cube setup
                realizations = realizations.astype(np.float32)
        else:
            realizations = np.arange(data.shape[0]).astype(np.int32)
        realization_coord = DimCoord(realizations, "realization", units="1")
        dim_coords = [(realization_coord, 0), (y_coord, 1), (x_coord, 2)]
    elif ndims == 2:
        dim_coords = [(y_coord, 0), (x_coord, 1)]
    else:
        raise ValueError(
            "Expected 2 or 3 dimensions on input data: got {}".format(ndims))

    # construct list of aux_coords_and_dims
    scalar_coords = construct_scalar_time_coords(time, time_bounds, frt)
    if include_scalar_coords is not None:
        for coord in include_scalar_coords:
            scalar_coords.append((coord, None))

    # set up attributes
    cube_attrs = {}
    if standard_grid_metadata is not None:
        cube_attrs.update(MOSG_GRID_DEFINITION[standard_grid_metadata])
    if attributes is not None:
        cube_attrs.update(attributes)

    # create data cube
    cube = iris.cube.Cube(
        data,
        units=units,
        attributes=cube_attrs,
        dim_coords_and_dims=dim_coords,
        aux_coords_and_dims=scalar_coords,
    )
    cube.rename(name)

    # don't allow unit tests to set up invalid cubes
    check_mandatory_standards(cube)

    return cube
Example #40
0
def ensemble_member(cube, field):
    """Add an 'ensemble member' coord to the cube, if present in the field."""
    ensemble_member = getattr(field, "ensemble_member")
    if ensemble_member != field.int_mdi:
        cube.add_aux_coord(DimCoord(ensemble_member, "realization"))
Example #41
0
def experiment(cube, field):
    """Add an 'experiment number' to the cube, if present in the field."""
    if field.experiment_num != field.int_mdi:
        cube.add_aux_coord(
            DimCoord(field.experiment_num, long_name="experiment_number"))
Example #42
0
 def test_pseudo_level(self):
     pseudo_level = 123
     coord = DimCoord(pseudo_level, long_name='pseudo_level', units='1')
     self.cube.add_aux_coord(coord)
     lbuser5_produced = _pp_save_ppfield_values(self.cube).lbuser[4]
     self.assertEqual(pseudo_level, lbuser5_produced)
Example #43
0
def get_time_coord(time_point):
    """Time coordinate."""
    return DimCoord([time_point],
                    var_name='time',
                    standard_name='time',
                    units='days since 6453-2-1')
Example #44
0
    def to_cube(self):
        """Return a new :class:`~iris.cube.Cube` from this ABFField."""

        cube = iris.cube.Cube(self.data)

        # Name.
        if self.format.lower() == "abf":
            cube.rename("leaf_area_index")
        elif self.format.lower() == "abl":
            cube.rename("FAPAR")
        else:
            msg = "Unknown ABF/ABL format: {}".format(self.format)
            raise iris.exceptions.TranslationError(msg)
        cube.units = "%"

        # Grid.
        step = 1.0 / 12.0

        llcs = GeogCS(semi_major_axis=6378137.0, semi_minor_axis=6356752.31424)

        x_coord = DimCoord(np.arange(X_SIZE) * step + (step / 2) - 180,
                           standard_name="longitude",
                           units="degrees",
                           coord_system=llcs)

        y_coord = DimCoord(np.arange(Y_SIZE) * step + (step / 2) - 90,
                           standard_name="latitude",
                           units="degrees",
                           coord_system=llcs)

        x_coord.guess_bounds()
        y_coord.guess_bounds()

        cube.add_dim_coord(x_coord, 1)
        cube.add_dim_coord(y_coord, 0)

        # Time.
        if self.period == "a":
            start = 1
            end = 15
        elif self.period == "b":
            start = 16
            end = calendar.monthrange(self.year, self.month)[1]
        else:
            raise iris.exceptions.TranslationError("Unknown period: "
                                                   "{}".format(self.period))

        start = datetime.date(year=self.year, month=self.month, day=start)
        end = datetime.date(year=self.year, month=self.month, day=end)

        # Convert to "days since 0001-01-01".
        # Iris will have proper datetime objects in the future.
        # This step will not be necessary.
        start = start.toordinal() - 1
        end = end.toordinal() - 1

        # TODO: Should we put the point in the middle of the period instead?
        cube.add_aux_coord(
            AuxCoord(start,
                     standard_name="time",
                     units="days since 0001-01-01",
                     bounds=[start, end]))

        # TODO: Do they only come from Boston?
        # Attributes.
        cube.attributes["source"] = "Boston University"

        return cube
Example #45
0
class TestConcatenate(unittest.TestCase):
    """Tests for :func:`esmvalcore.preprocessor._io.concatenate`."""
    def setUp(self):
        """Start tests."""
        self._model_coord = DimCoord([1., 2.],
                                     var_name='time',
                                     standard_name='time',
                                     units='days since 1950-01-01')
        self.raw_cubes = []
        self._add_cube([1., 2.], [1., 2.])
        self._add_cube([3., 4.], [3., 4.])
        self._add_cube([5., 6.], [5., 6.])

    def _add_cube(self, data, coord):
        self.raw_cubes.append(
            Cube(data,
                 var_name='sample',
                 dim_coords_and_dims=((self._model_coord.copy(coord), 0), )))

    def test_concatenate(self):
        """Test concatenation of two cubes."""
        concatenated = _io.concatenate(self.raw_cubes)
        np.testing.assert_array_equal(
            concatenated.coord('time').points, np.array([1, 2, 3, 4, 5, 6]))

    def test_concatenate_noop(self):
        """Test concatenation of a single cube."""
        concatenated = _io.concatenate([self.raw_cubes[0]])
        np.testing.assert_array_equal(
            concatenated.coord('time').points, np.array([1, 2]))

    def test_concatenate_with_overlap(self):
        """Test concatenation of time overalapping cubes."""
        self._add_cube([6.5, 7.5], [6., 7.])
        concatenated = _io.concatenate(self.raw_cubes)
        np.testing.assert_array_equal(
            concatenated.coord('time').points,
            np.array([1., 2., 3., 4., 5., 6., 7.]))
        np.testing.assert_array_equal(concatenated.data,
                                      np.array([1., 2., 3., 4., 5., 6.5, 7.5]))

    def test_concatenate_with_overlap_2(self):
        """Test a more generic case."""
        self._add_cube([65., 75., 100.], [9., 10., 11.])
        self._add_cube([65., 75., 100.], [7., 8., 9.])
        concatenated = _io.concatenate(self.raw_cubes)
        np.testing.assert_array_equal(
            concatenated.coord('time').points,
            np.array([1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.]))

    def test_concatenate_with_overlap_3(self):
        """Test a more generic case."""
        self._add_cube([65., 75., 100.], [9., 10., 11.])
        self._add_cube([65., 75., 100., 100., 100., 112.],
                       [7., 8., 9., 10., 11., 12.])
        concatenated = _io.concatenate(self.raw_cubes)
        np.testing.assert_array_equal(
            concatenated.coord('time').points,
            np.array([1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.]))

    def test_concatenate_with_overlap_same_start(self):
        """Test a more generic case."""
        cube1 = self.raw_cubes[0]
        raw_cubes = [
            cube1,
        ]
        time_coord = DimCoord([1., 7.],
                              var_name='time',
                              standard_name='time',
                              units='days since 1950-01-01')
        raw_cubes.append(
            Cube([33., 55.],
                 var_name='sample',
                 dim_coords_and_dims=((time_coord, 0), )))
        concatenated = _io.concatenate(raw_cubes)
        np.testing.assert_array_equal(
            concatenated.coord('time').points, np.array([1., 7.]))
        raw_cubes.reverse()
        concatenated = _io.concatenate(raw_cubes)
        np.testing.assert_array_equal(
            concatenated.coord('time').points, np.array([1., 7.]))

    def test_concatenate_with_iris_exception(self):
        """Test a more generic case."""
        time_coord_1 = DimCoord([1.5, 5., 7.],
                                var_name='time',
                                standard_name='time',
                                units='days since 1950-01-01')
        cube1 = Cube([33., 55., 77.],
                     var_name='sample',
                     dim_coords_and_dims=((time_coord_1, 0), ))
        time_coord_2 = DimCoord([1., 5., 7.],
                                var_name='time',
                                standard_name='time',
                                units='days since 1950-01-01')
        cube2 = Cube([33., 55., 77.],
                     var_name='sample',
                     dim_coords_and_dims=((time_coord_2, 0), ))
        cubes_single_ovlp = [cube2, cube1]
        with self.assertRaises(ConcatenateError):
            _io.concatenate(cubes_single_ovlp)

    def test_concatenate_no_time_coords(self):
        """Test a more generic case."""
        time_coord_1 = DimCoord([1.5, 5., 7.],
                                var_name='time',
                                standard_name='time',
                                units='days since 1950-01-01')
        cube1 = Cube([33., 55., 77.],
                     var_name='sample',
                     dim_coords_and_dims=((time_coord_1, 0), ))
        ap_coord_2 = DimCoord([1., 5., 7.],
                              var_name='air_pressure',
                              standard_name='air_pressure',
                              units='m',
                              attributes={'positive': 'down'})
        cube2 = Cube([33., 55., 77.],
                     var_name='sample',
                     dim_coords_and_dims=((ap_coord_2, 0), ))
        with self.assertRaises(ValueError):
            _io.concatenate([cube1, cube2])

    def test_concatenate_with_order(self):
        """Test a more generic case."""
        time_coord_1 = DimCoord([1.5, 2., 5., 7.],
                                var_name='time',
                                standard_name='time',
                                units='days since 1950-01-01')
        cube1 = Cube([33., 44., 55., 77.],
                     var_name='sample',
                     dim_coords_and_dims=((time_coord_1, 0), ))
        time_coord_2 = DimCoord([1., 2., 5., 7., 100.],
                                var_name='time',
                                standard_name='time',
                                units='days since 1950-01-01')
        cube2 = Cube([33., 44., 55., 77., 1000.],
                     var_name='sample',
                     dim_coords_and_dims=((time_coord_2, 0), ))
        cubes_ordered = [cube2, cube1]
        concatenated = _io.concatenate(cubes_ordered)
        np.testing.assert_array_equal(
            concatenated.coord('time').points, np.array([1., 2., 5., 7.,
                                                         100.]))
        cubes_reverse = [cube1, cube2]
        concatenated = _io.concatenate(cubes_reverse)
        np.testing.assert_array_equal(
            concatenated.coord('time').points, np.array([1., 2., 5., 7.,
                                                         100.]))

    def test_fail_on_calendar_concatenate_with_overlap(self):
        """Test fail of concatenation with overlap."""
        time_coord = DimCoord([3., 7000.],
                              var_name='time',
                              standard_name='time',
                              units=Unit('days since 1950-01-01',
                                         calendar='360_day'))
        self.raw_cubes.append(
            Cube([33., 55.],
                 var_name='sample',
                 dim_coords_and_dims=((time_coord, 0), )))
        with self.assertRaises(TypeError):
            _io.concatenate(self.raw_cubes)

    def test_fail_on_units_concatenate_with_overlap(self):
        """Test fail of concatenation with overlap."""
        time_coord_1 = DimCoord([3., 7000.],
                                var_name='time',
                                standard_name='time',
                                units=Unit('days since 1950-01-01',
                                           calendar='360_day'))
        time_coord_2 = DimCoord([3., 9000.],
                                var_name='time',
                                standard_name='time',
                                units=Unit('days since 1950-01-01',
                                           calendar='360_day'))
        time_coord_3 = DimCoord([3., 9000.],
                                var_name='time',
                                standard_name='time',
                                units=Unit('days since 1850-01-01',
                                           calendar='360_day'))
        raw_cubes = []
        raw_cubes.append(
            Cube([33., 55.],
                 var_name='sample',
                 dim_coords_and_dims=((time_coord_1, 0), )))
        raw_cubes.append(
            Cube([33., 55.],
                 var_name='sample',
                 dim_coords_and_dims=((time_coord_2, 0), )))
        raw_cubes.append(
            Cube([33., 55.],
                 var_name='sample',
                 dim_coords_and_dims=((time_coord_3, 0), )))
        with self.assertRaises(ValueError):
            _io.concatenate(raw_cubes)

    def test_fail_metadata_differs(self):
        """Test exception raised if two cubes have different metadata."""
        self.raw_cubes[0].units = 'm'
        self.raw_cubes[1].units = 'K'
        with self.assertRaises(ValueError):
            _io.concatenate(self.raw_cubes)

    def test_fix_attributes(self):
        """Test fixing attributes for concatenation."""
        identical_attrs = {
            'int': 42,
            'float': 3.1415,
            'bool': True,
            'str': 'Hello, world',
            'list': [1, 1, 2, 3, 5, 8, 13],
            'tuple': (1, 2, 3, 4, 5),
            'dict': {
                1: 'one',
                2: 'two',
                3: 'three'
            },
            'nparray': np.arange(42),
        }
        differing_attrs = [
            {
                'new_int': 0,
                'new_str': 'hello',
                'new_nparray': np.arange(3),
                'mix': np.arange(2),
            },
            {
                'new_int': 1,
                'new_str': 'world',
                'new_list': [1, 1, 2],
                'new_tuple': (0, 1),
                'new_dict': {
                    0: 'zero',
                },
                'mix': {
                    1: 'one',
                },
            },
            {
                'new_str': '!',
                'new_list': [1, 1, 2, 3],
                'new_tuple': (1, 2, 3),
                'new_dict': {
                    0: 'zeroo',
                    1: 'one',
                },
                'new_nparray': np.arange(2),
                'mix': False,
            },
        ]
        resulting_attrs = {
            'new_int': '0;1',
            'new_str': 'hello;world;!',
            'new_nparray': '[0 1 2];[0 1]',
            'new_list': '[1, 1, 2];[1, 1, 2, 3]',
            'new_tuple': '(0, 1);(1, 2, 3)',
            'new_dict': "{0: 'zero'};{0: 'zeroo', 1: 'one'}",
            'mix': "[0 1];{1: 'one'};False",
        }
        resulting_attrs.update(identical_attrs)

        for idx in range(3):
            self.raw_cubes[idx].attributes = identical_attrs
            self.raw_cubes[idx].attributes.update(differing_attrs[idx])
        _io._fix_cube_attributes(self.raw_cubes)  # noqa
        for cube in self.raw_cubes:
            self.assertEqual(cube.attributes, resulting_attrs)
Example #46
0
def convert(year, month, ndays, remove=False):
    """
    Now need to:
    - convert to q, RH , e, tw, DPD
    - aggregate to daily averages
    - regrid to 1by1 gridboxes
    """

    MDI = -999.

    # Set up null_cube with desired gridding format to use as a template
    # Does this have to have the same time dimensions?
    #    ndays = np.int(p_cube.data[:,0,0] / 24)

    time = DimCoord(np.arange(ndays * 24), standard_name='time', units='hours')
    latitude = DimCoord(
        np.linspace(89.5, -89.5, 180),  # DIFF FROM OTHER ERA5 DOWNLOAD
        #    latitude = DimCoord(np.linspace(90, -90, 181),
        standard_name='latitude',
        long_name='gridbox centre latitude',
        units='degrees_north')
    longitude = DimCoord(
        np.linspace(-179.5, 179.5, 360),  # DIFF FROM OTHER ERA5 DOWNLOAD
        #    longitude = DimCoord(np.linspace(0, 359, 360),
        standard_name='longitude',
        long_name='gridbox centre longitude',
        units='degrees_east')
    null_cube = Cube(np.zeros((ndays * 24, 180, 360), np.float32),
                     dim_coords_and_dims=[(time, 0), (latitude, 1),
                                          (longitude, 2)])
    print('Check null_cube for new grid')
    #    pdb.set_trace()

    # START OF LSM************************************************
    # read in land_sea_mask
    variable = "land_sea_mask"
    lsm_cube = iris.load(
        os.path.join(DataLoc,
                     "{}{:02d}_hourly_{}.nc".format(year, month, variable)))
    #pdb.set_trace()
    # convert from list to cube
    lsm_cube = lsm_cube[0]  #

    # REgrid to 1by1 degree - cash the source, template, gridding type for later use - faster
    regridder = iris.analysis.Linear().regridder(lsm_cube, null_cube)
    lsm_cube_1by1 = regridder(lsm_cube)
    print('Check lsm_cube_1by1 for new grid')
    #    pdb.set_trace()#

    # remove old cube
    lsm_cube = 0

    lsm_cube_1by1 = lsm_cube_1by1[0, :, :]
    #    lsm_cube_1by1_field = lsm_cube_1by1.extract(iris.Constraint(time=0))
    lsm_cube_1by1.units = "1"
    print(lsm_cube_1by1)
    print('Check lsm_cube_1by1 for land_sea_mask')
    #pdb.set_trace()

    # output
    iris.save(lsm_cube_1by1,
              os.path.join(
                  DataLoc,
                  "{}{:02d}_hourly_{}_ERA5.nc".format(year, month, variable)),
              zlib=True)
    print('Check lsm_cube_1by1 output')
    #    pdb.set_trace()
    # END OF LSM************************************************************

    # remove input files
    if remove:
        for variable in [
                "2m_temperature", "2m_dewpoint_temperature", "surface_pressure"
        ]:
            #        for variable in ["2m_temperature", "2m_dewpoint_temperature", "surface_pressure", "land_sea_mask"]:
            os.remove(
                os.path.join(
                    DataLoc,
                    "{}{:02d}_hourly_{}.nc".format(year, month, variable)))

    return  # combine
Example #47
0
 def test_dtype_change(self):
     c1 = self.ref_co_1d
     c2 = DimCoord(np.array([1.0, 2.0], dtype=np.float64))
     self._coords_eq(c1, c2)
Example #48
0
 def test_formula_terms_no_p0_term(self):
     coord_a = DimCoord(np.arange(5), units='Pa')
     self.provides['coordinates'].append((coord_a, 'a'))
     self.requires['formula_terms'] = dict(a='a', b='b', ps='ps')
     _load_aux_factory(self.engine, self.cube)
     self._check_no_delta()
Example #49
0
 def setUp(self):
     self.ref_co_1d = DimCoord([1, 2])
     self.co_a = DimCoord([1, 2], long_name='a')
     self.msg_metadata = "Coords 'a' have different metadata"
Example #50
0
def sample_mesh_cube(nomesh_faces=None,
                     n_z=2,
                     with_parts=False,
                     **meshcoord_kwargs):
    """
    Create a 2d test cube with 1 'normal' and 1 unstructured dimension (with a Mesh).

    Result contains : dimcoords for both dims; an auxcoord on the unstructured dim; 2 mesh-coords.
    By default, the mesh is provided by :func:`sample_mesh`, so coordinates and connectivity  are not realistic.

    Kwargs:
    * nomesh_faces (int or None):
        If set, don't add MeshCoords, so dim 1 is just a plain anonymous dim.
        Set its length to the given value.
    * n_z (int):
        Length of the 'normal' dim.  If 0, it is *omitted*.
    * with_parts (bool):
        If set, return all the constituent component coords
    * meshcoord_kwargs (dict):
        Extra controls passed to :func:`sample_meshcoord` for MeshCoord creation, to allow user-specified
        location/mesh.  The 'axis' key is not available, as we always add both an 'x' and 'y' MeshCOord.

    Returns:
    * cube  :  if with_parts not set
    * (cube, parts)  : if with_parts is set
        'parts' is (mesh, dim0-dimcoord, dim1-dimcoord, dim1-auxcoord, x-meshcoord [or None], y-meshcoord [or None]).

    """
    nomesh = nomesh_faces is not None
    if nomesh:
        mesh = None
        n_faces = nomesh_faces
    else:
        mesh = meshcoord_kwargs.pop("mesh", None)
        if mesh is None:
            mesh = sample_mesh()
        meshx, meshy = (sample_meshcoord(axis=axis,
                                         mesh=mesh,
                                         **meshcoord_kwargs)
                        for axis in ("x", "y"))
        n_faces = meshx.shape[0]

    mesh_dimco = DimCoord(np.arange(n_faces),
                          long_name="i_mesh_face",
                          units="1")

    auxco_x = AuxCoord(np.zeros(n_faces), long_name="mesh_face_aux", units="1")

    zco = DimCoord(np.arange(n_z), long_name="level", units=1)
    cube = Cube(np.zeros((n_z, n_faces)), long_name="mesh_phenom")
    cube.add_dim_coord(zco, 0)
    if nomesh:
        mesh_coords = []
    else:
        mesh_coords = [meshx, meshy]

    cube.add_dim_coord(mesh_dimco, 1)
    for co in mesh_coords + [auxco_x]:
        cube.add_aux_coord(co, 1)

    if not with_parts:
        result = cube
    else:
        if nomesh:
            meshx, meshy = None, None
        parts = (mesh, zco, mesh_dimco, auxco_x, meshx, meshy)
        result = (cube, parts)

    return result
Example #51
0
    def setUp(self):
        """
        Create a cube containing a regular lat-lon grid.

        Data is striped horizontally,
        e.g.
              1 1 1 1 1 1
              1 1 1 1 1 1
              2 2 2 2 2 2
              2 2 2 2 2 2
              3 3 3 3 3 3
              3 3 3 3 3 3
        """
        data = np.ones((12, 12))
        data[0:4, :] = 1
        data[4:8, :] = 2
        data[8:, :] = 3

        latitudes = np.linspace(-90, 90, 12)
        longitudes = np.linspace(-180, 180, 12)
        latitude = DimCoord(latitudes,
                            standard_name='latitude',
                            units='degrees',
                            coord_system=GeogCS(6371229.0))
        longitude = DimCoord(longitudes,
                             standard_name='longitude',
                             units='degrees',
                             coord_system=GeogCS(6371229.0),
                             circular=True)

        # Use time of 2017-02-17 06:00:00
        time = DimCoord([1487311200],
                        standard_name='time',
                        units=cf_units.Unit(
                            'seconds since 1970-01-01 00:00:00',
                            calendar='gregorian'))
        long_time_coord = DimCoord(list(range(1487311200, 1487397600, 3600)),
                                   standard_name='time',
                                   units=cf_units.Unit(
                                       'seconds since 1970-01-01 00:00:00',
                                       calendar='gregorian'))

        time_dt = dt(2017, 2, 17, 6, 0)
        time_extract = Constraint(
            time=lambda cell: cell.point == PartialDateTime(
                time_dt.year, time_dt.month, time_dt.day, time_dt.hour))

        cube = Cube(data.reshape((1, 12, 12)),
                    long_name="air_temperature",
                    dim_coords_and_dims=[(time, 0), (latitude, 1),
                                         (longitude, 2)],
                    units="K")

        long_cube = Cube(np.arange(3456).reshape(24, 12, 12),
                         long_name="air_temperature",
                         dim_coords_and_dims=[(long_time_coord, 0),
                                              (latitude, 1), (longitude, 2)],
                         units="K")

        orography = Cube(np.ones((12, 12)),
                         long_name="surface_altitude",
                         dim_coords_and_dims=[(latitude, 0), (longitude, 1)],
                         units="m")

        # Western half of grid at altitude 0, eastern half at 10.
        # Note that the pressure_on_height_levels data is left unchanged,
        # so it is as if there is a sharp front running up the grid with
        # differing pressures on either side at equivalent heights above
        # the surface (e.g. east 1000hPa at 0m AMSL, west 1000hPa at 10m AMSL).
        # So there is higher pressure in the west.
        orography.data[0:10] = 0
        orography.data[10:] = 10
        ancillary_data = {}
        ancillary_data['orography'] = orography

        additional_data = {}
        adlist = CubeList()
        adlist.append(cube)
        additional_data['air_temperature'] = adlist

        data_indices = [list(data.nonzero()[0]), list(data.nonzero()[1])]

        self.cube = cube
        self.long_cube = long_cube
        self.data = data
        self.time_dt = time_dt
        self.time_extract = time_extract
        self.data_indices = data_indices
        self.ancillary_data = ancillary_data
        self.additional_data = additional_data
Example #52
0
 def test_1d_contiguous(self):
     # Test that a 1D coordinate which is contiguous does not fail.
     coord = DimCoord([1, 3, 5], bounds=[[0, 2], [2, 4], [4, 6]])
     data = np.array([278, 300, 282])
     _check_bounds_contiguity_and_mask(coord, data, atol=1e-3)
Example #53
0
 def test_1d_discontigous_masked(self):
     # Test a 1D coordinate which is discontiguous but masked at
     # discontiguities.
     coord = DimCoord([1, 3, 5], bounds=[[0, 2], [2, 4], [5, 6]])
     data = ma.array(np.array([278, 300, 282]), mask=[0, 1, 0])
     _check_bounds_contiguity_and_mask(coord, data, atol=1e-3)
Example #54
0
 def test_no_bounds(self):
     coord = DimCoord(self.pts_real)
     result = coord.core_bounds()
     self.assertIsNone(result)
Example #55
0
 def test_formula_terms_no_a_term(self):
     coord_p0 = DimCoord(10, units='1')
     self.provides['coordinates'].append((coord_p0, 'p0'))
     self.requires['formula_terms'] = dict(a='p0', b='b', ps='ps')
     _load_aux_factory(self.engine, self.cube)
     self._check_no_delta()
Example #56
0
    def create_data_object(self, filenames, variable, index_offset=1):
        from cis.data_io.hdf_vd import get_data
        from cis.data_io.hdf_vd import VDS
        from pyhdf.error import HDF4Error
        from cis.data_io import hdf_sd
        from iris.coords import DimCoord, AuxCoord
        from iris.cube import Cube, CubeList
        from cis.data_io.gridded_data import GriddedData
        from cis.time_util import cis_standard_time_unit
        from datetime import datetime
        from iris.util import new_axis
        import numpy as np

        logging.debug("Creating data object for variable " + variable)

        variables = ["Pressure_Mean"]
        logging.info("Listing coordinates: " + str(variables))

        variables.append(variable)

        # reading data from files
        sdata = {}
        for filename in filenames:
            try:
                sds_dict = hdf_sd.read(filename, variables)
            except HDF4Error as e:
                raise IOError(str(e))

            for var in list(sds_dict.keys()):
                utils.add_element_to_list_in_dict(sdata, var, sds_dict[var])

        # work out size of data arrays
        # the coordinate variables will be reshaped to match that.
        # NOTE: This assumes that all Caliop_L1 files have the same altitudes.
        #       If this is not the case, then the following line will need to be changed
        #       to concatenate the data from all the files and not just arbitrarily pick
        #       the altitudes from the first file.
        alt_data = self._get_calipso_data(
            hdf_sd.HDF_SDS(filenames[0], 'Altitude_Midpoint'))[0, :]
        alt_coord = DimCoord(alt_data, standard_name='altitude', units='km')
        alt_coord.convert_units('m')

        lat_data = self._get_calipso_data(
            hdf_sd.HDF_SDS(filenames[0], 'Latitude_Midpoint'))[0, :]
        lat_coord = DimCoord(lat_data,
                             standard_name='latitude',
                             units='degrees_north')

        lon_data = self._get_calipso_data(
            hdf_sd.HDF_SDS(filenames[0], 'Longitude_Midpoint'))[0, :]
        lon_coord = DimCoord(lon_data,
                             standard_name='longitude',
                             units='degrees_east')

        cubes = CubeList()
        for f in filenames:
            t = get_data(VDS(f, "Nominal_Year_Month"), True)[0]
            time_data = cis_standard_time_unit.date2num(
                datetime(int(t[0:4]), int(t[4:6]), 15))
            time_coord = AuxCoord(time_data,
                                  long_name='Profile_Time',
                                  standard_name='time',
                                  units=cis_standard_time_unit)

            # retrieve data + its metadata
            var = sdata[variable]
            metadata = hdf.read_metadata(var, "SD")

            data = self._get_calipso_data(hdf_sd.HDF_SDS(f, variable))

            pres_data = self._get_calipso_data(
                hdf_sd.HDF_SDS(f, 'Pressure_Mean'))
            pres_coord = AuxCoord(pres_data,
                                  standard_name='air_pressure',
                                  units='hPa')

            if data.ndim == 2:
                # pres_coord = new_axis()
                cube = Cube(data,
                            long_name=metadata.long_name or variable,
                            units=self.clean_units(metadata.units),
                            dim_coords_and_dims=[(lat_coord, 0),
                                                 (lon_coord, 1)],
                            aux_coords_and_dims=[(time_coord, ())])
                # Promote the time scalar coord to a length one dimension
                new_cube = new_axis(cube, 'time')
                cubes.append(new_cube)
            elif data.ndim == 3:
                # pres_coord = new_axis()
                cube = Cube(data,
                            long_name=metadata.long_name or variable,
                            units=self.clean_units(metadata.units),
                            dim_coords_and_dims=[(lat_coord, 0),
                                                 (lon_coord, 1),
                                                 (alt_coord, 2)],
                            aux_coords_and_dims=[(time_coord, ())])
                # Promote the time scalar coord to a length one dimension
                new_cube = new_axis(cube, 'time')
                # Then add the (extended) pressure coord so that it is explicitly a function of time
                new_cube.add_aux_coord(pres_coord[np.newaxis, ...],
                                       (0, 1, 2, 3))
                cubes.append(new_cube)
            else:
                raise ValueError(
                    "Unexpected number of dimensions for CALIOP data: {}".
                    format(data.ndim))

        # Concatenate the cubes from each file into a single GriddedData object
        gd = GriddedData.make_from_cube(cubes.concatenate_cube())
        return gd
Example #57
0
 def test_formula_terms_p0_non_scalar(self):
     coord_p0 = DimCoord(np.arange(5))
     self.provides['coordinates'].append((coord_p0, 'p0'))
     self.requires['formula_terms'] = dict(p0='p0')
     with self.assertRaises(ValueError):
         _load_aux_factory(self.engine, self.cube)
Example #58
0
 def test_lazy_points(self):
     lazy_data = self.pts_lazy
     coord = DimCoord(lazy_data)
     result = coord.core_points()
     self.assertEqualRealArraysAndDtypes(result, self.pts_real)
Example #59
0
def _make_cube(data, aux_coord=True, dim_coord=True, dtype=None):
    """
    Create a 3d synthetic test cube.

    """
    if dtype is None:
        dtype = np.dtype('int8')

    if not isinstance(data, np.ndarray):
        data = np.empty(data, dtype=dtype)

    z, y, x = data.shape

    # Create the cube.
    cm = CellMethod(method='mean',
                    coords='time',
                    intervals='20 minutes',
                    comments=None)
    kwargs = dict(standard_name='air_temperature',
                  long_name='Air Temperature',
                  var_name='ta',
                  units='K',
                  attributes=dict(cube='attribute'),
                  cell_methods=(cm, ))
    cube = iris.cube.Cube(data, **kwargs)

    # Create a synthetic test vertical coordinate.
    if dim_coord:
        cube.add_dim_coord(_make_vcoord(z, dtype=dtype), 0)

    # Create a synthetic test latitude coordinate.
    data = np.arange(y, dtype=dtype) + 1
    cs = iris.coord_systems.GeogCS(iris.fileformats.pp.EARTH_RADIUS)
    kwargs = dict(standard_name='latitude',
                  long_name='Latitude',
                  var_name='lat',
                  units='degrees_north',
                  attributes=dict(latitude='attribute'),
                  coord_system=cs)
    ycoord = DimCoord(data, **kwargs)
    if data.size > 1:
        ycoord.guess_bounds()
    cube.add_dim_coord(ycoord, 1)

    # Create a synthetic test longitude coordinate.
    data = np.arange(x, dtype=dtype) + 1
    kwargs = dict(standard_name='longitude',
                  long_name='Longitude',
                  var_name='lon',
                  units='degrees_east',
                  attributes=dict(longitude='attribute'),
                  coord_system=cs)
    xcoord = DimCoord(data, **kwargs)
    if data.size > 1:
        xcoord.guess_bounds()
    cube.add_dim_coord(xcoord, 2)

    # Create a synthetic test 2d auxiliary coordinate
    # that spans the vertical dimension.
    if aux_coord:
        data = np.arange(np.prod((z, y)), dtype=dtype).reshape(z, y)
        kwargs = dict(standard_name=None,
                      long_name='Pressure Slice',
                      var_name='aplev',
                      units='hPa',
                      attributes=dict(positive='down'),
                      coord_system=None)
        zycoord = AuxCoord(data, **kwargs)
        cube.add_aux_coord(zycoord, (0, 1))

    return cube
Example #60
0
 def test_1d_not_checked(self):
     # Test a 1D coordinate, which is not checked as atol is not set.
     coord = DimCoord([1, 3, 5], bounds=[[0, 2], [2, 4], [5, 6]])
     data = np.array([278, 300, 282])
     # Make sure contiguity checking doesn't throw an error
     _check_bounds_contiguity_and_mask(coord, data)