anemoi-datasets 0.5.15__py3-none-any.whl → 0.5.17__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- anemoi/datasets/__init__.py +4 -1
- anemoi/datasets/__main__.py +12 -2
- anemoi/datasets/_version.py +9 -4
- anemoi/datasets/commands/cleanup.py +17 -2
- anemoi/datasets/commands/compare.py +18 -2
- anemoi/datasets/commands/copy.py +196 -14
- anemoi/datasets/commands/create.py +50 -7
- anemoi/datasets/commands/finalise-additions.py +17 -2
- anemoi/datasets/commands/finalise.py +17 -2
- anemoi/datasets/commands/init-additions.py +17 -2
- anemoi/datasets/commands/init.py +16 -2
- anemoi/datasets/commands/inspect.py +283 -62
- anemoi/datasets/commands/load-additions.py +16 -2
- anemoi/datasets/commands/load.py +16 -2
- anemoi/datasets/commands/patch.py +17 -2
- anemoi/datasets/commands/publish.py +17 -2
- anemoi/datasets/commands/scan.py +31 -3
- anemoi/datasets/compute/recentre.py +47 -11
- anemoi/datasets/create/__init__.py +612 -85
- anemoi/datasets/create/check.py +142 -20
- anemoi/datasets/create/chunks.py +64 -4
- anemoi/datasets/create/config.py +185 -21
- anemoi/datasets/create/filter.py +50 -0
- anemoi/datasets/create/filters/__init__.py +33 -0
- anemoi/datasets/create/filters/empty.py +37 -0
- anemoi/datasets/create/filters/legacy.py +93 -0
- anemoi/datasets/create/filters/noop.py +37 -0
- anemoi/datasets/create/filters/orog_to_z.py +58 -0
- anemoi/datasets/create/{functions/filters → filters}/pressure_level_relative_humidity_to_specific_humidity.py +33 -10
- anemoi/datasets/create/{functions/filters → filters}/pressure_level_specific_humidity_to_relative_humidity.py +32 -8
- anemoi/datasets/create/filters/rename.py +205 -0
- anemoi/datasets/create/{functions/filters → filters}/rotate_winds.py +43 -28
- anemoi/datasets/create/{functions/filters → filters}/single_level_dewpoint_to_relative_humidity.py +32 -9
- anemoi/datasets/create/{functions/filters → filters}/single_level_relative_humidity_to_dewpoint.py +33 -9
- anemoi/datasets/create/{functions/filters → filters}/single_level_relative_humidity_to_specific_humidity.py +55 -7
- anemoi/datasets/create/{functions/filters → filters}/single_level_specific_humidity_to_relative_humidity.py +98 -37
- anemoi/datasets/create/filters/speeddir_to_uv.py +95 -0
- anemoi/datasets/create/{functions/filters → filters}/sum.py +24 -27
- anemoi/datasets/create/filters/transform.py +53 -0
- anemoi/datasets/create/{functions/filters → filters}/unrotate_winds.py +27 -18
- anemoi/datasets/create/filters/uv_to_speeddir.py +94 -0
- anemoi/datasets/create/{functions/filters → filters}/wz_to_w.py +51 -33
- anemoi/datasets/create/input/__init__.py +76 -5
- anemoi/datasets/create/input/action.py +149 -13
- anemoi/datasets/create/input/concat.py +81 -10
- anemoi/datasets/create/input/context.py +39 -4
- anemoi/datasets/create/input/data_sources.py +72 -6
- anemoi/datasets/create/input/empty.py +21 -3
- anemoi/datasets/create/input/filter.py +60 -12
- anemoi/datasets/create/input/function.py +154 -37
- anemoi/datasets/create/input/join.py +86 -14
- anemoi/datasets/create/input/misc.py +67 -17
- anemoi/datasets/create/input/pipe.py +33 -6
- anemoi/datasets/create/input/repeated_dates.py +189 -41
- anemoi/datasets/create/input/result.py +202 -87
- anemoi/datasets/create/input/step.py +119 -22
- anemoi/datasets/create/input/template.py +100 -13
- anemoi/datasets/create/input/trace.py +62 -7
- anemoi/datasets/create/patch.py +52 -4
- anemoi/datasets/create/persistent.py +134 -17
- anemoi/datasets/create/size.py +15 -1
- anemoi/datasets/create/source.py +51 -0
- anemoi/datasets/create/sources/__init__.py +36 -0
- anemoi/datasets/create/{functions/sources → sources}/accumulations.py +296 -30
- anemoi/datasets/create/{functions/sources → sources}/constants.py +27 -2
- anemoi/datasets/create/{functions/sources → sources}/eccc_fstd.py +7 -3
- anemoi/datasets/create/sources/empty.py +37 -0
- anemoi/datasets/create/{functions/sources → sources}/forcings.py +25 -1
- anemoi/datasets/create/sources/grib.py +297 -0
- anemoi/datasets/create/{functions/sources → sources}/hindcasts.py +38 -4
- anemoi/datasets/create/sources/legacy.py +93 -0
- anemoi/datasets/create/{functions/sources → sources}/mars.py +168 -20
- anemoi/datasets/create/sources/netcdf.py +42 -0
- anemoi/datasets/create/sources/opendap.py +43 -0
- anemoi/datasets/create/{functions/sources/__init__.py → sources/patterns.py} +35 -4
- anemoi/datasets/create/sources/recentre.py +150 -0
- anemoi/datasets/create/{functions/sources → sources}/source.py +27 -5
- anemoi/datasets/create/{functions/sources → sources}/tendencies.py +64 -7
- anemoi/datasets/create/sources/xarray.py +92 -0
- anemoi/datasets/create/sources/xarray_kerchunk.py +36 -0
- anemoi/datasets/create/sources/xarray_support/README.md +1 -0
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/__init__.py +109 -8
- anemoi/datasets/create/sources/xarray_support/coordinates.py +442 -0
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/field.py +94 -16
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/fieldlist.py +90 -25
- anemoi/datasets/create/sources/xarray_support/flavour.py +1036 -0
- anemoi/datasets/create/{functions/sources/xarray → sources/xarray_support}/grid.py +92 -31
- anemoi/datasets/create/sources/xarray_support/metadata.py +395 -0
- anemoi/datasets/create/sources/xarray_support/patch.py +91 -0
- anemoi/datasets/create/sources/xarray_support/time.py +391 -0
- anemoi/datasets/create/sources/xarray_support/variable.py +331 -0
- anemoi/datasets/create/sources/xarray_zarr.py +41 -0
- anemoi/datasets/create/{functions/sources → sources}/zenodo.py +34 -5
- anemoi/datasets/create/statistics/__init__.py +233 -44
- anemoi/datasets/create/statistics/summary.py +52 -6
- anemoi/datasets/create/testing.py +76 -0
- anemoi/datasets/create/{functions/filters/noop.py → typing.py} +6 -3
- anemoi/datasets/create/utils.py +97 -6
- anemoi/datasets/create/writer.py +26 -4
- anemoi/datasets/create/zarr.py +170 -23
- anemoi/datasets/data/__init__.py +51 -4
- anemoi/datasets/data/complement.py +191 -40
- anemoi/datasets/data/concat.py +141 -16
- anemoi/datasets/data/dataset.py +552 -61
- anemoi/datasets/data/debug.py +197 -26
- anemoi/datasets/data/ensemble.py +93 -8
- anemoi/datasets/data/fill_missing.py +165 -18
- anemoi/datasets/data/forwards.py +428 -56
- anemoi/datasets/data/grids.py +323 -97
- anemoi/datasets/data/indexing.py +112 -19
- anemoi/datasets/data/interpolate.py +92 -12
- anemoi/datasets/data/join.py +158 -19
- anemoi/datasets/data/masked.py +129 -15
- anemoi/datasets/data/merge.py +137 -23
- anemoi/datasets/data/misc.py +172 -16
- anemoi/datasets/data/missing.py +233 -29
- anemoi/datasets/data/rescale.py +111 -10
- anemoi/datasets/data/select.py +168 -26
- anemoi/datasets/data/statistics.py +67 -6
- anemoi/datasets/data/stores.py +149 -64
- anemoi/datasets/data/subset.py +159 -25
- anemoi/datasets/data/unchecked.py +168 -57
- anemoi/datasets/data/xy.py +168 -25
- anemoi/datasets/dates/__init__.py +191 -16
- anemoi/datasets/dates/groups.py +189 -47
- anemoi/datasets/grids.py +270 -31
- anemoi/datasets/testing.py +28 -1
- {anemoi_datasets-0.5.15.dist-info → anemoi_datasets-0.5.17.dist-info}/METADATA +10 -7
- anemoi_datasets-0.5.17.dist-info/RECORD +137 -0
- {anemoi_datasets-0.5.15.dist-info → anemoi_datasets-0.5.17.dist-info}/WHEEL +1 -1
- {anemoi_datasets-0.5.15.dist-info → anemoi_datasets-0.5.17.dist-info/licenses}/LICENSE +1 -1
- anemoi/datasets/create/functions/__init__.py +0 -66
- anemoi/datasets/create/functions/filters/__init__.py +0 -9
- anemoi/datasets/create/functions/filters/empty.py +0 -17
- anemoi/datasets/create/functions/filters/orog_to_z.py +0 -58
- anemoi/datasets/create/functions/filters/rename.py +0 -79
- anemoi/datasets/create/functions/filters/speeddir_to_uv.py +0 -78
- anemoi/datasets/create/functions/filters/uv_to_speeddir.py +0 -56
- anemoi/datasets/create/functions/sources/empty.py +0 -15
- anemoi/datasets/create/functions/sources/grib.py +0 -150
- anemoi/datasets/create/functions/sources/netcdf.py +0 -15
- anemoi/datasets/create/functions/sources/opendap.py +0 -15
- anemoi/datasets/create/functions/sources/recentre.py +0 -60
- anemoi/datasets/create/functions/sources/xarray/coordinates.py +0 -255
- anemoi/datasets/create/functions/sources/xarray/flavour.py +0 -472
- anemoi/datasets/create/functions/sources/xarray/metadata.py +0 -148
- anemoi/datasets/create/functions/sources/xarray/patch.py +0 -44
- anemoi/datasets/create/functions/sources/xarray/time.py +0 -177
- anemoi/datasets/create/functions/sources/xarray/variable.py +0 -188
- anemoi/datasets/create/functions/sources/xarray_kerchunk.py +0 -42
- anemoi/datasets/create/functions/sources/xarray_zarr.py +0 -15
- anemoi/datasets/utils/fields.py +0 -47
- anemoi_datasets-0.5.15.dist-info/RECORD +0 -129
- {anemoi_datasets-0.5.15.dist-info → anemoi_datasets-0.5.17.dist-info}/entry_points.txt +0 -0
- {anemoi_datasets-0.5.15.dist-info → anemoi_datasets-0.5.17.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# (C) Copyright 2024 Anemoi contributors.
|
|
2
|
+
#
|
|
3
|
+
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
4
|
+
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
+
#
|
|
6
|
+
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
7
|
+
# granted to it by virtue of its status as an intergovernmental organisation
|
|
8
|
+
# nor does it submit to any jurisdiction.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
import math
|
|
13
|
+
from functools import cached_property
|
|
14
|
+
from typing import Any
|
|
15
|
+
from typing import Dict
|
|
16
|
+
from typing import List
|
|
17
|
+
from typing import Optional
|
|
18
|
+
from typing import Tuple
|
|
19
|
+
|
|
20
|
+
import numpy as np
|
|
21
|
+
import xarray as xr
|
|
22
|
+
|
|
23
|
+
from .field import XArrayField
|
|
24
|
+
|
|
25
|
+
LOG = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Variable:
|
|
29
|
+
"""Represents a variable in an xarray dataset.
|
|
30
|
+
|
|
31
|
+
Attributes
|
|
32
|
+
----------
|
|
33
|
+
ds : xr.Dataset
|
|
34
|
+
The xarray dataset.
|
|
35
|
+
variable : xr.DataArray
|
|
36
|
+
The data array representing the variable.
|
|
37
|
+
coordinates : List[Any]
|
|
38
|
+
List of coordinates associated with the variable.
|
|
39
|
+
grid : Any
|
|
40
|
+
The grid associated with the variable.
|
|
41
|
+
time : Any
|
|
42
|
+
The time dimension associated with the variable.
|
|
43
|
+
metadata : Dict[str, Any]
|
|
44
|
+
Metadata associated with the variable.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
*,
|
|
50
|
+
ds: xr.Dataset,
|
|
51
|
+
variable: xr.DataArray,
|
|
52
|
+
coordinates: List[Any],
|
|
53
|
+
grid: Any,
|
|
54
|
+
time: Any,
|
|
55
|
+
metadata: Dict[str, Any],
|
|
56
|
+
):
|
|
57
|
+
"""Initialize the Variable object.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
ds : xr.Dataset
|
|
62
|
+
The xarray dataset.
|
|
63
|
+
variable : xr.DataArray
|
|
64
|
+
The data array representing the variable.
|
|
65
|
+
coordinates : List[Any]
|
|
66
|
+
List of coordinates associated with the variable.
|
|
67
|
+
grid : Any
|
|
68
|
+
The grid associated with the variable.
|
|
69
|
+
time : Any
|
|
70
|
+
The time dimension associated with the variable.
|
|
71
|
+
metadata : Dict[str, Any]
|
|
72
|
+
Metadata associated with the variable.
|
|
73
|
+
"""
|
|
74
|
+
self.ds = ds
|
|
75
|
+
self.variable = variable
|
|
76
|
+
|
|
77
|
+
self.grid = grid
|
|
78
|
+
self.coordinates = coordinates
|
|
79
|
+
|
|
80
|
+
self._metadata = metadata.copy()
|
|
81
|
+
self._metadata.update({"variable": variable.name, "param": variable.name})
|
|
82
|
+
|
|
83
|
+
self.time = time
|
|
84
|
+
|
|
85
|
+
self.shape = tuple(len(c.variable) for c in coordinates if c.is_dim and not c.scalar and not c.is_grid)
|
|
86
|
+
self.names = {c.variable.name: c for c in coordinates if c.is_dim and not c.scalar and not c.is_grid}
|
|
87
|
+
self.by_name = {c.variable.name: c for c in coordinates}
|
|
88
|
+
|
|
89
|
+
# We need that alias for the time dimension
|
|
90
|
+
self._aliases = dict(valid_datetime="time")
|
|
91
|
+
|
|
92
|
+
self.length = math.prod(self.shape)
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def name(self) -> str:
|
|
96
|
+
"""Return the name of the variable."""
|
|
97
|
+
return str(self.variable.name)
|
|
98
|
+
|
|
99
|
+
def __len__(self) -> int:
|
|
100
|
+
"""Return the length of the variable.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
int
|
|
105
|
+
The length of the variable.
|
|
106
|
+
"""
|
|
107
|
+
return self.length
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def grid_mapping(self) -> Optional[Dict[str, Any]]:
|
|
111
|
+
"""Return the grid mapping of the variable."""
|
|
112
|
+
grid_mapping = self.variable.attrs.get("grid_mapping", None)
|
|
113
|
+
if grid_mapping is None:
|
|
114
|
+
return None
|
|
115
|
+
return self.ds[grid_mapping].attrs
|
|
116
|
+
|
|
117
|
+
def grid_points(self) -> Any:
|
|
118
|
+
"""Return the grid points of the variable.
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
Any
|
|
123
|
+
The grid points of the variable.
|
|
124
|
+
"""
|
|
125
|
+
return self.grid.grid_points
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def latitudes(self) -> Any:
|
|
129
|
+
"""Return the latitudes of the variable."""
|
|
130
|
+
return self.grid.latitudes
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def longitudes(self) -> Any:
|
|
134
|
+
"""Return the longitudes of the variable."""
|
|
135
|
+
return self.grid.longitudes
|
|
136
|
+
|
|
137
|
+
def __repr__(self) -> str:
|
|
138
|
+
"""Return a string representation of the variable.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
str
|
|
143
|
+
A string representation of the variable.
|
|
144
|
+
"""
|
|
145
|
+
return "Variable[name=%s,coordinates=%s,metadata=%s]" % (
|
|
146
|
+
self.variable.name,
|
|
147
|
+
self.coordinates,
|
|
148
|
+
self._metadata,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
def __getitem__(self, i: int) -> "XArrayField":
|
|
152
|
+
"""Get a 2D field from the variable.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
i : int
|
|
157
|
+
Index of the field.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
XArrayField
|
|
162
|
+
The 2D field at the specified index.
|
|
163
|
+
|
|
164
|
+
Raises
|
|
165
|
+
------
|
|
166
|
+
IndexError
|
|
167
|
+
If the index is out of range.
|
|
168
|
+
"""
|
|
169
|
+
if i >= self.length:
|
|
170
|
+
raise IndexError(i)
|
|
171
|
+
|
|
172
|
+
coords = np.unravel_index(i, self.shape)
|
|
173
|
+
kwargs = {k: v for k, v in zip(self.names, coords)}
|
|
174
|
+
return XArrayField(self, self.variable.isel(kwargs))
|
|
175
|
+
|
|
176
|
+
def sel(self, missing: Dict[str, Any], **kwargs: Any) -> Optional["Variable"]:
|
|
177
|
+
"""Select a subset of the variable based on the given coordinates.
|
|
178
|
+
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
missing : Dict[str, Any]
|
|
182
|
+
Dictionary to store missing coordinates.
|
|
183
|
+
**kwargs : Any
|
|
184
|
+
Coordinates to select.
|
|
185
|
+
|
|
186
|
+
Returns
|
|
187
|
+
-------
|
|
188
|
+
Optional[Variable]
|
|
189
|
+
The selected subset of the variable.
|
|
190
|
+
"""
|
|
191
|
+
if not kwargs:
|
|
192
|
+
return self
|
|
193
|
+
|
|
194
|
+
k, v = kwargs.popitem()
|
|
195
|
+
|
|
196
|
+
user_provided_k = k
|
|
197
|
+
|
|
198
|
+
if k == "valid_datetime":
|
|
199
|
+
# Ask the Time object to select the valid datetime
|
|
200
|
+
k = self.time.select_valid_datetime(self)
|
|
201
|
+
if k is None:
|
|
202
|
+
return None
|
|
203
|
+
|
|
204
|
+
c = self.by_name.get(k)
|
|
205
|
+
|
|
206
|
+
# assert c is not None, f"Could not find coordinate {k} in {self.variable.name} {self.coordinates} {list(self.by_name)}"
|
|
207
|
+
|
|
208
|
+
if c is None:
|
|
209
|
+
missing[k] = v
|
|
210
|
+
return self.sel(missing, **kwargs)
|
|
211
|
+
|
|
212
|
+
i = c.index(v)
|
|
213
|
+
if i is None:
|
|
214
|
+
if k != user_provided_k:
|
|
215
|
+
LOG.warning(f"Could not find {user_provided_k}={v} in {c} (alias of {k})")
|
|
216
|
+
else:
|
|
217
|
+
LOG.warning(f"Could not find {k}={v} in {c}")
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
coordinates = [x.reduced(i) if c is x else x for x in self.coordinates]
|
|
221
|
+
|
|
222
|
+
metadata = self._metadata.copy()
|
|
223
|
+
metadata.update({k: v})
|
|
224
|
+
|
|
225
|
+
variable = Variable(
|
|
226
|
+
ds=self.ds,
|
|
227
|
+
variable=self.variable.isel({k: i}),
|
|
228
|
+
coordinates=coordinates,
|
|
229
|
+
grid=self.grid,
|
|
230
|
+
time=self.time,
|
|
231
|
+
metadata=metadata,
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
return variable.sel(missing, **kwargs)
|
|
235
|
+
|
|
236
|
+
def match(self, **kwargs: Any) -> Tuple[bool, Optional[Dict[str, Any]]]:
|
|
237
|
+
"""Match the variable based on the given metadata.
|
|
238
|
+
|
|
239
|
+
Parameters
|
|
240
|
+
----------
|
|
241
|
+
**kwargs : Any
|
|
242
|
+
Metadata to match.
|
|
243
|
+
|
|
244
|
+
Returns
|
|
245
|
+
-------
|
|
246
|
+
Tuple[bool, Optional[Dict[str, Any]]]
|
|
247
|
+
A tuple containing a boolean indicating if the match was successful and the remaining metadata.
|
|
248
|
+
"""
|
|
249
|
+
if "param" in kwargs:
|
|
250
|
+
assert "variable" not in kwargs
|
|
251
|
+
kwargs["variable"] = kwargs.pop("param")
|
|
252
|
+
|
|
253
|
+
if "variable" in kwargs:
|
|
254
|
+
name = kwargs.pop("variable")
|
|
255
|
+
if not isinstance(name, (list, tuple)):
|
|
256
|
+
name = [name]
|
|
257
|
+
if self.variable.name not in name:
|
|
258
|
+
return False, None
|
|
259
|
+
return True, kwargs
|
|
260
|
+
return True, kwargs
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class FilteredVariable:
|
|
264
|
+
"""Represents a filtered variable based on metadata.
|
|
265
|
+
|
|
266
|
+
Attributes
|
|
267
|
+
----------
|
|
268
|
+
variable : Variable
|
|
269
|
+
The variable to filter.
|
|
270
|
+
kwargs : Any
|
|
271
|
+
Metadata to filter the variable.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
def __init__(self, variable: Variable, **kwargs: Any):
|
|
275
|
+
"""Initialize the FilteredVariable object.
|
|
276
|
+
|
|
277
|
+
Parameters
|
|
278
|
+
----------
|
|
279
|
+
variable : Variable
|
|
280
|
+
The variable to filter.
|
|
281
|
+
**kwargs : Any
|
|
282
|
+
Metadata to filter the variable.
|
|
283
|
+
"""
|
|
284
|
+
self.variable = variable
|
|
285
|
+
self.kwargs = kwargs
|
|
286
|
+
|
|
287
|
+
@cached_property
|
|
288
|
+
def fields(self) -> List["XArrayField"]:
|
|
289
|
+
"""Filter the fields of a variable based on metadata."""
|
|
290
|
+
return [
|
|
291
|
+
field
|
|
292
|
+
for field in self.variable
|
|
293
|
+
if all(field.metadata(k, default=None) == v for k, v in self.kwargs.items())
|
|
294
|
+
]
|
|
295
|
+
|
|
296
|
+
@property
|
|
297
|
+
def length(self) -> int:
|
|
298
|
+
"""Return the length of the filtered variable."""
|
|
299
|
+
return len(self.fields)
|
|
300
|
+
|
|
301
|
+
def __len__(self) -> int:
|
|
302
|
+
"""Return the length of the filtered variable.
|
|
303
|
+
|
|
304
|
+
Returns
|
|
305
|
+
-------
|
|
306
|
+
int
|
|
307
|
+
The length of the filtered variable.
|
|
308
|
+
"""
|
|
309
|
+
return self.length
|
|
310
|
+
|
|
311
|
+
def __getitem__(self, i: int) -> "XArrayField":
|
|
312
|
+
"""Get a field from the filtered variable.
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
i : int
|
|
317
|
+
Index of the field.
|
|
318
|
+
|
|
319
|
+
Returns
|
|
320
|
+
-------
|
|
321
|
+
XArrayField
|
|
322
|
+
The field at the specified index.
|
|
323
|
+
|
|
324
|
+
Raises
|
|
325
|
+
------
|
|
326
|
+
IndexError
|
|
327
|
+
If the index is out of range.
|
|
328
|
+
"""
|
|
329
|
+
if i >= self.length:
|
|
330
|
+
raise IndexError(i)
|
|
331
|
+
return self.fields[i]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# (C) Copyright 2024 Anemoi contributors.
|
|
2
|
+
#
|
|
3
|
+
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
4
|
+
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
5
|
+
#
|
|
6
|
+
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
7
|
+
# granted to it by virtue of its status as an intergovernmental organisation
|
|
8
|
+
# nor does it submit to any jurisdiction.
|
|
9
|
+
|
|
10
|
+
from typing import Any
|
|
11
|
+
from typing import List
|
|
12
|
+
|
|
13
|
+
import earthkit.data as ekd
|
|
14
|
+
|
|
15
|
+
from .legacy import legacy_source
|
|
16
|
+
from .xarray import load_many
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@legacy_source(__file__)
|
|
20
|
+
def execute(context: Any, dates: List[str], url: str, *args: Any, **kwargs: Any) -> ekd.FieldList:
|
|
21
|
+
"""Execute the data loading process.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
context : Any
|
|
26
|
+
The context in which the execution occurs.
|
|
27
|
+
dates : List[str]
|
|
28
|
+
List of dates for which data is to be loaded.
|
|
29
|
+
url : str
|
|
30
|
+
The URL from which data is to be loaded.
|
|
31
|
+
*args : tuple
|
|
32
|
+
Additional positional arguments.
|
|
33
|
+
**kwargs : dict
|
|
34
|
+
Additional keyword arguments.
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
ekd.FieldList
|
|
39
|
+
The loaded data.
|
|
40
|
+
"""
|
|
41
|
+
return load_many("🇿", context, url, *args, **kwargs).execute(dates)
|
|
@@ -8,25 +8,54 @@
|
|
|
8
8
|
# nor does it submit to any jurisdiction.
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
from typing import Any
|
|
12
|
+
from typing import Dict
|
|
13
|
+
from typing import List
|
|
14
|
+
|
|
15
|
+
import earthkit.data as ekd
|
|
11
16
|
from earthkit.data.core.fieldlist import MultiFieldList
|
|
12
17
|
from earthkit.data.sources.url import download_and_cache
|
|
13
18
|
|
|
14
|
-
from . import
|
|
19
|
+
from .legacy import legacy_source
|
|
20
|
+
from .patterns import iterate_patterns
|
|
15
21
|
from .xarray import load_one
|
|
16
22
|
|
|
17
23
|
|
|
18
|
-
|
|
24
|
+
@legacy_source(__file__)
|
|
25
|
+
def execute(context: Any, dates: Any, record_id: str, file_key: str, *args: Any, **kwargs: Any) -> ekd.FieldList:
|
|
26
|
+
"""Executes the download and processing of files from Zenodo.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
context : Any
|
|
31
|
+
The context in which the function is executed.
|
|
32
|
+
dates : Any
|
|
33
|
+
The dates for which the data is required.
|
|
34
|
+
record_id : str
|
|
35
|
+
The Zenodo record ID.
|
|
36
|
+
file_key : str
|
|
37
|
+
The key to identify the file.
|
|
38
|
+
*args : Any
|
|
39
|
+
Additional arguments.
|
|
40
|
+
**kwargs : Any
|
|
41
|
+
Additional keyword arguments.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
MultiFieldList
|
|
46
|
+
A list of fields loaded from the downloaded files.
|
|
47
|
+
"""
|
|
19
48
|
import requests
|
|
20
49
|
|
|
21
|
-
result = []
|
|
50
|
+
result: List[Any] = []
|
|
22
51
|
|
|
23
52
|
URLPATTERN = "https://zenodo.org/api/records/{record_id}"
|
|
24
53
|
url = URLPATTERN.format(record_id=record_id)
|
|
25
54
|
r = requests.get(url)
|
|
26
55
|
r.raise_for_status()
|
|
27
|
-
record = r.json()
|
|
56
|
+
record: Dict[str, Any] = r.json()
|
|
28
57
|
|
|
29
|
-
urls = {}
|
|
58
|
+
urls: Dict[str, str] = {}
|
|
30
59
|
for file in record["files"]:
|
|
31
60
|
urls[file["key"]] = file["links"]["self"]
|
|
32
61
|
|