def test_missing_cube(self): """Test that an exception is raised if either of the historic forecasts or truth were missing.""" self.historic_temperature_forecast_cube.convert_units("Fahrenheit") plugin = Plugin(self.distribution) msg = ".*cubes must be provided" with self.assertRaisesRegex(ValueError, msg): plugin.process(self.historic_temperature_forecast_cube, None)
def test_non_matching_units(self): """Test that an exception is raised if the historic forecasts and truth have non matching units.""" self.historic_temperature_forecast_cube.convert_units("Fahrenheit") plugin = Plugin(self.distribution) msg = "The historic forecast units" with self.assertRaisesRegex(ValueError, msg): plugin.process( self.historic_temperature_forecast_cube, self.temperature_truth_cube )
def test_coefficient_values_for_truncnorm_distribution(self): """Ensure that the values for the optimised_coefficients match the expected values, and the coefficient names also match expected values for a truncated normal distribution. In this case, a linear least-squares regression is used to construct the initial guess.""" distribution = "truncnorm" plugin = Plugin(distribution) result = plugin.process( self.historic_wind_speed_forecast_cube, self.wind_speed_truth_cube ) self.assertEMOSCoefficientsAlmostEqual( np.array([cube.data for cube in result]), self.expected_mean_predictor_truncnorm, ) self.assertArrayEqual( [cube.name() for cube in result], self.expected_coeff_names ) for cube in result: self.assertArrayEqual( cube.attributes["shape_parameters"], np.array([0, np.inf], dtype=np.float32), )
def test_basic(self): """Ensure that the optimised_coefficients are returned as a cube, with the expected number of coefficients.""" plugin = Plugin(self.distribution) result = plugin.process( self.historic_temperature_forecast_cube, self.temperature_truth_cube ) self.assertIsInstance(result, iris.cube.CubeList) self.assertEqual(len(result), len(self.coeff_names))
def test_historic_forecast_unit_conversion(self): """Ensure the expected optimised coefficients are generated, even if the input historic forecast cube has different units.""" self.historic_temperature_forecast_cube.convert_units("Fahrenheit") desired_units = "Kelvin" plugin = Plugin(self.distribution, desired_units=desired_units) result = plugin.process( self.historic_temperature_forecast_cube, self.temperature_truth_cube ) self.assertEMOSCoefficientsAlmostEqual( np.array([cube.data for cube in result]), self.expected_mean_predictor_norm, )
def test_coefficient_values_for_norm_distribution(self): """Ensure that the values for the optimised_coefficients match the expected values, and the coefficient names also match expected values for a normal distribution. In this case, a linear least-squares regression is used to construct the initial guess.""" plugin = Plugin(self.distribution) result = plugin.process( self.historic_temperature_forecast_cube, self.temperature_truth_cube ) self.assertEMOSCoefficientsAlmostEqual( np.array([cube.data for cube in result]), self.expected_mean_predictor_norm, ) self.assertArrayEqual( [cube.name() for cube in result], self.expected_coeff_names )
def test_coefficient_values_for_norm_distribution_max_iterations(self): """Ensure that the values for the optimised_coefficients match the expected values, and the coefficient names also match expected values for a normal distribution, when the max_iterations argument is specified.""" max_iterations = 800 plugin = Plugin(self.distribution, max_iterations=max_iterations) result = plugin.process( self.historic_temperature_forecast_cube, self.temperature_truth_cube ) self.assertEMOSCoefficientsAlmostEqual( np.array([cube.data for cube in result]), self.expected_mean_predictor_norm, ) self.assertArrayEqual( [cube.name() for cube in result], self.expected_coeff_names )
def test_coefficients_norm_realizations_no_statsmodels(self): """Ensure that the values for the optimised_coefficients match the expected values, and the coefficient names also match expected values for a normal distribution where the realizations are used as the predictor. """ predictor = "realizations" plugin = Plugin(self.distribution, predictor=predictor) result = plugin.process( self.historic_temperature_forecast_cube, self.temperature_truth_cube ) self.assertEMOSCoefficientsAlmostEqual( np.concatenate([np.atleast_1d(cube.data) for cube in result]), self.expected_realizations_norm_no_statsmodels, ) self.assertArrayEqual( [cube.name() for cube in result], self.expected_coeff_names )
def test_coefficient_values_for_norm_distribution_mismatching_inputs(self): """Test that the values for the optimised coefficients match the expected values, and the coefficient names also match expected values for a normal distribution for when the historic forecasts and truths input having some mismatches in validity time. """ expected = [23.4593, 0.9128, 0.0041, 0.4885] partial_historic_forecasts = ( self.historic_forecasts[:2] + self.historic_forecasts[3:] ).merge_cube() partial_truth = self.truth[1:].merge_cube() plugin = Plugin(self.distribution) result = plugin.process(partial_historic_forecasts, partial_truth) self.assertEMOSCoefficientsAlmostEqual( np.array([cube.data for cube in result]), expected ) self.assertArrayEqual( [cube.name() for cube in result], self.expected_coeff_names )
def test_coefficient_values_for_norm_distribution_landsea_mask(self): """Ensure that the values for the optimised_coefficients match the expected values, and the coefficient names also match expected values for a normal distribution. In this case, a linear least-squares regression is used to construct the initial guess. The original data is surrounded by a halo that is masked out by the landsea_mask, giving the same results as the original data. """ plugin = Plugin(self.distribution) result = plugin.process( self.historic_temperature_forecast_cube_halo, self.temperature_truth_cube_halo, landsea_mask=self.landsea_cube, ) self.assertEMOSCoefficientsAlmostEqual( np.array([cube.data for cube in result]), self.expected_mean_predictor_norm, ) self.assertArrayEqual( [cube.name() for cube in result], self.expected_coeff_names )
def test_coefficients_norm_distribution_default_initial_guess(self): """Ensure that the values for the optimised_coefficients match the expected values, and the coefficient names also match expected values for a normal distribution, where the default values for the initial guess are used, rather than using a linear least-squares regression to construct an initial guess. Reducing the value for the tolerance would result in the coefficients more closely matching the coefficients created when using a linear least-squares regression to construct the initial guess.""" expected = [-0.0001, 0.9974, 0.0001, 1.0374] plugin = Plugin(self.distribution) plugin.ESTIMATE_COEFFICIENTS_FROM_LINEAR_MODEL_FLAG = False result = plugin.process( self.historic_temperature_forecast_cube, self.temperature_truth_cube ) self.assertEMOSCoefficientsAlmostEqual( np.array([cube.data for cube in result]), expected ) self.assertArrayEqual( [cube.name() for cube in result], self.expected_coeff_names )