Exemplo n.º 1
0
    def test_contrived_non_spherical_curl1(self):
        # testing :
        # F(x, y, z) = (y, 0, 0)
        # curl( F(x, y, z) ) = (0, 0, -1)

        cube = build_cube(np.empty((25, 50)), spherical=False)

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(cube)

        u = cube.copy(data=x_ones * y_pts)
        u.rename("u_wind")
        v = cube.copy(data=u.data * 0)
        v.rename("v_wind")

        r = iris.analysis.calculus.curl(u, v)

        # Curl returns None when there is no components of Curl
        self.assertEqual(r[0], None)
        self.assertEqual(r[1], None)
        cube = r[2]
        self.assertCML(
            cube,
            ('analysis', 'calculus', 'grad_contrived_non_spherical1.cml'),
            checksum=False)
        self.assertTrue(np.all(np.abs(cube.data - (-1.0)) < 1.0e-7))
Exemplo n.º 2
0
    def test_contrived_spherical_curl1(self):
        # testing:
        # F(lon, lat, r) = (- r sin(lon), -r cos(lon) sin(lat), 0)
        # curl( F(x, y, z) ) = (0, 0, 0)
        cube = build_cube(np.empty((30, 60)), spherical=True)
        radius = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS

        x = cube.coord('longitude')
        y = cube.coord('latitude')

        cos_x_pts = np.cos(np.radians(x.points)).reshape(1, x.shape[0])
        sin_x_pts = np.sin(np.radians(x.points)).reshape(1, x.shape[0])
        cos_y_pts = np.cos(np.radians(y.points)).reshape(y.shape[0], 1)
        sin_y_pts = np.sin(np.radians(y.points)).reshape(y.shape[0], 1)
        y_ones = np.ones((cube.shape[0], 1))

        u = cube.copy(data=-sin_x_pts * y_ones * radius)
        v = cube.copy(data=-cos_x_pts * sin_y_pts * radius)
        u.rename('u_wind')
        v.rename('v_wind')

        r = iris.analysis.calculus.curl(u, v)[2]

        result = r.copy(data=r.data * 0)

        # Note: This numerical comparison was created when the radius was 1000 times smaller
        np.testing.assert_array_almost_equal(result.data[5:-5],
                                             r.data[5:-5] / 1000.0,
                                             decimal=1)
        self.assertCML(r, ('analysis', 'calculus', 'grad_contrived1.cml'),
                       checksum=False)
    def test_contrived_non_spherical_curl1(self):
        # testing :
        # F(x, y, z) = (y, 0, 0)
        # curl( F(x, y, z) ) = (0, 0, -1)

        cube = build_cube(np.empty((25, 50)), spherical=False)

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(cube)

        u = cube.copy(data=x_ones * y_pts)
        u.rename("u_wind")
        v = cube.copy(data=u.data * 0)
        v.rename("v_wind")

        r = iris.analysis.calculus.curl(u, v)

        # Curl returns None when there is no components of Curl
        self.assertEqual(r[0], None)
        self.assertEqual(r[1], None)
        cube = r[2]
        self.assertCML(
            cube,
            ('analysis', 'calculus', 'grad_contrived_non_spherical1.cml'),
            checksum=False)
        self.assertTrue(np.all(np.abs(cube.data - (-1.0)) < 1.0e-7))
    def test_contrived_spherical_curl1(self):
        # testing:
        # F(lon, lat, r) = (- r sin(lon), -r cos(lon) sin(lat), 0)
        # curl( F(x, y, z) ) = (0, 0, 0)
        cube = build_cube(np.empty((30, 60)), spherical=True)
        radius = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS

        x = cube.coord('longitude')
        y = cube.coord('latitude')

        cos_x_pts = np.cos(np.radians(x.points)).reshape(1, x.shape[0])
        sin_x_pts = np.sin(np.radians(x.points)).reshape(1, x.shape[0])
        cos_y_pts = np.cos(np.radians(y.points)).reshape(y.shape[0], 1)
        sin_y_pts = np.sin(np.radians(y.points)).reshape(y.shape[0], 1)
        y_ones = np.ones((cube.shape[0], 1))

        u = cube.copy(data=-sin_x_pts * y_ones * radius)
        v = cube.copy(data=-cos_x_pts * sin_y_pts * radius)
        u.rename('u_wind')
        v.rename('v_wind')

        r = iris.analysis.calculus.curl(u, v)[2]

        result = r.copy(data=r.data * 0)

        # Note: This numerical comparison was created when the radius was 1000 times smaller
        np.testing.assert_array_almost_equal(result.data[5:-5], r.data[5:-5]/1000.0, decimal=1)
        self.assertCML(r, ('analysis', 'calculus', 'grad_contrived1.cml'), checksum=False)
