Example #1
0
class Test_process(IrisTest):
    """Test process method"""
    def setUp(self):
        """
        Set up a basic cube and linear weights cube for the process
        method. Input cube has 2 thresholds on and 3
        forecast_reference_times
        """
        thresholds = [10, 20]
        data = np.ones((2, 2, 3), dtype=np.float32)
        cycle1 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 0, 0),
        )
        cycle2 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 1, 0),
        )
        cycle3 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 2, 0),
        )
        self.cube_to_collapse = CubeList([cycle1, cycle2, cycle3]).merge_cube()
        self.cube_to_collapse = squeeze(self.cube_to_collapse)
        self.cube_to_collapse.rename("weights")
        # This input array has 3 forecast reference times and 2 thresholds.
        # The two thresholds have the same weights.
        self.cube_to_collapse.data = np.array(
            [[[[1, 0, 1], [1, 1, 1]], [[1, 0, 1], [1, 1, 1]]],
             [[[0, 0, 1], [0, 1, 1]], [[0, 0, 1], [0, 1, 1]]],
             [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]]],
            dtype=np.float32)
        self.cube_to_collapse.data = np.ma.masked_equal(
            self.cube_to_collapse.data, 0)
        # Create a one_dimensional weights cube by slicing the larger
        # weights cube.
        # The resulting cube only has a forecast_reference_time coordinate.
        self.one_dimensional_weights_cube = self.cube_to_collapse[:, 0, 0, 0]
        self.one_dimensional_weights_cube.remove_coord(
            "projection_x_coordinate")
        self.one_dimensional_weights_cube.remove_coord(
            "projection_y_coordinate")
        self.one_dimensional_weights_cube.remove_coord(
            find_threshold_coordinate(self.one_dimensional_weights_cube))
        self.one_dimensional_weights_cube.data = np.array([0.2, 0.5, 0.3],
                                                          dtype=np.float32)
        self.plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=4)

    @ManageWarnings(record=True)
    def test_none_masked(self, warning_list=None):
        """Test when we have no masked data in the input cube."""
        self.cube_to_collapse.data = np.ones(self.cube_to_collapse.data.shape)
        self.cube_to_collapse.data = np.ma.masked_equal(
            self.cube_to_collapse.data, 0)
        expected_data = np.array([[[0.2, 0.2, 0.2], [0.2, 0.2, 0.2]],
                                  [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5]],
                                  [[0.3, 0.3, 0.3], [0.3, 0.3, 0.3]]],
                                 dtype=np.float32)
        message = ("Input cube to SpatiallyVaryingWeightsFromMask "
                   "must be masked")
        result = self.plugin.process(self.cube_to_collapse,
                                     self.one_dimensional_weights_cube,
                                     "forecast_reference_time")
        self.assertTrue(any(message in str(item) for item in warning_list))
        self.assertArrayEqual(result.data, expected_data)
        self.assertEqual(result.dtype, np.float32)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_all_masked(self):
        """Test when we have all masked data in the input cube."""
        self.cube_to_collapse.data = np.ones(self.cube_to_collapse.data.shape)
        self.cube_to_collapse.data = np.ma.masked_equal(
            self.cube_to_collapse.data, 1)
        result = self.plugin.process(self.cube_to_collapse,
                                     self.one_dimensional_weights_cube,
                                     "forecast_reference_time")
        expected_data = np.zeros((3, 2, 3))
        self.assertArrayAlmostEqual(expected_data, result.data)
        self.assertTrue(result.metadata, self.cube_to_collapse.data)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_no_fuzziness_no_one_dimensional_weights(self):
        """Test a simple case where we have no fuzziness in the spatial
        weights and no adjustment from the one_dimensional weights."""
        plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=1)
        self.one_dimensional_weights_cube.data = np.ones((3))
        expected_result = np.array(
            [[[0.5, 0., 0.33333333], [0.5, 0.33333333, 0.33333333]],
             [[0., 0., 0.33333333], [0., 0.33333333, 0.33333333]],
             [[0.5, 1., 0.33333333], [0.5, 0.33333333, 0.33333333]]],
            dtype=np.float32)
        result = plugin.process(self.cube_to_collapse,
                                self.one_dimensional_weights_cube,
                                "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_no_fuzziness_no_one_dimensional_weights_transpose(self):
        """Test a simple case where we have no fuzziness in the spatial
        weights and no adjustment from the one_dimensional weights and
        transpose the input cube."""
        plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=1)
        self.one_dimensional_weights_cube.data = np.ones((3))
        expected_result = np.array(
            [[[0.5, 0., 0.33333333], [0.5, 0.33333333, 0.33333333]],
             [[0., 0., 0.33333333], [0., 0.33333333, 0.33333333]],
             [[0.5, 1., 0.33333333], [0.5, 0.33333333, 0.33333333]]],
            dtype=np.float32)
        self.cube_to_collapse.transpose([2, 0, 1, 3])
        result = plugin.process(self.cube_to_collapse,
                                self.one_dimensional_weights_cube,
                                "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_no_fuzziness_with_one_dimensional_weights(self):
        """Test a simple case where we have no fuzziness in the spatial
        weights and an adjustment from the one_dimensional weights."""
        plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=1)
        expected_result = np.array([[[0.4, 0., 0.2], [0.4, 0.2, 0.2]],
                                    [[0., 0., 0.5], [0., 0.5, 0.5]],
                                    [[0.6, 1., 0.3], [0.6, 0.3, 0.3]]],
                                   dtype=np.float32)
        result = plugin.process(self.cube_to_collapse,
                                self.one_dimensional_weights_cube,
                                "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_fuzziness_no_one_dimensional_weights(self):
        """Test a simple case where we have some fuzziness in the spatial
        weights and no adjustment from the one_dimensional weights."""
        plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=2)
        self.one_dimensional_weights_cube.data = np.ones((3))
        expected_result = np.array(
            [[[0.33333334, 0., 0.25], [0.41421354, 0.25, 0.2928932]],
             [[0., 0., 0.25], [0., 0.25, 0.2928932]],
             [[0.6666667, 1., 0.5], [0.5857864, 0.5, 0.41421354]]],
            dtype=np.float32)
        result = plugin.process(self.cube_to_collapse,
                                self.one_dimensional_weights_cube,
                                "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_fuzziness_with_one_dimensional_weights(self):
        """Test a simple case where we have some fuzziness in the spatial
        sweights and with adjustment from the one_dimensional weights."""
        plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=2)
        expected_result = np.array(
            [[[0.25, 0., 0.15384616], [0.32037723, 0.15384616, 0.17789416]],
             [[0., 0., 0.3846154], [0., 0.3846154, 0.44473538]],
             [[0.75, 1., 0.4615385], [0.6796227, 0.4615385, 0.3773705]]],
            dtype=np.float32)
        result = plugin.process(self.cube_to_collapse,
                                self.one_dimensional_weights_cube,
                                "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)
Example #2
0
class Test_process(IrisTest):
    """Test process method"""
    def setUp(self):
        """
        Set up a basic cube and linear weights cube for the process
        method. Input cube has 2 thresholds and 3 forecast_reference_times
        """
        thresholds = [10, 20]
        data = np.ones((2, 2, 3), dtype=np.float32)
        cycle1 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 0, 0),
        )
        cycle2 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 1, 0),
        )
        cycle3 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 2, 0),
        )
        self.cube_to_collapse = CubeList([cycle1, cycle2, cycle3]).merge_cube()
        self.cube_to_collapse = squeeze(self.cube_to_collapse)
        self.cube_to_collapse.rename("weights")
        # This input array has 3 forecast reference times and 2 thresholds.
        # The two thresholds have the same weights.
        self.cube_to_collapse.data = np.array(
            [
                [[[1, 0, 1], [1, 1, 1]], [[1, 0, 1], [1, 1, 1]]],
                [[[0, 0, 1], [0, 1, 1]], [[0, 0, 1], [0, 1, 1]]],
                [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]],
            ],
            dtype=np.float32,
        )
        self.cube_to_collapse.data = np.ma.masked_equal(
            self.cube_to_collapse.data, 0)
        # Create a one_dimensional weights cube by slicing the larger
        # weights cube.
        # The resulting cube only has a forecast_reference_time coordinate.
        self.one_dimensional_weights_cube = self.cube_to_collapse[:, 0, 0, 0]
        self.one_dimensional_weights_cube.remove_coord(
            "projection_x_coordinate")
        self.one_dimensional_weights_cube.remove_coord(
            "projection_y_coordinate")
        self.one_dimensional_weights_cube.remove_coord(
            find_threshold_coordinate(self.one_dimensional_weights_cube))
        self.one_dimensional_weights_cube.data = np.array([0.2, 0.5, 0.3],
                                                          dtype=np.float32)
        self.plugin = SpatiallyVaryingWeightsFromMask(
            "forecast_reference_time", fuzzy_length=2)
        self.plugin_no_fuzzy = SpatiallyVaryingWeightsFromMask(
            "forecast_reference_time", fuzzy_length=1)

    @ManageWarnings(record=True)
    def test_none_masked(self, warning_list=None):
        """Test when we have no masked data in the input cube."""
        self.cube_to_collapse.data = np.ones(self.cube_to_collapse.data.shape)
        self.cube_to_collapse.data = np.ma.masked_equal(
            self.cube_to_collapse.data, 0)
        expected_data = np.array(
            [
                [[0.2, 0.2, 0.2], [0.2, 0.2, 0.2]],
                [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5]],
                [[0.3, 0.3, 0.3], [0.3, 0.3, 0.3]],
            ],
            dtype=np.float32,
        )
        message = "Expected masked input"
        result = self.plugin.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        self.assertTrue(any(message in str(item) for item in warning_list))
        self.assertArrayEqual(result.data, expected_data)
        self.assertEqual(result.dtype, np.float32)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_all_masked(self):
        """Test when we have all masked data in the input cube."""
        self.cube_to_collapse.data = np.ones(self.cube_to_collapse.data.shape)
        self.cube_to_collapse.data = np.ma.masked_equal(
            self.cube_to_collapse.data, 1)
        result = self.plugin.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        expected_data = np.zeros((3, 2, 3))
        self.assertArrayAlmostEqual(expected_data, result.data)
        self.assertTrue(result.metadata, self.cube_to_collapse.data)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_no_fuzziness_no_one_dimensional_weights(self):
        """Test a simple case where we have no fuzziness in the spatial
        weights and no adjustment from the one_dimensional weights."""
        self.one_dimensional_weights_cube.data = np.ones((3))
        expected_result = np.array(
            [
                [[0.5, 0.0, 0.333333], [0.5, 0.333333, 0.333333]],
                [[0.0, 0.0, 0.333333], [0.0, 0.333333, 0.333333]],
                [[0.5, 1.0, 0.333333], [0.5, 0.333333, 0.333333]],
            ],
            dtype=np.float32,
        )
        result = self.plugin_no_fuzzy.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_no_fuzziness_no_one_dimensional_weights_transpose(self):
        """Test a simple case where we have no fuzziness in the spatial
        weights and no adjustment from the one_dimensional weights and
        transpose the input cube."""
        self.one_dimensional_weights_cube.data = np.ones((3))
        expected_result = np.array(
            [
                [[0.5, 0.0, 0.333333], [0.5, 0.333333, 0.333333]],
                [[0.0, 0.0, 0.333333], [0.0, 0.333333, 0.333333]],
                [[0.5, 1.0, 0.333333], [0.5, 0.333333, 0.333333]],
            ],
            dtype=np.float32,
        )
        self.cube_to_collapse.transpose([2, 0, 1, 3])
        result = self.plugin_no_fuzzy.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_no_fuzziness_with_one_dimensional_weights(self):
        """Test a simple case where we have no fuzziness in the spatial
        weights and an adjustment from the one_dimensional weights."""
        expected_result = np.array(
            [
                [[0.4, 0.0, 0.2], [0.4, 0.2, 0.2]],
                [[0.0, 0.0, 0.5], [0.0, 0.5, 0.5]],
                [[0.6, 1.0, 0.3], [0.6, 0.3, 0.3]],
            ],
            dtype=np.float32,
        )
        result = self.plugin_no_fuzzy.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_fuzziness_no_one_dimensional_weights(self):
        """Test a simple case where we have some fuzziness in the spatial
        weights and no adjustment from the one_dimensional weights."""
        self.one_dimensional_weights_cube.data = np.ones((3))
        expected_result = np.array(
            [
                [[0.25, 0.0, 0.166667], [0.353553, 0.166667, 0.235702]],
                [[0.00, 0.0, 0.166667], [0.000000, 0.166667, 0.235702]],
                [[0.75, 1.0, 0.666667], [0.646447, 0.666667, 0.528595]],
            ],
            dtype=np.float32,
        )
        result = self.plugin.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_fuzziness_with_one_dimensional_weights(self):
        """Test a simple case where we have some fuzziness in the spatial
        weights and with adjustment from the one_dimensional weights."""
        expected_result = np.array(
            [
                [[0.2, 0.0, 0.10], [0.282843, 0.10, 0.141421]],
                [[0.0, 0.0, 0.25], [0.000000, 0.25, 0.353553]],
                [[0.8, 1.0, 0.65], [0.717157, 0.65, 0.505025]],
            ],
            dtype=np.float32,
        )
        result = self.plugin.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.cube_to_collapse.metadata)

    def test_fuzziness_with_unequal_weightings(self):
        """Simulate the case of two models and a nowcast at short lead times: two
        unmasked slices with low weights, and one masked slice with high weights"""
        self.cube_to_collapse.data[0].mask = np.full_like(
            self.cube_to_collapse.data[0], False)
        self.one_dimensional_weights_cube.data = np.array([0.025, 1.0, 0.075],
                                                          dtype=np.float32)
        expected_data = np.array(
            [
                [[0.25, 0.25, 0.136364], [0.25, 0.136364, 0.0892939]],
                [[0.0, 0.0, 0.45454544], [0.0, 0.454545, 0.642824]],
                [[0.75, 0.75, 0.409091], [0.75, 0.409091, 0.267882]],
            ],
            dtype=np.float32,
        )
        result = self.plugin.process(
            self.cube_to_collapse,
            self.one_dimensional_weights_cube,
        )
        self.assertArrayAlmostEqual(result.data, expected_data)
