Exemplo n.º 1
0
 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
     )
Exemplo n.º 2
0
 def setUp(self):
     """Set up an example cube to test with"""
     thresholds = [10]
     data = np.ones((1, 2, 3), dtype=np.float32)
     cycle1 = set_up_probability_cube(
         data,
         thresholds,
         time=datetime(2017, 11, 10, 4, 0),
         frt=datetime(2017, 11, 10, 0, 0),
     )
     cycle2 = set_up_probability_cube(
         data,
         thresholds,
         time=datetime(2017, 11, 10, 4, 0),
         frt=datetime(2017, 11, 10, 1, 0),
     )
     cycle3 = set_up_probability_cube(
         data,
         thresholds,
         time=datetime(2017, 11, 10, 4, 0),
         frt=datetime(2017, 11, 10, 2, 0),
     )
     self.cube = CubeList([cycle1, cycle2, cycle3]).merge_cube()
     self.cube = squeeze(self.cube)
     self.plugin = SpatiallyVaryingWeightsFromMask()
Exemplo n.º 3
0
 def test_aux_blending_coord(self):
     """Test a correct template slice is returned when blending_coord is
        an AuxCoord"""
     expected = self.cube_to_collapse.copy()[:, 0, :, :]
     plugin = SpatiallyVaryingWeightsFromMask("forecast_period")
     result = plugin._create_template_slice(self.cube_to_collapse)
     self.assertEqual(expected.metadata, result.metadata)
     self.assertArrayAlmostEqual(expected.data, result.data)
Exemplo n.º 4
0
 def test_varying_mask_fail(self):
     """Test error is raised when mask varies along collapsing dim"""
     # Check fails when blending along threshold coordinate, as mask
     # varies along this coordinate.
     threshold_coord = find_threshold_coordinate(self.cube_to_collapse)
     message = "The mask on the input cube can only vary along the blend_coord"
     plugin = SpatiallyVaryingWeightsFromMask(threshold_coord.name())
     with self.assertRaisesRegex(ValueError, message):
         plugin._create_template_slice(self.cube_to_collapse)
Exemplo n.º 5
0
 def setUp(self):
     """
     Set up a basic weights cube with 2 thresholds to multiple with
     a cube with one_dimensional weights.
     """
     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(
         [
             [[[1, 0, 1], [1, 0, 1]], [[1, 0, 1], [1, 0, 1]]],
             [[[0, 0, 1], [0, 0, 1]], [[0, 0, 1], [0, 0, 1]]],
             [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]],
         ],
         dtype=np.float32,
     )
     # 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.spatial_weights_cube[:, 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()
Exemplo n.º 6
0
 def test_multi_dim_blend_coord_fail(self):
     """Test error is raised when we have a multi-dimensional blend_coord"""
     # Add a surface altitude coordinate which covers x and y dimensions.
     altitudes = np.array([[10, 20, 30], [20, 30, 10]])
     altitudes_coord = AuxCoord(altitudes,
                                standard_name="surface_altitude",
                                units="m")
     self.cube_to_collapse.add_aux_coord(altitudes_coord, data_dims=(2, 3))
     message = "Blend coordinate must only be across one dimension."
     plugin = SpatiallyVaryingWeightsFromMask("surface_altitude")
     with self.assertRaisesRegex(ValueError, message):
         plugin._create_template_slice(self.cube_to_collapse)
Exemplo n.º 7
0
 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)
Exemplo n.º 8
0
 def test_fuzziness_block_zero_weight_points(self):
     """Test fuzzy weights with a block of zero weight points"""
     # Set 4 grid points to zero in a square.
     self.cube.data[2:4, 3:5] = 0.0
     plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=2)
     expected = np.array(
         [[1., 1., 1., 1., 1., 1., 1.],
          [1., 1., 0.70710678, 0.5, 0.5, 0.70710678, 1.],
          [1., 1., 0.5, 0., 0., 0.5, 1.], [1., 1., 0.5, 0., 0., 0.5, 1.],
          [1., 1., 0.70710678, 0.5, 0.5, 0.70710678, 1.],
          [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.]],
         dtype=np.float32)
     result = plugin.smooth_initial_weights(self.cube)
     self.assertArrayAlmostEqual(result.data, expected)
