Description
In PR #460 the possibility to add a check_norain to a steps nowcast was added, which is very nice!
Currently, however, the check_norain function checks if the entire precip array is above the no_rain threshold or not. This means that when it is given a 3d precip array (time, lat, lon), it can pass the no_rain check, and still fail later on if one of the timesteps contains a zero precip field but the total of all time steps is above the threshold.
Example: the following dummy precip array passes the no_rain check:
import numpy as np
import pysteps
from pysteps import utils
# Create a dummy 3d precip array of which one slice has zero precip
np.random.seed(24)
slice1 = np.random.rand(100, 100)
slice2 = np.random.rand(100, 100)
slice3 = np.random.rand(100, 100)
slice4 = np.zeros((100, 100))
precip_arr = np.stack([slice1, slice2, slice3, slice4], axis=0)
precip_thr = 0.1
norain_thr = 0.03
win_fun = 'tukey'
norain = utils.check_norain.check_norain(precip_arr[-3:, :, :], precip_thr, norain_thr, win_fun)
print(norain)
However, if we use this array of shape (4, 100, 100) to compute a motion field and then want to perform the nowcast using the following code:
# First compute the motion field
motion_method = 'LK'
oflow_method = pysteps.motion.get_method(motion_method)
velocity = oflow_method(precip_arr)
nwc_method = pysteps.nowcasts.get_method("steps")
precip_forecast = nwc_method(precip_arr[-3:, :, :],
velocity=velocity,
timesteps=12,
norain_thr=0.03,
precip_thr=0.1,
kmperpixel=1.0,
timestep=5)
the following error is returned pointing to the temporal autocorrelation function
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[3], line 7
4 velocity = oflow_method(precip_arr)
6 nwc_method = pysteps.nowcasts.get_method("steps")
----> 7 precip_forecast = nwc_method(precip_arr[-3:, :, :],
8 velocity=velocity,
9 timesteps=12,
10 norain_thr=0.03,
11 precip_thr=0.1,
12 kmperpixel=1.0,
13 timestep=5)
File ~/.conda/envs/pysteps/lib/python3.10/site-packages/pysteps/nowcasts/steps.py:1533, in forecast(precip, velocity, timesteps, n_ens_members, n_cascade_levels, precip_thr, norain_thr, kmperpixel, timestep, extrap_method, decomp_method, bandpass_filter_method, noise_method, noise_stddev_adj, ar_order, vel_pert_method, conditional, probmatching_method, mask_method, seed, num_workers, fft_method, domain, extrap_kwargs, filter_kwargs, noise_kwargs, vel_pert_kwargs, mask_kwargs, measure_time, callback, return_output)
1529 # Create an instance of the new class with all the provided arguments
1530 nowcaster = StepsNowcaster(
1531 precip, velocity, timesteps, steps_config=nowcaster_config
1532 )
-> 1533 forecast_steps_nowcast = nowcaster.compute_forecast()
1534 nowcaster.reset_states_and_params()
1535 # Call the appropriate methods within the class
File ~/.conda/envs/pysteps/lib/python3.10/site-packages/pysteps/nowcasts/steps.py:377, in StepsNowcaster.compute_forecast(self)
366 return zero_precipitation_forecast(
367 self.__config.n_ens_members,
368 self.__time_steps,
(...)
373 self.__start_time_init,
374 )
376 self.__perform_extrapolation()
--> 377 self.__apply_noise_and_ar_model()
378 self.__initialize_velocity_perturbations()
379 self.__initialize_precipitation_mask()
File ~/.conda/envs/pysteps/lib/python3.10/site-packages/pysteps/nowcasts/steps.py:832, in StepsNowcaster.__apply_noise_and_ar_model(self)
827 self.__params.autocorrelation_coefficients = np.empty(
828 (self.__config.n_cascade_levels, self.__config.ar_order)
829 )
830 for i in range(self.__config.n_cascade_levels):
831 self.__params.autocorrelation_coefficients[i, :] = (
--> 832 correlation.temporal_autocorrelation(
833 self.__state.precip_cascades[i], mask=self.__state.mask_threshold
834 )
835 )
837 nowcast_utils.print_corrcoefs(self.__params.autocorrelation_coefficients)
839 # Adjust the lag-2 correlation coefficient if AR(2) model is used
File ~/.conda/envs/pysteps/lib/python3.10/site-packages/pysteps/timeseries/correlation.py:107, in temporal_autocorrelation(x, d, domain, x_shape, mask, use_full_fft, window, window_radius)
102 raise ValueError(
103 "dimension mismatch between x and mask: x.shape[1:]=%s, mask.shape=%s"
104 % (str(x.shape[1:]), str(mask.shape))
105 )
106 if np.any(~np.isfinite(x)):
--> 107 raise ValueError("x contains non-finite values")
109 if d == 1:
110 x = np.diff(x, axis=0)
ValueError: x contains non-finite values
To fix this we could modify the check_norain function slightly like:
if win_fun is not None:
tapering = utils.tapering.compute_window_function(
precip_arr.shape[-2], precip_arr.shape[-1], win_fun
)
else:
tapering = np.ones((precip_arr.shape[-2], precip_arr.shape[-1]))
tapering_mask = tapering == 0.0
masked_precip = precip_arr.copy()
masked_precip[..., tapering_mask] = np.nanmin(precip_arr)
if precip_thr is None:
precip_thr = np.nanmin(masked_precip)
if precip_arr.ndim == 3:
n_fields = precip_arr.shape[0]
for i in range(n_fields):
precip_field = masked_precip[i]
rain_pixels = precip_field[precip_field > precip_thr]
norain = rain_pixels.size / precip_field.size <= norain_thr
print(
f"Rain fraction in precip_field {i} is: {str(rain_pixels.size / precip_field.size)}, while minimum fraction is {str(norain_thr)}"
)
if norain == True:
# all fields should be False, if any is True return True
return True
elif precip_arr.ndim == 2:
rain_pixels = masked_precip[masked_precip > precip_thr]
norain = rain_pixels.size / masked_precip.size <= norain_thr
print(
f"Rain fraction is: {str(rain_pixels.size / masked_precip.size)}, while minimum fraction is {str(norain_thr)}"
)
return norain
Metadata
Metadata
Assignees
Labels
Type
Projects
Status