Ejemplo n.º 1
0
def process(*cubes: cli.inputcube,
            wxtree="high_resolution",
            model_id_attr: str = None):
    """ Processes cube for Weather symbols.

    Args:
        cubes (iris.cube.CubeList):
            A cubelist containing the diagnostics required for the
            weather symbols decision tree, these at co-incident times.
        wxtree (str):
            Weather Code tree: high_resolution or global.
        model_id_attr (str):
            Name of attribute recording source models that should be
            inherited by the output cube. The source models are expected as
            a space-separated string.

    Returns:
        iris.cube.Cube:
            A cube of weather symbols.
    """
    from iris.cube import CubeList

    from improver.wxcode.weather_symbols import WeatherSymbols

    if not cubes:
        raise RuntimeError("Not enough input arguments. "
                           "See help for more information.")

    return WeatherSymbols(wxtree=wxtree,
                          model_id_attr=model_id_attr)(CubeList(cubes))
Ejemplo n.º 2
0
 def test_day_night(self):
     """Test process returns the right values for night. """
     plugin = WeatherSymbols()
     for i, cube in enumerate(self.cubes):
         self.cubes[i].coord("time").points = cube.coord("time").points + 3600 * 12
     result = plugin.process(self.cubes)
     self.assertArrayEqual(result.data, self.expected_wxcode_night)
Ejemplo n.º 3
0
    def test_sleet(self):
        """Test process returns the sleet weather code."""
        plugin = WeatherSymbols()
        data_snow = np.zeros_like(self.cubes[0].data)
        data_sleet = np.ones_like(self.cubes[0].data)
        data_rain = np.zeros_like(self.cubes[0].data)
        # pylint: disable=no-member
        data_precip = np.maximum.reduce([data_snow, data_sleet, data_rain])
        data_precipv = np.ones_like(self.cubes[0].data)
        data_cloud = np.ones_like(self.cubes[4].data)
        data_cld_low = np.ones_like(self.cubes[5].data)
        data_vis = np.zeros_like(self.cubes[6].data)
        data_lightning = np.zeros_like(self.cubes[7].data)
        expected = np.ones_like(self.expected_wxcode_alternate) * 18

        cubes = self.cubes
        cubes[0].data = data_snow
        cubes[1].data = data_sleet
        cubes[2].data = data_rain
        cubes[3].data = data_precipv
        cubes[4].data = data_cloud
        cubes[5].data = data_cld_low
        cubes[6].data = data_vis
        cubes[7].data = data_lightning
        cubes[8].data = data_precip
        result = plugin.process(cubes)
        self.assertArrayEqual(result.data, expected)
Ejemplo n.º 4
0
 def test_basic(self):
     """Test cube is constructed with appropriate metadata"""
     result = WeatherSymbols().create_symbol_cube([self.cube])
     self.assertIsInstance(result, iris.cube.Cube)
     self.assertArrayEqual(result.attributes["weather_code"], self.wxcode)
     self.assertEqual(result.attributes["weather_code_meaning"], self.wxmeaning)
     self.assertTrue((result.data == -1).all())
Ejemplo n.º 5
0
 def test_raises_error_missing_cubes(self):
     """Test check_input_cubes method raises error if data is missing"""
     plugin = WeatherSymbols()
     cubes = self.cubes.pop()
     msg = 'Weather Symbols input cubes are missing'
     with self.assertRaisesRegex(IOError, msg):
         plugin.check_input_cubes(cubes)