Exemplo n.º 9
0
 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)
Exemplo n.º 10
0
 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)
Exemplo n.º 11
0
 def test_non_integer_fuzziness(self):
     """Test fuzzy weights over 2.5 grid squares"""
     self.cube.data[3, 3] = 0.0
     plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=2.5)
     expected = np.array(
         [[1., 1., 1., 1., 1., 1., 1.],
          [1., 1., 0.89442719, 0.8, 0.89442719, 1., 1.],
          [1., 0.89442719, 0.56568542, 0.4, 0.56568542, 0.89442719, 1.],
          [1., 0.8, 0.4, 0., 0.4, 0.8, 1.],
          [1., 0.89442719, 0.56568542, 0.4, 0.56568542, 0.89442719, 1.],
          [1., 1., 0.89442719, 0.8, 0.89442719, 1., 1.],
          [1., 1., 1., 1., 1., 1., 1.]],
         dtype=np.float32)
     result = plugin.smooth_initial_weights(self.cube)
     self.assertArrayAlmostEqual(result.data, expected)
Exemplo n.º 12
0
 def test_basic_fuzziness(self):
     """Test fuzzy weights over 3 grid squares"""
     self.cube.data[3, 3] = 0.0
     plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=3)
     expected = np.array(
         [[1., 1., 1., 1., 1., 1., 1.],
          [1., 0.942809, 0.745356, 0.666667, 0.745356, 0.942809, 1.],
          [1., 0.745356, 0.471405, 0.333333, 0.471405, 0.745356, 1.],
          [1., 0.666667, 0.333333, 0., 0.333333, 0.666667, 1.],
          [1., 0.745356, 0.471405, 0.333333, 0.471405, 0.745356, 1.],
          [1., 0.942809, 0.745356, 0.666667, 0.745356, 0.942809, 1.],
          [1., 1., 1., 1., 1., 1., 1.]],
         dtype=np.float32)
     result = plugin.smooth_initial_weights(self.cube)
     self.assertArrayAlmostEqual(result.data, expected)
Exemplo n.º 13
0
    def _update_spatial_weights(self, cube, weights, fuzzy_length):
        """
        Update weights using spatial information

        Args:
            cube (iris.cube.Cube):
                Cube of input data to be blended
            weights (iris.cube.Cube):
                Initial 1D cube of weights scaled by self.weighting_coord
            fuzzy_length (float):
                Distance (in metres) over which to smooth weights at domain
                boundaries

        Returns:
            iris.cube.Cube:
                Updated 3D cube of spatially-varying weights
        """
        check_if_grid_is_equal_area(cube)
        grid_cells = distance_to_number_of_grid_cells(
            cube, fuzzy_length, return_int=False
        )
        plugin = SpatiallyVaryingWeightsFromMask(
            self.blend_coord, fuzzy_length=grid_cells
        )
        weights = plugin(cube, weights)
        return weights
Exemplo n.º 14
0
 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)
Exemplo n.º 15
0
 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()
