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
anemoi/datasets/data/xy.py
CHANGED
|
@@ -10,7 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
import logging
|
|
12
12
|
from functools import cached_property
|
|
13
|
-
|
|
13
|
+
from typing import Any
|
|
14
|
+
from typing import Dict
|
|
15
|
+
from typing import List
|
|
16
|
+
from typing import Set
|
|
17
|
+
from typing import Tuple
|
|
18
|
+
|
|
19
|
+
from .dataset import Dataset
|
|
20
|
+
from .dataset import FullIndex
|
|
14
21
|
from .debug import Node
|
|
15
22
|
from .forwards import Combined
|
|
16
23
|
from .misc import _auto_adjust
|
|
@@ -20,94 +27,217 @@ LOG = logging.getLogger(__name__)
|
|
|
20
27
|
|
|
21
28
|
|
|
22
29
|
class ZipBase(Combined):
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
"""Base class for handling zipped datasets."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, datasets: List[Any], check_compatibility: bool = True) -> None:
|
|
33
|
+
"""Initialize ZipBase with a list of datasets.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
datasets : List[Any]
|
|
38
|
+
List of datasets.
|
|
39
|
+
check_compatibility : bool, optional
|
|
40
|
+
Flag to check compatibility of datasets, by default True.
|
|
41
|
+
"""
|
|
25
42
|
self._check_compatibility = check_compatibility
|
|
26
43
|
super().__init__(datasets)
|
|
27
44
|
|
|
28
|
-
def swap_with_parent(self, parent):
|
|
45
|
+
def swap_with_parent(self, parent: Any) -> Any:
|
|
46
|
+
"""Swap datasets with the parent.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
parent : Any
|
|
51
|
+
Parent dataset.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
Any
|
|
56
|
+
New parent dataset with swapped datasets.
|
|
57
|
+
"""
|
|
29
58
|
new_parents = [parent.clone(ds) for ds in self.datasets]
|
|
30
59
|
return self.clone(new_parents)
|
|
31
60
|
|
|
32
|
-
def clone(self, datasets):
|
|
61
|
+
def clone(self, datasets: List[Any]) -> "ZipBase":
|
|
62
|
+
"""Clone the ZipBase with new datasets.
|
|
63
|
+
|
|
64
|
+
Parameters
|
|
65
|
+
----------
|
|
66
|
+
datasets : List[Any]
|
|
67
|
+
List of new datasets.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
ZipBase
|
|
72
|
+
Cloned ZipBase instance.
|
|
73
|
+
"""
|
|
33
74
|
return self.__class__(datasets, check_compatibility=self._check_compatibility)
|
|
34
75
|
|
|
35
|
-
def tree(self):
|
|
76
|
+
def tree(self) -> Node:
|
|
77
|
+
"""Get the tree representation of the datasets.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
Node
|
|
82
|
+
Tree representation of the datasets.
|
|
83
|
+
"""
|
|
36
84
|
return Node(self, [d.tree() for d in self.datasets], check_compatibility=self._check_compatibility)
|
|
37
85
|
|
|
38
|
-
def __len__(self):
|
|
86
|
+
def __len__(self) -> int:
|
|
87
|
+
"""Get the length of the smallest dataset.
|
|
88
|
+
|
|
89
|
+
Returns
|
|
90
|
+
-------
|
|
91
|
+
int
|
|
92
|
+
Length of the smallest dataset.
|
|
93
|
+
"""
|
|
39
94
|
return min(len(d) for d in self.datasets)
|
|
40
95
|
|
|
41
|
-
def __getitem__(self, n):
|
|
96
|
+
def __getitem__(self, n: FullIndex) -> Tuple[Any, ...]:
|
|
97
|
+
"""Get the item at the specified index from all datasets.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
n : FullIndex
|
|
102
|
+
Index to retrieve.
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
Tuple[Any, ...]
|
|
107
|
+
Tuple of items from all datasets.
|
|
108
|
+
"""
|
|
42
109
|
return tuple(d[n] for d in self.datasets)
|
|
43
110
|
|
|
44
|
-
def check_same_resolution(self, d1, d2):
|
|
111
|
+
def check_same_resolution(self, d1: Dataset, d2: Dataset) -> None:
|
|
112
|
+
"""Check if two datasets have the same resolution.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
d1 : Dataset
|
|
117
|
+
First dataset.
|
|
118
|
+
d2 : Dataset
|
|
119
|
+
Second dataset.
|
|
120
|
+
"""
|
|
45
121
|
pass
|
|
46
122
|
|
|
47
|
-
def check_same_grid(self, d1, d2):
|
|
123
|
+
def check_same_grid(self, d1: Dataset, d2: Dataset) -> None:
|
|
124
|
+
"""Check if two datasets have the same grid.
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
d1 : Dataset
|
|
129
|
+
First dataset.
|
|
130
|
+
d2 : Dataset
|
|
131
|
+
Second dataset.
|
|
132
|
+
"""
|
|
48
133
|
pass
|
|
49
134
|
|
|
50
|
-
def check_same_variables(self, d1, d2):
|
|
135
|
+
def check_same_variables(self, d1: Dataset, d2: Dataset) -> None:
|
|
136
|
+
"""Check if two datasets have the same variables.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
d1 : Dataset
|
|
141
|
+
First dataset.
|
|
142
|
+
d2 : Dataset
|
|
143
|
+
Second dataset.
|
|
144
|
+
"""
|
|
51
145
|
pass
|
|
52
146
|
|
|
53
147
|
@cached_property
|
|
54
|
-
def missing(self):
|
|
55
|
-
|
|
148
|
+
def missing(self) -> Set[int]:
|
|
149
|
+
"""Get the set of missing indices from all datasets."""
|
|
150
|
+
result: Set[int] = set()
|
|
56
151
|
for d in self.datasets:
|
|
57
152
|
result = result | d.missing
|
|
58
153
|
return result
|
|
59
154
|
|
|
60
155
|
@property
|
|
61
|
-
def shape(self):
|
|
156
|
+
def shape(self) -> Tuple[Any, ...]:
|
|
157
|
+
"""Get the shape of all datasets."""
|
|
62
158
|
return tuple(d.shape for d in self.datasets)
|
|
63
159
|
|
|
64
160
|
@property
|
|
65
|
-
def field_shape(self):
|
|
161
|
+
def field_shape(self) -> Tuple[Any, ...]:
|
|
162
|
+
"""Get the field shape of all datasets."""
|
|
66
163
|
return tuple(d.shape for d in self.datasets)
|
|
67
164
|
|
|
68
165
|
@property
|
|
69
|
-
def latitudes(self):
|
|
166
|
+
def latitudes(self) -> Tuple[Any, ...]:
|
|
167
|
+
"""Get the latitudes of all datasets."""
|
|
70
168
|
return tuple(d.latitudes for d in self.datasets)
|
|
71
169
|
|
|
72
170
|
@property
|
|
73
|
-
def longitudes(self):
|
|
171
|
+
def longitudes(self) -> Tuple[Any, ...]:
|
|
172
|
+
"""Get the longitudes of all datasets."""
|
|
74
173
|
return tuple(d.longitudes for d in self.datasets)
|
|
75
174
|
|
|
76
175
|
@property
|
|
77
|
-
def dtype(self):
|
|
176
|
+
def dtype(self) -> Tuple[Any, ...]:
|
|
177
|
+
"""Get the data types of all datasets."""
|
|
78
178
|
return tuple(d.dtype for d in self.datasets)
|
|
79
179
|
|
|
80
180
|
@property
|
|
81
|
-
def grids(self):
|
|
181
|
+
def grids(self) -> Tuple[Any, ...]:
|
|
182
|
+
"""Get the grids of all datasets."""
|
|
82
183
|
return tuple(d.grids for d in self.datasets)
|
|
83
184
|
|
|
84
185
|
@property
|
|
85
|
-
def statistics(self):
|
|
186
|
+
def statistics(self) -> Tuple[Any, ...]:
|
|
187
|
+
"""Get the statistics of all datasets."""
|
|
86
188
|
return tuple(d.statistics for d in self.datasets)
|
|
87
189
|
|
|
88
190
|
@property
|
|
89
|
-
def resolution(self):
|
|
191
|
+
def resolution(self) -> Tuple[Any, ...]:
|
|
192
|
+
"""Get the resolution of all datasets."""
|
|
90
193
|
return tuple(d.resolution for d in self.datasets)
|
|
91
194
|
|
|
92
195
|
@property
|
|
93
|
-
def name_to_index(self):
|
|
196
|
+
def name_to_index(self) -> Tuple[Any, ...]:
|
|
197
|
+
"""Get the name to index mapping of all datasets."""
|
|
94
198
|
return tuple(d.name_to_index for d in self.datasets)
|
|
95
199
|
|
|
96
|
-
def check_compatibility(self, d1, d2):
|
|
200
|
+
def check_compatibility(self, d1: Dataset, d2: Dataset) -> None:
|
|
201
|
+
"""Check compatibility between two datasets.
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
d1 : Dataset
|
|
206
|
+
First dataset.
|
|
207
|
+
d2 : Dataset
|
|
208
|
+
Second dataset.
|
|
209
|
+
"""
|
|
97
210
|
if self._check_compatibility:
|
|
98
211
|
super().check_compatibility(d1, d2)
|
|
99
212
|
|
|
100
213
|
|
|
101
214
|
class Zip(ZipBase):
|
|
215
|
+
"""Class for handling zipped datasets."""
|
|
216
|
+
|
|
102
217
|
pass
|
|
103
218
|
|
|
104
219
|
|
|
105
220
|
class XY(ZipBase):
|
|
221
|
+
"""Class for handling XY datasets."""
|
|
222
|
+
|
|
106
223
|
pass
|
|
107
224
|
|
|
108
225
|
|
|
109
|
-
def xy_factory(args, kwargs):
|
|
226
|
+
def xy_factory(args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> XY:
|
|
227
|
+
"""Factory function to create an XY instance.
|
|
110
228
|
|
|
229
|
+
Parameters
|
|
230
|
+
----------
|
|
231
|
+
args : Tuple[Any, ...]
|
|
232
|
+
Positional arguments.
|
|
233
|
+
kwargs : Dict[str, Any]
|
|
234
|
+
Keyword arguments.
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
XY
|
|
239
|
+
An instance of XY.
|
|
240
|
+
"""
|
|
111
241
|
if "xy" in kwargs:
|
|
112
242
|
xy = kwargs.pop("xy")
|
|
113
243
|
else:
|
|
@@ -126,8 +256,21 @@ def xy_factory(args, kwargs):
|
|
|
126
256
|
return XY(datasets, check_compatibility=check_compatibility)._subset(**kwargs)
|
|
127
257
|
|
|
128
258
|
|
|
129
|
-
def zip_factory(args, kwargs):
|
|
259
|
+
def zip_factory(args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Zip:
|
|
260
|
+
"""Factory function to create a Zip instance.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
args : Tuple[Any, ...]
|
|
265
|
+
Positional arguments.
|
|
266
|
+
kwargs : Dict[str, Any]
|
|
267
|
+
Keyword arguments.
|
|
130
268
|
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
Zip
|
|
272
|
+
An instance of Zip.
|
|
273
|
+
"""
|
|
131
274
|
zip = kwargs.pop("zip")
|
|
132
275
|
assert len(args) == 0
|
|
133
276
|
assert isinstance(zip, (list, tuple))
|
|
@@ -12,6 +12,13 @@ import datetime
|
|
|
12
12
|
import warnings
|
|
13
13
|
from functools import reduce
|
|
14
14
|
from math import gcd
|
|
15
|
+
from typing import Any
|
|
16
|
+
from typing import Dict
|
|
17
|
+
from typing import Iterator
|
|
18
|
+
from typing import List
|
|
19
|
+
from typing import Optional
|
|
20
|
+
from typing import Tuple
|
|
21
|
+
from typing import Union
|
|
15
22
|
|
|
16
23
|
# from anemoi.utils.dates import as_datetime
|
|
17
24
|
from anemoi.utils.dates import DateTimes
|
|
@@ -22,7 +29,17 @@ from anemoi.utils.hindcasts import HindcastDatesTimes
|
|
|
22
29
|
from anemoi.utils.humanize import print_dates
|
|
23
30
|
|
|
24
31
|
|
|
25
|
-
def extend(x):
|
|
32
|
+
def extend(x: Union[str, List[Any], Tuple[Any, ...]]) -> Iterator[datetime.datetime]:
|
|
33
|
+
"""Extend a date range or list of dates into individual datetime objects.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
x (Union[str, List[Any], Tuple[Any, ...]]): A date range string or list/tuple of dates.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
Iterator[datetime.datetime]
|
|
41
|
+
An iterator of datetime objects.
|
|
42
|
+
"""
|
|
26
43
|
|
|
27
44
|
if isinstance(x, (list, tuple)):
|
|
28
45
|
for y in x:
|
|
@@ -69,7 +86,14 @@ class DatesProvider:
|
|
|
69
86
|
3
|
|
70
87
|
"""
|
|
71
88
|
|
|
72
|
-
def __init__(self, missing=None):
|
|
89
|
+
def __init__(self, missing: Optional[List[Union[str, datetime.datetime]]] = None) -> None:
|
|
90
|
+
"""Initialize the DatesProvider with optional missing dates.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
missing : Optional[List[Union[str, datetime.datetime]]]
|
|
95
|
+
List of missing dates.
|
|
96
|
+
"""
|
|
73
97
|
if not missing:
|
|
74
98
|
missing = []
|
|
75
99
|
self.missing = list(extend(missing))
|
|
@@ -78,8 +102,17 @@ class DatesProvider:
|
|
|
78
102
|
warnings.warn(f"Missing dates {len(diff)=} not in list.")
|
|
79
103
|
|
|
80
104
|
@classmethod
|
|
81
|
-
def from_config(cls, **kwargs):
|
|
105
|
+
def from_config(cls, **kwargs: Any) -> "DatesProvider":
|
|
106
|
+
"""Create a DatesProvider instance from configuration.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
**kwargs (Any): Configuration parameters.
|
|
82
110
|
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
DatesProvider
|
|
114
|
+
An instance of DatesProvider.
|
|
115
|
+
"""
|
|
83
116
|
if kwargs.pop("hindcasts", False):
|
|
84
117
|
return HindcastsDates(**kwargs)
|
|
85
118
|
|
|
@@ -88,35 +121,113 @@ class DatesProvider:
|
|
|
88
121
|
|
|
89
122
|
return StartEndDates(**kwargs)
|
|
90
123
|
|
|
91
|
-
def __iter__(self):
|
|
124
|
+
def __iter__(self) -> Iterator[datetime.datetime]:
|
|
125
|
+
"""Iterate over the dates.
|
|
126
|
+
|
|
127
|
+
Yields
|
|
128
|
+
------
|
|
129
|
+
Iterator[datetime.datetime]
|
|
130
|
+
An iterator of datetime objects.
|
|
131
|
+
"""
|
|
92
132
|
yield from self.values
|
|
93
133
|
|
|
94
|
-
def __getitem__(self, i):
|
|
134
|
+
def __getitem__(self, i: int) -> datetime.datetime:
|
|
135
|
+
"""Get a date by index.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
i (int): Index of the date.
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
datetime.datetime
|
|
143
|
+
The date at the specified index.
|
|
144
|
+
"""
|
|
95
145
|
return self.values[i]
|
|
96
146
|
|
|
97
|
-
def __len__(self):
|
|
147
|
+
def __len__(self) -> int:
|
|
148
|
+
"""Get the number of dates.
|
|
149
|
+
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
int
|
|
153
|
+
The number of dates.
|
|
154
|
+
"""
|
|
98
155
|
return len(self.values)
|
|
99
156
|
|
|
100
157
|
@property
|
|
101
|
-
def summary(self):
|
|
158
|
+
def summary(self) -> str:
|
|
159
|
+
"""Get a summary of the date range."""
|
|
102
160
|
return f"📅 {self.values[0]} ... {self.values[-1]}"
|
|
103
161
|
|
|
104
162
|
|
|
105
163
|
class ValuesDates(DatesProvider):
|
|
106
|
-
|
|
164
|
+
"""Class for handling a list of date values.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
values (List[Union[str, datetime.datetime]]): List of date values.
|
|
168
|
+
**kwargs (Any): Additional arguments.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def __init__(self, values: List[Union[str, datetime.datetime]], **kwargs: Any) -> None:
|
|
172
|
+
"""Initialize ValuesDates with a list of values.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
values (List[Union[str, datetime.datetime]]): List of date values.
|
|
176
|
+
**kwargs (Any): Additional arguments.
|
|
177
|
+
"""
|
|
107
178
|
self.values = sorted([as_datetime(_) for _ in values])
|
|
108
179
|
super().__init__(**kwargs)
|
|
109
180
|
|
|
110
|
-
def __repr__(self):
|
|
181
|
+
def __repr__(self) -> str:
|
|
182
|
+
"""Get a string representation of the ValuesDates instance.
|
|
183
|
+
|
|
184
|
+
Returns
|
|
185
|
+
-------
|
|
186
|
+
str
|
|
187
|
+
String representation of the instance.
|
|
188
|
+
"""
|
|
111
189
|
return f"{self.__class__.__name__}({self.values[0]}..{self.values[-1]})"
|
|
112
190
|
|
|
113
|
-
def as_dict(self):
|
|
191
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
192
|
+
"""Convert the ValuesDates instance to a dictionary.
|
|
193
|
+
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
Dict[str, Any]
|
|
197
|
+
Dictionary representation of the instance.
|
|
198
|
+
"""
|
|
114
199
|
return {"values": self.values[0]}
|
|
115
200
|
|
|
116
201
|
|
|
117
202
|
class StartEndDates(DatesProvider):
|
|
118
|
-
|
|
203
|
+
"""Class for generating dates between a start and end date with a specified frequency.
|
|
119
204
|
|
|
205
|
+
Args:
|
|
206
|
+
start (Union[str, datetime.datetime]): Start date.
|
|
207
|
+
end (Union[str, datetime.datetime]): End date.
|
|
208
|
+
frequency (Union[int, str]): Frequency of dates.
|
|
209
|
+
**kwargs (Any): Additional arguments.
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
def __repr__(self) -> str:
|
|
213
|
+
"""Get a string representation of the StartEndDates instance."""
|
|
214
|
+
return f"{self.__class__.__name__}({self.start}..{self.end} every {self.frequency})"
|
|
215
|
+
|
|
216
|
+
def __init__(
|
|
217
|
+
self,
|
|
218
|
+
start: Union[str, datetime.datetime],
|
|
219
|
+
end: Union[str, datetime.datetime],
|
|
220
|
+
frequency: Union[int, str] = 1,
|
|
221
|
+
**kwargs: Any,
|
|
222
|
+
) -> None:
|
|
223
|
+
"""Initialize StartEndDates with start, end, and frequency.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
start (Union[str, datetime.datetime]): Start date.
|
|
227
|
+
end (Union[str, datetime.datetime]): End date.
|
|
228
|
+
frequency (Union[int, str]): Frequency of dates.
|
|
229
|
+
**kwargs (Any): Additional arguments.
|
|
230
|
+
"""
|
|
120
231
|
frequency = frequency_to_timedelta(frequency)
|
|
121
232
|
assert isinstance(frequency, datetime.timedelta), frequency
|
|
122
233
|
|
|
@@ -148,7 +259,14 @@ class StartEndDates(DatesProvider):
|
|
|
148
259
|
|
|
149
260
|
super().__init__(missing=missing)
|
|
150
261
|
|
|
151
|
-
def as_dict(self):
|
|
262
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
263
|
+
"""Convert the StartEndDates instance to a dictionary.
|
|
264
|
+
|
|
265
|
+
Returns
|
|
266
|
+
-------
|
|
267
|
+
Dict[str, Any]
|
|
268
|
+
Dictionary representation of the instance.
|
|
269
|
+
"""
|
|
152
270
|
return {
|
|
153
271
|
"start": self.start.isoformat(),
|
|
154
272
|
"end": self.end.isoformat(),
|
|
@@ -157,8 +275,26 @@ class StartEndDates(DatesProvider):
|
|
|
157
275
|
|
|
158
276
|
|
|
159
277
|
class Hindcast:
|
|
278
|
+
"""Class representing a single hindcast date.
|
|
160
279
|
|
|
161
|
-
|
|
280
|
+
Args:
|
|
281
|
+
date (datetime.datetime): The date of the hindcast.
|
|
282
|
+
refdate (datetime.datetime): The reference date.
|
|
283
|
+
hdate (datetime.datetime): The hindcast date.
|
|
284
|
+
step (int): The step value.
|
|
285
|
+
"""
|
|
286
|
+
|
|
287
|
+
def __init__(
|
|
288
|
+
self, date: datetime.datetime, refdate: datetime.datetime, hdate: datetime.datetime, step: int
|
|
289
|
+
) -> None:
|
|
290
|
+
"""Initialize a Hindcast instance.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
date (datetime.datetime): The date of the hindcast.
|
|
294
|
+
refdate (datetime.datetime): The reference date.
|
|
295
|
+
hdate (datetime.datetime): The hindcast date.
|
|
296
|
+
step (int): The step value.
|
|
297
|
+
"""
|
|
162
298
|
self.date = date
|
|
163
299
|
self.refdate = refdate
|
|
164
300
|
self.hdate = hdate
|
|
@@ -166,8 +302,33 @@ class Hindcast:
|
|
|
166
302
|
|
|
167
303
|
|
|
168
304
|
class HindcastsDates(DatesProvider):
|
|
169
|
-
|
|
305
|
+
"""Class for generating hindcast dates over a range of years.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
start (Union[str, List[str]]): Start date(s).
|
|
309
|
+
end (Union[str, List[str]]): End date(s).
|
|
310
|
+
steps (List[int]): List of step values.
|
|
311
|
+
years (int): Number of years.
|
|
312
|
+
**kwargs (Any): Additional arguments.
|
|
313
|
+
"""
|
|
170
314
|
|
|
315
|
+
def __init__(
|
|
316
|
+
self,
|
|
317
|
+
start: Union[str, List[str]],
|
|
318
|
+
end: Union[str, List[str]],
|
|
319
|
+
steps: List[int] = [0],
|
|
320
|
+
years: int = 20,
|
|
321
|
+
**kwargs: Any,
|
|
322
|
+
) -> None:
|
|
323
|
+
"""Initialize HindcastsDates with start, end, steps, and years.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
start (Union[str, List[str]]): Start date(s).
|
|
327
|
+
end (Union[str, List[str]]): End date(s).
|
|
328
|
+
steps (List[int]): List of step values.
|
|
329
|
+
years (int): Number of years.
|
|
330
|
+
**kwargs (Any): Additional arguments.
|
|
331
|
+
"""
|
|
171
332
|
if not isinstance(start, list):
|
|
172
333
|
start = [start]
|
|
173
334
|
end = [end]
|
|
@@ -232,10 +393,24 @@ class HindcastsDates(DatesProvider):
|
|
|
232
393
|
|
|
233
394
|
super().__init__(missing=missing)
|
|
234
395
|
|
|
235
|
-
def __repr__(self):
|
|
396
|
+
def __repr__(self) -> str:
|
|
397
|
+
"""Get a string representation of the HindcastsDates instance.
|
|
398
|
+
|
|
399
|
+
Returns
|
|
400
|
+
-------
|
|
401
|
+
str
|
|
402
|
+
String representation of the instance.
|
|
403
|
+
"""
|
|
236
404
|
return f"{self.__class__.__name__}({self.values[0]}..{self.values[-1]})"
|
|
237
405
|
|
|
238
|
-
def as_dict(self):
|
|
406
|
+
def as_dict(self) -> Dict[str, Any]:
|
|
407
|
+
"""Convert the HindcastsDates instance to a dictionary.
|
|
408
|
+
|
|
409
|
+
Returns
|
|
410
|
+
-------
|
|
411
|
+
Dict[str, Any]
|
|
412
|
+
Dictionary representation of the instance.
|
|
413
|
+
"""
|
|
239
414
|
return {"hindcasts": self.hindcasts}
|
|
240
415
|
|
|
241
416
|
|