Ejemplo n.º 6
0
 def test_works_with_lists(self):
     """Test that the construct_condition method works with a list
     of Constraints. """
     plugin = WeatherSymbols()
     constraint_list = [
         iris.Constraint(
             name='probability_of_lwe_snowfall_rate_above_threshold',
             coord_values={'threshold': 0.03}),
         iris.Constraint(
             name='probability_of_rainfall_rate_above_threshold',
             coord_values={'threshold': 0.03})
     ]
     condition = '<'
     prob_threshold = 0.5
     gamma = 0.7
     expected = ("(cubes.extract(Constraint(name="
                 "'probability_of_lwe_snowfall_rate_above_threshold', "
                 "coord_values={'threshold': 0.03}))[0].data - "
                 "cubes.extract(Constraint(name="
                 "'probability_of_rainfall_rate_above_threshold', "
                 "coord_values={'threshold': 0.03}))[0].data * 0.7) < 0.5")
     result = plugin.construct_condition(constraint_list, condition,
                                         prob_threshold, gamma)
     self.assertIsInstance(result, str)
     self.assertEqual(result, expected)
Ejemplo n.º 7
0
 def test_raises_error_missing_cubes_global(self):
     """Test check_input_cubes method raises error if data is missing"""
     plugin = WeatherSymbols(wxtree='global')
     cubes = set_up_wxcubes_global()[0:3]
     msg = 'Weather Symbols input cubes are missing'
     with self.assertRaisesRegex(IOError, msg):
         plugin.check_input_cubes(cubes)
Ejemplo n.º 8
0
 def test_raises_error_missing_cubes_global(self):
     """Test check_input_cubes method raises error if data is missing"""
     plugin = WeatherSymbols(wxtree="global")
     cubes = self.cubes.extract(self.gbl)[0:3]
     msg = "Weather Symbols input cubes are missing"
     with self.assertRaisesRegex(IOError, msg):
         plugin.check_input_cubes(cubes)
Ejemplo n.º 9
0
 def test_old_naming_convention(self):
     """Test construct_extract_constraint can return a constraint with a
     "threshold" coordinate"""
     plugin = WeatherSymbols()
     diagnostic = 'probability_of_rainfall_rate_above_threshold'
     threshold = AuxCoord(0.03, units='mm hr-1')
     result = plugin.construct_extract_constraint(diagnostic, threshold,
                                                  True)
     expected = ("iris.Constraint("
                 "name='probability_of_rainfall_rate_above_threshold', "
                 "threshold=lambda cell: 0.03 * {t_min} < cell < 0.03 * "
                 "{t_max})".format(
                     t_min=(1. - WeatherSymbols().float_tolerance),
                     t_max=(1. + WeatherSymbols().float_tolerance)))
     self.assertIsInstance(result, str)
     self.assertEqual(result, expected)
Ejemplo n.º 10
0
    def test_weather_data_global(self):
        """Test process returns the right weather values global part2 """
        plugin = WeatherSymbols(wxtree='global')

        data_snow = np.array([
            0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.1, 0.0, 0.0, 1.0, 1.0,
            1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
            1.0
        ]).reshape(3, 1, 3, 3)
        data_rain = np.array([
            1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
            0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
            0.0
        ]).reshape(3, 1, 3, 3)
        data_cloud = np.array([
            0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
            0.0, 1.0, 0.0, 1.0, 1.0
        ]).reshape(2, 1, 3, 3)
        data_cld_low = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                                 0.0]).reshape(1, 1, 3, 3)
        data_vis = np.array([
            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.0, 0.0, 0.0
        ]).reshape(2, 1, 3, 3)
        cubes = set_up_wxcubes_global()
        cubes[0].data = data_snow
        cubes[1].data = data_rain
        cubes[2].data = data_cloud
        cubes[3].data = data_cld_low
        cubes[4].data = data_vis
        result = plugin.process(cubes)
        expected_wxcode = np.array([14, 15, 17, 18, 23, 24, 26, 27,
                                    27]).reshape(1, 3, 3)
        self.assertArrayEqual(result.data, expected_wxcode)
Ejemplo n.º 11
0
 def test_basic(self):
     """Test find_all_routes returns a list of expected nodes."""
     plugin = WeatherSymbols()
     result = plugin.find_all_routes(self.test_graph, 'start_node', 3)
     expected_nodes = [['start_node', 'fail_0', 3]]
     self.assertIsInstance(result, list)
     self.assertListEqual(result, expected_nodes)