Exemplo n.º 16
0
 def setUp(self):
     """
     Set up a basic input cube. 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)
     self.plugin = SpatiallyVaryingWeightsFromMask(
         "forecast_reference_time")
Exemplo n.º 17
0
 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.1, 0.0, 0.1], [0.14142136, 0.1, 0.14142136]],
             [[0.0, 0.0, 0.25], [0.0, 0.25, 0.35355338]],
             [[0.3, 0.3, 0.3], [0.3, 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)
Exemplo n.º 18
0
 def test_fuzziness_more_zero_weight_points(self):
     """Test fuzzy weights with multiple zero weight points"""
     # Set 4 grid points to zero in a square.
     self.cube.data[2, 2] = 0.0
     self.cube.data[4, 4] = 0.0
     plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=2)
     expected = np.array(
         [
             [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
             [1.0, 0.70710678, 0.5, 0.70710678, 1.0, 1.0, 1.0],
             [1.0, 0.5, 0.0, 0.5, 1.0, 1.0, 1.0],
             [1.0, 0.70710678, 0.5, 0.70710678, 0.5, 0.70710678, 1.0],
             [1.0, 1.0, 1.0, 0.5, 0.0, 0.5, 1.0],
             [1.0, 1.0, 1.0, 0.70710678, 0.5, 0.70710678, 1.0],
             [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
         ],
         dtype=np.float32,
     )
     result = plugin.smooth_initial_weights(self.cube)
     self.assertArrayAlmostEqual(result.data, expected)
Exemplo n.º 19
0
 def test_basic_fuzziness_3D_input_cube(self):
     """Test fuzzy weights over 3 grid squares with 3D input cube."""
     thresholds = [10, 20, 30]
     data = np.ones((3, 7, 7), dtype=np.float32)
     cube = set_up_probability_cube(
         data,
         thresholds,
         spatial_grid="equalarea",
         time=datetime(2017, 11, 10, 4, 0),
         frt=datetime(2017, 11, 10, 0, 0),
     )
     cube.data[0, 3, 3] = 0.0
     cube.data[1, 0, 0] = 0.0
     cube.data[2, 6, 6] = 0.0
     plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=3)
     expected = np.array(
         [[[1., 1., 1., 1., 1., 1., 1.],
           [1., 0.942809, 0.745356, 0.666667, 0.745356, 0.942809, 1.],
           [1., 0.745356, 0.471405, 0.333333, 0.471405, 0.745356, 1.],
           [1., 0.666667, 0.333333, 0., 0.333333, 0.666667, 1.],
           [1., 0.745356, 0.471405, 0.333333, 0.471405, 0.745356, 1.],
           [1., 0.942809, 0.745356, 0.666667, 0.745356, 0.942809, 1.],
           [1., 1., 1., 1., 1., 1., 1.]],
          [[0., 0.33333334, 0.6666667, 1., 1., 1., 1.],
           [0.33333334, 0.47140452, 0.74535596, 1., 1., 1., 1.],
           [0.6666667, 0.74535596, 0.94280905, 1., 1., 1., 1.],
           [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.],
           [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.]],
          [[1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.],
           [1., 1., 1., 1., 1., 1., 1.], [1., 1., 1., 1., 1., 1., 1.],
           [1., 1., 1., 1., 0.94280905, 0.74535596, 0.6666667],
           [1., 1., 1., 1., 0.74535596, 0.47140452, 0.33333334],
           [1., 1., 1., 1., 0.6666667, 0.33333334, 0.]]],
         dtype=np.float32)
     result = plugin.smooth_initial_weights(cube)
     self.assertArrayAlmostEqual(result.data, expected)
Exemplo n.º 20
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)
Exemplo n.º 21
0
class Test__create_template_slice(IrisTest):
    """Test create_template_slice method"""
    def setUp(self):
        """
        Set up a basic input cube. 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)
        self.plugin = SpatiallyVaryingWeightsFromMask(
            "forecast_reference_time")

    def test_multi_dim_blend_coord_fail(self):
        """Test error is raised when we have a multi-dimensional blend_coord"""
        # Add a surface altitude coordinate which covers x and y dimensions.
        altitudes = np.array([[10, 20, 30], [20, 30, 10]])
        altitudes_coord = AuxCoord(altitudes,
                                   standard_name="surface_altitude",
                                   units="m")
        self.cube_to_collapse.add_aux_coord(altitudes_coord, data_dims=(2, 3))
        message = "Blend coordinate must only be across one dimension."
        plugin = SpatiallyVaryingWeightsFromMask("surface_altitude")
        with self.assertRaisesRegex(ValueError, message):
            plugin._create_template_slice(self.cube_to_collapse)

    def test_varying_mask_fail(self):
        """Test error is raised when mask varies along collapsing dim"""
        # Check fails when blending along threshold coordinate, as mask
        # varies along this coordinate.
        threshold_coord = find_threshold_coordinate(self.cube_to_collapse)
        message = "The mask on the input cube can only vary along the blend_coord"
        plugin = SpatiallyVaryingWeightsFromMask(threshold_coord.name())
        with self.assertRaisesRegex(ValueError, message):
            plugin._create_template_slice(self.cube_to_collapse)

    def test_scalar_blend_coord_fail(self):
        """Test error is raised when blend_coord is scalar"""
        message = "Blend coordinate must only be across one dimension."
        with self.assertRaisesRegex(ValueError, message):
            self.plugin._create_template_slice(self.cube_to_collapse[0])

    def test_basic(self):
        """Test a correct template slice is returned for simple case"""
        expected = self.cube_to_collapse.copy()[:, 0, :, :]
        result = self.plugin._create_template_slice(self.cube_to_collapse)
        self.assertEqual(expected.metadata, result.metadata)
        self.assertArrayAlmostEqual(expected.data, result.data)

    def test_basic_no_change(self):
        """Test a correct template slice is returned for a case where
           no slicing is needed"""
        input_cube = self.cube_to_collapse.copy()[:, 0, :, :]
        expected = input_cube.copy()
        result = self.plugin._create_template_slice(input_cube)
        self.assertEqual(expected.metadata, result.metadata)
        self.assertArrayAlmostEqual(expected.data, result.data)

    def test_aux_blending_coord(self):
        """Test a correct template slice is returned when blending_coord is
           an AuxCoord"""
        expected = self.cube_to_collapse.copy()[:, 0, :, :]
        plugin = SpatiallyVaryingWeightsFromMask("forecast_period")
        result = self.plugin._create_template_slice(self.cube_to_collapse)
        self.assertEqual(expected.metadata, result.metadata)
        self.assertArrayAlmostEqual(expected.data, result.data)