Exemplo n.º 5
0
def _math_op_common(cube, operation_function, new_unit, new_dtype=None,
                    in_place=False):
    _assert_is_cube(cube)

    if in_place:
        new_cube = cube
        if cube.has_lazy_data():
            new_cube.data = operation_function(cube.lazy_data())
        else:
            try:
                operation_function(cube.data, out=cube.data)
            except TypeError:
                # Non ufunc function
                operation_function(cube.data)
    else:
        new_cube = cube.copy(data=operation_function(cube.core_data()))

    # If the result of the operation is scalar and masked, we need to fix up
    # the dtype
    if new_dtype is not None \
            and not new_cube.has_lazy_data() \
            and new_cube.data.shape == () \
            and ma.is_masked(new_cube.data):
        new_cube.data = ma.masked_array(0, 1, dtype=new_dtype)

    iris.analysis.clear_phenomenon_identity(new_cube)
    new_cube.units = new_unit
    return new_cube
Exemplo n.º 6
0
def cube_delta(cube, coord):
    """
    Given a cube calculate the difference between each value in the given coord's direction.


    Args:

    * coord
        either a Coord instance or the unique name of a coordinate in the cube.
        If a Coord instance is provided, it does not necessarily have to exist in the cube.

    Example usage::

        change_in_temperature_wrt_pressure = cube_delta(temperature_cube, 'pressure')

    .. note:: Missing data support not yet implemented.

    """
    # handle the case where a user passes a coordinate name
    if isinstance(coord, basestring):
        coord = cube.coord(coord)

    if coord.ndim != 1:
        raise iris.exceptions.CoordinateMultiDimError(coord)

    # Try and get a coord dim
    delta_dims = cube.coord_dims(coord)
    if (coord.shape[0] == 1
            and not getattr(coord, 'circular', False)) or not delta_dims:
        raise ValueError(
            'Cannot calculate delta over "%s" as it has length of 1.' %
            coord.name())
    delta_dim = delta_dims[0]

    # Calculate the actual delta, taking into account whether the given coordinate is circular
    delta_cube_data = delta(cube.data,
                            delta_dim,
                            circular=getattr(coord, 'circular', False))

    # If the coord/dim is circular there is no change in cube shape
    if getattr(coord, 'circular', False):
        delta_cube = cube.copy(data=delta_cube_data)
    else:
        # Subset the cube to the appropriate new shape by knocking off the last row of the delta dimension
        subset_slice = [slice(None, None)] * cube.ndim
        subset_slice[delta_dim] = slice(None, -1)
        delta_cube = cube[tuple(subset_slice)]
        delta_cube.data = delta_cube_data

    # Replace the delta_dim coords with midpoints (no shape change if circular).
    for cube_coord in cube.coords(dimensions=delta_dim):
        delta_cube.replace_coord(
            _construct_midpoint_coord(cube_coord,
                                      circular=getattr(coord, 'circular',
                                                       False)))

    delta_cube.rename('change_in_%s_wrt_%s' %
                      (delta_cube.name(), coord.name()))

    return delta_cube
Exemplo n.º 7
0
Arquivo: maths.py Projeto: zklaus/iris
def _math_op_common(cube, operation_function, new_unit, new_dtype=None,
                    in_place=False):
    _assert_is_cube(cube)

    if in_place:
        new_cube = cube
        if cube.has_lazy_data():
            new_cube.data = operation_function(cube.lazy_data())
        else:
            try:
                operation_function(cube.data, out=cube.data)
            except TypeError:
                # Non ufunc function
                operation_function(cube.data)
    else:
        new_cube = cube.copy(data=operation_function(cube.core_data()))

    # If the result of the operation is scalar and masked, we need to fix up
    # the dtype
    if new_dtype is not None \
            and not new_cube.has_lazy_data() \
            and new_cube.data.shape == () \
            and ma.is_masked(new_cube.data):
        new_cube.data = ma.masked_array(0, 1, dtype=new_dtype)

    iris.analysis.clear_phenomenon_identity(new_cube)
    new_cube.units = new_unit
    return new_cube
Exemplo n.º 8
0
    def test_contrived_spherical_curl2(self):
        # testing:
        # F(lon, lat, r) = (r sin(lat) cos(lon), -r sin(lon), 0)
        # curl( F(x, y, z) ) = (0, 0, -2 cos(lon) cos(lat) )
        cube = build_cube(np.empty((70, 150)), spherical=True)
        radius = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS

        x = cube.coord('longitude')
        y = cube.coord('latitude')

        cos_x_pts = np.cos(np.radians(x.points)).reshape(1, x.shape[0])
        sin_x_pts = np.sin(np.radians(x.points)).reshape(1, x.shape[0])
        cos_y_pts = np.cos(np.radians(y.points)).reshape(y.shape[0], 1)
        sin_y_pts = np.sin(np.radians(y.points)).reshape(y.shape[0], 1)
        y_ones = np.ones((cube.shape[0], 1))

        u = cube.copy(data=sin_y_pts * cos_x_pts * radius)
        v = cube.copy(data=-sin_x_pts * y_ones * radius)
        u.rename('u_wind')
        v.rename('v_wind')

        lon_coord = x.copy()
        lon_coord.convert_units('radians')
        lat_coord = y.copy()
        lat_coord.convert_units('radians')
        cos_lat_coord = iris.coords.AuxCoord.from_coord(lat_coord)
        cos_lat_coord.points = np.cos(lat_coord.points)
        cos_lat_coord.units = '1'
        cos_lat_coord.rename('cos({})'.format(lat_coord.name()))

        r = iris.analysis.calculus.curl(u, v)[2]

        x = r.coord('longitude')
        y = r.coord('latitude')

        cos_x_pts = np.cos(np.radians(x.points)).reshape(1, x.shape[0])
        cos_y_pts = np.cos(np.radians(y.points)).reshape(y.shape[0], 1)

        # Expected r-component value: -2 cos(lon) cos(lat)
        result = r.copy(data=-2 * cos_x_pts * cos_y_pts)

        # Note: This numerical comparison was created when the radius was 1000 times smaller
        np.testing.assert_array_almost_equal(result.data[30:-30, :],
                                             r.data[30:-30, :] / 1000.0,
                                             decimal=1)
        self.assertCML(r, ('analysis', 'calculus', 'grad_contrived2.cml'),
                       checksum=False)
