def test_check_coordinate_name(self):
     """
     Test that the utility returns an iris.cube.Cube with an
     ensemble_member_id coordinate.
     """
     rename_coordinate(self.cube, "realization", "ensemble_member_id")
     self.assertTrue(self.cube.coord("ensemble_member_id"))
예제 #2
0
 def test_absent_original_coord(self):
     """
     Test that the utility returns an iris.cube.Cube after the renaming
     was not successful, as the original coordinate was not found in
     the cube.
     """
     rename_coordinate(self.cube, "fake", "ensemble_member_id")
     self.assertFalse(self.cube.coords("ensemble_member_id"))
 def test_check_type_error(self):
     """
     Test that a TyoeError is raised, if the input variable is not an
     iris.cube.Cube.
     """
     fake_cube = "fake"
     msg = "A Cube or CubeList is not provided for renaming"
     with self.assertRaisesRegexp(TypeError, msg):
         rename_coordinate(fake_cube, "realization", "ensemble_member_id")
 def test_basic_cubelist(self):
     """
     Test that the utility returns an iris.cube.CubeList and that
     the cubes in the cubelist have an ensemble_member_id coordinate.
     """
     cube1 = self.cube.copy()
     cube2 = self.cube.copy()
     cubes = iris.cube.CubeList([cube1, cube2])
     rename_coordinate(cubes, "realization", "ensemble_member_id")
     self.assertIsInstance(cubes, iris.cube.CubeList)
     for cube in cubes:
         self.assertTrue(cube.coord("ensemble_member_id"))
예제 #5
0
    def apply_params_entry(self):
        """
        Wrapping function to calculate the forecast predictor and forecast
        variance prior to applying coefficients to the current forecast.

        Returns:
            (tuple) : tuple containing:
                **calibrated_forecast_predictor** (CubeList):
                    CubeList containing both the calibrated version of the
                    ensemble predictor, either the ensemble mean/members.
                **calibrated_forecast_variance** (CubeList):
                    CubeList containing both the calibrated version of the
                    ensemble variance, either the ensemble mean/members.
                **calibrated_forecast_coefficients** (CubeList):
                    CubeList containing both the coefficients for calibrating
                    the ensemble.

        """
        # Ensure predictor_of_mean_flag is valid.
        check_predictor_of_mean_flag(self.predictor_of_mean_flag)

        rename_coordinate(
            self.current_forecast, "ensemble_member_id", "realization")

        current_forecast_cubes = concatenate_cubes(
            self.current_forecast)

        if self.predictor_of_mean_flag.lower() in ["mean"]:
            forecast_predictors = current_forecast_cubes.collapsed(
                "realization", iris.analysis.MEAN)
        elif self.predictor_of_mean_flag.lower() in ["members"]:
            forecast_predictors = current_forecast_cubes

        forecast_vars = current_forecast_cubes.collapsed(
            "realization", iris.analysis.VARIANCE)

        (calibrated_forecast_predictor, calibrated_forecast_var,
         calibrated_forecast_coefficients) = self._apply_params(
             forecast_predictors, forecast_vars, self.optimised_coeffs,
             self.coeff_names, self.predictor_of_mean_flag)
        return (calibrated_forecast_predictor,
                calibrated_forecast_var,
                calibrated_forecast_coefficients)
