Skip to content

Commit 2a6af01

Browse files
mats-knmidnerini
andauthored
Use max rain pixels for timestep and member to decompose for precip cascades in case of zero radar (#461)
* Use max rain pixels for timestep and member to decompose for precip cascades in case of zero radar * store precip threshold in state --------- Co-authored-by: Daniele Nerini <daniele.nerini@gmail.com>
1 parent 769880c commit 2a6af01

File tree

1 file changed

+41
-51
lines changed

1 file changed

+41
-51
lines changed

pysteps/blending/steps.py

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ class StepsBlendingParams:
325325
precip_models_provided_is_cascade: bool = False
326326
xy_coordinates: np.ndarray | None = None
327327
precip_zerovalue: float | None = None
328+
precip_threshold: float | None = None
328329
mask_threshold: np.ndarray | None = None
329330
zero_precip_radar: bool = False
330331
zero_precip_model_fields: bool = False
@@ -806,6 +807,8 @@ def __check_inputs(self):
806807
else:
807808
self.__params.mask_kwargs = deepcopy(self.__config.mask_kwargs)
808809

810+
self.__params.precip_threshold = self.__config.precip_threshold
811+
809812
if np.any(~np.isfinite(self.__velocity)):
810813
raise ValueError("velocity contains non-finite values")
811814

@@ -815,12 +818,12 @@ def __check_inputs(self):
815818
% self.__config.mask_method
816819
)
817820

818-
if self.__config.conditional and self.__config.precip_threshold is None:
821+
if self.__config.conditional and self.__params.precip_threshold is None:
819822
raise ValueError("conditional=True but precip_thr is not set")
820823

821824
if (
822825
self.__config.mask_method is not None
823-
and self.__config.precip_threshold is None
826+
and self.__params.precip_threshold is None
824827
):
825828
raise ValueError("mask_method!=None but precip_thr=None")
826829

@@ -931,7 +934,7 @@ def __print_forecast_info(self):
931934
) = (None, None)
932935

933936
if self.__config.conditional or self.__config.mask_method is not None:
934-
print(f"precip. intensity threshold: {self.__config.precip_threshold}")
937+
print(f"precip. intensity threshold: {self.__params.precip_threshold}")
935938
print(f"no-rain fraction threshold for radar: {self.__config.norain_threshold}")
936939
print("")
937940

