Example #1
0
 def test_unevenly_spaced_coord(self):
     """Test the case where the input coordinate is not equally spaced.
        This represents the case where the data changes to 3 hourly. In this
        case the weights are assigned according to the value in the
        coordinate."""
     width = 5
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(10)
     coord_vals = np.append(coord_vals, [12, 15, 18, 21, 24])
     midpoint = 8
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     expected_weights = np.array([
         0.0,
         0.0,
         0.0,
         0.0,
         0.05,
         0.1,
         0.15,
         0.2,
         0.25,
         0.2,
         0.05,
         0.0,
         0.0,
         0.0,
         0.0,
     ])
     self.assertArrayAlmostEqual(weights, expected_weights)
    def __init__(self, coord, central_point, parameter_units, width):
        """Set up for a Weighted Blending plugin

        Args:
            coord (str):
                The name of a coordinate dimension in the cube that we
                will blend over.
            central_point (float or int):
                Central point at which the output from the triangular weighted
                blending will be calculated.
            parameter_units (str):
                The units of the width of the triangular weighting function
                and the units of the central_point.
                This does not need to be the same as the units of the
                coordinate we are blending over, but it should be possible to
                convert between them.
            width (float):
                The width of the triangular weighting function we will use
                to blend.
        """
        self.coord = coord
        self.central_point = central_point
        self.parameter_units = parameter_units
        self.width = width

        # Set up a plugin to calculate the triangular weights.
        self.WeightsPlugin = ChooseDefaultWeightsTriangular(
            width, units=parameter_units
        )

        # Set up the blending function, based on whether weighted blending or
        # maximum probabilities are needed.
        self.BlendingPlugin = WeightedBlendAcrossWholeDimension(
            coord, timeblending=True
        )
Example #3
0
 def test_basic_weights(self):
     """Test that the function returns the correct triangular weights in a
        simple case"""
     width = 3
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(15)
     midpoint = 5
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     expected_weights = np.array([
         0.0,
         0.0,
         0.0,
         0.11111111,
         0.22222222,
         0.33333333,
         0.22222222,
         0.11111111,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
     ])
     self.assertArrayAlmostEqual(weights, expected_weights)
Example #4
0
 def test_non_integer_midpoint(self):
     """Test the case where the midpoint of the triangle is not a point in
        the input coordinate.
        In this case we do not sample the peak of the triangle."""
     width = 2
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(15)
     midpoint = 3.5
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     expected_weights = np.array([
         0.0,
         0.0,
         0.125,
         0.375,
         0.375,
         0.125,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
     ])
     self.assertArrayAlmostEqual(weights, expected_weights)
Example #5
0
 def test_non_integer_width(self):
     """Test when the width of the triangle does not fall on a grid point.
        This only affects the slope of the triangle slightly."""
     width = 3.5
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(15)
     midpoint = 5
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     expected_weights = np.array([
         0.0,
         0.0,
         0.04,
         0.12,
         0.2,
         0.28,
         0.2,
         0.12,
         0.04,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
     ])
     self.assertArrayAlmostEqual(weights, expected_weights)
Example #6
0
 def test_large_width(self):
     """Test the case where the width of the triangle is larger than the
        coordinate input.
        In this case all the weights are non-zero but still form the
        shape of a triangle."""
     width = 10
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(15)
     midpoint = 5
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     expected_weights = np.array([
         0.055556,
         0.066667,
         0.077778,
         0.088889,
         0.1,
         0.111111,
         0.1,
         0.088889,
         0.077778,
         0.066667,
         0.055556,
         0.044444,
         0.033333,
         0.022222,
         0.011111,
     ])
     self.assertArrayAlmostEqual(weights, expected_weights)
Example #7
0
 def test_midpoint_at_edge(self):
     """Test that the correct triangular weights are returned for a case
        where the midpoint is close to the end of the input coordinate.
        In this case the triangle is cut off at the end of the coordinate"""
     width = 3
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(15)
     midpoint = 1
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     expected_weights = np.array([
         0.25,
         0.375,
         0.25,
         0.125,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
         0.0,
     ])
     self.assertArrayAlmostEqual(weights, expected_weights)
Example #8
0
 def test_basic_no_units(self):
     """Test the repr function formats the arguments correctly"""
     width = 3.0
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     result = str(triangular_weights_instance)
     expected = ("<ChooseDefaultTriangularWeights "
                 "width=3.0, parameters_units=no_unit>")
     self.assertEqual(result, expected)