Ejemplo n.º 12
0
 def test_basic_global(self):
     """Test process returns a wxcode cube with right values for global. """
     plugin = WeatherSymbols(wxtree="global")
     cubes = self.cubes.extract(self.gbl)
     result = plugin.process(cubes)
     self.assertArrayAndMaskEqual(result.data,
                                  self.expected_wxcode_no_lightning)
Ejemplo n.º 13
0
 def test_no_lightning(self):
     """Test process returns right values if no lightning. """
     plugin = WeatherSymbols()
     cubes = self.cubes.extract(self.uk_no_lightning)
     result = plugin.process(cubes)
     self.assertArrayAndMaskEqual(result.data,
                                  self.expected_wxcode_no_lightning)
Ejemplo n.º 14
0
 def test_basic(self):
     """Test construct_extract_constraint returns a iris.Constraint."""
     plugin = WeatherSymbols()
     diagnostic = "probability_of_rainfall_rate_above_threshold"
     threshold = AuxCoord(0.03, units="mm hr-1")
     result = plugin.construct_extract_constraint(diagnostic, threshold,
                                                  False)
     expected = ("iris.Constraint("
                 "name='probability_of_rainfall_rate_above_threshold', "
                 "rainfall_rate=lambda cell: 0.03 * {t_min} < cell < "
                 "0.03 * {t_max})".format(
                     t_min=(1.0 - WeatherSymbols().float_tolerance),
                     t_max=(1.0 + WeatherSymbols().float_tolerance),
                 ))
     self.assertIsInstance(result, str)
     self.assertEqual(result, expected)
 def test_basic(self):
     """Test create_condition_chain returns a list of strings."""
     plugin = WeatherSymbols()
     test_condition = self.dummy_queries['significant_precipitation']
     result = plugin.create_condition_chain(test_condition)
     expected = ("(cubes.extract(iris.Constraint(name='probability_of_"
                 "rainfall_rate', threshold=lambda cell: 0.03 * {t_min} < "
                 "cell < 0.03 * {t_max}))[0].data >= 0.5) | (cubes.extract"
                 "(iris.Constraint(name='probability_of_lwe_snowfall_rate',"
                 " threshold=lambda cell: 0.03 * {t_min} < cell < 0.03 * "
                 "{t_max}))[0].data >= 0.5)".format(
                     t_min=(1. - WeatherSymbols().float_tolerance),
                     t_max=(1. + WeatherSymbols().float_tolerance)))
     self.assertIsInstance(result, list)
     self.assertIsInstance(result[0], str)
     self.assertEqual(result[0], expected)
Ejemplo n.º 16
0
    def test_weather_data_global(self):
        """Test process returns the right weather values global part2 """
        plugin = WeatherSymbols(wxtree='global')

        data_snow = np.array([
            0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.1, 0.0, 0.0, 1.0, 1.0,
            1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
            1.0
        ]).reshape((3, 3, 3))
        data_rain = np.array([
            1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
            0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
            0.0
        ]).reshape((3, 3, 3))
        data_cloud = np.array([
            0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
            0.0, 1.0, 0.0, 1.0, 1.0
        ]).reshape((2, 3, 3))
        data_cld_low = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
                                 0.0]).reshape((1, 3, 3))
        data_vis = np.array([
            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.0, 0.0, 0.0
        ]).reshape((2, 3, 3))
        cubes = self.cubes.extract(self.gbl)
        cubes[0].data = data_snow
        cubes[1].data = data_rain
        cubes[2].data = data_cloud
        cubes[3].data = data_cld_low
        cubes[4].data = data_vis
        result = plugin.process(cubes)
        self.assertArrayEqual(result.data, self.expected_wxcode_alternate)