Exemplo n.º 9
0
def cube_delta(cube, coord):
    """
    Given a cube calculate the difference between each value in the
    given coord's direction.


    Args:

    * coord
        either a Coord instance or the unique name of a coordinate in the cube.
        If a Coord instance is provided, it does not necessarily have to
        exist in the cube.

    Example usage::

        change_in_temperature_wrt_pressure = \
cube_delta(temperature_cube, 'pressure')

    .. note:: Missing data support not yet implemented.

    """
    # handle the case where a user passes a coordinate name
    if isinstance(coord, six.string_types):
        coord = cube.coord(coord)

    if coord.ndim != 1:
        raise iris.exceptions.CoordinateMultiDimError(coord)

    # Try and get a coord dim
    delta_dims = cube.coord_dims(coord.name())
    if (coord.shape[0] == 1 and not getattr(coord, "circular", False)) or not delta_dims:
        raise ValueError("Cannot calculate delta over {!r} as it has " "length of 1.".format(coord.name()))
    delta_dim = delta_dims[0]

    # Calculate the actual delta, taking into account whether the given
    # coordinate is circular.
    delta_cube_data = delta(cube.data, delta_dim, circular=getattr(coord, "circular", False))

    # If the coord/dim is circular there is no change in cube shape
    if getattr(coord, "circular", False):
        delta_cube = cube.copy(data=delta_cube_data)
    else:
        # Subset the cube to the appropriate new shape by knocking off
        # the last row of the delta dimension.
        subset_slice = [slice(None, None)] * cube.ndim
        subset_slice[delta_dim] = slice(None, -1)
        delta_cube = cube[tuple(subset_slice)]
        delta_cube.data = delta_cube_data

    # Replace the delta_dim coords with midpoints
    # (no shape change if circular).
    for cube_coord in cube.coords(dimensions=delta_dim):
        delta_cube.replace_coord(_construct_midpoint_coord(cube_coord, circular=getattr(coord, "circular", False)))

    delta_cube.rename("change_in_{}_wrt_{}".format(delta_cube.name(), coord.name()))

    return delta_cube
Exemplo n.º 10
0
    def test_contrived_spherical_curl2(self):
        # testing:
        # F(lon, lat, r) = (r sin(lat) cos(lon), -r sin(lon), 0)
        # curl( F(x, y, z) ) = (0, 0, -2 cos(lon) cos(lat) )
        cube = build_cube(np.empty((70, 150)), spherical=True)
        radius = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS

        x = cube.coord('longitude')
        y = cube.coord('latitude')

        cos_x_pts = np.cos(np.radians(x.points)).reshape(1, x.shape[0])
        sin_x_pts = np.sin(np.radians(x.points)).reshape(1, x.shape[0])
        cos_y_pts = np.cos(np.radians(y.points)).reshape(y.shape[0], 1)
        sin_y_pts = np.sin(np.radians(y.points)).reshape(y.shape[0], 1)
        y_ones = np.ones((cube.shape[0], 1))

        u = cube.copy(data=sin_y_pts * cos_x_pts * radius)
        v = cube.copy(data=-sin_x_pts * y_ones * radius)
        u.rename('u_wind')
        v.rename('v_wind')

        lon_coord = x.copy()
        lon_coord.convert_units('radians')
        lat_coord = y.copy()
        lat_coord.convert_units('radians')
        cos_lat_coord = iris.coords.AuxCoord.from_coord(lat_coord)
        cos_lat_coord.points = np.cos(lat_coord.points)
        cos_lat_coord.units = '1'
        cos_lat_coord.rename('cos({})'.format(lat_coord.name()))

        r = iris.analysis.calculus.curl(u, v)[2]

        x = r.coord('longitude')
        y = r.coord('latitude')

        cos_x_pts = np.cos(np.radians(x.points)).reshape(1, x.shape[0])
        cos_y_pts = np.cos(np.radians(y.points)).reshape(y.shape[0], 1)

        # Expected r-component value: -2 cos(lon) cos(lat)
        result = r.copy(data=-2*cos_x_pts*cos_y_pts)

        # Note: This numerical comparison was created when the radius was 1000 times smaller
        np.testing.assert_array_almost_equal(result.data[30:-30, :], r.data[30:-30, :]/1000.0, decimal=1)
        self.assertCML(r, ('analysis', 'calculus', 'grad_contrived2.cml'), checksum=False)
