Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion test/core/test_dataarray.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import numpy as np
import uxarray as ux
from uxarray.errors import DimensionError
from uxarray.grid.geometry import _build_polygon_shells, _build_corrected_polygon_shells
from uxarray.core.dataset import UxDataset, UxDataArray
import pytest
Expand Down Expand Up @@ -124,7 +125,7 @@ def test_isel_invalid_dim(gridpath, datasetpath):
uxda = UxDataArray(data, dims=["time", "n_face"], uxgrid=uxds.uxgrid)

with pytest.raises(
ValueError,
DimensionError,
match=r"Dimensions \{'invalid_dim'\} do not exist\..*Available dimensions: \('time', 'n_face'\)",
):
uxda.isel(invalid_dim=0)
Expand Down
3 changes: 2 additions & 1 deletion test/grid/integrate/test_zonal.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import uxarray as ux
from uxarray.constants import ERROR_TOLERANCE
from uxarray.errors import DataCenteringError

class TestZonalCSne30:

Expand Down Expand Up @@ -380,7 +381,7 @@ def test_non_face_centered_raises(self, gridpath, datasetpath):
uxda = ux.UxDataArray(
np.zeros(uxgrid.n_node), dims=["n_node"], uxgrid=uxgrid
)
with pytest.raises(ValueError, match="face-centered"):
with pytest.raises(DataCenteringError, match="face-centered"):
uxda.zonal_anomaly()

def test_invalid_lat_input_raises(self):
Expand Down
3 changes: 2 additions & 1 deletion test/test_remap_yac.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import pytest

import uxarray as ux
from uxarray.remap.yac import YacNotAvailableError, _import_yac
from uxarray.errors import YacNotAvailableError
from uxarray.remap.yac import _import_yac


try:
Expand Down
9 changes: 5 additions & 4 deletions uxarray/core/aggregation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import numpy as np

import uxarray.core.dataarray
from uxarray.errors import DataCenteringError
from uxarray.grid.connectivity import get_face_node_partitions