예제 #6
0
    def estimate_coefficients_for_ngr(self, current_forecast,
                                      historic_forecast, truth):
        """
        Using Nonhomogeneous Gaussian Regression/Ensemble Model Output
        Statistics, estimate the required coefficients from historical
        forecasts.

        The main contents of this method is:

        1. Metadata checks to ensure that the current forecast, historic
           forecast and truth exist in a form that can be processed.
        2. Loop through times within the concatenated current forecast cube:

           1. Extract the desired forecast period from the historic forecasts
              to match the current forecasts. Apply unit conversion to ensure
              that historic forecasts have the desired units for calibration.
           2. Extract the relevant truth to co-incide with the time within
              the historic forecasts. Apply unit conversion to ensure
              that the truth has the desired units for calibration.
           3. Calculate mean and variance.
           4. Calculate initial guess at coefficient values by performing a
              linear regression, if requested, otherwise default values are
              used.
           5. Perform minimisation.

        Args:
            current_forecast (Iris Cube or CubeList):
                The cube containing the current forecast.
            historical_forecast (Iris Cube or CubeList):
                The cube or cubelist containing the historical forecasts used
                for calibration.
            truth (Iris Cube or CubeList):
                The cube or cubelist containing the truth used for calibration.

        Returns:
            (tuple): tuple containing:
                **optimised_coeffs** (Dictionary):
                    Dictionary containing a list of the optimised coefficients
                    for each date.
                **coeff_names** (List):
                    The name of each coefficient.

        """
        def convert_to_cubelist(cubes, cube_type="forecast"):
            """
            Convert cube to cubelist, if necessary.

            Args:
                cubes (Iris Cube or Iris CubeList):
                    Cube to be converted to CubeList.
                cube_type (String):
                    String to describe the cube, which is being converted to a
                    CubeList.

            Raises
            ------
            TypeError: The input cube is not an Iris cube.

            """
            if not isinstance(cubes, iris.cube.CubeList):
                cubes = iris.cube.CubeList([cubes])
            for cube in cubes:
                if not isinstance(cube, iris.cube.Cube):
                    msg = ("The input data within the {} "
                           "is not an Iris Cube.".format(cube_type))
                    raise TypeError(msg)
            return cubes

        # Ensure predictor_of_mean_flag is valid.
        check_predictor_of_mean_flag(self.predictor_of_mean_flag)

        # Setting default values for optimised_coeffs and coeff_names.
        optimised_coeffs = {}
        coeff_names = ["gamma", "delta", "a", "beta"]

        # Set default values for whether there are NaN values within the
        # initial guess.
        nan_in_initial_guess = False

        for var in [current_forecast, historic_forecast, truth]:
            if (isinstance(var, iris.cube.Cube)
                    or isinstance(var, iris.cube.CubeList)):
                current_forecast_cubes = current_forecast
                historic_forecast_cubes = historic_forecast
                truth_cubes = truth
            else:
                msg = ("{} is not a Cube or CubeList."
                       "Returning default values for optimised_coeffs {} "
                       "and coeff_names {}.").format(var, optimised_coeffs,
                                                     coeff_names)
                warnings.warn(msg)
                return optimised_coeffs, coeff_names

        current_forecast_cubes = (convert_to_cubelist(
            current_forecast_cubes, cube_type="current forecast"))
        historic_forecast_cubes = (convert_to_cubelist(
            historic_forecast_cubes, cube_type="historic forecast"))
        truth_cubes = convert_to_cubelist(truth_cubes, cube_type="truth")

        if (len(current_forecast_cubes) == 0
                or len(historic_forecast_cubes) == 0 or len(truth_cubes) == 0):
            msg = ("Insufficient input data present to estimate "
                   "coefficients using NGR. "
                   "\nNumber of current_forecast_cubes: {}"
                   "\nNumber of historic_forecast_cubes: {}"
                   "\nNumber of truth_cubes: {}".format(
                       len(current_forecast_cubes),
                       len(historic_forecast_cubes), len(truth_cubes)))
            warnings.warn(msg)
            return optimised_coeffs, coeff_names

        rename_coordinate(current_forecast_cubes, "ensemble_member_id",
                          "realization")
        rename_coordinate(historic_forecast_cubes, "ensemble_member_id",
                          "realization")

        current_forecast_cubes = concatenate_cubes(current_forecast_cubes)
        historic_forecast_cubes = concatenate_cubes(historic_forecast_cubes)
        truth_cubes = concatenate_cubes(truth_cubes)

        for current_forecast_cube in current_forecast_cubes.slices_over(
                "time"):
            date = unit.num2date(
                current_forecast_cube.coord("time").points,
                current_forecast_cube.coord("time").units.name,
                current_forecast_cube.coord("time").units.calendar)[0]
            # Extract desired forecast_period from historic_forecast_cubes.
            forecast_period_constr = iris.Constraint(
                forecast_period=current_forecast_cube.coord(
                    "forecast_period").points)
            historic_forecast_cube = historic_forecast_cubes.extract(
                forecast_period_constr)

            # Extract truth matching the time of the historic forecast.
            truth_constr = iris.Constraint(
                forecast_reference_time=historic_forecast_cube.coord(
                    "time").points)
            truth_cube = truth_cubes.extract(truth_constr)

            if truth_cube is None:
                msg = ("Unable to calibrate for the time points {} "
                       "as no truth data is available."
                       "Moving on to try to calibrate "
                       "next time point.".format(
                           historic_forecast_cube.coord("time").points))
                warnings.warn(msg)
                continue

            # Make sure inputs have the same units.
            historic_forecast_cube.convert_units(self.desired_units)
            truth_cube.convert_units(self.desired_units)

            if self.predictor_of_mean_flag.lower() in ["mean"]:
                no_of_members = None
                forecast_predictor = historic_forecast_cube.collapsed(
                    "realization", iris.analysis.MEAN)
            elif self.predictor_of_mean_flag.lower() in ["members"]:
                no_of_members = len(
                    historic_forecast_cube.coord("realization").points)
                forecast_predictor = historic_forecast_cube

            forecast_var = historic_forecast_cube.collapsed(
                "realization", iris.analysis.VARIANCE)

            # Computing initial guess for EMOS coefficients
            # If no initial guess from a previous iteration, or if there
            # are NaNs in the initial guess, calculate an initial guess.
            if "initial_guess" not in locals() or nan_in_initial_guess:
                initial_guess = self.compute_initial_guess(
                    truth_cube,
                    forecast_predictor,
                    self.predictor_of_mean_flag,
                    self.ESTIMATE_COEFFICIENTS_FROM_LINEAR_MODEL_FLAG,
                    no_of_members=no_of_members)

            if np.any(np.isnan(initial_guess)):
                nan_in_initial_guess = True

            if not nan_in_initial_guess:
                # Need to access the x attribute returned by the
                # minimisation function.
                optimised_coeffs[date] = (
                    self.minimiser.crps_minimiser_wrapper(
                        initial_guess, forecast_predictor, truth_cube,
                        forecast_var, self.predictor_of_mean_flag,
                        self.distribution.lower()))
                initial_guess = optimised_coeffs[date]
            else:
                optimised_coeffs[date] = initial_guess

        return optimised_coeffs, coeff_names
 def test_basic_cube(self):
     """Test that the utility returns an iris.cube.Cube."""
     rename_coordinate(self.cube, "realization", "ensemble_member_id")
     self.assertIsInstance(self.cube, iris.cube.Cube)