Ejemplo n.º 17
0
def process(
    *cubes: cli.inputcube,
    wxtree: cli.inputjson = None,
    model_id_attr: str = None,
    record_run_attr: str = None,
    target_period: int = None,
    check_tree: bool = False,
):
    """ Processes cube for Weather symbols.

    Args:
        cubes (iris.cube.CubeList):
            A cubelist containing the diagnostics required for the
            weather symbols decision tree, these at co-incident times.
        wxtree (dict):
            A JSON file containing a weather symbols decision tree definition.
        model_id_attr (str):
            Name of attribute recording source models that should be
            inherited by the output cube. The source models are expected as
            a space-separated string.
        record_run_attr:
            Name of attribute used to record models and cycles used in
            constructing the weather symbols.
        target_period:
            The period in seconds that the weather symbol being produced should
            represent. This should correspond with any period diagnostics, e.g.
            precipitation accumulation, being used as input. This is used to scale
            any threshold values that are defined with an associated period in
            the decision tree. It will only be used if the decision tree
            provided has threshold values defined with an associated period.
        check_tree (bool):
            If set, the decision tree will be checked to see if it conforms to
            the expected format and that all nodes can be reached; the only other
            argument required is the path to the decision tree. If the tree is found
            to be valid the required inputs will be listed. Setting this flag will
            prevent the CLI performing any other actions.

    Returns:
        iris.cube.Cube:
            A cube of weather symbols.
    """
    if check_tree:
        from improver.wxcode.utilities import check_tree

        return check_tree(wxtree, target_period=target_period)

    from iris.cube import CubeList

    from improver.wxcode.weather_symbols import WeatherSymbols

    if not cubes:
        raise RuntimeError("Not enough input arguments. See help for more information.")

    return WeatherSymbols(
        wxtree,
        model_id_attr=model_id_attr,
        record_run_attr=record_run_attr,
        target_period=target_period,
    )(CubeList(cubes))
Ejemplo n.º 18
0
 def test_multiple_routes(self):
     """Test finds multiple routes."""
     plugin = WeatherSymbols()
     result = plugin.find_all_routes(self.test_graph, 'start_node', 1)
     expected_nodes = [['start_node', 'success_1', 'success_1_1', 1],
                       ['start_node', 'fail_0', 'success_0_1', 1]]
     self.assertIsInstance(result, list)
     self.assertListEqual(result, expected_nodes)
Ejemplo n.º 19
0
 def test_no_lightning(self):
     """Test check_input_cubes raises no error if lightning missing"""
     plugin = WeatherSymbols()
     cubes = self.cubes.extract(self.uk_no_lightning)
     result = plugin.check_input_cubes(cubes)
     self.assertIsInstance(result, dict)
     self.assertEqual(len(result), 1)
     self.assertTrue("lightning" in result)
Ejemplo n.º 20
0
 def test_basic(self):
     """Test that the format_condition_chain method returns a string."""
     plugin = WeatherSymbols()
     conditions = ['condition1', 'condition2']
     expected = '(condition1) & (condition2)'
     result = plugin.format_condition_chain(conditions)
     self.assertIsInstance(result, str)
     self.assertEqual(result, expected)
Ejemplo n.º 21
0
 def test_raises_error_missing_threshold(self):
     """Test check_input_cubes method raises error if data is missing"""
     plugin = WeatherSymbols()
     cubes = self.cubes
     cubes[0] = cubes[0][0]
     msg = "Weather Symbols input cubes are missing"
     with self.assertRaisesRegex(IOError, msg):
         plugin.check_input_cubes(cubes)
Ejemplo n.º 22
0
 def test_works_with_or(self):
     """Test that the format_condition_chain method works with OR."""
     plugin = WeatherSymbols()
     conditions = ["condition1", "condition2"]
     expected = "(condition1) | (condition2)"
     result = plugin.format_condition_chain(conditions, condition_combination="OR")
     self.assertIsInstance(result, str)
     self.assertEqual(result, expected)
    def test_incorrect_units(self):
        """Test that check_input_cubes method raises an error if the units are
        incompatible between the input cube and the decision tree."""
        plugin = WeatherSymbols()

        msg = "Unable to convert from"
        self.cubes[0].coord('threshold').units = Unit('mm kg-1')
        with self.assertRaisesRegexp(ValueError, msg):
            plugin.check_input_cubes(self.cubes)
