class Test__calculate_location_parameter_from_realizations(
    SetupCoefficientsCubes, EnsembleCalibrationAssertions
):

    """Test the _calculate_location_parameter_from_realizations method."""

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def setUp(self):
        """Set-up coefficients and plugin for testing."""
        super().setUp()

        self.plugin = Plugin()
        self.plugin.current_forecast = self.current_temperature_forecast_cube

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_with_statsmodels(self):
        """Test that the expected values for the location parameter are
        calculated when using the ensemble realizations with statsmodels.
        These expected values are compared to the results when using the
        ensemble mean and when statsmodels is not used to ensure that the
        results are similar."""
        self.plugin.coefficients_cubelist = self.coeffs_from_statsmodels_realizations
        location_parameter = (
            self.plugin._calculate_location_parameter_from_realizations()
        )
        self.assertCalibratedVariablesAlmostEqual(
            location_parameter, self.expected_loc_param_statsmodels_realizations
        )
        assert_array_almost_equal(
            location_parameter, self.expected_loc_param_mean, decimal=0
        )
        assert_array_almost_equal(
            location_parameter,
            self.expected_loc_param_no_statsmodels_realizations,
            decimal=0,
        )

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_without_statsmodels(self):
        """Test that the expected values for the location parameter are
        calculated when using the ensemble realizations without statsmodels.
        These expected values are compared to the results when using the
        ensemble mean and when statsmodels is used to ensure that the results
        are similar."""
        self.plugin.coefficients_cubelist = self.coeffs_from_no_statsmodels_realizations
        location_parameter = (
            self.plugin._calculate_location_parameter_from_realizations()
        )
        self.assertCalibratedVariablesAlmostEqual(
            location_parameter, self.expected_loc_param_no_statsmodels_realizations
        )
        assert_array_almost_equal(
            location_parameter, self.expected_loc_param_mean, decimal=0
        )
        assert_array_almost_equal(
            location_parameter,
            self.expected_loc_param_statsmodels_realizations,
            decimal=0,
        )
class Test__spatial_domain_match(SetupCoefficientsCubes):

    """ Test the _spatial_domain_match method."""

    def setUp(self):
        super().setUp()
        self.plugin = Plugin()

    def test_matching(self):
        """Test case in which spatial domains match."""
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cubelist = self.coeffs_from_mean
        self.plugin._spatial_domain_match()

    def test_unmatching_x_axis_points(self):
        """Test when the points of the x dimension do not match."""
        self.current_temperature_forecast_cube.coord(axis="x").bounds = (
            self.current_temperature_forecast_cube.coord(axis="x").bounds + 2.0
        )
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cubelist = self.coeffs_from_mean
        msg = "The points or bounds of the x axis given by the current forecast"
        with self.assertRaisesRegex(ValueError, msg):
            self.plugin._spatial_domain_match()

    def test_unmatching_x_axis_bounds(self):
        """Test when the bounds of the x dimension do not match."""
        self.current_temperature_forecast_cube.coord(axis="x").bounds = [
            [-35, -5],
            [-5, 5],
            [5, 35],
        ]
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cubelist = self.coeffs_from_mean
        msg = "The points or bounds of the x axis given by the current forecast"
        with self.assertRaisesRegex(ValueError, msg):
            self.plugin._spatial_domain_match()

    def test_unmatching_y_axis(self):
        """Test case in which the y-dimensions of the domains do not match."""
        self.current_temperature_forecast_cube.coord(axis="y").bounds = (
            self.current_temperature_forecast_cube.coord(axis="y").bounds + 2.0
        )
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cubelist = self.coeffs_from_mean
        msg = "The points or bounds of the y axis given by the current forecast"
        with self.assertRaisesRegex(ValueError, msg):
            self.plugin._spatial_domain_match()

    def test_skipping_spot_forecast(self):
        """Test passing a spot forecast. In this case, the spatial domain
        is not checked."""
        self.plugin.current_forecast = self.current_forecast_spot_cube
        self.plugin._spatial_domain_match()
    def setUp(self):
        """Set-up coefficients and plugin for testing."""
        super().setUp()

        self.plugin = Plugin()
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cubelist = self.coeffs_from_mean
    def test_end_to_end_point_by_point_sites_realizations(self):
        """An example end-to-end calculation when a separate set of
        coefficients are computed for each site using the realizations as the
        predictor. This repeats the test elements above but all grouped together."""
        plugin = Plugin(predictor="realizations")
        calibrated_forecast_predictor, calibrated_forecast_var = plugin.process(
            self.current_forecast_spot_cube, self.coeffs_from_realizations_sites
        )

        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_predictor.data,
            self.expected_loc_param_realizations_sites,
        )
        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_var.data, self.expected_scale_param_realizations_sites
        )
        self.assertEqual(calibrated_forecast_predictor.dtype, np.float32)
    def setUp(self):
        """Set-up coefficients and plugin for testing."""
        super().setUp()

        self.optimised_coeffs = dict(
            zip(
                self.coeffs_from_mean.coord("coefficient_name").points,
                self.coeffs_from_mean.data,
            ))
        self.plugin = Plugin()
        self.plugin.current_forecast = self.current_temperature_forecast_cube