Exemplo n.º 22
0
 def test_basic(self):
     """Test that the __repr__ returns the expected string."""
     result = str(SpatiallyVaryingWeightsFromMask("model_id"))
     msg = "<SpatiallyVaryingWeightsFromMask: fuzzy_length: 10>"
     self.assertEqual(result, msg)
Exemplo n.º 23
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)
Exemplo n.º 24
0
 def test_no_fuzziness(self):
     """Test fuzziness over only 1 grid square, i.e. no fuzziness"""
     self.cube.data[3, 3] = 0.0
     plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=1)
     result = plugin.smooth_initial_weights(self.cube)
     self.assertArrayEqual(self.cube.data, result.data)
Exemplo n.º 25
0
def main(argv=None):
    """Load in arguments and ensure they are set correctly.
       Then load in the data to blend and calculate default weights
       using the method chosen before carrying out the blending."""
    parser = ArgParser(
        description='Calculate the default weights to apply in weighted '
        'blending plugins using the ChooseDefaultWeightsLinear or '
        'ChooseDefaultWeightsNonLinear plugins. Then apply these '
        'weights to the dataset using the BasicWeightedAverage plugin.'
        ' Required for ChooseDefaultWeightsLinear: y0val and ynval.'
        ' Required for ChooseDefaultWeightsNonLinear: cval.'
        ' Required for ChooseWeightsLinear with dict: wts_dict.')

    parser.add_argument('--wts_calc_method',
                        metavar='WEIGHTS_CALCULATION_METHOD',
                        choices=['linear', 'nonlinear', 'dict'],
                        default='linear',
                        help='Method to use to calculate '
                        'weights used in blending. "linear" (default): '
                        'calculate linearly varying blending weights. '
                        '"nonlinear": calculate blending weights that decrease'
                        ' exponentially with increasing blending coordinate. '
                        '"dict": calculate weights using a dictionary passed '
                        'in as a command line argument.')

    parser.add_argument('coordinate',
                        type=str,
                        metavar='COORDINATE_TO_AVERAGE_OVER',
                        help='The coordinate over which the blending '
                        'will be applied.')
    parser.add_argument('--coordinate_unit',
                        metavar='UNIT_STRING',
                        default='hours since 1970-01-01 00:00:00',
                        help='Units for blending coordinate. Default= '
                        'hours since 1970-01-01 00:00:00')
    parser.add_argument('--calendar',
                        metavar='CALENDAR',
                        help='Calendar for time coordinate. Default=gregorian')
    parser.add_argument('--cycletime',
                        metavar='CYCLETIME',
                        type=str,
                        help='The forecast reference time to be used after '
                        'blending has been applied, in the format '
                        'YYYYMMDDTHHMMZ. If not provided, the blended file '
                        'will take the latest available forecast reference '
                        'time from the input cubes supplied.')
    parser.add_argument('--model_id_attr',
                        metavar='MODEL_ID_ATTR',
                        type=str,
                        default="mosg__model_configuration",
                        help='The name of the netCDF file attribute to be '
                        'used to identify the source model for '
                        'multi-model blends. Default assumes Met Office '
                        'model metadata. Must be present on all input '
                        'files if blending over models.')
    parser.add_argument('--spatial_weights_from_mask',
                        action='store_true',
                        default=False,
                        help='If set this option will result in the generation'
                        ' of spatially varying weights based on the'
                        ' masks of the data we are blending. The'
                        ' one dimensional weights are first calculated '
                        ' using the chosen weights calculation method,'
                        ' but the weights will then be adjusted spatially'
                        ' based on where there is masked data in the data'
                        ' we are blending. The spatial weights are'
                        ' calculated using the'
                        ' SpatiallyVaryingWeightsFromMask plugin.')
    parser.add_argument('weighting_mode',
                        metavar='WEIGHTED_BLEND_MODE',
                        choices=['weighted_mean', 'weighted_maximum'],
                        help='The method used in the weighted blend. '
                        '"weighted_mean": calculate a normal weighted'
                        ' mean across the coordinate. '
                        '"weighted_maximum": multiplies the values in the'
                        ' coordinate by the weights, and then takes the'
                        ' maximum.')

    parser.add_argument('input_filepaths',
                        metavar='INPUT_FILES',
                        nargs="+",
                        help='Paths to input files to be blended.')
    parser.add_argument('output_filepath',
                        metavar='OUTPUT_FILE',
                        help='The output path for the processed NetCDF.')

    spatial = parser.add_argument_group(
        'Spatial weights from mask options',
        'Options for calculating the spatial weights using the '
        'SpatiallyVaryingWeightsFromMask plugin.')
    spatial.add_argument('--fuzzy_length',
                         metavar='FUZZY_LENGTH',
                         type=float,
                         default=20000,
                         help='When calculating spatially varying weights we'
                         ' can smooth the weights so that areas close to'
                         ' areas that are masked have lower weights than'
                         ' those further away. This fuzzy length controls'
                         ' the scale over which the weights are smoothed.'
                         ' The fuzzy length is in terms of m, the'
                         ' default is 20km. This distance is then'
                         ' converted into a number of grid squares,'
                         ' which does not have to be an integer. Assumes'
                         ' the grid spacing is the same in the x and y'
                         ' directions, and raises an error if this is not'
                         ' true. See SpatiallyVaryingWeightsFromMask for'
                         ' more detail.')

    linear = parser.add_argument_group(
        'linear weights options', 'Options for the linear weights '
        'calculation in '
        'ChooseDefaultWeightsLinear')
    linear.add_argument('--y0val',
                        metavar='LINEAR_STARTING_POINT',
                        type=float,
                        help='The relative value of the weighting start point '
                        '(lowest value of blend coord) for choosing default '
                        'linear weights. This must be a positive float or 0.')
    linear.add_argument('--ynval',
                        metavar='LINEAR_END_POINT',
                        type=float,
                        help='The relative value of the weighting '
                        'end point (highest value of blend coord) for choosing'
                        ' default linear weights. This must be a positive '
                        'float or 0.  Note that if blending over forecast '
                        'reference time, ynval >= y0val would normally be '
                        'expected (to give greater weight to the more recent '
                        'forecast).')

    nonlinear = parser.add_argument_group(
        'nonlinear weights options', 'Options for the non-linear '
        'weights calculation in '
        'ChooseDefaultWeightsNonLinear')
    nonlinear.add_argument('--cval',
                           metavar='NON_LINEAR_FACTOR',
                           type=float,
                           help='Factor used to determine how skewed the '
                           'non linear weights will be. '
                           'A value of 1 implies equal weighting. If not '
                           'set, a default value of cval=0.85 is set.')

    wts_dict = parser.add_argument_group(
        'dict weights options', 'Options for linear weights to be '
        'calculated based on parameters '
        'read from a json file dict')
    wts_dict.add_argument('--wts_dict',
                          metavar='WEIGHTS_DICTIONARY',
                          help='Path to json file containing dictionary from '
                          'which to calculate blending weights. Dictionary '
                          'format is as specified in the improver.blending.'
                          'weights.ChooseWeightsLinear plugin.')
    wts_dict.add_argument('--weighting_coord',
                          metavar='WEIGHTING_COORD',
                          default='forecast_period',
                          help='Name of '
                          'coordinate over which linear weights should be '
                          'scaled. This coordinate must be avilable in the '
                          'weights dictionary.')

    args = parser.parse_args(args=argv)

    # if the linear weights method is called with non-linear args or vice
    # versa, exit with error
    if (args.wts_calc_method == "linear") and args.cval:
        parser.wrong_args_error('cval', 'linear')
    if ((args.wts_calc_method == "nonlinear")
            and np.any([args.y0val, args.ynval])):
        parser.wrong_args_error('y0val, ynval', 'non-linear')
    if (args.wts_calc_method == "dict") and not args.wts_dict:
        parser.error('Dictionary is required if --wts_calc_method="dict"')

    # set blending coordinate units
    if "time" in args.coordinate:
        coord_unit = Unit(args.coordinate_unit, args.calendar)
    elif args.coordinate_unit != 'hours since 1970-01-01 00:00:00.':
        coord_unit = args.coordinate_unit
    else:
        coord_unit = 'no_unit'

    # For blending across models, only blending across "model_id" is directly
    # supported. This is because the blending coordinate must be sortable, in
    # order to ensure that the data cube and the weights cube have coordinates
    # in the same order for blending. Whilst the model_configuration is
    # sortable itself, as it is associated with model_id, which is the
    # dimension coordinate, sorting the model_configuration coordinate can
    # result in the model_id coordinate becoming non-monotonic. As dimension
    # coordinates must be monotonic, this leads to the model_id coordinate
    # being demoted to an auxiliary coordinate. Therefore, for simplicity
    # model_id is used as the blending coordinate, instead of
    # model_configuration.
    # TODO: Support model_configuration as a blending coordinate directly.
    if args.coordinate == "model_configuration":
        blend_coord = "model_id"
        dict_coord = "model_configuration"
    else:
        blend_coord = args.coordinate
        dict_coord = args.coordinate

    # load cubes to be blended
    cubelist = load_cubelist(args.input_filepaths)

    # determine whether or not to equalise forecast periods for model
    # blending weights calculation
    weighting_coord = (args.weighting_coord
                       if args.weighting_coord else "forecast_period")

    # prepare cubes for weighted blending
    merger = MergeCubesForWeightedBlending(blend_coord,
                                           weighting_coord=weighting_coord,
                                           model_id_attr=args.model_id_attr)
    cube = merger.process(cubelist, cycletime=args.cycletime)

    # if the coord for blending does not exist or has only one value,
    # update metadata only
    coord_names = [coord.name() for coord in cube.coords()]
    if (blend_coord not in coord_names) or (len(
            cube.coord(blend_coord).points) == 1):
        result = cube.copy()
        conform_metadata(result, cube, blend_coord, cycletime=args.cycletime)
        # raise a warning if this happened because the blend coordinate
        # doesn't exist
        if blend_coord not in coord_names:
            warnings.warn('Blend coordinate {} is not present on input '
                          'data'.format(blend_coord))

    # otherwise, calculate weights and blend across specified dimension
    else:
        weights = calculate_blending_weights(
            cube,
            blend_coord,
            args.wts_calc_method,
            wts_dict=args.wts_dict,
            weighting_coord=args.weighting_coord,
            coord_unit=coord_unit,
            y0val=args.y0val,
            ynval=args.ynval,
            cval=args.cval,
            dict_coord=dict_coord)

        if args.spatial_weights_from_mask:
            check_if_grid_is_equal_area(cube)
            grid_cells_x, _ = convert_distance_into_number_of_grid_cells(
                cube, args.fuzzy_length, int_grid_cells=False)
            SpatialWeightsPlugin = SpatiallyVaryingWeightsFromMask(
                grid_cells_x)
            weights = SpatialWeightsPlugin.process(cube, weights, blend_coord)

        # blend across specified dimension
        BlendingPlugin = WeightedBlendAcrossWholeDimension(
            blend_coord, args.weighting_mode, cycletime=args.cycletime)
        result = BlendingPlugin.process(cube, weights=weights)

    save_netcdf(result, args.output_filepath)