Ejemplo n.º 24
0
 def test_basic(self):
     """Test that the invert_condition method returns a tuple of strings."""
     plugin = WeatherSymbols()
     tree = plugin.queries
     result = plugin.invert_condition(tree[list(tree.keys())[0]])
     self.assertIsInstance(result, tuple)
     self.assertEqual(len(result), 2)
     self.assertIsInstance(result[0], str)
     self.assertIsInstance(result[1], str)
Ejemplo n.º 25
0
 def test_day_night(self):
     """Test process returns the right values for night. """
     plugin = WeatherSymbols()
     for i, cube in enumerate(self.cubes):
         self.cubes[i].coord('time').points = (cube.coord('time').points +
                                               11.5)
     result = plugin.process(self.cubes)
     expected_wxcode = np.array([0, 2, 5, 6, 7, 8, 9, 11,
                                 12]).reshape(1, 3, 3)
     self.assertArrayEqual(result.data, expected_wxcode)
Ejemplo n.º 26
0
    def test_basic(self):
        """Test construct_extract_constraint method returns a iris.Constraint.
            or list of iris.Constraint"""
        plugin = WeatherSymbols()

        result = plugin.create_symbol_cube(self.cube[0])
        self.assertIsInstance(result, iris.cube.Cube)
        self.assertArrayEqual(result.attributes['weather_code'], self.wxcode)
        self.assertEqual(result.attributes['weather_code_meaning'],
                         self.wxmeaning)
Ejemplo n.º 27
0
 def test_invert_combination_correctly(self):
     """Test invert_condition inverts combination correctly."""
     plugin = WeatherSymbols()
     node = {'threshold_condition': '>=', 'condition_combination': ''}
     possible_inputs = ['AND', 'OR', '']
     inverse_outputs = ['OR', 'AND', '']
     for i, val in enumerate(possible_inputs):
         node['condition_combination'] = val
         result = plugin.invert_condition(node)
         self.assertEqual(result[1], inverse_outputs[i])
Ejemplo n.º 28
0
 def test_omit_nodes_blocked(self):
     """Test find_all_routes where omitted node is no longer accessible."""
     omit_nodes = {"fail_0": 3}
     plugin = WeatherSymbols()
     result = plugin.find_all_routes(
         self.test_graph, "start_node", 5, omit_nodes=omit_nodes,
     )
     expected_nodes = []
     self.assertIsInstance(result, list)
     self.assertListEqual(result, expected_nodes)
Ejemplo n.º 29
0
 def test_omit_nodes_multi(self):
     """Test find_all_routes where multiple omitted nodes."""
     omit_nodes = {"fail_0": 3, "success_1": "success_1_1"}
     plugin = WeatherSymbols()
     result = plugin.find_all_routes(
         self.test_graph, "start_node", 1, omit_nodes=omit_nodes,
     )
     expected_nodes = [["start_node", "success_1_1", 1]]
     self.assertIsInstance(result, list)
     self.assertListEqual(result, expected_nodes)
Ejemplo n.º 30
0
 def test_basic(self):
     """Test process returns a weather code cube with right values and type.
     """
     plugin = WeatherSymbols()
     result = plugin.process(self.cubes)
     self.assertIsInstance(result, iris.cube.Cube)
     self.assertArrayEqual(result.attributes["weather_code"], self.wxcode)
     self.assertEqual(result.attributes["weather_code_meaning"], self.wxmeaning)
     self.assertArrayEqual(result.data, self.expected_wxcode)
     self.assertEqual(result.dtype, np.int32)