class Test__spatial_domain_match(SetupCoefficientsCubes):
    """ Test the _spatial_domain_match method."""
    def setUp(self):
        super().setUp()
        self.plugin = Plugin()

    def test_matching(self):
        """Test case in which spatial domains match."""
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cube = self.coeffs_from_mean
        self.plugin._spatial_domain_match()

    def test_unmatching_x_axis(self):
        """Test case in which the x-dimensions of the domains do not match."""
        self.current_temperature_forecast_cube.coord(axis="x").points = (
            self.current_temperature_forecast_cube.coord(axis="x").points *
            2.0)
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cube = self.coeffs_from_mean
        msg = "The domain along the x axis given by the current forecast"
        with self.assertRaisesRegex(ValueError, msg):
            self.plugin._spatial_domain_match()

    def test_unmatching_y_axis(self):
        """Test case in which the y-dimensions of the domains do not match."""
        self.current_temperature_forecast_cube.coord(axis="y").points = (
            self.current_temperature_forecast_cube.coord(axis="y").points *
            2.0)
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cube = self.coeffs_from_mean
        msg = "The domain along the y axis given by the current forecast"
        with self.assertRaisesRegex(ValueError, msg):
            self.plugin._spatial_domain_match()
class Test__calculate_location_parameter_from_mean(
    SetupCoefficientsCubes, EnsembleCalibrationAssertions
):

    """Test the __calculate_location_parameter_from_mean method."""

    def setUp(self):
        """Set-up coefficients and plugin for testing."""
        super().setUp()

        self.plugin = Plugin()
        self.plugin.current_forecast = self.current_temperature_forecast_cube
        self.plugin.coefficients_cubelist = self.coeffs_from_mean

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_basic(self):
        """Test that the expected values for the location parameter are
        calculated when using the ensemble mean. These expected values are
        compared to the results when using the ensemble realizations to ensure
        that the results are similar."""
        location_parameter = self.plugin._calculate_location_parameter_from_mean()
        self.assertCalibratedVariablesAlmostEqual(
            location_parameter, self.expected_loc_param_mean
        )
        assert_array_almost_equal(
            location_parameter, self.expected_loc_param_realizations, decimal=0,
        )

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_missing_additional_predictor(self):
        """Test that an error is raised if an additional predictor is expected
        based on the contents of the coefficients cube."""
        self.plugin.coefficients_cubelist = self.coeffs_from_mean_alt
        msg = "The number of forecast predictors must equal the number"
        with self.assertRaisesRegex(ValueError, msg):
            self.plugin._calculate_location_parameter_from_mean()
Esempio n. 8
0
class Test__calculate_scale_parameter(SetupCoefficientsCubes,
                                      EnsembleCalibrationAssertions):
    """Test the _calculate_scale_parameter method."""
    def setUp(self):
        """Set-up the plugin for testing."""
        super().setUp()
        self.plugin = Plugin()
        self.plugin.current_forecast = self.current_temperature_forecast_cube

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_basic(self):
        """Test the scale parameter is calculated correctly."""
        self.plugin.coefficients_cubelist = self.coeffs_from_mean
        scale_parameter = self.plugin._calculate_scale_parameter()
        self.assertCalibratedVariablesAlmostEqual(
            scale_parameter, self.expected_scale_param_mean)