Exemplo n.º 26
0
 def test_initial_weights_all_1(self):
     """Test the input cube all containing weights of one."""
     plugin = SpatiallyVaryingWeightsFromMask(fuzzy_length=4)
     result = plugin.smooth_initial_weights(self.cube)
     self.assertArrayEqual(self.cube.data, result.data)
Exemplo n.º 27
0
class Test_multiply_weights(IrisTest):
    """Test multiply_weights method"""
    def setUp(self):
        """
        Set up a basic weights cube with 2 thresholds to multiple with
        a cube with one_dimensional weights.
        """
        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(
            [[[[1, 0, 1], [1, 0, 1]], [[1, 0, 1], [1, 0, 1]]],
             [[[0, 0, 1], [0, 0, 1]], [[0, 0, 1], [0, 0, 1]]],
             [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]]],
            dtype=np.float32)
        # 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.spatial_weights_cube[:, 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()

    def test_basic(self):
        """Test a basic cube multiplication with a 4D input cube"""
        expected_result = 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)
        result = self.plugin.multiply_weights(
            self.spatial_weights_cube, self.one_dimensional_weights_cube,
            "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata, self.spatial_weights_cube.metadata)

    def test_3D_cube(self):
        """Test when we only have a 3D cube as input."""
        expected_result = np.array(
            [[[0.2, 0, 0.2], [0.2, 0, 0.2]], [[0, 0, 0.5], [0, 0, 0.5]],
             [[0.3, 0.3, 0.3], [0.3, 0.3, 0.3]]],
            dtype=np.float32)
        result = self.plugin.multiply_weights(
            self.spatial_weights_cube[:, 0, :, :],
            self.one_dimensional_weights_cube, "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata,
                         self.spatial_weights_cube[:, 0, :, :].metadata)

    def test_2D_cube(self):
        """Test when we only have a 2D cube as input.
        This probably won't happen in reality, but check it does something
        sensible anyway."""
        expected_result = np.array([[0.2, 0, 0.2], [0.2, 0, 0.2]],
                                   dtype=np.float32)
        result = self.plugin.multiply_weights(
            self.spatial_weights_cube[0, 0, :, :],
            self.one_dimensional_weights_cube[0], "forecast_reference_time")
        self.assertArrayAlmostEqual(result.data, expected_result)
        self.assertEqual(result.metadata,
                         self.spatial_weights_cube[0, 0, :, :].metadata)

    def test_mismatching_cubes(self):
        """Test the input cubes don't match along the blend_coord dim"""
        message = ("The blend_coord forecast_reference_time does not "
                   "match on weights_from_mask and "
                   "one_dimensional_weights_cube")
        with self.assertRaisesRegex(ValueError, message):
            self.plugin.multiply_weights(self.spatial_weights_cube,
                                         self.one_dimensional_weights_cube[0],
                                         "forecast_reference_time")

    def test_wrong_coord(self):
        """Test when we try to multiply over a coordinate not in the weights
        cubes."""
        message = (
            "Expected to find exactly 1 model coordinate, but found none.")
        with self.assertRaisesRegex(CoordinateNotFoundError, message):
            self.plugin.multiply_weights(self.spatial_weights_cube,
                                         self.one_dimensional_weights_cube,
                                         "model")
Exemplo n.º 28
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)
Exemplo n.º 29
0
class Test_create_initial_weights_from_mask(IrisTest):
    """Test the create_initial_weights_from_mask method """
    def setUp(self):
        """Set up an example cube to test with"""
        thresholds = [10]
        data = np.ones((1, 2, 3), dtype=np.float32)
        cycle1 = set_up_probability_cube(data,
                                         thresholds,
                                         time=datetime(2017, 11, 10, 4, 0),
                                         frt=datetime(2017, 11, 10, 0, 0))
        cycle2 = set_up_probability_cube(data,
                                         thresholds,
                                         time=datetime(2017, 11, 10, 4, 0),
                                         frt=datetime(2017, 11, 10, 1, 0))
        cycle3 = set_up_probability_cube(data,
                                         thresholds,
                                         time=datetime(2017, 11, 10, 4, 0),
                                         frt=datetime(2017, 11, 10, 2, 0))
        self.cube = CubeList([cycle1, cycle2, cycle3]).merge_cube()
        self.cube = squeeze(self.cube)
        self.plugin = SpatiallyVaryingWeightsFromMask()

    @ManageWarnings(record=True)
    def test_no_mask(self, warning_list=None):
        """Test what happens when no mask is on the input cube"""
        expected_data = np.ones((3, 2, 3), dtype=np.float32)
        message = ("Input cube to SpatiallyVaryingWeightsFromMask "
                   "must be masked")
        result = self.plugin.create_initial_weights_from_mask(self.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)

    def test_basic(self):
        """Test the weights coming out of a simple masked cube."""
        input_data = np.array(
            [[[10, 5, 10], [10, 5, 10]], [[5, 5, 10], [5, 5, 10]],
             [[10, 10, 10], [10, 10, 10]]],
            dtype=np.float32)
        mask = np.array([[[False, True, False], [False, True, False]],
                         [[True, True, False], [True, True, False]],
                         [[False, False, False], [False, False, False]]])
        input_data = np.ma.MaskedArray(input_data, mask=mask)
        self.cube.data = input_data
        expected = np.array([[[1, 0, 1], [1, 0, 1]], [[0, 0, 1], [0, 0, 1]],
                             [[1, 1, 1], [1, 1, 1]]],
                            dtype=np.float32)
        result = self.plugin.create_initial_weights_from_mask(self.cube)
        self.assertArrayEqual(result.data, expected)
        self.assertEqual(result.dtype, np.float32)
        self.assertEqual(result.name(), "weights")

    @ManageWarnings(record=True)
    def test_none_masked(self, warning_list=None):
        """Test what happens if we try to create a masked array for input, but
        where all the values should be unmasked."""
        input_data = np.array(
            [[[10, 5, 10], [10, 5, 10]], [[5, 5, 10], [5, 5, 10]],
             [[10, 10, 10], [10, 10, 10]]],
            dtype=np.float32)
        expected_data = np.ones((3, 2, 3), dtype=np.float32)
        # This actually produces an array which numpy classes as NOT a masked
        # array.
        input_data = np.ma.masked_equal(input_data, 0)
        self.cube.data = input_data
        message = ("Input cube to SpatiallyVaryingWeightsFromMask "
                   "must be masked")
        result = self.plugin.create_initial_weights_from_mask(self.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)

    def test_all_masked(self):
        """Test the weights coming out of a simple masked cube."""
        input_data = np.array(
            [[[10, 10, 10], [10, 10, 10]], [[10, 10, 10], [10, 10, 10]],
             [[10, 10, 10], [10, 10, 10]]],
            dtype=np.float32)
        input_data = np.ma.masked_equal(input_data, 10)
        self.cube.data = input_data
        expected = np.array([[[0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0]],
                             [[0, 0, 0], [0, 0, 0]]],
                            dtype=np.float32)
        result = self.plugin.create_initial_weights_from_mask(self.cube)
        self.assertArrayEqual(result.data, expected)
        self.assertEqual(result.dtype, np.float32)
        self.assertEqual(result.name(), "weights")