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
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
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
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)
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)
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
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)
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
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