示例#1
0
    def test_unmodified_cell_methods(self):
        """Test that plugin leaves cell methods that are diagnostic name
        agnostic unchanged."""

        cell_methods = list(self.cube.cell_methods)
        additional_cell_method_1 = CellMethod("sum", coords="longitude")
        additional_cell_method_2 = CellMethod("sum",
                                              coords="latitude",
                                              comments="Kittens are great")
        cell_methods.extend(
            [additional_cell_method_1, additional_cell_method_2])

        self.cube.cell_methods = cell_methods
        cubelist = iris.cube.CubeList([self.cube, self.multiplier])

        new_cube_name = "new_cube_name"
        expected = [
            CellMethod("sum", coords="time", comments=f"of {new_cube_name}"),
            additional_cell_method_1,
            additional_cell_method_2,
        ]

        result = CubeMultiplier()(cubelist,
                                  new_cube_name,
                                  broadcast_to_threshold=True)
        self.assertArrayEqual(result.cell_methods, expected)
示例#2
0
 def test_multiply_preserves_bounds(self):
     """Test specific case for precipitation type, where multiplying a
     precipitation accumulation by a point-time probability of snow retains
     the bounds on the original accumulation."""
     validity_time = datetime(2015, 11, 19, 0)
     time_bounds = [datetime(2015, 11, 18, 23), datetime(2015, 11, 19, 0)]
     forecast_reference_time = datetime(2015, 11, 18, 22)
     precip_accum = set_up_variable_cube(
         np.full((2, 3, 3), 1.5, dtype=np.float32),
         name="lwe_thickness_of_precipitation_amount",
         units="mm",
         time=validity_time,
         time_bounds=time_bounds,
         frt=forecast_reference_time,
     )
     snow_prob = set_up_variable_cube(
         np.full(precip_accum.shape, 0.2, dtype=np.float32),
         name="probability_of_snow",
         units="1",
         time=validity_time,
         frt=forecast_reference_time,
     )
     result = CubeMultiplier()(
         [precip_accum, snow_prob],
         "lwe_thickness_of_snowfall_amount",
     )
     self.assertArrayAlmostEqual(result.data, np.full((2, 3, 3), 0.3))
     self.assertArrayEqual(result.coord("time"), precip_accum.coord("time"))
示例#3
0
 def test_exception_for_single_entry_cubelist(self):
     """Test that the plugin raises an exception if a cubelist containing
     only one cube is passed in."""
     plugin = CubeMultiplier()
     msg = "Expecting 2 or more cubes in cube_list"
     cubelist = iris.cube.CubeList([self.cube1])
     with self.assertRaisesRegex(ValueError, msg):
         plugin.process(cubelist, "new_cube_name")
示例#4
0
def process(
    *cubes: cli.inputcube,
    operation="+",
    new_name=None,
    use_midpoint=False,
    check_metadata=False,
    broadcast_to_threshold=False,
):
    r"""Combine input cubes.

    Combine the input cubes into a single cube using the requested operation.
    The first cube in the input list provides the template for output metadata.

    Args:
        cubes (iris.cube.CubeList or list of iris.cube.Cube):
            An iris CubeList to be combined.
        operation (str):
            An operation to use in combining input cubes. One of:
            +, -, \*, add, subtract, multiply, min, max, mean
        new_name (str):
            New name for the resulting dataset.
        use_midpoint (bool):
            If False (not set), uses the upper bound as the new coordinate
            point for expanded coordinates (eg time for accumulations / max in
            period).  If True, uses the mid-point.
        check_metadata (bool):
            If True, warn on metadata mismatch between inputs.
        broadcast_to_threshold (bool):
            If True, broadcast input cubes to the threshold coord prior to combining -
            a threshold coord must already exist on the first input cube.

    Returns:
        result (iris.cube.Cube):
            Returns a cube with the combined data.
    """
    from improver.cube_combiner import CubeCombiner, CubeMultiplier
    from iris.cube import CubeList

    if not cubes:
        raise TypeError("A cube is needed to be combined.")
    if new_name is None:
        new_name = cubes[0].name()

    if operation == "*" or operation == "multiply":
        result = CubeMultiplier()(
            CubeList(cubes),
            new_name,
            broadcast_to_threshold=broadcast_to_threshold,
        )

    else:
        result = CubeCombiner(operation)(
            CubeList(cubes),
            new_name,
            use_midpoint=use_midpoint,
        )

    return result
示例#5
0
 def test_error_broadcast_coord_is_auxcoord(self):
     """Test that plugin throws an error if asked to broadcast to a threshold coord
     that already exists on later cubes"""
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cubelist = iris.cube.CubeList([self.cube4.copy(), cube])
     msg = "Cannot broadcast to coord threshold as it already exists as an AuxCoord"
     with self.assertRaisesRegex(TypeError, msg):
         CubeMultiplier()(cubelist, "new_cube_name", broadcast_to_threshold=True)
示例#6
0
 def test_error_broadcast_coord_is_auxcoord(self):
     """Test that plugin throws an error if asked to broadcast to a threshold coord
     that already exists on later cubes"""
     self.multiplier.add_aux_coord(self.threshold_aux)
     cubelist = iris.cube.CubeList([self.cube.copy(), self.multiplier])
     msg = "Cannot broadcast to coord threshold as it already exists as an AuxCoord"
     with self.assertRaisesRegex(TypeError, msg):
         CubeMultiplier(broadcast_to_threshold=True)(cubelist,
                                                     "new_cube_name")
