Skip to content

[Bug?] ValueError: mask must have the same shape as the latitude/longitudecoordinates, got: mask.shape = (72, 144), lon.shape = (144, 72) #447

@tomvothecoder

Description

@tomvothecoder

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().

  1. In xcdat.create_grid() we add a mask variable with the same shape as the grid being created, (lon, lat) order
  2. xESMF extracts lon and lat then creates a 2D mesh grid using np.meshgrid, which transposes the dimensions
    • Example: lon and lat both have shape (72, 144)
    • Code:
      lon, lat = as_2d_mesh(np.asarray(lon), np.asarray(lat))
  3. xESMF attempts to create the grid using lon, lat, and mask (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:

      xESMF/xesmf/frontend.py

      Lines 161 to 162 in abd266c

      if mask is not None:
      grid = Grid.from_xarray(lon.T, lat.T, periodic=periodic, mask=mask.T)

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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions