Skip to content

Scalar coordinates may lead to exception when using parallel=True #443

@sol1105

Description

@sol1105

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)

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