-
Notifications
You must be signed in to change notification settings - Fork 37
Description
When a scalar coordinate is defined in the dataset, and cf_xarray recognizes it, building a Regridder with parallel=True will lead to an exception. _init_para_regrid prepares the dataset for parallel regridding and thereby drops certain dimensions, which fails for the scalar coordinate as it is not associated with any dimension.
To fix this one could for example loop over each dimension to be dropped and wrap it in a try/except to have it only remove the dimension when it is safe. Alternatively one could check the coordinates designated for their dimensions to be dropped if they are at all associated with any dimensions. Maybe it also makes sense to make the cf_xarray method ds.cf.drop_dims more robust in that sense.
Exception:
[xesmf/frontend.py) in _init_para_regrid(self, ds_in, ds_out, kwargs)
1093 # Drop unnecessary variables in ds_in to save memory
1094 if not self.sequence_in:
1095 # Drop unnecessary dims
1096 ds_in_dims_drop = set(ds_in.cf.coordinates.keys()).difference(['longitude', 'latitude'])
-> 1097 ds_in = ds_in.cf.drop_dims(ds_in_dims_drop)
ValueError: Dimensions ('vertical',) not found in data dimensions ('time', 'rlat', 'rlon')
Used packages:
- cf_xarray 0.10.6
- xarray 2025.7.1
- xesmf 0.8.10
Example:
import numpy as np
import pandas as pd
import xarray as xr
import xesmf as xe
# Compile Test Dataset (more or less a typical CORDEX dataset)
# Dims
nt = 1
nx = 4
ny = 3
# Coordinates
time = pd.date_range("2000-01-01", periods=nt)
rlat = np.linspace(-2.0, 2.0, ny)
rlon = np.linspace(-3.0, 3.0, nx)
# 2D auxiliary coordinates (lat/lon fields)
lat_2d, lon_2d = np.meshgrid(rlat, rlon, indexing="ij")
lat_2d = 50 + lat_2d
lon_2d = 10 + lon_2d
# Scalar coordinate
height = 2.0 # 2 meters above ground
# Define grid mapping variable for rotated pole
rotated_pole = xr.DataArray(
0,
attrs={
"grid_mapping_name": "rotated_latitude_longitude",
"grid_north_pole_latitude": 39.25,
"grid_north_pole_longitude": -162.0,
"north_pole_grid_longitude": 0.0,
},
)
# Build the Dataset
ds = xr.Dataset(
data_vars={
"var": (
("time", "rlat", "rlon"),
np.random.rand(nt, ny, nx),
{
"coordinates": "lat lon height",
"grid_mapping": "rotated_pole",
"units": "K",
"long_name": "Air temperature at 2m"
}
),
"rotated_pole": rotated_pole
},
coords={
"time": ("time", time, {"standard_name": "time"}),
"rlat": ("rlat", rlat, {"standard_name": "grid_latitude", "units": "degrees"}),
"rlon": ("rlon", rlon, {"standard_name": "grid_longitude", "units": "degrees"}),
"lat": (("rlat", "rlon"), lat_2d, {"standard_name": "latitude", "units": "degrees_north"}),
"lon": (("rlat", "rlon"), lon_2d, {"standard_name": "longitude", "units": "degrees_east"}),
"height": height
},
attrs={}
)
# Add variable attributes to height
# -> cf_xarray will identify height as 'vertical' coordinate
ds.height.attrs = {
"units": "m",
"axis": "Z",
"positive": "up",
"long_name": "height",
"standard_name": "height"
}
# Output dataset (chunked)
ds_out = xe.util.grid_global(1,1) # global 5 degree grid
mask = np.ones((180,360))
ds_out['mask'] = xr.DataArray(data=mask, dims=("y","x"))
ds_out = ds_out.chunk({"y": 30, "x": 60})
# Parallel regridder
# -> will try to drop a 'vertical' dimension that does not exist
# as 'height' is a scalar coordinate
regridder = xe.Regridder(ds, ds_out, 'bilinear', parallel=True)