Skip to content

Commit

Permalink
Minor changes following review. Update checksums for change to accept…
Browse files Browse the repository at this point in the history
…ance test data.
  • Loading branch information
brhooper committed May 16, 2023
1 parent b4e002e commit 834ea2a
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 38 deletions.
12 changes: 7 additions & 5 deletions improver/cli/enforce_consistent_forecasts.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
def process(
*cubes: cli.inputcubelist,
ref_name: str = None,
additive_amount: float = 0.0,
multiplicative_amount: float = 1.0,
additive_amount: float = None,
multiplicative_amount: float = None,
comparison_operator: str = ">=",
diff_for_warning: float = None,
):
Expand All @@ -54,7 +54,7 @@ def process(
containing:
forecast_cube (iris.cube.Cube):
Cube of forecasts to be updated by using the reference forecast to
create a bound on the value of the forecasts
create a bound on the value of the forecasts.
ref_forecast (iris.cube.Cube)
Cube of forecasts used to create a bound for the values in
forecast_cube. It must be the same shape as forecast_cube but have
Expand All @@ -64,11 +64,13 @@ def process(
the units of the reference forecast) prior to enforcing consistency between
the forecast and reference forecast. If both an additive_amount and
multiplicative_amount are specified then addition occurs after
multiplication.
multiplication. This option cannot be used for probability forecasts, if it
is then an error will be raised.
multiplicative_amount (float): The amount to multiply the reference forecast by
prior to enforcing consistency between the forecast and reference
forecast. If both an additive_amount and multiplicative_amount are
specified then addition occurs after multiplication.
specified then addition occurs after multiplication. This option cannot be
used for probability forecasts, if it is then an error will be raised.
comparison_operator (str): Determines whether the forecast is enforced to be not
less than or not greater than the reference forecast. Valid choices are
">=", for not less than, and "<=" for not greater than.
Expand Down
27 changes: 17 additions & 10 deletions improver/utilities/enforce_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class EnforceConsistentForecasts(PostProcessingPlugin):

def __init__(
self,
additive_amount: float = 0.0,
multiplicative_amount: float = 1.0,
additive_amount: float = None,
multiplicative_amount: float = None,
comparison_operator: str = ">=",
diff_for_warning: Optional[float] = None,
) -> None:
Expand All @@ -62,13 +62,13 @@ def __init__(
additive_amount: The amount to be added to the reference forecast prior to
enforcing consistency between the forecast and reference forecast. If
both an additive_amount and multiplicative_amount are specified then
addition occurs after multiplication. This must be 0 for probability
forecasts.
addition occurs after multiplication. This option cannot be used for
probability forecasts, if it is then an error will be raised.
multiplicative_amount: The amount to multiply the reference forecast by
prior to enforcing consistency between the forecast and reference
forecast. If both an additive_amount and multiplicative_amount are
specified then addition occurs after multiplication. This must be 1
for probability forecasts.
specified then addition occurs after multiplication. This option cannot
be used for probability forecasts, if it is then an error will be raised.
comparison_operator: Determines whether the forecast is enforced to be not
less than or not greater than the reference forecast. Valid choices are
">=", for not less than, and "<=" for not greater than.
Expand Down Expand Up @@ -107,16 +107,23 @@ def process(self, forecast: Cube, reference_forecast: Cube) -> Cube:
raise ValueError(msg)

# linear transformation cannot be applied to probability forecasts
if forecast.name().startswith("probability_of"):
if self.additive_amount != 0 or self.multiplicative_amount != 1:
if self.additive_amount is not None or self.multiplicative_amount is not None:
if forecast.name().startswith("probability_of"):
msg = (
"For probability data, the additive_amount must be 0 and the "
"multiplicative_amount must be 1. The input additive_amount was "
"For probability data, the additive_amount and multiplicative_amount"
"inputs cannot be used. The input additive_amount was "
f"{self.additive_amount}, the input multiplicative amount was "
f"{self.multiplicative_amount}."
)
raise ValueError(msg)

# if additive_amount or multiplicative_amount not specified, then use identity
# function
if self.additive_amount is None:
self.additive_amount = 0
if self.multiplicative_amount is None:
self.multiplicative_amount = 1

# calculate forecast_bound by applying specified linear transformation to
# reference_forecast
forecast_bound = reference_forecast.copy()
Expand Down
2 changes: 1 addition & 1 deletion improver_tests/acceptance/SHA256SUMS
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ e210bf956dd3574eda3a64fdc3371ab16f85048ca120a3823e90d751d2325c46 ./enforce-cons
5474c4c2309dcc0991355007f20869eb6d1d234d721bdf37542cddb0570d7217 ./enforce-consistent-forecasts/probability_forecast.nc
7e435c2db5e792b71bb5170140fbe1e37cc03d96bd88f73ce7196f9469ba3e13 ./enforce-consistent-forecasts/probability_kgo.nc
764833f16f1ed5939ba82130fa73961fdecacceebcf2b4cdb2970cb670e2ee3e ./enforce-consistent-forecasts/probability_reference.nc
b4a9f862d1d9f2c0ede6d1ad545f17e59515da517b4a167de7e3dd4ca2422a18 ./enforce-consistent-forecasts/realization_forecast.nc
40a05397b22e614bce592c1644a8443a27a94e70914cb482117a2fcc11ea8408 ./enforce-consistent-forecasts/realization_forecast.nc
09eb8d42b1df18831660bfebef46a09436e66946a48488d8be89157e8e3666ef ./enforce-consistent-forecasts/realization_kgo.nc
9604ec25ad2256d41f824c8be957ae20158d75a7a8d632af249b2778d20934d0 ./enforce-consistent-forecasts/realization_reference.nc
9b48f3eabeed93a90654a5e6a2f06fcb7297cdba40f650551d99a5e310cf27dd ./estimate-emos-coefficients-from-table/altitude.nc
Expand Down
44 changes: 28 additions & 16 deletions improver_tests/acceptance/test_enforce_consistent_forecasts.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@
(
"probability",
"probability_of_cloud_area_fraction_above_threshold",
"0.0",
"1.0",
"",
"",
"<=",
),
("percentile", "wind_speed", "0.0", "1.1", ">="),
Expand All @@ -71,20 +71,32 @@ def test_enforce_consistent_forecasts(
reference = kgo_dir / f"{forecast_type}_reference.nc"
output_path = tmp_path / "output.nc"

args = [
forecast,
reference,
"--ref-name",
ref_name,
"--additive-amount",
additive_amount,
"--multiplicative-amount",
multiplicative_amount,
"--comparison-operator",
comparison_operator,
"--output",
output_path,
]
if forecast_type == "probability":
args = [
forecast,
reference,
"--ref-name",
ref_name,
"--comparison-operator",
comparison_operator,
"--output",
output_path,
]
else:
args = [
forecast,
reference,
"--ref-name",
ref_name,
"--additive-amount",
additive_amount,
"--multiplicative-amount",
multiplicative_amount,
"--comparison-operator",
comparison_operator,
"--output",
output_path,
]

run_cli(args)
acc.compare(output_path, kgo_path)
Expand Down
15 changes: 9 additions & 6 deletions improver_tests/utilities/test_enforce_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ def get_percentile_forecast(value, shape, name):
Create a percentile forecast cube.
"""
data = get_percentiles(value, shape)
np.full(shape, data, dtype=np.float32)
forecast_cube = set_up_percentile_cube(
data, percentiles=[10, 50, 90], name=name, units="m s-1",
)
Expand All @@ -87,7 +86,7 @@ def get_probability_forecast(value, shape, name) -> Cube:

def get_realization_forecast(value, shape, name) -> Cube:
"""
Create a probability forecast cube.
Create a realization forecast cube.
"""
data = np.full(shape, fill_value=value, dtype=np.float32)
forecast_cube = set_up_variable_cube(
Expand Down Expand Up @@ -117,9 +116,9 @@ def get_expected(forecast_data, bound_data, comparison_operator):
"forecast_type, additive_amount, multiplicative_amount, reference_value, "
"forecast_value, comparison_operator",
(
("probability", 0, 1, 0.5, 0.4, ">="),
("probability", 0, 1, 0.4, 0.5, "<="),
("probability", 0, 1, 0.4, 0.5, ">="), # no change required
("probability", None, None, 0.5, 0.4, ">="),
("probability", None, None, 0.4, 0.5, "<="),
("probability", None, None, 0.4, 0.5, ">="), # no change required
("percentile", 0, 1.1, 50, 40, ">="),
("percentile", 0, 0.9, 40, 50, "<="),
("percentile", 10, 1, 50, 40, ">="),
Expand Down Expand Up @@ -170,6 +169,10 @@ def test_basic(
comparison_operator=comparison_operator,
)(forecast_cube, reference_cube)

if additive_amount is None:
additive_amount = 0
if multiplicative_amount is None:
multiplicative_amount = 1
bound_data = additive_amount + (multiplicative_amount * reference_cube.copy().data)
expected = get_expected(forecast_cube.data, bound_data, comparison_operator)

Expand All @@ -191,7 +194,7 @@ def test_basic(
0.6,
">=",
0.5,
), # check that additive and multiplicative amounts aren't used
), # cannot specify additive and multiplicative amounts with probabilities
("realization", 15, 293.15, ">=", 30), # mismatching units
),
)
Expand Down

0 comments on commit 834ea2a

Please sign in to comment.