def test_basic_realizations_predictor(self):
        """
        Test that the plugin returns a numpy float value with the ensemble
        realizations as the predictor. The result indicates the minimum value
        for the CRPS that was achieved by the minimisation.
        """
        predictor = "realizations"

        plugin = Plugin()
        result = plugin.calculate_normal_crps(
            self.initial_guess_for_realization,
            self.forecast_predictor_data_realizations, self.truth_data,
            self.forecast_variance_data, self.sqrt_pi, predictor)

        self.assertIsInstance(result, np.float64)
        self.assertAlmostEqual(result, 0.2609061)
    def test_basic_mean_predictor_bad_value(self):
        """
        Test that the plugin returns a numpy float64 value
        and that the value matches the BAD_VALUE, when the appropriate
        condition is found. The ensemble mean is the predictor.
        The initial guess is specifically set to float32 precision for the
        purpose for generating the BAD_VALUE for the unit test.
        """
        initial_guess = np.array([1e65, 1e65, 1e65, 1e65], dtype=np.float32)

        predictor = "mean"

        plugin = Plugin()
        result = plugin.calculate_normal_crps(initial_guess,
                                              self.forecast_predictor_data,
                                              self.truth_data,
                                              self.forecast_variance_data,
                                              self.sqrt_pi, predictor)

        self.assertIsInstance(result, np.float64)
        self.assertAlmostEqual(result, plugin.BAD_VALUE)
class Test_calculate_normal_crps(SetupNormalInputs):
    """
    Test minimising the CRPS for a normal distribution.
    Either the ensemble mean or the individual ensemble realizations are
    used as the predictors.
    """
    def setUp(self):
        """Set up plugin."""
        super().setUp()
        self.precision = 4
        self.plugin = Plugin(tolerance=1e-4)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_basic_mean_predictor(self):
        """
        Test that the plugin returns a numpy float value with the
        mean as the predictor. The result indicates the minimum value for the
        CRPS that was achieved by the minimisation.
        """
        predictor = "mean"

        result = self.plugin.calculate_normal_crps(
            self.initial_guess_for_mean,
            self.forecast_predictor_data,
            self.truth_data,
            self.forecast_variance_data,
            self.sqrt_pi,
            predictor,
        )

        self.assertIsInstance(result, np.float64)
        self.assertAlmostEqual(result, 0.3006, places=self.precision)

    @ManageWarnings(
        ignored_messages=["Collapsing a non-contiguous coordinate."])
    def test_basic_realizations_predictor(self):
        """
        Test that the plugin returns a numpy float value with the ensemble
        realizations as the predictor. The result indicates the minimum value
        for the CRPS that was achieved by the minimisation.
        """
        predictor = "realizations"

        result = self.plugin.calculate_normal_crps(
            self.initial_guess_for_realization,
            self.forecast_predictor_data_realizations,
            self.truth_data,
            self.forecast_variance_data,
            self.sqrt_pi,
            predictor,
        )

        self.assertIsInstance(result, np.float64)
        self.assertAlmostEqual(result, 0.3006, places=self.precision)

    @ManageWarnings(
        ignored_messages=[
            "Collapsing a non-contiguous coordinate.",
            "invalid value encountered in",
        ],
        warning_types=[UserWarning, RuntimeWarning],
    )
    def test_basic_mean_predictor_bad_value(self):
        """
        Test that the plugin returns a numpy float64 value
        and that the value matches the BAD_VALUE, when the appropriate
        condition is found. The ensemble mean is the predictor.
        The initial guess is specifically set to float32 precision for the
        purpose for generating the BAD_VALUE for the unit test.
        """
        initial_guess = np.array([1e65, 1e65, 1e65, 1e65], dtype=np.float32)

        predictor = "mean"

        result = self.plugin.calculate_normal_crps(
            initial_guess,
            self.forecast_predictor_data,
            self.truth_data,
            self.forecast_variance_data,
            self.sqrt_pi,
            predictor,
        )

        self.assertIsInstance(result, np.float64)
        self.assertAlmostEqual(result, self.plugin.BAD_VALUE, self.precision)