示例#7
0
 def test_error_broadcast_coord_not_found(self):
     """Test that plugin throws an error if asked to broadcast to a threshold coord
     that is not present on the first cube"""
     cubelist = iris.cube.CubeList([self.multiplier, self.cube.copy()])
     msg = (
         r"Cannot find coord threshold in "
         r"<iris 'Cube' of "
         r"probability_of_lwe_thickness_of_precipitation_amount_above_threshold / \(1\) "
         r"\(realization: 3; latitude: 2; longitude: 2\)> to broadcast to")
     with self.assertRaisesRegex(CoordinateNotFoundError, msg):
         CubeMultiplier(broadcast_to_threshold=True)(cubelist,
                                                     "new_cube_name")
示例#8
0
 def test_vicinity_names(self):
     """Test plugin names the cube and threshold coordinate correctly for a
     vicinity diagnostic"""
     input = "lwe_thickness_of_precipitation_amount_in_vicinity"
     output = "thickness_of_rainfall_amount_in_vicinity"
     self.cube.rename(f"probability_of_{input}_above_threshold")
     cubelist = iris.cube.CubeList([self.cube.copy(), self.multiplier])
     result = CubeMultiplier(broadcast_to_threshold=True)(cubelist, output)
     self.assertEqual(result.name(),
                      f"probability_of_{output}_above_threshold")
     self.assertEqual(
         result.coord(var_name="threshold").name(),
         "thickness_of_rainfall_amount")
示例#9
0
    def test_update_cell_methods(self):
        """Test that plugin updates cell methods where required when a new
        diagnostic name is provided."""
        cubelist = iris.cube.CubeList([self.cube, self.multiplier])

        new_cube_name = "new_cube_name"
        expected = CellMethod("sum",
                              coords="time",
                              comments=f"of {new_cube_name}")

        result = CubeMultiplier(broadcast_to_threshold=True)(cubelist,
                                                             new_cube_name)
        self.assertEqual(result.cell_methods[0], expected)
示例#10
0
 def test_error_broadcast_coord_not_found(self):
     """Test that plugin throws an error if asked to broadcast to a threshold coord
     that is not present on the first cube"""
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cube.remove_coord("lwe_thickness_of_precipitation_amount")
     cubelist = iris.cube.CubeList([cube, self.cube4.copy()])
     msg = (
         "Cannot find coord threshold in "
         "<iris 'Cube' of probability_of_lwe_thickness_of_precipitation_amount_above_threshold / \(1\) "
         "\(realization: 3; latitude: 2; longitude: 2\)> to broadcast to"
     )
     with self.assertRaisesRegex(CoordinateNotFoundError, msg):
         CubeMultiplier()(cubelist, "new_cube_name", broadcast_to_threshold=True)
示例#11
0
 def test_vicinity_names(self):
     """Test plugin names the cube and threshold coordinate correctly for a
     vicinity diagnostic"""
     input = "lwe_thickness_of_precipitation_amount_in_vicinity"
     output = "thickness_of_rainfall_amount_in_vicinity"
     self.cube4.rename(f"probability_of_{input}_above_threshold")
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cube.remove_coord("lwe_thickness_of_precipitation_amount")
     cubelist = iris.cube.CubeList([self.cube4.copy(), cube])
     input_copy = deepcopy(cubelist)
     result = CubeMultiplier()(cubelist, output, broadcast_to_threshold=True)
     self.assertEqual(result.name(), f"probability_of_{output}_above_threshold")
     self.assertEqual(
         result.coord(var_name="threshold").name(), "thickness_of_rainfall_amount"
     )
示例#12
0
 def test_broadcast_coord(self):
     """Test that plugin broadcasts to threshold coord without changing inputs.
     Using the broadcast_to_coords argument including a value of "threshold"
     will result in the returned cube maintaining the probabilistic elements
     of the name of the first input cube."""
     cubelist = iris.cube.CubeList([self.cube.copy(), self.multiplier])
     input_copy = deepcopy(cubelist)
     result = CubeMultiplier(broadcast_to_threshold=True)(cubelist,
                                                          "new_cube_name")
     self.assertIsInstance(result, Cube)
     self.assertEqual(result.name(),
                      "probability_of_new_cube_name_above_threshold")
     self.assertEqual(
         result.coord(var_name="threshold").name(), "new_cube_name")
     self.assertArrayAlmostEqual(result.data, self.cube.data)
     self.assertCubeListEqual(input_copy, cubelist)
示例#13
0
 def test_broadcast_coord(self):
     """Test that plugin broadcasts to threshold coord without changing inputs.
     Using the broadcast_to_coords argument including a value of "threshold"
     will result in the returned cube maintaining the probabilistic elements
     of the name of the first input cube."""
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cube.remove_coord("lwe_thickness_of_precipitation_amount")
     cubelist = iris.cube.CubeList([self.cube4.copy(), cube])
     input_copy = deepcopy(cubelist)
     result = CubeMultiplier()(
         cubelist, "new_cube_name", broadcast_to_threshold=True
     )
     self.assertIsInstance(result, Cube)
     self.assertEqual(result.name(), "probability_of_new_cube_name_above_threshold")
     self.assertEqual(result.coord(var_name="threshold").name(), "new_cube_name")
     self.assertArrayAlmostEqual(result.data, self.cube4.data)
     self.assertCubeListEqual(input_copy, cubelist)