class Test__create_output_cubes(SetupCoefficientsCubes, EnsembleCalibrationAssertions):

    """Test the _create_output_cubes method."""

    def setUp(self):
        """Set-up the plugin for testing."""
        super().setUp()
        self.plugin = Plugin()
        self.plugin.current_forecast = self.current_temperature_forecast_cube

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_basic(self):
        """Test that the cubes created containing the location and scale
        parameter are formatted as expected."""
        (
            location_parameter_cube,
            scale_parameter_cube,
        ) = self.plugin._create_output_cubes(
            self.expected_loc_param_mean, self.expected_scale_param_mean
        )
        self.assertEqual(location_parameter_cube, self.expected_loc_param_mean_cube)
        self.assertEqual(scale_parameter_cube, self.expected_scale_param_mean_cube)
class Test__calculate_location_parameter_from_mean(
        SetupCoefficientsCubes, EnsembleCalibrationAssertions):
    """Test the __calculate_location_parameter_from_mean method."""
    def setUp(self):
        """Set-up coefficients and plugin for testing."""
        super().setUp()

        self.optimised_coeffs = dict(
            zip(
                self.coeffs_from_mean.coord("coefficient_name").points,
                self.coeffs_from_mean.data,
            ))
        self.plugin = Plugin()
        self.plugin.current_forecast = self.current_temperature_forecast_cube

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_basic(self):
        """Test that the expected values for the location parameter are
        calculated when using the ensemble mean. These expected values are
        compared to the results when using the ensemble realizations to ensure
        that the results are similar."""
        location_parameter = self.plugin._calculate_location_parameter_from_mean(
            self.optimised_coeffs)
        self.assertCalibratedVariablesAlmostEqual(location_parameter,
                                                  self.expected_loc_param_mean)
        assert_array_almost_equal(
            location_parameter,
            self.expected_loc_param_statsmodels_realizations,
            decimal=0,
        )
        assert_array_almost_equal(
            location_parameter,
            self.expected_loc_param_no_statsmodels_realizations,
            decimal=0,
        )
 def setUp(self):
     """Set-up the plugin for testing."""
     super().setUp()
     self.plugin = Plugin()
class Test_process(SetupCoefficientsCubes, EnsembleCalibrationAssertions):

    """Test the process plugin."""

    def setUp(self):
        """Set-up the plugin for testing."""
        super().setUp()
        self.plugin = Plugin()

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_diagnostic_match(self):
        """Test that an error is raised if the diagnostic_standard_name does
        not match when comparing a forecast cube and coefficients cubelist."""
        msg = "The forecast diagnostic"
        with self.assertRaisesRegex(ValueError, msg):
            self.plugin.process(
                self.current_wind_speed_forecast_cube, self.coeffs_from_mean
            )

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_variable_setting(self):
        """Test that the cubes passed into the plugin are allocated to
        plugin variables appropriately."""

        _, _ = self.plugin.process(
            self.current_temperature_forecast_cube, self.coeffs_from_mean
        )
        self.assertEqual(
            self.current_temperature_forecast_cube, self.plugin.current_forecast
        )
        self.assertEqual(self.coeffs_from_mean, self.plugin.coefficients_cubelist)

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_end_to_end(self):
        """An example end-to-end calculation. This repeats the test elements
        above but all grouped together."""
        calibrated_forecast_predictor, calibrated_forecast_var = self.plugin.process(
            self.current_temperature_forecast_cube, self.coeffs_from_mean
        )

        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_predictor.data, self.expected_loc_param_mean
        )
        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_var.data, self.expected_scale_param_mean
        )
        self.assertEqual(calibrated_forecast_predictor.dtype, np.float32)

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_end_to_end_point_by_point(self):
        """An example end-to-end calculation when a separate set of
        coefficients are computed for each grid point. This repeats the test
        elements above but all grouped together."""
        calibrated_forecast_predictor, calibrated_forecast_var = self.plugin.process(
            self.current_temperature_forecast_cube, self.coeffs_from_mean_point_by_point
        )

        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_predictor.data, self.expected_loc_param_mean
        )
        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_var.data, self.expected_scale_param_mean
        )
        self.assertEqual(calibrated_forecast_predictor.dtype, np.float32)

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_end_to_end_point_by_point_sites_realizations(self):
        """An example end-to-end calculation when a separate set of
        coefficients are computed for each site using the realizations as the
        predictor. This repeats the test elements above but all grouped together."""
        plugin = Plugin(predictor="realizations")
        calibrated_forecast_predictor, calibrated_forecast_var = plugin.process(
            self.current_forecast_spot_cube, self.coeffs_from_realizations_sites
        )

        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_predictor.data,
            self.expected_loc_param_realizations_sites,
        )
        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_var.data, self.expected_scale_param_realizations_sites
        )
        self.assertEqual(calibrated_forecast_predictor.dtype, np.float32)

    @ManageWarnings(ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_end_to_end_with_mask(self):
        """An example end-to-end calculation, but making sure that the
        areas that are masked within the landsea mask, are masked at the
        end."""

        # Construct a mask and encapsulate as a cube.
        mask = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
        mask_cube = self.current_temperature_forecast_cube[0].copy(data=mask)
        # Convention for IMPROVER is that land points are ones and sea points
        # are zeros in land-sea masks. In this case we want to mask sea points.
        expected_mask = np.array(
            [[False, True, True], [True, False, True], [True, True, False]]
        )

        calibrated_forecast_predictor, calibrated_forecast_var = self.plugin.process(
            self.current_temperature_forecast_cube,
            self.coeffs_from_mean,
            landsea_mask=mask_cube,
        )

        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_predictor.data.data, self.expected_loc_param_mean
        )
        self.assertArrayEqual(calibrated_forecast_predictor.data.mask, expected_mask)
        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_var.data.data, self.expected_scale_param_mean
        )
        self.assertArrayEqual(calibrated_forecast_var.data.mask, expected_mask)
 def setUp(self):
     """Set-up the plugin for testing."""
     super().setUp()
     self.plugin = Plugin()
     self.plugin.current_forecast = self.current_temperature_forecast_cube
 def setUp(self):
     super().setUp()
     self.plugin = Plugin()
