diff --git a/CHANGELOG.md b/CHANGELOG.md index 4036bc4..2ceb99f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - consider full time information for derived calculation of TOA radiation [\#84](https://github.com/mllam/mllam-data-prep/pull/84) @observingClouds ### Fixes +- fix `crop_with_convex_hull` crash when `margin_thickness == 0.0` caused by not unpacking the tuple returned by `create_convex_hull_mask` [\#99](https://github.com/mllam/mllam-data-prep/issues/99) @RajdeepKushwaha5 - fix bug where coordinate selection of an unshared dimension isn't applied to subsequent ouput variables when an output variable without this dimension is processed before the others [\#90](https://github.com/mllam/mllam-data-prep/pull/90) @zweihuehner & @leifdenby ## [v0.7.0](https://github.com/mllam/mllam-data-prep/release/tag/v0.7.0) diff --git a/mllam_data_prep/ops/cropping.py b/mllam_data_prep/ops/cropping.py index 213215d..e0d0f0d 100644 --- a/mllam_data_prep/ops/cropping.py +++ b/mllam_data_prep/ops/cropping.py @@ -28,7 +28,7 @@ def _get_latlon_coords(da: xr.DataArray) -> tuple: raise Exception("Could not find lat/lon coordinates in DataArray.") -def create_convex_hull_mask(ds: xr.Dataset, ds_reference: xr.Dataset) -> xr.DataArray: +def create_convex_hull_mask(ds: xr.Dataset, ds_reference: xr.Dataset) -> Tuple[xr.DataArray, xr.Dataset]: """ Create a grid-point mask for lat/lon coordinates in `da` indicating which points are interior to the convex hull of the lat/lon coordinates of @@ -334,9 +334,9 @@ def crop_with_convex_hull( if margin_thickness == 0.0: if not include_interior_points: raise Exception( - "With no margin and exclude_interior=False, all points would be excluded." + "With no margin and include_interior_points=False, all points would be excluded." ) - da_mask = create_convex_hull_mask(ds=ds, ds_reference=ds_reference) + da_mask, _ = create_convex_hull_mask(ds=ds, ds_reference=ds_reference) else: da_min_dist_to_ref, da_ch_mask = distance_to_convex_hull_boundary( ds, diff --git a/tests/test_convex_hull_cropping.py b/tests/test_convex_hull_cropping.py index d9d3042..537ebc9 100644 --- a/tests/test_convex_hull_cropping.py +++ b/tests/test_convex_hull_cropping.py @@ -4,6 +4,7 @@ import numpy as np import pytest +import xarray as xr import mllam_data_prep as mdp import mllam_data_prep.config as mdp_config @@ -208,3 +209,63 @@ def test_crop_era5_with_generated_lam_domain(): assert var in ds_cropped.data_vars for coord in ds_uncropped[var].coords: assert coord in ds_cropped[var].coords + + +def test_crop_with_zero_margin_thickness(): + """ + Regression test for https://github.com/mllam/mllam-data-prep/issues/99 + crop_with_convex_hull should work when margin_thickness=0.0 with + include_interior_points=True, returning only the interior points. + """ + tmpdir = tempfile.TemporaryDirectory() + domain_size = 500 * 1.0e3 + N = 50 + config_lam = testdata.create_input_datasets_and_config( + identifier="lam", + data_categories=["state"], + tmpdir=tmpdir, + xlim=[-domain_size / 2.0, domain_size / 2.0], + ylim=[-domain_size / 2.0, domain_size / 2.0], + nx=N, + ny=N, + add_latlon=True, + ) + config_global = testdata.create_input_datasets_and_config( + identifier="global", + data_categories=["state"], + tmpdir=tmpdir, + xlim=[-domain_size, domain_size], + ylim=[-domain_size, domain_size], + nx=N // 2, + ny=N // 2, + add_latlon=True, + ) + + ds_lam = mdp.create_dataset(config=config_lam) + ds_global = mdp.create_dataset(config=config_global) + + # this previously crashed with AttributeError: 'tuple' object has no + # attribute 'dims' because create_convex_hull_mask returns a tuple + ds_cropped = cropping.crop_with_convex_hull( + ds=ds_global, + ds_reference=ds_lam, + margin_thickness=0.0, + include_interior_points=True, + ) + + assert isinstance(ds_cropped, xr.Dataset) + # with zero margin and interior points included, the result should have + # fewer points than the full global domain + assert ds_cropped.grid_index.size < ds_global.grid_index.size + assert ds_cropped.grid_index.size > 0 + + # also test the return_mask path + _, da_mask = cropping.crop_with_convex_hull( + ds=ds_global, + ds_reference=ds_lam, + margin_thickness=0.0, + include_interior_points=True, + return_mask=True, + ) + assert isinstance(da_mask, xr.DataArray) + assert da_mask.dtype == bool