Exemplo n.º 11
0
def _math_op_common(cube, operation_function, new_unit, in_place=False):
    _assert_is_cube(cube)
    if in_place:
        new_cube = cube
        operation_function(new_cube.data, out=new_cube.data)
    else:
        new_cube = cube.copy(data=operation_function(cube.data))
    iris.analysis.clear_phenomenon_identity(new_cube)
    new_cube.units = new_unit
    return new_cube
Exemplo n.º 12
0
def _math_op_common(cube, operation_function, new_unit, in_place=False):
    _assert_is_cube(cube)
    if in_place:
        new_cube = cube
        operation_function(new_cube.data, out=new_cube.data)
    else:
        new_cube = cube.copy(data=operation_function(cube.data))
    iris.analysis.clear_phenomenon_identity(new_cube)
    new_cube.units = new_unit
    return new_cube
Exemplo n.º 13
0
    def test_contrived_non_spherical_curl2(self):
        # testing :
        # F(x, y, z) = (z^3, x+2, y^2)
        # curl( F(x, y, z) ) = (2y, 3z^2, 1)

        cube = build_cube(np.empty((10, 25, 50)), spherical=False)

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(cube)

        u = cube.copy(data=pow(z_pts, 3) * x_ones * y_ones)
        v = cube.copy(data=z_ones * (x_pts + 2.0) * y_ones)
        w = cube.copy(data=z_ones * x_ones * pow(y_pts, 2.0))
        u.rename("u_wind")
        v.rename("v_wind")
        w.rename("w_wind")

        r = iris.analysis.calculus.curl(u, v, w)

        # TODO #235 When regridding is not nearest neighbour: the commented out code could be made to work
        # r[0].data should now be tending towards result.data as the resolution of the grid gets higher.
        #        result = r[0].copy(data=True)
        #        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(result)
        #        result.data = y_pts * 2. * x_ones * z_ones
        #        print(repr(r[0].data[0:1, 0:5, 0:25:5]))
        #        print(repr(result.data[0:1, 0:5, 0:25:5]))
        #        np.testing.assert_array_almost_equal(result.data, r[0].data, decimal=2)
        #
        #        result = r[1].copy(data=True)
        #        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(result)
        #        result.data = pow(z_pts, 2) * x_ones * y_ones
        #        np.testing.assert_array_almost_equal(result.data, r[1].data, decimal=6)

        result = r[2].copy()
        result.data = result.data * 0 + 1
        np.testing.assert_array_almost_equal(result.data, r[2].data, decimal=4)

        self.assertCML(
            r,
            ("analysis", "calculus", "curl_contrived_cartesian2.cml"),
            checksum=False,
        )
Exemplo n.º 14
0
    def test_contrived_non_spherical_curl2(self):
        # testing :
        # F(x, y, z) = (z^3, x+2, y^2)
        # curl( F(x, y, z) ) = (2y, 3z^2, 1)

        cube = build_cube(np.empty((10, 25, 50)), spherical=False)

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(cube)

        u = cube.copy(data=pow(z_pts, 3) * x_ones * y_ones)
        v = cube.copy(data=z_ones * (x_pts + 2.) * y_ones)
        w = cube.copy(data=z_ones * x_ones * pow(y_pts, 2.))
        u.rename('u_wind')
        v.rename('v_wind')
        w.rename('w_wind')

        r = iris.analysis.calculus.curl(u, v, w)


        # TODO #235 When regridding is not nearest neighbour: the commented out code could be made to work
        # r[0].data should now be tending towards result.data as the resolution of the grid gets higher.
#        result = r[0].copy(data=True)
#        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(result)
#        result.data = y_pts * 2. * x_ones * z_ones
#        print repr(r[0].data[0:1, 0:5, 0:25:5])
#        print repr(result.data[0:1, 0:5, 0:25:5])
#        np.testing.assert_array_almost_equal(result.data, r[0].data, decimal=2)
#
#        result = r[1].copy(data=True)
#        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(result)
#        result.data = pow(z_pts, 2) * x_ones * y_ones
#        np.testing.assert_array_almost_equal(result.data, r[1].data, decimal=6)

        result = r[2].copy()
        result.data = result.data * 0  + 1
        np.testing.assert_array_almost_equal(result.data, r[2].data, decimal=4)

        normalise_order(r[1])
        self.assertCML(r, ('analysis', 'calculus', 'curl_contrived_cartesian2.cml'), checksum=False)
Exemplo n.º 15
0
def _math_op_common(cube, math_op, new_unit, in_place):

    data = math_op(cube.data)

    if in_place:
        copy_cube = cube
        copy_cube.data = data
    else:
        copy_cube = cube.copy(data)

    # Update the metadata
    iris.analysis.clear_phenomenon_identity(copy_cube)
    copy_cube.units = new_unit

    return copy_cube
