Example #1
0
File: maths.py Project: 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
Example #2
0
    def __init__(self, cube):
        """
        Create a new _ProtoCube from the given cube and record the cube
        as a source-cube.

        Args:

        * cube:
            Source :class:`iris.cube.Cube` of the :class:`_ProtoCube`.

        """
        # Cache the source-cube of this proto-cube.
        self._cube = cube

        # The cube signature is a combination of cube and coordinate
        # metadata that defines this proto-cube.
        self._cube_signature = _CubeSignature(cube)

        # The coordinate signature allows suitable non-overlapping
        # source-cubes to be identified.
        self._coord_signature = _CoordSignature(self._cube_signature)

        # The list of source-cubes relevant to this proto-cube.
        self._skeletons = []
        self._add_skeleton(self._coord_signature, cube.lazy_data())

        # The nominated axis of concatenation.
        self._axis = None
Example #3
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
Example #4
0
    def __init__(self, cube):
        """
        Create a new _ProtoCube from the given cube and record the cube
        as a source-cube.

        Args:

        * cube:
            Source :class:`iris.cube.Cube` of the :class:`_ProtoCube`.

        """
        # Cache the source-cube of this proto-cube.
        self._cube = cube

        # The cube signature is a combination of cube and coordinate
        # metadata that defines this proto-cube.
        self._cube_signature = _CubeSignature(cube)

        # The coordinate signature allows suitable non-overlapping
        # source-cubes to be identified.
        self._coord_signature = _CoordSignature(self._cube_signature)

        # The list of source-cubes relevant to this proto-cube.
        self._skeletons = []
        self._add_skeleton(self._coord_signature, cube.lazy_data())

        # The nominated axis of concatenation.
        self._axis = None
Example #5
0
    def register(self, cube, axis=None, error_on_mismatch=False):
        """
        Determine whether the given source-cube is suitable for concatenation
        with this :class:`_ProtoCube`.

        Args:

        * cube:
            The :class:`iris.cube.Cube` source-cube candidate for
            concatenation.

        Kwargs:

        * axis:
            Seed the dimension of concatenation for the :class:`_ProtoCube`
            rather than rely on negotiation with source-cubes.

        * error_on_mismatch:
            If True, raise an informative error if registration fails.

        Returns:
            Boolean.

        """
        # Verify and assert the nominated axis.
        if axis is not None and self.axis is not None and self.axis != axis:
            msg = 'Nominated axis [{}] is not equal ' \
                'to negotiated axis [{}]'.format(axis, self.axis)
            raise ValueError(msg)

        # Check for compatible cube signatures.
        cube_signature = _CubeSignature(cube)
        match = self._cube_signature.match(cube_signature, error_on_mismatch)

        # Check for compatible coordinate signatures.
        if match:
            coord_signature = _CoordSignature(cube_signature)
            candidate_axis = self._coord_signature.candidate_axis(
                coord_signature)
            match = candidate_axis is not None and \
                (candidate_axis == axis or axis is None)

        # Check for compatible coordinate extents.
        if match:
            match = self._sequence(coord_signature.dim_extents[candidate_axis],
                                   candidate_axis)

        if match:
            # Register the cube as a source-cube for this proto-cube.
            self._add_skeleton(coord_signature, cube.lazy_data())
            # Declare the nominated axis of concatenation.
            self._axis = candidate_axis

        return match
Example #6
0
    def register(self, cube, axis=None, error_on_mismatch=False):
        """
        Determine whether the given source-cube is suitable for concatenation
        with this :class:`_ProtoCube`.

        Args:

        * cube:
            The :class:`iris.cube.Cube` source-cube candidate for
            concatenation.

        Kwargs:

        * axis:
            Seed the dimension of concatenation for the :class:`_ProtoCube`
            rather than rely on negotiation with source-cubes.

        * error_on_mismatch:
            If True, raise an informative error if registration fails.

        Returns:
            Boolean.

        """
        # Verify and assert the nominated axis.
        if axis is not None and self.axis is not None and self.axis != axis:
            msg = 'Nominated axis [{}] is not equal ' \
                'to negotiated axis [{}]'.format(axis, self.axis)
            raise ValueError(msg)

        # Check for compatible cube signatures.
        cube_signature = _CubeSignature(cube)
        match = self._cube_signature.match(cube_signature, error_on_mismatch)

        # Check for compatible coordinate signatures.
        if match:
            coord_signature = _CoordSignature(cube_signature)
            candidate_axis = self._coord_signature.candidate_axis(
                coord_signature)
            match = candidate_axis is not None and \
                (candidate_axis == axis or axis is None)

        # Check for compatible coordinate extents.
        if match:
            match = self._sequence(coord_signature.dim_extents[candidate_axis],
                                   candidate_axis)

        if match:
            # Register the cube as a source-cube for this proto-cube.
            self._add_skeleton(coord_signature, cube.lazy_data())
            # Declare the nominated axis of concatenation.
            self._axis = candidate_axis

        return match