Example #3
0
class Test_normalised_masked_weights(IrisTest):
    """Test normalised_masked_weights method"""
    def setUp(self):
        """Set up a cube with 2 thresholds to test normalisation. We are
        testing normalising along the leading dimension in this cube."""
        thresholds = [10, 20]
        data = np.ones((2, 2, 3), dtype=np.float32)
        cycle1 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 0, 0),
        )
        cycle2 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 1, 0),
        )
        cycle3 = set_up_probability_cube(
            data,
            thresholds,
            spatial_grid="equalarea",
            time=datetime(2017, 11, 10, 4, 0),
            frt=datetime(2017, 11, 10, 2, 0),
        )
        self.spatial_weights_cube = CubeList([cycle1, cycle2,
                                              cycle3]).merge_cube()
        self.spatial_weights_cube = squeeze(self.spatial_weights_cube)
        self.spatial_weights_cube.rename("weights")
        # This input array has 3 forecast reference times and 2 thresholds.
        # The two thresholds have the same weights.
        self.spatial_weights_cube.data = np.array(
            [[[[0.2, 0, 0.2], [0.2, 0, 0.2]], [[0.2, 0, 0.2], [0.2, 0, 0.2]]],
             [[[0, 0, 0.5], [0, 0, 0.5]], [[0, 0, 0.5], [0, 0, 0.5]]],
             [[[0.3, 0.3, 0.3], [0.3, 0.3, 0.3]],
              [[0.3, 0.3, 0.3], [0.3, 0.3, 0.3]]]],
            dtype=np.float32)
        self.plugin = SpatiallyVaryingWeightsFromMask()

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_basic(self):
        """Test a basic example normalising along forecast_reference_time"""
        expected_result = np.array(
            [[[[0.4, 0, 0.2], [0.4, 0, 0.2]], [[0.4, 0, 0.2], [0.4, 0, 0.2]]],
             [[[0, 0, 0.5], [0, 0, 0.5]], [[0, 0, 0.5], [0, 0, 0.5]]],
             [[[0.6, 1.0, 0.3], [0.6, 1.0, 0.3]],
              [[0.6, 1.0, 0.3], [0.6, 1.0, 0.3]]]],
            dtype=np.float32)
        result = self.plugin.normalised_masked_weights(
            self.spatial_weights_cube, "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.spatial_weights_cube.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_less_input_dims(self):
        """Test a smaller input cube"""
        expected_result = np.array(
            [[[0.4, 0, 0.2], [0.4, 0, 0.2]], [[0, 0, 0.5], [0, 0, 0.5]],
             [[0.6, 1.0, 0.3], [0.6, 1.0, 0.3]]],
            dtype=np.float32)
        result = self.plugin.normalised_masked_weights(
            self.spatial_weights_cube[:, 0, :, :], "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result[:, 0, :, :].metadata,
                         self.spatial_weights_cube.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_transpose_cube(self):
        """Test the function still works when we transpose the input cube.
           Same as test_basic except for transpose."""
        expected_result = np.array(
            [[[[0.4, 0, 0.2], [0.4, 0, 0.2]], [[0.4, 0, 0.2], [0.4, 0, 0.2]]],
             [[[0, 0, 0.5], [0, 0, 0.5]], [[0, 0, 0.5], [0, 0, 0.5]]],
             [[[0.6, 1.0, 0.3], [0.6, 1.0, 0.3]],
              [[0.6, 1.0, 0.3], [0.6, 1.0, 0.3]]]],
            dtype=np.float32)
        # The function always puts the blend_coord as a leading dimension.
        # The process method will ensure the order of the output dimensions
        # matches those in the input.
        expected_result = np.transpose(expected_result, axes=[0, 3, 2, 1])
        self.spatial_weights_cube.transpose(new_order=[3, 2, 0, 1])
        result = self.plugin.normalised_masked_weights(
            self.spatial_weights_cube, "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.spatial_weights_cube.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_already_normalised(self):
        """Test nothing happens if the input data is already normalised."""
        self.spatial_weights_cube.data = np.array(
            [[[[0.4, 0, 0.2], [0.4, 0, 0.2]], [[0.4, 0, 0.2], [0.4, 0, 0.2]]],
             [[[0, 0, 0.5], [0, 0, 0.5]], [[0, 0, 0.5], [0, 0, 0.5]]],
             [[[0.6, 1.0, 0.3], [0.6, 1.0, 0.3]],
              [[0.6, 1.0, 0.3], [0.6, 1.0, 0.3]]]],
            dtype=np.float32)
        result = self.plugin.normalised_masked_weights(
            self.spatial_weights_cube, "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data,
                                    self.spatial_weights_cube.data)
        self.assertEqual(result.metadata, self.spatial_weights_cube.metadata)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_weights_sum_to_zero(self):
        """Test all x-y slices have zero weight in the same index.
           This case corresponds to the case when all the input fields are
           all masked in the same place."""
        self.spatial_weights_cube.data[:, :, :, 0] = 0
        expected_result = np.array(
            [[[[0, 0, 0.2], [0, 0, 0.2]], [[0, 0, 0.2], [0, 0, 0.2]]],
             [[[0, 0, 0.5], [0, 0, 0.5]], [[0, 0, 0.5], [0, 0, 0.5]]],
             [[[0, 1.0, 0.3], [0, 1.0, 0.3]], [[0, 1.0, 0.3], [0, 1.0, 0.3]]]],
            dtype=np.float32)
        result = self.plugin.normalised_masked_weights(
            self.spatial_weights_cube, "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.spatial_weights_cube.metadata)