Exemplo n.º 16
0
def _math_op_common(cube, math_op, new_unit, in_place):

    data = math_op(cube.data)

    if in_place:
        copy_cube = cube
        copy_cube.data = data
    else:
        copy_cube = cube.copy(data)

    # Update the metadata
    iris.analysis.clear_phenomenon_identity(copy_cube)
    copy_cube.units = new_unit

    return copy_cube
Exemplo n.º 17
0
    def test_contrived_differential2(self):
        # testing :
        # w = y^2
        # dw_dy = 2*y
        cube = build_cube(np.empty((10, 30, 60)), spherical=False)

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(cube)

        w = cube.copy(data=z_ones * x_ones * pow(y_pts, 2.))

        r = iris.analysis.calculus.differentiate(w, 'projection_y_coordinate')

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(r)
        result = r.copy(data=y_pts * 2. * x_ones * z_ones)

        np.testing.assert_array_almost_equal(result.data, r.data, decimal=6)
Exemplo n.º 18
0
    def test_contrived_differential2(self):
        # testing :
        # w = y^2
        # dw_dy = 2*y
        cube = build_cube(np.empty((10, 30, 60)), spherical=False)

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(cube)

        w = cube.copy(data=z_ones * x_ones * pow(y_pts, 2.))

        r = iris.analysis.calculus.differentiate(w, 'projection_y_coordinate')

        x_pts, x_ones, y_pts, y_ones, z_pts, z_ones = self.get_coord_pts(r)
        result = r.copy(data = y_pts * 2. * x_ones * z_ones)

        np.testing.assert_array_almost_equal(result.data, r.data, decimal=6)
Exemplo n.º 19
0
def _compute_anomalies(cube, reference, period, seasons):
    cube_coord = _get_period_coord(cube, period, seasons)
    ref_coord = _get_period_coord(reference, period, seasons)

    data = cube.core_data()
    cube_time = cube.coord('time')
    ref = {}
    for ref_slice in reference.slices_over(ref_coord):
        ref[ref_slice.coord(ref_coord).points[0]] = ref_slice.core_data()

    cube_coord_dim = cube.coord_dims(cube_coord)[0]
    slicer = [slice(None)] * len(data.shape)
    new_data = []
    for i in range(cube_time.shape[0]):
        slicer[cube_coord_dim] = i
        new_data.append(data[tuple(slicer)] - ref[cube_coord.points[i]])
    data = da.stack(new_data, axis=cube_coord_dim)
    cube = cube.copy(data)
    cube.remove_coord(cube_coord)
    return cube
Exemplo n.º 20
0
def _math_op_common(
    cube,
    operation_function,
    new_unit,
    new_dtype=None,
    in_place=False,
    skeleton_cube=False,
):
    _assert_is_cube(cube)

    if in_place and not skeleton_cube:
        if cube.has_lazy_data():
            cube.data = operation_function(cube.lazy_data())
        else:
            try:
                operation_function(cube.data, out=cube.data)
            except TypeError:
                # Non-ufunc function
                operation_function(cube.data)
        new_cube = cube
    else:
        data = operation_function(cube.core_data())
        if skeleton_cube:
            # Simply wrap the resultant data in a cube, as no
            # cube metadata is required by the caller.
            new_cube = iris.cube.Cube(data)
        else:
            new_cube = cube.copy(data)

    # If the result of the operation is scalar and masked, we need to fix-up the dtype.
    if (new_dtype is not None and not new_cube.has_lazy_data()
            and new_cube.data.shape == () and ma.is_masked(new_cube.data)):
        new_cube.data = ma.masked_array(0, 1, dtype=new_dtype)

    _sanitise_metadata(new_cube, new_unit)

    return new_cube
