Ejemplo n.º 1
0
def check_diagnostic_lists_consistency(query):
    """
    Checks if specific input lists have same nested list
    structure. e.g. ['item'] != [['item']]

    Args:
        query (dict):
            of weather-symbols decision-making information

    Raises:
        ValueError: if diagnostic query lists have different nested list
            structure.

    """
    diagnostic_keys = [
        "diagnostic_fields",
        "diagnostic_conditions",
        "diagnostic_thresholds",
    ]
    values = [
        get_parameter_names(query[key])
        if key == "diagnostic_fields" else query[key]
        for key in diagnostic_keys
    ]
    if not check_nested_list_consistency(values):
        msg = f"Inconsistent list structure: \n"
        for key in diagnostic_keys:
            msg += f"{key} = {query[key]}; \n"
        raise ValueError(msg)
Ejemplo n.º 2
0
def test_probability_len_match(tree_name):
    """Test probability_thresholds list is right shape."""
    tree = TREES[tree_name]
    for _, query in tree.items():
        check_list = query["probability_thresholds"]
        assert all(isinstance(x, (int, float)) for x in check_list)
        assert len(check_list) == len(get_parameter_names(query["diagnostic_fields"]))
Ejemplo n.º 3
0
 def test_basic(self):
     """Test that the get_parameter_names method does what it says."""
     condition = [
         "parameter_name_one", "*", "4.0", "+", "parameter_name_two"
     ]
     expected = ["parameter_name_one", "parameter_name_two"]
     result = get_parameter_names(condition)
     self.assertEqual(result, expected)
Ejemplo n.º 4
0
 def test_nested(self):
     """Test getting parameter names from nested lists."""
     condition = [
         ["parameter_name_one", "*", "4.0", "+", "parameter_name_two"],
         ["parameter_name_three", "parameter_name_four"],
     ]
     expected = [
         ["parameter_name_one", "parameter_name_two"],
         ["parameter_name_three", "parameter_name_four"],
     ]
     result = get_parameter_names(condition)
     self.assertEqual(result, expected)
Ejemplo n.º 5
0
    def check_input_cubes(self, cubes: CubeList) -> Optional[Dict[str, Any]]:
        """
        Check that the input cubes contain all the diagnostics and thresholds
        required by the decision tree.  Sets self.coord_named_threshold to
        "True" if threshold-type coordinates have the name "threshold" (as
        opposed to the standard name of the diagnostic), for backward
        compatibility.

        Args:
            cubes:
                A CubeList containing the input diagnostic cubes.

        Returns:
            A dictionary of (keyword) nodes names where the diagnostic
            data is missing and (values) node associated with
            diagnostic_missing_action.

        Raises:
            IOError:
                Raises an IOError if any of the required input data is missing.
                The error includes details of which fields are missing.
        """
        optional_node_data_missing = {}
        missing_data = []
        for key, query in self.queries.items():
            diagnostics = get_parameter_names(
                expand_nested_lists(query, "diagnostic_fields")
            )
            thresholds = expand_nested_lists(query, "diagnostic_thresholds")
            conditions = expand_nested_lists(query, "diagnostic_conditions")
            for diagnostic, threshold, condition in zip(
                diagnostics, thresholds, conditions
            ):

                # First we check the diagnostic name and units, performing
                # a conversion is required and possible.
                test_condition = iris.Constraint(name=diagnostic)
                matched_cube = cubes.extract(test_condition)
                if not matched_cube:
                    if "diagnostic_missing_action" in query:
                        optional_node_data_missing.update(
                            {key: query[query["diagnostic_missing_action"]]}
                        )
                    else:
                        missing_data.append([diagnostic, threshold, condition])
                    continue

                cube_threshold_units = find_threshold_coordinate(matched_cube[0]).units
                threshold.convert_units(cube_threshold_units)

                # Then we check if the required threshold is present in the
                # cube, and that the thresholding is relative to it correctly.
                threshold = threshold.points.item()
                threshold_name = find_threshold_coordinate(matched_cube[0]).name()

                # Set flag to check for old threshold coordinate names
                if threshold_name == "threshold" and not self.coord_named_threshold:
                    self.coord_named_threshold = True

                # Check threshold == 0.0
                if abs(threshold) < self.float_abs_tolerance:
                    coord_constraint = {
                        threshold_name: lambda cell: np.isclose(
                            cell.point, 0, rtol=0, atol=self.float_abs_tolerance
                        )
                    }
                else:
                    coord_constraint = {
                        threshold_name: lambda cell: np.isclose(
                            cell.point, threshold, rtol=self.float_tolerance, atol=0
                        )
                    }

                # Checks whether the spp__relative_to_threshold attribute is above
                # or below a threshold and and compares to the diagnostic_condition.
                test_condition = iris.Constraint(
                    coord_values=coord_constraint,
                    cube_func=lambda cube: (
                        probability_is_above_or_below(cube) == condition
                    ),
                )
                matched_threshold = matched_cube.extract(test_condition)
                if not matched_threshold:
                    missing_data.append([diagnostic, threshold, condition])

        if missing_data:
            msg = (
                "Weather Symbols input cubes are missing"
                " the following required"
                " input fields:\n"
            )
            dyn_msg = "name: {}, threshold: {}, " "spp__relative_to_threshold: {}\n"
            for item in missing_data:
                msg = msg + dyn_msg.format(*item)
            raise IOError(msg)

        if not optional_node_data_missing:
            optional_node_data_missing = None
        return optional_node_data_missing