-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathaccessor.py
More file actions
202 lines (164 loc) · 6.15 KB
/
accessor.py
File metadata and controls
202 lines (164 loc) · 6.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import warnings
from typing import TYPE_CHECKING
# from typing import Optional, Union
import numpy as np
import xarray as xr
from xarray_subset_grid.grid import Grid
from xarray_subset_grid.grids import (
FVCOMGrid,
RegularGrid,
# @D version doesn't appear to be different ??
# RegularGrid2d,
SELFEGrid,
SGrid,
UGrid,
)
if TYPE_CHECKING:
from xarray.core.coordinates import DatasetCoordinates
_grid_impls = [
FVCOMGrid,
SELFEGrid,
UGrid,
SGrid,
# RegularGrid2d,
RegularGrid,
]
def register_grid_impl(grid_impl: Grid, priority: int = 0):
"""Register a new grid implementation.
:param grid_impl: The grid implementation to register
:param priority: The priority of the implementation. Highest
priority is 0. Default is 0.
"""
_grid_impls.insert(priority, grid_impl)
def grid_factory(ds: xr.Dataset) -> Grid | None:
"""Get the grid implementation for the given dataset.
:param ds: The dataset to get the grid implementation for
:return: The grid implementation or None if no implementation is
found
"""
for grid_impl in _grid_impls:
if grid_impl.recognize(ds):
return grid_impl()
warnings.warn("no grid type found in this dataset")
return None
@xr.register_dataset_accessor("xsg")
class GridDatasetAccessor:
"""Accessor for grid operations on datasets."""
_ds: xr.Dataset
_grid: Grid | None
def __init__(self, ds: xr.Dataset):
"""Create a new grid dataset accessor.
:param ds: The dataset to create the accessor for
"""
self._ds = ds
self._grid = grid_factory(ds)
@property
def grid(self) -> Grid | None:
"""The recognized grid implementation for the given dataset :return:
The grid implementation or None if no implementation is found."""
return self._grid
@property
def data_vars(self) -> set[str]:
"""List of data variables.
These variables exist on the grid and are available to used for
data analysis. These can be discarded when subsetting the
dataset when they are not needed.
"""
if self._grid:
return self._grid.data_vars(self._ds)
return set()
@property
def coords(self) -> "DatasetCoordinates":
return self._ds.coords
@property
def grid_vars(self) -> set[str]:
"""List of grid variables.
These variables are used to define the grid and thus should be
kept when subsetting the dataset
"""
if self._grid:
return self._grid.grid_vars(self._ds)
return set()
@property
def extra_vars(self) -> set[str]:
if self._grid:
return self._grid.extra_vars(self._ds)
return set()
def subset_vars(self, vars: list[str]) -> xr.Dataset:
"""Subset the dataset to the given variables, keeping the grid
variables as well.
:param vars: The variables to keep
:return: The subsetted dataset
"""
if self._grid:
return self._grid.subset_vars(self._ds, vars)
return self._ds
@property
def has_vertical_levels(self) -> bool:
"""Check if the dataset has vertical coordinates."""
if self._grid:
return self._grid.has_vertical_levels(self._ds)
return False
def subset_surface_level(self, method: str | None) -> xr.Dataset:
"""Subset the dataset to the surface level."""
if self._grid:
return self._grid.subset_surface_level(self._ds, method)
return self._ds
def subset_bottom_level(self) -> xr.Dataset:
"""Subset the dataset to the bottom level according to the datasets CF
metadata and available vertical coordinates using nearest neighbor
selection."""
if self._grid:
return self._grid.subset_bottom_level(self._ds)
return self._ds
def subset_top_level(self) -> xr.Dataset:
"""Subset the dataset to the top level according to the datasets CF
metadata and available vertical coordinates using nearest neighbor
selection."""
if self._grid:
return self._grid.subset_top_level(self._ds)
return self._ds
def subset_vertical_level(self, level: float, method: str | None = None) -> xr.Dataset:
"""Subset the dataset to the vertical level.
:param level: The vertical level to subset to
:param method: The method to use for the selection, this is the
same as the method in xarray.Dataset.sel
:return: The subsetted dataset
"""
if self._grid:
return self._grid.subset_vertical_level(self._ds, level, method)
return self._ds
def subset_vertical_levels(
self, levels: tuple[float, float], method: str | None = None
) -> xr.Dataset:
"""Subset the dataset to the vertical level.
:param levels: The vertical levels to subset to
:param method: The method to use for the selection, this is the
same as the method in xarray.Dataset.sel
:return: The subsetted dataset
"""
if self._grid:
return self._grid.subset_vertical_levels(self._ds, levels, method)
return self._ds
def subset_polygon(self, polygon: list[tuple[float, float]] | np.ndarray) -> xr.Dataset | None:
"""Subset the dataset to the grid.
This call is forwarded to the grid implementation with the
loaded dataset.
:param ds: The dataset to subset
:param polygon: The polygon to subset to
:return: The subsetted dataset
"""
if self._grid:
return self._grid.subset_polygon(self._ds, polygon)
return None
def subset_bbox(self, bbox: tuple[float, float, float, float]) -> xr.Dataset | None:
"""Subset the dataset to the bounding box.
This call is forwarded to the grid implementation with the
loaded dataset.
:param ds: The dataset to subset
:param bbox: The bounding box to subset to
:return: The subsetted dataset
"""
if self._grid:
return self._grid.subset_bbox(self._ds, bbox)
return None