Example #7
0
 def test_concat_masked_2y2d_with_lazy_and_concrete(self):
     cubes = []
     x = (0, 2)
     cube = _make_cube(x, (0, 2), 1)
     cube.data = np.ma.asarray(cube.data)
     cube.data[(0, 1), (0, 1)] = ma.masked
     cube.data = cube.lazy_data()
     cubes.append(cube)
     cube = _make_cube(x, (2, 4), 2)
     cube.data = ma.asarray(cube.data)
     cube.data[(0, 1), (1, 0)] = ma.masked
     cubes.append(cube)
     result = concatenate(cubes)
     self.assertCML(result, ('concatenate', 'concat_masked_2y2d.cml'))
     self.assertEqual(len(result), 1)
     self.assertEqual(result[0].shape, (4, 2))
     mask = np.array(
         [[True, False], [False, True], [False, True], [True, False]],
         dtype=np.bool)
     self.assertArrayEqual(result[0].data.mask, mask)
Example #8
0
 def test_concat_masked_2y2d_with_lazy_and_concrete(self):
     cubes = []
     x = (0, 2)
     cube = _make_cube(x, (0, 2), 1)
     cube.data = np.ma.asarray(cube.data)
     cube.data[(0, 1), (0, 1)] = ma.masked
     cube.data = cube.lazy_data()
     cubes.append(cube)
     cube = _make_cube(x, (2, 4), 2)
     cube.data = ma.asarray(cube.data)
     cube.data[(0, 1), (1, 0)] = ma.masked
     cubes.append(cube)
     result = concatenate(cubes)
     self.assertCML(result, ('concatenate', 'concat_masked_2y2d.cml'))
     self.assertEqual(len(result), 1)
     self.assertEqual(result[0].shape, (4, 2))
     mask = np.array([[True, False],
                      [False, True],
                      [False, True],
                      [True, False]], dtype=np.bool)
     self.assertArrayEqual(result[0].data.mask, mask)
Example #9
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
Example #10
0
 def test_concat_masked_2y2d_int16_with_lazy_and_concrete(self):
     cubes = []
     x = (0, 2)
     dtype = np.dtype('int16')
     fill_value = -37
     mask = [(0, 1), (1, 0)]
     cube = _make_cube(x, (2, 4), 2, dtype=dtype, mask=mask)
     cube.replace(cube.lazy_data(), dtype=dtype, fill_value=fill_value)
     cubes.append(cube)
     mask = [(0, 1), (0, 1)]
     cube = _make_cube(x, (0, 2), 1, dtype=dtype, mask=mask,
                       fill_value=fill_value)
     cubes.append(cube)
     result = concatenate(cubes)
     self.assertCML(result, ('concatenate', 'concat_masked_2y2d_int16.cml'))
     self.assertEqual(len(result), 1)
     self.assertEqual(result[0].shape, (4, 2))
     mask = np.array([[True, False],
                      [False, True],
                      [False, True],
                      [True, False]], dtype=np.bool)
     self.assertArrayEqual(result[0].data.mask, mask)
     self.assertEqual(result[0].fill_value, fill_value)
     self.assertEqual(result[0].data.fill_value, fill_value)