Exemplo n.º 21
0
def _multiply_divide_common(operation_function, operation_symbol, operation_noun,
                            cube, other, dim=None, update_history=True):
    """
    Function which shares common code between multiplication and division of cubes.

    operation_function   - function which does the operation (e.g. numpy.divide)
    operation_symbol     - the textual symbol of the operation (e.g. '/')
    operation_noun       - the noun of the operation (e.g. 'division')
    operation_past_tense - the past tesnse of the operation (e.g. 'divided')

    .. seealso:: For information on the dim keyword argument see :func:`multiply`.

    """
    if not isinstance(cube, iris.cube.Cube):
        raise TypeError('The "cube" argument must be an instance of iris.Cube.')

    if isinstance(other, (int, float)):
        other = np.array(other)

    other_unit = None
    history = None

    if isinstance(other, np.ndarray):
        _assert_compatible(cube, other)

        copy_cube = cube.copy(data=operation_function(cube.data, other))

        if update_history:
            if other.ndim == 0:
                history = '%s %s %s' % (cube.name(), operation_symbol, other)
            else:
                history = '%s %s array' % (cube.name(), operation_symbol)

        other_unit = '1'
    elif isinstance(other, iris.coords.Coord):
        # Deal with cube multiplication/division by coordinate

        # What dimension are we processing?
        data_dimension = None
        if dim is not None:
            # Ensure the given dim matches the coord
            if other in cube.coords() and cube.coord_dims(other) != [dim]:
                raise ValueError("dim provided does not match dim found for coord")
            data_dimension = dim
        else:
            # Try and get a coord dim
            if other.shape != (1,):
                try:
                    coord_dims = cube.coord_dims(other)
                    data_dimension = coord_dims[0] if coord_dims else None
                except iris.exceptions.CoordinateNotFoundError:
                    raise ValueError("Could not determine dimension for mul/div. Use mul(coord, dim=dim)")

        if other.ndim != 1:
            raise iris.exceptions.CoordinateMultiDimError(other)

        if other.has_bounds():
            warnings.warn('%s by a bounded coordinate not well defined, ignoring bounds.' % operation_noun)

        points = other.points

        # If the axis is defined then shape the provided points so that we can do the
        # division (this is needed as there is no "axis" keyword to numpy's divide/multiply)
        if data_dimension is not None:
            points_shape = [1] * cube.data.ndim
            points_shape[data_dimension] = -1
            points = points.reshape(points_shape)

        copy_cube = cube.copy(data=operation_function(cube.data, points))

        if update_history:
            history = '%s %s %s' % (cube.name(), operation_symbol, other.name())

        other_unit = other.units
    elif isinstance(other, iris.cube.Cube):
        # Deal with cube multiplication/division by cube
        copy_cube = cube.copy(data=operation_function(cube.data, other.data))

        if update_history:
            history = '%s %s %s' % (cube.name() or 'unknown', operation_symbol,
                                    other.name() or 'unknown')

        other_unit = other.units
    else:
        return NotImplemented

    # Update the units
    if operation_function == np.multiply:
        copy_cube.units = cube.units * other_unit
    elif operation_function == np.divide:
        copy_cube.units = cube.units / other_unit

    iris.analysis.clear_phenomenon_identity(copy_cube)

    if history is not None:
        copy_cube.add_history(history)

    return copy_cube
Exemplo n.º 22
0
def _add_subtract_common(operation_function, operation_symbol, operation_noun, operation_past_tense,
                         cube, other, dim=None, ignore=True, update_history=True, in_place=False):
    """
    Function which shares common code between addition and subtraction of cubes.

    operation_function   - function which does the operation (e.g. numpy.subtract)
    operation_symbol     - the textual symbol of the operation (e.g. '-')
    operation_noun       - the noun of the operation (e.g. 'subtraction')
    operation_past_tense - the past tense of the operation (e.g. 'subtracted')

    """
    if not isinstance(cube, iris.cube.Cube):
        raise TypeError('The "cube" argument must be an instance of iris.Cube.')

    if isinstance(other, (int, float)):
        # Promote scalar to a coordinate and associate unit type with cube unit type
        other = np.array(other)

    # Check that the units of the cube and the other item are the same, or if the other does not have a unit, skip this test
    if cube.units != getattr(other, 'units', cube.units) :
        raise iris.exceptions.NotYetImplementedError('Differing units (%s & %s) %s not implemented' % \
                                                     (cube.units, other.units, operation_noun))

    history = None

    if isinstance(other, np.ndarray):
        _assert_compatible(cube, other)

        if in_place:
            new_cube = cube
            operation_function(new_cube.data, other, new_cube.data)
        else:
            new_cube = cube.copy(data=operation_function(cube.data, other))

        if update_history:
            if other.ndim == 0:
                history = '%s %s %s' % (cube.name(), operation_symbol, other)
            else:
                history = '%s %s array' % (cube.name(), operation_symbol)
    elif isinstance(other, iris.coords.Coord):
        # Deal with cube addition/subtraction by coordinate

        # What dimension are we processing?
        data_dimension = None
        if dim is not None:
            # Ensure the given dim matches the coord
            if other in cube.coords() and cube.coord_dims(other) != [dim]:
                raise ValueError("dim provided does not match dim found for coord")
            data_dimension = dim
        else:
            # Try and get a coord dim
            if other.shape != (1,):
                try:
                    coord_dims = cube.coord_dims(other)
                    data_dimension = coord_dims[0] if coord_dims else None
                except iris.exceptions.CoordinateNotFoundError:
                    raise ValueError("Could not determine dimension for add/sub. Use add(coord, dim=dim)")

        if other.ndim != 1:
            raise iris.exceptions.CoordinateMultiDimError(other)

        if other.has_bounds():
            warnings.warn('%s by a bounded coordinate not well defined, ignoring bounds.' % operation_noun)

        points = other.points

        if data_dimension is not None:
            points_shape = [1] * cube.data.ndim
            points_shape[data_dimension] = -1
            points = points.reshape(points_shape)

        if in_place:
            new_cube = cube
            operation_function(new_cube.data, points, new_cube.data)
        else:
            new_cube = cube.copy(data=operation_function(cube.data, points))

        if update_history:
            history = '%s %s %s (coordinate)' % (cube.name(), operation_symbol, other.name())
    elif isinstance(other, iris.cube.Cube):
        # Deal with cube addition/subtraction by cube

        # get a coordinate comparison of this cube and the cube to do the operation with
        coord_comp = iris.analysis.coord_comparison(cube, other)

        if coord_comp['transposable']:
            raise ValueError('Cubes cannot be %s, differing axes. '
                                 'cube.transpose() may be required to re-order the axes.' % operation_past_tense)

        # provide a deprecation warning if the ignore keyword has been set
        if ignore is not True:
            warnings.warn('The "ignore" keyword has been deprecated in add/subtract. This functionality is now automatic. '
                          'The provided value to "ignore" has been ignored, and has been automatically calculated.')

        bad_coord_grps = (coord_comp['ungroupable_and_dimensioned'] + coord_comp['resamplable'])
        if bad_coord_grps:
            raise ValueError('This operation cannot be performed as there are differing coordinates (%s) remaining '
                             'which cannot be ignored.' % ', '.join({coord_grp.name() for coord_grp in bad_coord_grps}))

        if in_place:
            new_cube = cube
            operation_function(new_cube.data, other.data, new_cube.data)
        else:
            new_cube = cube.copy(data=operation_function(cube.data, other.data))

        # If a coordinate is to be ignored - remove it
        ignore = filter(None, [coord_grp[0] for coord_grp in coord_comp['ignorable']])
        if not ignore:
            ignore_string = ''
        else:
            ignore_string = ' (ignoring %s)' % ', '.join([coord.name() for coord in ignore])
        for coord in ignore:
            new_cube.remove_coord(coord)

        if update_history:
            history = '%s %s %s%s' % (cube.name() or 'unknown', operation_symbol,
                                      other.name() or 'unknown', ignore_string)

    else:
        return NotImplemented

    iris.analysis.clear_phenomenon_identity(new_cube)

    if history is not None:
        new_cube.add_history(history)

    return new_cube
