Source code for pycif.plugins.domains.gridded_NetCDF.utils
from logging import debug
from typing import Union
import numpy as np
import xarray as xr
[docs]
def get_bounds(
ds: xr.Dataset,
coord_name: str,
flip_coord: bool,
min_bound: float,
max_bound: float,
regular_extent: bool
) -> np.ndarray:
"""Get the bounds of a given coordinates.
"""
bounds_name = ds[coord_name].attrs.get('bounds')
# TODO: detect if coord dimensions == (N, 2) (-> in this bounds_name = coord_name)
bounds = None
if bounds_name is None:
shape = ds[coord_name].shape
if len(shape) == 2 and shape[1] == 2:
bounds_name = coord_name
if bounds_name is not None:
bounds = ds[bounds_name].values
bounds = np.concatenate([bounds[:, 0], bounds[-1:, 1]])
bounds = np.flip(bounds) if flip_coord else bounds
return bounds
else:
debug(f"no bounds found for coordinate '{coord_name}', "
f"assuming '{coord_name}' represents the cell centers")
coord = ds[coord_name].values
coord = np.flip(coord) if flip_coord else coord
delta = np.unique(np.round(np.diff(coord), 10))
if len(delta) == 1:
bounds = coord - delta[0] / 2
return np.concatenate(
[[max(bounds[0], min_bound)],
bounds[1:],
[min(bounds[-1] + delta[0], max_bound)]
]
)
elif len(delta) != 1 and regular_extent:
raise ValueError(
f"'{coord_name}' coordinate is not regular.\n"
"If the coordinate is not expected to be regular, please specify the corresponding "
"argument in the yaml: `regular_XXXX: False`\n"
f"Otherwise, the list of possible deltas is: {delta}.\n"
"If all delta are very similar apart from rounding difference, "
"it is possible to force a constant delta by using the parameter "
"'delta_XXXX' in the yml. Please check the documentation for "
"the domain plugin 'gridded_netcdf/std'"
)
else:
bounds = np.concatenate([
coord[[0]] - np.diff(coord)[0] / 2,
coord[1:] - np.diff(coord) / 2,
coord[[-1]] + np.diff(coord)[-1] / 2
])
return bounds
[docs]
def get_centers(coord: np.ndarray, flip_coord: bool) -> np.ndarray:
coord = np.flip(coord) if flip_coord else coord
center = coord[:-1] + np.diff(coord) / 2
return center
[docs]
def find_coord(
ds: Union[xr.Dataset, xr.DataArray],
name: str,
coord_name: str = None
) -> str:
"""Find a variable or coordinate name in a dataset based on its 'long_name'
or 'standard_name' attribute.
"""
all_keys = [*ds, *ds.coords, *ds.dims] if isinstance(ds, xr.Dataset) \
else [*ds.coords, *ds.dims]
# Search in coordinates and variables
for var_name in all_keys:
if len(ds[var_name].shape) > 1:
continue
if name == ds[var_name].attrs.get('standard_name'):
return var_name
elif name == ds[var_name].attrs.get('long_name'):
return var_name
elif name == var_name:
return name
if coord_name in all_keys:
return coord_name
raise ValueError("there is no variable or coordinate corresponding to "
f"'{name}' or '{coord_name}' in the dataset")