Skip to content

Commit 952e590

Browse files
committed
Relax get_bin_datarray checks and allow all NaNs
1 parent 11a34bb commit 952e590

2 files changed

Lines changed: 39 additions & 13 deletions

File tree

gpm/tests/test_utils/test_manipulations.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,12 @@ def test_extract_dataset_below_bin() -> None:
409409
expected_data = np.array([np.nan, np.nan, np.nan, np.nan, 16])
410410
np.testing.assert_allclose(ds_out[var].isel(cross_track=0).data.squeeze(), expected_data)
411411
# - With strict=True, it fails if all bins are the last range gate
412-
with pytest.raises(ValueError):
413-
extract_dataset_below_bin(ds, bins=bins, strict=True)
412+
# with pytest.raises(ValueError):
413+
# extract_dataset_below_bin(ds, bins=bins, strict=True)
414+
ds_out = extract_dataset_below_bin(ds, bins=bins, strict=True)
415+
expected_data = np.array([np.nan, np.nan, np.nan, np.nan, np.nan])
416+
np.testing.assert_allclose(ds_out[var].isel(cross_track=0).data.squeeze(), expected_data)
417+
414418
# - With strict=True and some valid bins (at cross_track_idx=0), it works
415419
ds[bins].data[0] = bin_value
416420
ds_out = extract_dataset_below_bin(ds, bins=bins, strict=True)
@@ -572,8 +576,12 @@ def test_extract_dataset_above_bin() -> None:
572576
expected_data = np.array([0, np.nan, np.nan, np.nan, np.nan])
573577
np.testing.assert_allclose(ds_out[var].isel(cross_track=0).data.squeeze(), expected_data)
574578
# - With strict=True, it fails if all bins are the first range gate
575-
with pytest.raises(ValueError):
576-
extract_dataset_above_bin(ds, bins=bins, strict=True)
579+
# with pytest.raises(ValueError):
580+
# extract_dataset_above_bin(ds, bins=bins, strict=True)
581+
ds_out = extract_dataset_above_bin(ds, bins=bins, strict=True)
582+
expected_data = np.array([np.nan, np.nan, np.nan, np.nan, np.nan])
583+
np.testing.assert_allclose(ds_out[var].isel(cross_track=0).data.squeeze(), expected_data)
584+
577585
# - With strict=True and some valid bins (at cross_track_idx=0), it works
578586
ds[bins].data[0] = bin_value
579587
ds_out = extract_dataset_above_bin(ds, bins=bins, strict=True)
@@ -672,15 +680,19 @@ def test_get_bin_dataarray() -> None:
672680
cross_track_size=cross_track_size,
673681
along_track_size=along_track_size,
674682
)
675-
with pytest.raises(ValueError) as excinfo:
676-
get_bin_dataarray(ds, bins="nan_bins")
677-
assert "All range bin indices are NaN" in str(excinfo.value)
683+
da_bin, da_mask = get_bin_dataarray(ds, bins="nan_bins")
684+
assert (da_bin == 5).all().item()
685+
assert da_mask.all().item() # mask is all True
686+
687+
# with pytest.raises(ValueError) as excinfo:
688+
# get_bin_dataarray(ds, bins="nan_bins")
689+
# assert "All range bin indices are NaN" in str(excinfo.value)
678690

679691
# Test mixture of invalid values
680692
ds["nan_bins"].data[0] = range_size + 1
681693
with pytest.raises(ValueError) as excinfo:
682694
get_bin_dataarray(ds, bins="nan_bins")
683-
assert "All range bin indices are invalid" in str(excinfo.value)
695+
assert "Some range bin indices are outside" in str(excinfo.value)
684696

685697

686698
def test_get_height_dataarray():

gpm/utils/manipulations.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,12 @@ def crop_around_valid_data(xr_obj, variable=None):
209209

210210

211211
def get_bin_dataarray(xr_obj, bins, mask_first_bin=False, mask_last_bin=False, fillvalue=None):
212-
"""Get bin xarray.DataArray."""
212+
"""Get bin and mask xarray.DataArray.
213+
214+
The nan or invalid bin index values of the input bin DataArray are replaced with fillvalue.
215+
The output bin DataArray does not have NaN or invalid values anymore !.
216+
The output mask DataArray has True values where input bin values were NaN or invalid.
217+
"""
213218
# Retrieve bins DataArray
214219
da_bin = _get_bin_dataarray(xr_obj, bins=bins)
215220

@@ -272,17 +277,20 @@ def _get_valid_da_bin(xr_obj, da_bin, mask_first_bin=False, mask_last_bin=False,
272277
# Identify bin values outside of available range gates
273278
da_invalid = np.logical_or(da_bin < vmin, da_bin > vmax)
274279
# Raise error if all bin index are nan
275-
if np.all(da_is_nan.data):
276-
raise ValueError("All range bin indices are NaN !")
280+
# if np.all(da_is_nan.data):
281+
# raise ValueError("All range bin indices are NaN !")
277282
# Raise error if all bin index are outside the available range bins
278283
if np.all(da_invalid.data):
279284
raise ValueError(f"All range bin indices are outside of the available range gates [{vmin}, {vmax}] !")
285+
# Raise error if any bin index is outside the available range bins
286+
if np.any(da_invalid.data):
287+
raise ValueError(f"Some range bin indices are outside of the available range gates [{vmin}, {vmax}] !")
280288
# Define mask with invalid bins
281289
# --> This address np.nan, 0, and out of range values
282290
da_mask = np.logical_or(da_is_nan, da_invalid)
283291
# Raise error if all bin index are outside the available range bins
284-
if np.all(da_mask.data):
285-
raise ValueError("All range bin indices are invalid !")
292+
# if np.all(da_mask.data):
293+
# raise ValueError("All range bin indices are invalid !")
286294
# Set invalid/ nan range bin indices to a fillvalue to enable selection with .sel
287295
# --> With the function defaults, the last range value vmax
288296
# --> The gates with invalid range bin indices will be masked out with da_mask
@@ -621,6 +629,12 @@ def get_height_at_bin(xr_obj, bins):
621629
da_height = get_height_dataarray(xr_obj)
622630
# Retrieve bins DataArray
623631
da_bins = _get_bin_dataarray(xr_obj, bins)
632+
# da_bins, da_mask = get_bin_dataarray(xr_obj, bins)
633+
634+
# Return NaN field if all NaN
635+
# - Useful when analyzing single profile and a bin variable is NaN
636+
if np.isnan(da_bins).all():
637+
return xr.ones_like(da_bins).rename("height") * np.nan
624638
# Return height
625639
return slice_range_at_bin(xr_obj=da_height, bins=da_bins)
626640

0 commit comments

Comments
 (0)