-
Notifications
You must be signed in to change notification settings - Fork 37
Open
Description
What happened?
Hello, I think I found a bug in xESMF when a mask variable is present in the ds_out passed to xe.Regridder().
- In
xcdat.create_grid()we add amaskvariable with the same shape as the grid being created, (lon, lat) order- Example:
maskhas a shape of(lon: 144, lat: 72) - Code: https://github.com/xCDAT/xcdat/blob/58dac7246be1fefbe22c382c746bf73f2418bbb9/xcdat/regridder/grid.py#L533
- Example:
- xESMF extracts
lonandlatthen creates a 2D mesh grid usingnp.meshgrid, which transposes the dimensions- Example:
lonandlatboth have shape(72, 144) - Code:
Line 153 in abd266c
lon, lat = as_2d_mesh(np.asarray(lon), np.asarray(lat))
- Example:
- xESMF attempts to create the grid using
lon,lat, andmask(transposed again), but the shapes don't align resulting in the error:ValueError: mask must have the same shape as the latitude/longitudecoordinates, got: mask.shape = (72, 144), lon.shape = (144, 72)- Code:
Lines 161 to 162 in abd266c
if mask is not None: grid = Grid.from_xarray(lon.T, lat.T, periodic=periodic, mask=mask.T)
- Code:
Minimal Complete Verifiable Example (MVCE)
Input data for the following minimal code: cmip5.ACCESS1-0.historical.r1i1p1.mo.pr.ver-1.1981-2005.interpolated.regrid2.global.AC.nc.zip
import xcdat as xc
ncfile = "cmip5.ACCESS1-0.historical.r1i1p1.mo.pr.ver-1.1981-2005.interpolated.regrid2.global.AC.nc"
ds = xc.open_dataset(ncfile)
# target grid set up
lat1: float = -90.0
lat2: float = 90.0
lon1: float = 0.0
lon2: float = 360.0
target_grid_resolution = "2.5x2.5"
res = target_grid_resolution.split("x")
lat_res = float(res[0])
lon_res = float(res[1])
start_lat = lat1 + lat_res / 2.0
start_lon = lon1 + lon_res / 2.0
end_lat = lat2 - lat_res / 2
end_lon = lon2 - lon_res / 2
t_grid = xc.create_uniform_grid(
start_lat, end_lat, lat_res, start_lon, end_lon, lon_res
)
# regrid
# Note: This calls xe.Regridder
ds_regridded = ds.regridder.horizontal("pr", t_grid, tool="xesmf", method="bilinear")Relevant log output
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[1], [line 51](vscode-notebook-cell:?execution_count=1&line=51)
24 t_grid = xc.create_uniform_grid(
25 start_lat, end_lat, lat_res, start_lon, end_lon, lon_res
26 )
29 # # Create target grid without xcdat
30 # lats = np.arange(start_lat, end_lat + lat_res, lat_res)
31 # lons = np.arange(start_lon, end_lon + lon_res, lon_res)
(...) 49
50 # # regrid
---> [51](vscode-notebook-cell:?execution_count=1&line=51) ds_regridded = ds.regridder.horizontal("pr", t_grid, tool="xesmf", method="bilinear")
File ~/repositories/xCDAT/xcdat/xcdat/regridder/accessor.py:232, in RegridderAccessor.horizontal(self, data_var, output_grid, tool, **options)
230 input_grid = _get_input_grid(self._ds, data_var, ["X", "Y"])
231 regridder = regrid_tool(input_grid, output_grid, **options)
--> [232](https://file+.vscode-resource.vscode-cdn.net/Users/vo13/repositories/xCDAT/xcdat/~/repositories/xCDAT/xcdat/xcdat/regridder/accessor.py:232) output_ds = regridder.horizontal(data_var, self._ds)
234 return output_ds
File ~/repositories/xCDAT/xcdat/xcdat/regridder/xesmf.py:180, in XESMFRegridder.horizontal(self, data_var, ds)
173 # Align output grid dims with input grid dims, self._input_grid is derived from ``ds``.
174 self._output_grid = self._output_grid.transpose(
175 *[x for x in input_da.dims if x in self._output_grid],
176 ...,
177 missing_dims="ignore",
178 )
--> [180](https://file+.vscode-resource.vscode-cdn.net/Users/vo13/repositories/xCDAT/xcdat/~/repositories/xCDAT/xcdat/xcdat/regridder/xesmf.py:180) regridder = xe.Regridder(
181 self._input_grid,
182 self._output_grid,
183 method=self._method,
184 **self._extra_options,
185 )
187 output_da = regridder(input_da, keep_attrs=True)
189 output_ds = xr.Dataset({data_var: output_da}, attrs=ds.attrs)
File /opt/miniconda3/envs/xcdat_784/lib/python3.13/site-packages/xesmf/frontend.py:923, in Regridder.__init__(self, ds_in, ds_out, method, locstream_in, locstream_out, periodic, parallel, **kwargs)
921 grid_out, shape_out, output_dims = ds_to_ESMFlocstream(ds_out)
922 else:
--> [923](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_784/lib/python3.13/site-packages/xesmf/frontend.py:923) grid_out, shape_out, output_dims = ds_to_ESMFgrid(ds_out, need_bounds=need_bounds)
925 # Create the BaseRegridder
926 super().__init__(
927 grid_in,
928 grid_out,
(...) 933 **kwargs,
934 )
File /opt/miniconda3/envs/xcdat_784/lib/python3.13/site-packages/xesmf/frontend.py:162, in ds_to_ESMFgrid(ds, need_bounds, periodic, append)
160 # tranpose the arrays so they become Fortran-ordered
161 if mask is not None:
--> [162](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_784/lib/python3.13/site-packages/xesmf/frontend.py:162) grid = Grid.from_xarray(lon.T, lat.T, periodic=periodic, mask=mask.T)
163 else:
164 grid = Grid.from_xarray(lon.T, lat.T, periodic=periodic, mask=None)
File /opt/miniconda3/envs/xcdat_784/lib/python3.13/site-packages/xesmf/backend.py:138, in Grid.from_xarray(cls, lon, lat, periodic, mask)
136 grid_mask = mask.astype(np.int32)
137 if not (grid_mask.shape == lon.shape):
--> [138](https://file+.vscode-resource.vscode-cdn.net/opt/miniconda3/envs/xcdat_784/lib/python3.13/site-packages/xesmf/backend.py:138) raise ValueError(
139 'mask must have the same shape as the latitude/longitude'
140 'coordinates, got: mask.shape = %s, lon.shape = %s' % (mask.shape, lon.shape)
141 )
142 grid.add_item(ESMF.GridItem.MASK, staggerloc=ESMF.StaggerLoc.CENTER, from_file=False)
143 grid.mask[0][:] = grid_mask
ValueError: mask must have the same shape as the latitude/longitudecoordinates, got: mask.shape = (72, 144), lon.shape = (144, 72)Anything else we need to know?
No response
Environment
Latest xCDAT and xESMF
Metadata
Metadata
Assignees
Labels
No labels