Exemplo n.º 23
0
def _add_subtract_common(operation_function,
                         operation_symbol,
                         operation_noun,
                         operation_past_tense,
                         cube,
                         other,
                         dim=None,
                         ignore=True,
                         in_place=False):
    """
    Function which shares common code between addition and subtraction of cubes.

    operation_function   - function which does the operation (e.g. numpy.subtract)
    operation_symbol     - the textual symbol of the operation (e.g. '-')
    operation_noun       - the noun of the operation (e.g. 'subtraction')
    operation_past_tense - the past tense of the operation (e.g. 'subtracted')

    """
    if not isinstance(cube, iris.cube.Cube):
        raise TypeError(
            'The "cube" argument must be an instance of iris.Cube.')

    if isinstance(other, (int, float)):
        # Promote scalar to a coordinate and associate unit type with cube unit type
        other = np.array(other)

    # Check that the units of the cube and the other item are the same, or if the other does not have a unit, skip this test
    if cube.units != getattr(other, 'units', cube.units):
        raise iris.exceptions.NotYetImplementedError('Differing units (%s & %s) %s not implemented' % \
                                                     (cube.units, other.units, operation_noun))

    if isinstance(other, np.ndarray):
        _assert_compatible(cube, other)

        if in_place:
            new_cube = cube
            operation_function(new_cube.data, other, new_cube.data)
        else:
            new_cube = cube.copy(data=operation_function(cube.data, other))
    elif isinstance(other, iris.coords.Coord):
        # Deal with cube addition/subtraction by coordinate

        # What dimension are we processing?
        data_dimension = None
        if dim is not None:
            # Ensure the given dim matches the coord
            if other in cube.coords() and cube.coord_dims(other) != [dim]:
                raise ValueError(
                    "dim provided does not match dim found for coord")
            data_dimension = dim
        else:
            # Try and get a coord dim
            if other.shape != (1, ):
                try:
                    coord_dims = cube.coord_dims(other)
                    data_dimension = coord_dims[0] if coord_dims else None
                except iris.exceptions.CoordinateNotFoundError:
                    raise ValueError(
                        "Could not determine dimension for add/sub. Use add(coord, dim=dim)"
                    )

        if other.ndim != 1:
            raise iris.exceptions.CoordinateMultiDimError(other)

        if other.has_bounds():
            warnings.warn(
                '%s by a bounded coordinate not well defined, ignoring bounds.'
                % operation_noun)

        points = other.points

        if data_dimension is not None:
            points_shape = [1] * cube.ndim
            points_shape[data_dimension] = -1
            points = points.reshape(points_shape)

        if in_place:
            new_cube = cube
            operation_function(new_cube.data, points, new_cube.data)
        else:
            new_cube = cube.copy(data=operation_function(cube.data, points))
    elif isinstance(other, iris.cube.Cube):
        # Deal with cube addition/subtraction by cube

        # get a coordinate comparison of this cube and the cube to do the operation with
        coord_comp = iris.analysis.coord_comparison(cube, other)

        if coord_comp['transposable']:
            # User does not need to transpose their cubes if numpy
            # array broadcasting will make the dimensions match
            broadcast_padding = cube.ndim - other.ndim
            coord_dims_equal = True
            for coord_group in coord_comp['transposable']:
                cube_coord, other_coord = coord_group.coords
                cube_coord_dims = cube.coord_dims(coord=cube_coord)
                other_coord_dims = other.coord_dims(coord=other_coord)
                other_coord_dims_broadcasted = tuple(
                    [dim + broadcast_padding for dim in other_coord_dims])
                if cube_coord_dims != other_coord_dims_broadcasted:
                    coord_dims_equal = False

            if not coord_dims_equal:
                raise ValueError('Cubes cannot be %s, differing axes. '
                                 'cube.transpose() may be required to '
                                 're-order the axes.' % operation_past_tense)

        # provide a deprecation warning if the ignore keyword has been set
        if ignore is not True:
            warnings.warn(
                'The "ignore" keyword has been deprecated in add/subtract. This functionality is now automatic. '
                'The provided value to "ignore" has been ignored, and has been automatically calculated.'
            )

        bad_coord_grps = (coord_comp['ungroupable_and_dimensioned'] +
                          coord_comp['resamplable'])
        if bad_coord_grps:
            raise ValueError(
                'This operation cannot be performed as there are differing coordinates (%s) remaining '
                'which cannot be ignored.' %
                ', '.join({coord_grp.name()
                           for coord_grp in bad_coord_grps}))

        if in_place:
            new_cube = cube
            operation_function(new_cube.data, other.data, new_cube.data)
        else:
            new_cube = cube.copy(
                data=operation_function(cube.data, other.data))

        # If a coordinate is to be ignored - remove it
        ignore = filter(
            None, [coord_grp[0] for coord_grp in coord_comp['ignorable']])
        if not ignore:
            ignore_string = ''
        else:
            ignore_string = ' (ignoring %s)' % ', '.join(
                [coord.name() for coord in ignore])
        for coord in ignore:
            new_cube.remove_coord(coord)

    else:
        return NotImplemented

    iris.analysis.clear_phenomenon_identity(new_cube)

    return new_cube