class Test_process(SetupCoefficientsCubes, EnsembleCalibrationAssertions):
    """Test the process plugin."""
    def setUp(self):
        """Set-up the plugin for testing."""
        super().setUp()
        self.plugin = Plugin()

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_variable_setting(self):
        """Test that the cubes passed into the plugin are allocated to
        plugin variables appropriately."""

        _, _ = self.plugin.process(self.current_temperature_forecast_cube,
                                   self.coeffs_from_mean)
        self.assertEqual(self.current_temperature_forecast_cube,
                         self.plugin.current_forecast)
        self.assertEqual(self.coeffs_from_mean, self.plugin.coefficients_cube)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_end_to_end(self):
        """An example end-to-end calculation. This repeats the test elements
        above but all grouped together."""
        calibrated_forecast_predictor, calibrated_forecast_var = self.plugin.process(
            self.current_temperature_forecast_cube, self.coeffs_from_mean)

        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_predictor.data, self.expected_loc_param_mean)
        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_var.data, self.expected_scale_param_mean)
        self.assertEqual(calibrated_forecast_predictor.dtype, np.float32)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_end_to_end_with_mask(self):
        """An example end-to-end calculation, but making sure that the
        areas that are masked within the landsea mask, are masked at the
        end."""

        # Construct a mask and encapsulate as a cube.
        mask = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
        mask_cube = self.current_temperature_forecast_cube[0].copy(data=mask)
        # Convention for IMPROVER is that land points are ones and sea points
        # are zeros in land-sea masks. In this case we want to mask sea points.
        expected_mask = np.array([[False, True, True], [True, False, True],
                                  [True, True, False]])

        calibrated_forecast_predictor, calibrated_forecast_var = self.plugin.process(
            self.current_temperature_forecast_cube,
            self.coeffs_from_mean,
            landsea_mask=mask_cube,
        )

        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_predictor.data.data,
            self.expected_loc_param_mean)
        self.assertArrayEqual(calibrated_forecast_predictor.data.mask,
                              expected_mask)
        self.assertCalibratedVariablesAlmostEqual(
            calibrated_forecast_var.data.data, self.expected_scale_param_mean)
        self.assertArrayEqual(calibrated_forecast_var.data.mask, expected_mask)