NUMPY_AGGREGATIONS = {
Expand Down Expand Up @@ -32,7 +33,7 @@ def _uxda_grid_aggregate(uxda, destination, aggregation, **kwargs):
elif destination == "edge":
return _node_to_edge_aggregation(uxda, aggregation, kwargs)
else:
raise ValueError(
raise DataCenteringError(
f"Invalid destination for a node-centered data variable. Expected"
f"one of ['face', 'edge' but received {destination}"
)
Expand Down Expand Up @@ -62,7 +63,7 @@ def _uxda_grid_aggregate(uxda, destination, aggregation, **kwargs):
# raise ValueError("TODO: ")

else:
raise ValueError(
raise DataCenteringError(
"Invalid data mapping. Data variable is expected to be mapped to either the "
"nodes, faces, or edges of the source grid."
)
Expand All @@ -73,7 +74,7 @@ def _node_to_face_aggregation(uxda, aggregation, aggregation_func_kwargs):
import dask.array as da

if not uxda._node_centered():
raise ValueError(
raise DataCenteringError(
f"Data Variable must be mapped to the corner nodes of each face, with dimension "
f"{uxda.uxgrid.n_face}."
)
Expand Down Expand Up @@ -141,7 +142,7 @@ def _node_to_edge_aggregation(uxda, aggregation, aggregation_func_kwargs):
import dask.array as da

if not uxda._node_centered():
raise ValueError(
raise DataCenteringError(
f"Data Variable must be mapped to the corner nodes of each face, with dimension "
f"{uxda.uxgrid.n_face}."
)
Expand Down
3 changes: 2 additions & 1 deletion uxarray/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
_open_dataset_with_fallback,
match_chunks_to_ugrid,
)
from uxarray.errors import GridInvalidError
from uxarray.grid import Grid
from uxarray.io._scrip import (
_detect_multigrid,
Expand Down Expand Up @@ -248,7 +249,7 @@ def _active_mask_values_for_grid(grid_name: str) -> np.ndarray:
}

if not grids_dict:
raise ValueError(f"No grids detected in file: {grid_filename_or_obj}")
raise GridInvalidError(f"No grids detected in file: {grid_filename_or_obj}")

available_grids = list(grids_dict.keys())

Expand Down
73 changes: 39 additions & 34 deletions uxarray/core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
_compute_zonal_anomaly,
)
from uxarray.cross_sections import UxDataArrayCrossSectionAccessor
from uxarray.errors import DataCenteringError, DimensionError, GridsMismatchError
from uxarray.formatting_html import array_repr
from uxarray.grid import Grid
from uxarray.grid.dual import construct_dual
Expand Down Expand Up @@ -247,7 +248,7 @@ def to_geodataframe(

if self.values.ndim > 1:
# data is multidimensional, must be a 1D slice
raise ValueError(
raise DimensionError(
f"Data Variable must be 1-dimensional, with shape {self.uxgrid.n_face} "
f"for face-centered data."
)
Expand Down Expand Up @@ -290,19 +291,19 @@ def to_geodataframe(
gdf[var_name] = _data

elif self.values.size == self.uxgrid.n_node:
raise ValueError(
raise DataCenteringError(
f"Data Variable with size {self.values.size} does not match the number of faces "
f"({self.uxgrid.n_face}. Current size matches the number of nodes. Consider running "
f"``UxDataArray.topological_mean(destination='face') to aggregate the data onto the faces."
)
elif self.values.size == self.uxgrid.n_edge:
raise ValueError(
raise DataCenteringError(
f"Data Variable with size {self.values.size} does not match the number of faces "
f"({self.uxgrid.n_face}. Current size matches the number of edges."
)
else:
# data is not mapped to
raise ValueError(
raise DimensionError(
f"Data Variable with size {self.values.size} does not match the number of faces "
f"({self.uxgrid.n_face}."
)
Expand Down Expand Up @@ -340,7 +341,7 @@ def to_polycollection(
"""
# data is multidimensional, must be a 1D slice
if self.values.ndim > 1:
raise ValueError(
raise DimensionError(
f"Data Variable must be 1-dimensional, with shape {self.uxgrid.n_face} "
f"for face-centered data."
)
Expand Down Expand Up @@ -391,7 +392,7 @@ def to_polycollection(
else:
return poly_collection
else:
raise ValueError("Data variable must be face centered.")
raise DataCenteringError("Data variable must be face centered.")

def to_raster(
self,
Expand Down Expand Up @@ -616,13 +617,17 @@ def integrate(
integral = np.einsum("i,...i", face_areas, self.values)

elif self.values.shape[-1] == self.uxgrid.n_node:
raise ValueError("Integrating data mapped to each node not yet supported.")
raise DataCenteringError(
"Integrating data mapped to each node not yet supported."
)

elif self.values.shape[-1] == self.uxgrid.n_edge:
raise ValueError("Integrating data mapped to each edge not yet supported.")
raise DataCenteringError(
"Integrating data mapped to each edge not yet supported."
)

else:
raise ValueError(
raise DimensionError(
f"The final dimension of the data variable does not match the number of nodes, edges, "
f"or faces. Expected one of "
f"{self.uxgrid.n_node}, {self.uxgrid.n_edge}, or {self.uxgrid.n_face}, "
Expand Down Expand Up @@ -684,7 +689,7 @@ def zonal_mean(self, lat=(-90, 90, 10), conservative: bool = False, **kwargs):
physical analysis. Non-conservative averaging samples at latitude lines.
"""
if not self._face_centered():
raise ValueError(
raise DataCenteringError(
"Zonal mean computations are currently only supported for face-centered data variables."
)

Expand Down Expand Up @@ -765,7 +770,7 @@ def zonal_mean(self, lat=(-90, 90, 10), conservative: bool = False, **kwargs):
)

if edges.ndim != 1 or edges.size < 2:
raise ValueError("Band edges must be 1D with at least two values")
raise DimensionError("Band edges must be 1D with at least two values")

res = _compute_conservative_zonal_mean_bands(self, edges)

Expand Down Expand Up @@ -832,7 +837,7 @@ def zonal_anomaly(self, lat=(-90, 90, 10), conservative: bool = False):
>>> uxds["var"].zonal_anomaly(lat=(-60, 60, 5), conservative=True)
"""
if not self._face_centered():
raise ValueError(
raise DataCenteringError(
"Zonal anomaly is only supported for face-centered data variables."
)

Expand All @@ -851,7 +856,7 @@ def zonal_anomaly(self, lat=(-90, 90, 10), conservative: bool = False):
)

if edges.ndim != 1 or edges.size < 2:
raise ValueError("Band edges must be 1D with at least two values.")
raise DimensionError("Band edges must be 1D with at least two values.")

res = _compute_zonal_anomaly(self, edges, conservative=conservative)

Expand Down Expand Up @@ -911,7 +916,7 @@ def azimuthal_mean(
from uxarray.grid.coordinates import _lonlat_rad_to_xyz

if not self._face_centered():
raise ValueError(
raise DataCenteringError(
"Azimuthal mean computations are currently only supported for face-centered data variables."
)

Expand Down Expand Up @@ -1630,13 +1635,13 @@ def curl(
raise TypeError("other must be a UxDataArray")

if self.uxgrid != other.uxgrid:
raise ValueError("Both vector components must be on the same grid")
raise GridsMismatchError("Both vector components must be on the same grid")

if self.dims != other.dims:
raise ValueError("Both vector components must have the same dimensions")
raise DimensionError("Both vector components must have the same dimensions")

if len(self.dims) != 1:
raise ValueError(
raise DimensionError(
"Curl computation currently only supports 1-dimensional data. "
"Use .isel() to select a single time slice or level."
)
Expand Down Expand Up @@ -1721,20 +1726,20 @@ def divergence(
raise TypeError("other must be a UxDataArray")

if self.uxgrid != other.uxgrid:
raise ValueError("Both UxDataArrays must have the same grid")
raise GridsMismatchError("Both UxDataArrays must have the same grid")

if self.dims != other.dims:
raise ValueError("Both UxDataArrays must have the same dimensions")
raise DimensionError("Both UxDataArrays must have the same dimensions")

if self.ndim > 1:
raise ValueError(
raise DimensionError(
"Divergence currently requires 1D face-centered data. Consider "
"reducing the dimension by selecting data across leading dimensions (e.g., `.isel(time=0)`, "
"`.sel(lev=500)`, or `.mean('time')`)."
)

if not (self._face_centered() and other._face_centered()):
raise ValueError(
raise DataCenteringError(
"Computing the divergence is only supported for face-centered data variables."
)

Expand Down Expand Up @@ -1801,19 +1806,19 @@ def scalardotgradient(self, v: "UxDataArray", q: "UxDataArray") -> "UxDataArray"
raise TypeError("q must be a UxDataArray")

if self.uxgrid != v.uxgrid or self.uxgrid != q.uxgrid:
raise ValueError("All UxDataArrays must have the same grid")
raise GridsMismatchError("All UxDataArrays must have the same grid")

if self.dims != v.dims or self.dims != q.dims:
raise ValueError("All UxDataArrays must have the same dimensions")
raise DimensionError("All UxDataArrays must have the same dimensions")

if self.ndim > 1:
raise ValueError(
raise DimensionError(
"Scalar dot gradient currently requires 1D face-centered data. "
"Consider selecting a single slice before computing."
)

if not (self._face_centered() and v._face_centered() and q._face_centered()):
raise ValueError(
raise DataCenteringError(
"Computing the scalar dot gradient is only supported for face-centered data variables."
)

Expand Down Expand Up @@ -1876,12 +1881,12 @@ def difference(self, destination: str | None = "edge"):
dims[-1] = "n_edge"
name = f"{var_name}edge_face_difference"
elif destination == "face":
raise ValueError(
raise DataCenteringError(
"Invalid destination 'face' for a face-centered data variable, computing"
"the difference and storing it on each face is not possible"
)
elif destination == "node":
raise ValueError(
raise DataCenteringError(
"Support for computing the difference of a face-centered data variable and storing"
"the result on each node not yet supported."
)
Expand All @@ -1894,13 +1899,13 @@ def difference(self, destination: str | None = "edge"):
dims[-1] = "n_edge"
name = f"{var_name}edge_node_difference"
elif destination == "node":
raise ValueError(
raise DataCenteringError(
"Invalid destination 'node' for a node-centered data variable, computing"
"the difference and storing it on each node is not possible"
)

elif destination == "face":
raise ValueError(
raise DataCenteringError(
"Support for computing the difference of a node-centered data variable and storing"
"the result on each face not yet supported."
)
Expand All @@ -1911,7 +1916,7 @@ def difference(self, destination: str | None = "edge"):
)

else:
raise ValueError("TODO: ")
raise DataCenteringError("TODO: ")

uxda = UxDataArray(
_difference,
Expand Down Expand Up @@ -1983,7 +1988,7 @@ def isel(

Raises
------
ValueError
DimensionError (subclass of ValueError)
If more than one grid dimension is selected and `ignore_grid=False`.
"""
from uxarray.core.utils import _validate_indexers
Expand Down Expand Up @@ -2037,7 +2042,7 @@ def isel(
# e.g. "Dimensions {'level'} do not exist. Expected one of ('n_face', 'time', 'lev')"
# Let's just append the available dimensions.
original_error_msg = str(e)
raise ValueError(
raise DimensionError(
f"{original_error_msg}. Available dimensions: {self.dims}"
) from e
else:
Expand Down Expand Up @@ -2102,7 +2107,7 @@ def from_healpix(
raise ValueError("`da` must be a xr.DataArray")

if face_dim not in da.dims:
raise ValueError(
raise DimensionError(
f"The provided face dimension '{face_dim}' is present in the provided healpix data array."
f"Please set 'face_dim' to the dimension corresponding to the healpix face dimension."
)
Expand Down Expand Up @@ -2136,7 +2141,7 @@ def _slice_from_grid(self, sliced_grid):
)

else:
raise ValueError(
raise DataCenteringError(
"Data variable must be either node, edge, or face centered."
)

Expand Down
3 changes: 2 additions & 1 deletion uxarray/core/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import uxarray
from uxarray.core.dataarray import UxDataArray
from uxarray.core.utils import _map_dims_to_ugrid, _open_dataset_with_fallback
from uxarray.errors import DimensionError
from uxarray.formatting_html import dataset_repr
from uxarray.grid import Grid
from uxarray.grid.dual import construct_dual
Expand Down Expand Up @@ -347,7 +348,7 @@ def from_healpix(
ds = _open_dataset_with_fallback(ds, **kwargs)

if face_dim not in ds.dims:
raise ValueError(
raise DimensionError(
f"The provided face dimension '{face_dim}' is not present in the provided healpix dataset."
f"Please set 'face_dim' to the dimension corresponding to the healpix face dimension."
)
Expand Down
Loading