Example #11
0
    def register(self, cube, axis=None, error_on_mismatch=False,
                 check_aux_coords=False):
        """
        Determine whether the given source-cube is suitable for concatenation
        with this :class:`_ProtoCube`.

        Args:

        * cube:
            The :class:`iris.cube.Cube` source-cube candidate for
            concatenation.

        Kwargs:

        * axis:
            Seed the dimension of concatenation for the :class:`_ProtoCube`
            rather than rely on negotiation with source-cubes.

        * error_on_mismatch:
            If True, raise an informative error if registration fails.

        Returns:
            Boolean.

        """
        # Verify and assert the nominated axis.
        if axis is not None and self.axis is not None and self.axis != axis:
            msg = 'Nominated axis [{}] is not equal ' \
                'to negotiated axis [{}]'.format(axis, self.axis)
            raise ValueError(msg)

        # Check for compatible cube signatures.
        cube_signature = _CubeSignature(cube)
        match = self._cube_signature.match(cube_signature, error_on_mismatch)

        # Check for compatible coordinate signatures.
        if match:
            coord_signature = _CoordSignature(cube_signature)
            candidate_axis = self._coord_signature.candidate_axis(
                coord_signature)
            match = candidate_axis is not None and \
                (candidate_axis == axis or axis is None)

        # Check for compatible coordinate extents.
        if match:
            match = self._sequence(coord_signature.dim_extents[candidate_axis],
                                   candidate_axis)

        # Check for compatible AuxCoords.
        if match:
            if check_aux_coords:
                for coord_a, coord_b in zip(
                        self._cube_signature.aux_coords_and_dims,
                        cube_signature.aux_coords_and_dims):
                    # AuxCoords that span the candidate axis can difffer
                    if (candidate_axis not in coord_a.dims or
                            candidate_axis not in coord_b.dims):
                        if not coord_a == coord_b:
                            match = False

        if match:
            # Register the cube as a source-cube for this proto-cube.
            self._add_skeleton(coord_signature, cube.lazy_data())
            # Declare the nominated axis of concatenation.
            self._axis = candidate_axis

        if match:
            # If the protocube dimension order is constant (indicating it was
            # created from a cube with a length 1 dimension coordinate) but
            # a subsequently registered cube has a non-constant dimension
            # order we should use that instead of _CONSTANT to make sure all
            # the ordering checks and sorts work as expected.
            existing_order = self._coord_signature.dim_order[self.axis]
            this_order = coord_signature.dim_order[self.axis]
            if existing_order == _CONSTANT and this_order != _CONSTANT:
                self._coord_signature.dim_order[self.axis] = this_order

        return match
Example #12
0
    def register(
        self, cube, axis=None, error_on_mismatch=False, check_aux_coords=False
    ):
        """
        Determine whether the given source-cube is suitable for concatenation
        with this :class:`_ProtoCube`.

        Args:

        * cube:
            The :class:`iris.cube.Cube` source-cube candidate for
            concatenation.

        Kwargs:

        * axis:
            Seed the dimension of concatenation for the :class:`_ProtoCube`
            rather than rely on negotiation with source-cubes.

        * error_on_mismatch:
            If True, raise an informative error if registration fails.

        Returns:
            Boolean.

        """
        # Verify and assert the nominated axis.
        if axis is not None and self.axis is not None and self.axis != axis:
            msg = (
                "Nominated axis [{}] is not equal "
                "to negotiated axis [{}]".format(axis, self.axis)
            )
            raise ValueError(msg)

        # Check for compatible cube signatures.
        cube_signature = _CubeSignature(cube)
        match = self._cube_signature.match(cube_signature, error_on_mismatch)

        # Check for compatible coordinate signatures.
        if match:
            coord_signature = _CoordSignature(cube_signature)
            candidate_axis = self._coord_signature.candidate_axis(
                coord_signature
            )
            match = candidate_axis is not None and (
                candidate_axis == axis or axis is None
            )

        # Check for compatible coordinate extents.
        if match:
            dim_ind = self._coord_signature.dim_mapping.index(candidate_axis)
            match = self._sequence(
                coord_signature.dim_extents[dim_ind], candidate_axis
            )

        # Check for compatible AuxCoords.
        if match:
            if check_aux_coords:
                for coord_a, coord_b in zip(
                    self._cube_signature.aux_coords_and_dims,
                    cube_signature.aux_coords_and_dims,
                ):
                    # AuxCoords that span the candidate axis can difffer
                    if (
                        candidate_axis not in coord_a.dims
                        or candidate_axis not in coord_b.dims
                    ):
                        if not coord_a == coord_b:
                            match = False

        if match:
            # Register the cube as a source-cube for this proto-cube.
            self._add_skeleton(coord_signature, cube.lazy_data())
            # Declare the nominated axis of concatenation.
            self._axis = candidate_axis

        if match:
            # If the protocube dimension order is constant (indicating it was
            # created from a cube with a length 1 dimension coordinate) but
            # a subsequently registered cube has a non-constant dimension
            # order we should use that instead of _CONSTANT to make sure all
            # the ordering checks and sorts work as expected.
            dim_ind = self._coord_signature.dim_mapping.index(candidate_axis)
            existing_order = self._coord_signature.dim_order[dim_ind]
            this_order = coord_signature.dim_order[dim_ind]
            if existing_order == _CONSTANT and this_order != _CONSTANT:
                self._coord_signature.dim_order[dim_ind] = this_order

        return match