Skip to content

Commit 4f9a7eb

Browse files
authored
Regridding to larger grid results in NaNs outside of data range (#33)
* Added mask to replace zeros outside of original data grid with NaNs * Masked regridded regions outside of data range with NaN * Linting fixes * Most common NaN test * Updated CHANGELOG
1 parent 432b847 commit 4f9a7eb

File tree

4 files changed

+70
-0
lines changed

4 files changed

+70
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
88

99
Fixed:
1010
- Ensured all attributes are kept upon regridding (dataset, variable and coordinate attrs).
11+
- Regridding to larger grid now result in NaNs at locations outside of starting data grid.
1112

1213
Changed:
1314
- Moved to the Ruff formatter, instead of black.

src/xarray_regrid/methods/conservative.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,13 @@ def conservative_regrid_dataset(
9090
da_attrs = [da.attrs for da in dataarrays]
9191
coord_attrs = [data[coord].attrs for coord in data_coords]
9292

93+
# track which target coordinate values are not covered by the source grid
94+
uncovered_target_grid = {}
9395
for coord in coords:
96+
uncovered_target_grid[coord] = (coords[coord] <= data[coord].max()) & (
97+
coords[coord] >= data[coord].min()
98+
)
99+
94100
target_coords = coords[coord].to_numpy()
95101
source_coords = data[coord].to_numpy()
96102
weights = get_weights(source_coords, target_coords)
@@ -112,6 +118,10 @@ def conservative_regrid_dataset(
112118
da.attrs = attr
113119
regridded = xr.merge(dataarrays)
114120

121+
# Replace zeros outside of original data grid with NaNs
122+
for coord in coords:
123+
regridded = regridded.where(uncovered_target_grid[coord])
124+
115125
regridded.attrs = attrs
116126

117127
new_coords = [regridded[coord] for coord in data_coords]
@@ -133,6 +143,10 @@ def conservative_regrid_dataarray(
133143
coord_attrs = [data[coord].attrs for coord in data_coords]
134144

135145
for coord in coords:
146+
uncovered_target_grid = (coords[coord] <= data[coord].max()) & (
147+
coords[coord] >= data[coord].min()
148+
)
149+
136150
if coord in data.coords:
137151
target_coords = coords[coord].to_numpy()
138152
source_coords = data[coord].to_numpy()
@@ -150,6 +164,9 @@ def conservative_regrid_dataarray(
150164
data = data.transpose(coord, ...)
151165
data = apply_weights(data, weights, coord, target_coords)
152166

167+
# Replace zeros outside of original data grid with NaNs
168+
data = data.where(uncovered_target_grid)
169+
153170
new_coords = [data[coord] for coord in data_coords]
154171
for coord, attr in zip(new_coords, coord_attrs, strict=True):
155172
coord.attrs = attr

src/xarray_regrid/methods/most_common.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,13 @@ def most_common(data: xr.Dataset, target_ds: xr.Dataset, time_dim: str) -> xr.Da
190190
ds_regrid = ds_regrid.rename({f"{coord}_bins": coord for coord in coords})
191191
for coord in coords:
192192
ds_regrid[coord] = target_ds[coord]
193+
194+
# Replace zeros outside of original data grid with NaNs
195+
uncovered_target_grid = (target_ds[coord] <= data[coord].max()) & (
196+
target_ds[coord] >= data[coord].min()
197+
)
198+
ds_regrid = ds_regrid.where(uncovered_target_grid)
199+
193200
ds_regrid[coord].attrs = coord_attrs[coord]
194201

195202
return ds_regrid.transpose(*dim_order)

tests/test_most_common.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@ def dummy_target_grid():
5151
return create_regridding_dataset(new_grid)
5252

5353

54+
@pytest.fixture
55+
def oversized_dummy_target_grid():
56+
new_grid = Grid(
57+
north=48,
58+
east=48,
59+
south=-8,
60+
west=-8,
61+
resolution_lat=8,
62+
resolution_lon=8,
63+
)
64+
return create_regridding_dataset(new_grid)
65+
66+
5467
def test_most_common(dummy_lc_data, dummy_target_grid):
5568
expected_data = np.array(
5669
[
@@ -81,6 +94,38 @@ def test_most_common(dummy_lc_data, dummy_target_grid):
8194
)
8295

8396

97+
def test_oversized_most_common(dummy_lc_data, oversized_dummy_target_grid):
98+
expected_data = np.array(
99+
[
100+
[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN],
101+
[np.NaN, 2, 2, 0, 0, 0, 0, np.NaN],
102+
[np.NaN, 0, 0, 0, 0, 0, 0, np.NaN],
103+
[np.NaN, 0, 0, 0, 0, 0, 0, np.NaN],
104+
[np.NaN, 0, 0, 0, 0, 0, 0, np.NaN],
105+
[np.NaN, 0, 0, 0, 0, 0, 0, np.NaN],
106+
[np.NaN, 3, 3, 0, 0, 0, 1, np.NaN],
107+
[np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN],
108+
]
109+
)
110+
111+
lat_coords = np.linspace(-8, 48, num=8)
112+
lon_coords = np.linspace(-8, 48, num=8)
113+
114+
expected = xr.Dataset(
115+
data_vars={
116+
"lc": (["longitude", "latitude"], expected_data),
117+
},
118+
coords={
119+
"longitude": (["longitude"], lon_coords),
120+
"latitude": (["latitude"], lat_coords),
121+
},
122+
)
123+
xr.testing.assert_equal(
124+
dummy_lc_data.regrid.most_common(oversized_dummy_target_grid)["lc"],
125+
expected["lc"],
126+
)
127+
128+
84129
def test_attrs_dataarray(dummy_lc_data, dummy_target_grid):
85130
dummy_lc_data["lc"].attrs = {"test": "testing"}
86131
da_regrid = dummy_lc_data["lc"].regrid.most_common(dummy_target_grid)

0 commit comments

Comments
 (0)