@@ -994,7 +997,7 @@ def __prepare_radar_and_NWP_fields(self):
994997
# TODO: is this logical_and correct here? Now only those places where precip is in all images is saved?
995998
self.__params.mask_threshold = np.logical_and.reduce(
996999
[
997-
self.__precip[i, :, :] >= self.__config.precip_threshold
1000+
self.__precip[i, :, :] >= self.__params.precip_threshold
9981001
for i in range(self.__precip.shape[0])
9991002
]
10001003
)
@@ -1098,15 +1101,15 @@ def transform_to_lagrangian(precip, i):
10981101
# Check for zero input fields in the radar and NWP data.
10991102
self.__params.zero_precip_radar = check_norain(
11001103
self.__precip,
1101-
self.__config.precip_threshold,
1104+
self.__params.precip_threshold,
11021105
self.__config.norain_threshold,
11031106
self.__params.noise_kwargs["win_fun"],
11041107
)
11051108
# The norain fraction threshold used for nwp is the default value of 0.0,
11061109
# since nwp does not suffer from clutter.
11071110
self.__params.zero_precip_model_fields = check_norain(
11081111
self.__precip_models,
1109-
self.__config.precip_threshold,
1112+
self.__params.precip_threshold,
11101113
self.__config.norain_threshold,
11111114
self.__params.noise_kwargs["win_fun"],
11121115
)
@@ -1173,43 +1176,6 @@ def __prepare_nowcast_for_zero_radar(self):
11731176
updates the cascade with NWP data, uses the NWP velocity field, and
11741177
initializes the noise model based on the time step with the most rain.
11751178
"""
1176-
# If zero_precip_radar, make sure that precip_cascade does not contain
1177-
# only nans or infs. If so, fill it with the zero value.
1178-
1179-
# Look for a timestep and member with rain so that we have a sensible decomposition
1180-
done = False
1181-
for t in self.__timesteps:
1182-
if done:
1183-
break
1184-
for j in range(self.__precip_models.shape[0]):
1185-
if not check_norain(
1186-
self.__precip_models[j, t],
1187-
self.__config.precip_threshold,
1188-
self.__config.norain_threshold,
1189-
self.__params.noise_kwargs["win_fun"],
1190-
):
1191-
if self.__state.precip_models_cascades is not None:
1192-
self.__state.precip_cascades[
1193-
~np.isfinite(self.__state.precip_cascades)
1194-
] = np.nanmin(
1195-
self.__state.precip_models_cascades[j, t]["cascade_levels"]
1196-
)
1197-
continue
1198-
precip_models_cascade_timestep = self.__params.decomposition_method(
1199-
self.__precip_models[j, t, :, :],
1200-
bp_filter=self.__params.bandpass_filter,
1201-
fft_method=self.__params.fft,
1202-
output_domain=self.__config.domain,
1203-
normalize=True,
1204-
compute_stats=True,
1205-
compact_output=True,
1206-
)["cascade_levels"]
1207-
self.__state.precip_cascades[
1208-
~np.isfinite(self.__state.precip_cascades)
1209-
] = np.nanmin(precip_models_cascade_timestep)
1210-
done = True
1211-
break
1212-
12131179
# If zero_precip_radar is True, only use the velocity field of the NWP
12141180
# forecast. I.e., velocity (radar) equals velocity_model at the first time
12151181
# step.
@@ -1227,16 +1193,16 @@ def __prepare_nowcast_for_zero_radar(self):
12271193
# might be zero as well). Else, initialize the noise with the radar
12281194
# rainfall data
12291195
# Initialize noise based on the NWP field time step where the fraction of rainy cells is highest
1230-
if self.__config.precip_threshold is None:
1231-
self.__config.precip_threshold = np.nanmin(self.__precip_models)
1196+
if self.__params.precip_threshold is None:
1197+
self.__params.precip_threshold = np.nanmin(self.__precip_models)
12321198

12331199
max_rain_pixels = -1
12341200
max_rain_pixels_j = -1
12351201
max_rain_pixels_t = -1
12361202
for j in range(self.__precip_models.shape[0]):
12371203
for t in self.__timesteps:
12381204
rain_pixels = self.__precip_models[j][t][
1239-
self.__precip_models[j][t] > self.__config.precip_threshold
1205+
self.__precip_models[j][t] > self.__params.precip_threshold
12401206
].size
12411207
if rain_pixels > max_rain_pixels:
12421208
max_rain_pixels = rain_pixels
@@ -1249,6 +1215,30 @@ def __prepare_nowcast_for_zero_radar(self):
12491215
np.float64, copy=False
12501216
)
12511217

1218+
# If zero_precip_radar, make sure that precip_cascade does not contain
1219+
# only nans or infs. If so, fill it with the zero value.
1220+
if self.__state.precip_models_cascades is not None:
1221+
self.__state.precip_cascades[~np.isfinite(self.__state.precip_cascades)] = (
1222+
np.nanmin(
1223+
self.__state.precip_models_cascades[
1224+
max_rain_pixels_j, max_rain_pixels_t
1225+
]["cascade_levels"]
1226+
)
1227+
)
1228+
else:
1229+
precip_models_cascade_timestep = self.__params.decomposition_method(
1230+
self.__precip_models[max_rain_pixels_j, max_rain_pixels_t, :, :],
1231+
bp_filter=self.__params.bandpass_filter,
1232+
fft_method=self.__params.fft,
1233+
output_domain=self.__config.domain,
1234+
normalize=True,
1235+
compute_stats=True,
1236+
compact_output=True,
1237+
)["cascade_levels"]
1238+
self.__state.precip_cascades[~np.isfinite(self.__state.precip_cascades)] = (
1239+
np.nanmin(precip_models_cascade_timestep)
1240+
)
1241+
12521242
# Make sure precip_noise_input is three-dimensional
12531243
if len(self.__state.precip_noise_input.shape) != 3:
12541244
self.__state.precip_noise_input = self.__state.precip_noise_input[
@@ -1281,7 +1271,7 @@ def __initialize_noise(self):
12811271
precip_forecast_min = np.min(self.__state.precip_noise_input)
12821272
self.__params.noise_std_coeffs = noise.utils.compute_noise_stddev_adjs(
12831273
self.__state.precip_noise_input[-1, :, :],
1284-
self.__config.precip_threshold,
1274+
self.__params.precip_threshold,
12851275
precip_forecast_min,
12861276
self.__params.bandpass_filter,
12871277
self.__params.decomposition_method,
@@ -2687,7 +2677,7 @@ def __post_process_output(
26872677
# steps, the buffer mask keeps increasing.
26882678
precip_field_mask = (
26892679
precip_forecast_probability_matching_blended
2690-
>= self.__config.precip_threshold
2680+
>= self.__params.precip_threshold
26912681
)
26922682

26932683
# Buffer the mask
@@ -2731,7 +2721,7 @@ def __post_process_output(
27312721
# rainfall field
27322722
precip_field_mask_temp = (
27332723
precip_forecast_probability_matching_blended
2734-
>= self.__config.precip_threshold
2724+
>= self.__params.precip_threshold
27352725
)
27362726

27372727
# Set to min value outside of mask
@@ -2789,12 +2779,12 @@ def __post_process_output(
27892779
mean_probabiltity_matching_forecast = np.mean(
27902780
precip_forecast_probability_matching_resampled[
27912781
precip_forecast_probability_matching_resampled
2792-
>= self.__config.precip_threshold
2782+
>= self.__params.precip_threshold
27932783
]
27942784
)
27952785
no_rain_mask = (
27962786
worker_state.final_blended_forecast_recomposed
2797-
>= self.__config.precip_threshold
2787+
>= self.__params.precip_threshold
27982788
)
27992789
mean_precip_forecast = np.mean(
28002790
worker_state.final_blended_forecast_recomposed[no_rain_mask]

0 commit comments

Comments
 (0)