Open scoatsclim opened 2 months ago
I am fairly sure this is due to the order of the vertex. I ran into this problem in another context.
Just dropping some code I used to fix this in a brute force manner (by trying each combination and testing the resulting vertex points).
import itertools
# might be missing some imports
def cmip_bounds_to_xesmf(ds: xr.Dataset, order=None):
# the order is specific to the way I reorganized vertex order in xmip (if not passed we get the stripes in the regridded output!
if not all(var in ds.variables for var in ["lon_b", "lat_b"]):
ds = ds.assign_coords(
lon_b=cf_xarray.bounds_to_vertices(
ds.lon_verticies.load(), bounds_dim="vertex", order=order
),
lat_b=cf_xarray.bounds_to_vertices(
ds.lat_verticies.load(), bounds_dim="vertex", order=order
),
)
return ds
def test_vertex_order(ds):
# pick a point in the southern hemisphere to avoid curving nonsense
p = {"x": slice(20, 22), "y": slice(20, 22)}
ds_p = ds.isel(**p).squeeze()
# get rid of all the unneccesary variables
for var in ds_p.variables:
if (
("lev" in ds_p[var].dims)
or ("time" in ds_p[var].dims)
or (var in ["sub_experiment_label", "variant_label"])
):
ds_p = ds_p.drop_vars(var)
ds_p = cmip_bounds_to_xesmf(
ds_p, order=None
) # woudld be nice if this could automatically get the settings provided to `cmip_bounds_to_xesmf`
ds_p = ds_p.load().transpose(..., "x", "y", "vertex")
if (
not (ds_p.lon_b.diff("x_vertices") > 0).all()
and (ds_p.lat_b.diff("y_vertices") > 0).all()
):
raise ValueError("Test vertices not strictly monotinically increasing")
def reorder_vertex(ds, new_order):
ds_wo_vertex = ds.drop_vars([va for va in ds.variables if 'vertex' in ds[va].dims])
ds_w_vertex = ds.drop_vars([va for va in ds.variables if 'vertex' not in ds[va].dims])
ds_w_vertex_reordered = xr.concat([ds_w_vertex.isel(vertex=i) for i in new_order], dim='vertex')
return xr.merge([ds_w_vertex_reordered, ds_wo_vertex])
def get_order(ds):
order = [0, 1, 2, 3]
all_orders = itertools.permutations(order, len(order))
for new_order in all_orders:
ds_reordered = reorder_vertex(ds, new_order)
try:
test_vertex_order(ds_reordered)
print(f"{new_order=} worked!")
return new_order
except:
pass
from xmip.utils import cmip6_dataset_id
import warnings
def test_and_reorder_vertex(ds):
"""This is an expensive check that tries every possible order of the vertex and confirms
that we get strictly monontonic lon_b/lat_b coordinates for a test point.
"""
new_order = get_order(ds)
if new_order is None:
# drop them, maybe another one works better? This is a nightmare TBH.
ds_out = ds.drop_vars([va for va in ds.variables if 'vertex' in ds[va].dims])
print(f"Unable to find a vertex order for {cmip6_dataset_id(ds)}")
# raise ValueError(f"Unable to find a vertex order for {cmip6_dataset_id(ds)}")
else:
print(f"Changing vertex order for {cmip6_dataset_id(ds)}")
ds_out = reorder_vertex(ds, new_order)
return ds_out
This cannot be the most elegant solution, but Ill try to work on this some time soon.
Julius told me he had a solution for this, sorry for the messy code. Thanks!
This code produces a seam in the regridded tos output.