Example #9
0
 def test_cf_unit_input(self):
     """Test the case where an instance of cf_units.Unit is passed in"""
     units = Unit("hour")
     width = 5
     weights_instance = ChooseDefaultWeightsTriangular(width, units=units)
     expected_width = 5
     expected_unit = units
     self.assertEqual(weights_instance.width, expected_width)
     self.assertEqual(weights_instance.parameters_units, expected_unit)
Example #10
0
 def test_same_units(self):
     """Test plugin produces the correct weights when the parameters for
        the triangle are in the same units as the input cube's coordinate"""
     width = 2
     WeightsClass = ChooseDefaultWeightsTriangular(width, units=self.units)
     midpoint = 1
     weights = WeightsClass.process(self.cube, self.coord_name, midpoint)
     expected_weights = np.array([0.33333333, 0.66666667])
     self.assertArrayAlmostEqual(weights, expected_weights)
Example #11
0
 def test_basic(self):
     """Test the repr function formats the arguments correctly"""
     width = 3
     TriangularWeightsClass = ChooseDefaultWeightsTriangular(width,
                                                             units='hours')
     result = str(TriangularWeightsClass)
     expected = ("<ChooseDefaultTriangularWeights width= 3.0,"
                 " parameters_units=hours>")
     self.assertEqual(result, expected)
Example #12
0
 def test_string_input(self):
     """Test the case where a string is passed and gets converted to a
        Unit instance"""
     units = "hour"
     width = 5
     weights_instance = ChooseDefaultWeightsTriangular(width, units=units)
     expected_width = 5
     expected_unit = Unit("hour")
     self.assertEqual(weights_instance.width, expected_width)
     self.assertEqual(weights_instance.parameters_units, expected_unit)
Example #13
0
 def test_unconvertable_units(self):
     """"Test plugin produces the correct weights when the parameters for
         the triangle cannot be converted to the same units as the
         coordinate"""
     width = 7200
     weights_instance = ChooseDefaultWeightsTriangular(width, units="m")
     midpoint = 3600
     message = r"Unable to convert from 'Unit\('m'\)' to 'Unit\('hours'\)'"
     with self.assertRaisesRegex(ValueError, message):
         weights_instance.process(self.cube, self.coord_name, midpoint)
Example #14
0
 def test_different_units(self):
     """"Test plugin produces the correct weights when the parameters for
         the triangle (width and midpoint are in different units to the
         input cube's coordinate"""
     width = 2
     weights_instance = ChooseDefaultWeightsTriangular(width, units="hours")
     midpoint = 1
     weights = weights_instance.process(self.cube, self.coord_name,
                                        midpoint)
     expected_weights = np.array([0.33333333, 0.66666667])
     self.assertArrayAlmostEqual(weights.data, expected_weights)
Example #15
0
 def test_basic(self):
     """Test that the function returns a numpy array.
        Also check that the length of the weights is correct and they add
        up to 1.0"""
     width = 3
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(15)
     midpoint = 5
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     self.assertIsInstance(weights, np.ndarray)
     self.assertEqual(len(weights), len(coord_vals))
     self.assertEqual(weights.sum(), 1.0)