Exemplo n.º 24
0
def _multiply_divide_common(operation_function,
                            operation_symbol,
                            operation_noun,
                            cube,
                            other,
                            dim=None,
                            in_place=False):
    """
    Function which shares common code between multiplication and division of cubes.

    operation_function   - function which does the operation (e.g. numpy.divide)
    operation_symbol     - the textual symbol of the operation (e.g. '/')
    operation_noun       - the noun of the operation (e.g. 'division')
    operation_past_tense - the past tense of the operation (e.g. 'divided')

    .. seealso:: For information on the dim keyword argument see :func:`multiply`.

    """
    if not isinstance(cube, iris.cube.Cube):
        raise TypeError(
            'The "cube" argument must be an instance of iris.Cube.')

    if isinstance(other, (int, float)):
        other = np.array(other)

    other_unit = None

    if isinstance(other, np.ndarray):
        _assert_compatible(cube, other)

        if in_place:
            new_cube = cube
            new_cube.data = operation_function(cube.data, other)
        else:
            new_cube = cube.copy(data=operation_function(cube.data, other))

        other_unit = '1'
    elif isinstance(other, iris.coords.Coord):
        # Deal with cube multiplication/division by coordinate

        # What dimension are we processing?
        data_dimension = None
        if dim is not None:
            # Ensure the given dim matches the coord
            if other in cube.coords() and cube.coord_dims(other) != [dim]:
                raise ValueError(
                    "dim provided does not match dim found for coord")
            data_dimension = dim
        else:
            # Try and get a coord dim
            if other.shape != (1, ):
                try:
                    coord_dims = cube.coord_dims(other)
                    data_dimension = coord_dims[0] if coord_dims else None
                except iris.exceptions.CoordinateNotFoundError:
                    raise ValueError(
                        "Could not determine dimension for mul/div. Use mul(coord, dim=dim)"
                    )

        if other.ndim != 1:
            raise iris.exceptions.CoordinateMultiDimError(other)

        if other.has_bounds():
            warnings.warn(
                '%s by a bounded coordinate not well defined, ignoring bounds.'
                % operation_noun)

        points = other.points

        # If the axis is defined then shape the provided points so that we can do the
        # division (this is needed as there is no "axis" keyword to numpy's divide/multiply)
        if data_dimension is not None:
            points_shape = [1] * cube.ndim
            points_shape[data_dimension] = -1
            points = points.reshape(points_shape)

        if in_place:
            new_cube = cube
            new_cube.data = operation_function(cube.data, points)
        else:
            new_cube = cube.copy(data=operation_function(cube.data, points))

        other_unit = other.units
    elif isinstance(other, iris.cube.Cube):
        # Deal with cube multiplication/division by cube

        if in_place:
            new_cube = cube
            new_cube.data = operation_function(cube.data, other.data)
        else:
            new_cube = cube.copy(
                data=operation_function(cube.data, other.data))

        other_unit = other.units
    else:
        return NotImplemented

    # Update the units
    if operation_function == np.multiply:
        new_cube.units = cube.units * other_unit
    elif operation_function == np.divide:
        new_cube.units = cube.units / other_unit

    iris.analysis.clear_phenomenon_identity(new_cube)

    return new_cube