Example #16
0
 def test_basic(self):
     """Test that the function returns a numpy array.
        Also check that the length of the weights is correct and they add
        up to 1.0"""
     width = 3
     triangular_weights_instance = ChooseDefaultWeightsTriangular(width)
     coord_vals = np.arange(15)
     midpoint = 5
     weights = triangular_weights_instance.triangular_weights(
         coord_vals, midpoint, width)
     self.assertIsInstance(weights, np.ndarray)
     self.assertEqual(len(weights), len(coord_vals))
     # Using float32s for weights can give 1.0000001 here - good enough.
     self.assertAlmostEqual(weights.sum(), 1.0, places=6)
    def __init__(self, coord, central_point, parameter_units, width,
                 weighting_mode):
        """Set up for a Weighted Blending plugin

        Args:
            coord (string):
                The name of a coordinate dimension in the cube that we
                will blend over.
            central_point (float or int):
                Central point at which the output from the triangular weighted
                blending will be calculated.
            parameter_units (string):
                The units of the width of the triangular weighting function
                and the units of the central_point.
                This does not need to be the same as the units of the
                coordinate we are blending over, but it should be possible to
                convert between them.
            width (float):
                The width of the triangular weighting function we will use
                to blend.
            weighting_mode (string):
                The mode of blending, either weighted_mean or
                weighted_maximum. Weighted average finds the weighted mean
                across the dimension of interest. Maximum probability
                multiplies the values across the dimension of interest by the
                given weights and returns the maximum value.

        Raises:
            ValueError : If an invalid weighting_mode is given
        """
        self.coord = coord
        self.central_point = central_point
        self.parameter_units = parameter_units
        self.width = width
        if weighting_mode not in ['weighted_maximum', 'weighted_mean']:
            msg = ("weighting_mode: {} is not recognised, must be either "
                   "weighted_maximum or weighted_mean").format(weighting_mode)
            raise ValueError(msg)
        self.mode = weighting_mode

        # Set up a plugin to calculate the triangular weights.
        self.WeightsPlugin = ChooseDefaultWeightsTriangular(
            width, units=parameter_units)

        # Set up the blending function, based on whether weighted blending or
        # maximum probabilities are needed.
        self.BlendingPlugin = (WeightedBlendAcrossWholeDimension(
            coord, weighting_mode, timeblending=True))
    def process(self, cube):
        """
        Apply the weighted blend for each point in the given coordinate.

        Args:
            cube : iris.cube.Cube
                Cube to blend.

        Returns:
            cube: iris.cube.Cube
                The processed cube, with the same coordinates as the input
                cube. The points in one coordinate will be blended with the
                adjacent points based on a triangular weighting function of the
                specified width.

        """
        # We need to correct all the coordinates associated with the dimension
        # we are collapsing over, so find the relevant coordinates now.
        dimension_to_collapse = cube.coord_dims(self.coord)
        coords_to_correct = cube.coords(dimensions=dimension_to_collapse)
        coords_to_correct = [coord.name() for coord in coords_to_correct]
        # We will also need to correct the bounds on these coordinates,
        # as bounds will be added when the blending happens, so add bounds if
        # it doesn't have some already.
        for coord in coords_to_correct:
            if not cube.coord(coord).has_bounds():
                cube.coord(coord).guess_bounds()
        # Set up a plugin to calculate the triangular weights.
        WeightsPlugin = ChooseDefaultWeightsTriangular(
            self.width, units=self.parameter_units)
        # Set up the blending function, based on whether weighted blending or
        # maximum probabilities are needed.
        BlendingPlugin = WeightedBlendAcrossWholeDimension(self.coord,
                                                           self.mode)
        result = iris.cube.CubeList([])
        # Loop over each point in the coordinate we are blending over, and
        # calculate a new weighted average for it.
        for cube_slice in cube.slices_over(self.coord):
            point = cube_slice.coord(self.coord).points[0]
            weights = WeightsPlugin.process(cube, self.coord, point)
            blended_cube = BlendingPlugin.process(cube, weights)
            self.correct_collapsed_coordinates(cube_slice, blended_cube,
                                               coords_to_correct)
            result.append(blended_cube)
        result = concatenate_cubes(result)
        return result
    def __init__(
        self,
        coord: str,
        central_point: Union[int, float],
        parameter_units: str,
        width: float,
    ) -> None:
        """Set up for a Weighted Blending plugin

        Args:
            coord:
                The name of a coordinate dimension in the cube to be blended
                over.
            central_point:
                Central point at which the output from the triangular weighted
                blending will be calculated. This should be in the units of the
                units argument that is passed in. This value should be a point
                on the coordinate for blending over.
            parameter_units:
                The units of the width of the triangular weighting function
                and the units of the central_point.
                This does not need to be the same as the units of the
                coordinate being blending over, but it should be possible to
                convert between them.
            width:
                The width from the triangle’s centre point, in units of the units
                argument, which will determine the triangular weighting function
                used to blend that specified point with its adjacent points. Beyond
                this width the weighting drops to zero.
        """
        self.coord = coord
        self.central_point = central_point
        self.parameter_units = parameter_units
        self.width = width

        # Set up a plugin to calculate the triangular weights.
        self.WeightsPlugin = ChooseDefaultWeightsTriangular(
            width, units=parameter_units
        )

        # Set up the blending function, based on whether weighted blending or
        # maximum probabilities are needed.
        self.BlendingPlugin = WeightedBlendAcrossWholeDimension(
            coord, timeblending=True
        )