anemoi-datasets 0.5.16__py3-none-any.whl → 0.5.18__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 +558 -62
- 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.16.dist-info → anemoi_datasets-0.5.18.dist-info}/METADATA +9 -6
- anemoi_datasets-0.5.18.dist-info/RECORD +137 -0
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info}/WHEEL +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.16.dist-info/RECORD +0 -129
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info}/entry_points.txt +0 -0
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info/licenses}/LICENSE +0 -0
- {anemoi_datasets-0.5.16.dist-info → anemoi_datasets-0.5.18.dist-info}/top_level.txt +0 -0
|
@@ -13,22 +13,44 @@ import math
|
|
|
13
13
|
import time
|
|
14
14
|
from collections import defaultdict
|
|
15
15
|
from functools import cached_property
|
|
16
|
+
from typing import Any
|
|
17
|
+
from typing import DefaultDict
|
|
18
|
+
from typing import Dict
|
|
19
|
+
from typing import List
|
|
20
|
+
from typing import Optional
|
|
21
|
+
from typing import Tuple
|
|
16
22
|
|
|
17
23
|
import numpy as np
|
|
24
|
+
from anemoi.utils.dates import as_timedelta
|
|
18
25
|
from anemoi.utils.humanize import seconds_to_human
|
|
19
26
|
from anemoi.utils.humanize import shorten_list
|
|
20
27
|
from earthkit.data.core.order import build_remapping
|
|
21
28
|
|
|
29
|
+
from .action import ActionContext
|
|
22
30
|
from .trace import trace
|
|
23
31
|
from .trace import trace_datasource
|
|
24
32
|
|
|
25
33
|
LOG = logging.getLogger(__name__)
|
|
26
34
|
|
|
27
35
|
|
|
28
|
-
def _fields_metatata(variables, cube):
|
|
36
|
+
def _fields_metatata(variables: Tuple[str, ...], cube: Any) -> Dict[str, Any]:
|
|
37
|
+
"""Retrieve metadata for the given variables and cube.
|
|
38
|
+
|
|
39
|
+
Parameters
|
|
40
|
+
----------
|
|
41
|
+
variables : tuple of str
|
|
42
|
+
The variables to retrieve metadata for.
|
|
43
|
+
cube : Any
|
|
44
|
+
The data cube.
|
|
45
|
+
|
|
46
|
+
Returns
|
|
47
|
+
-------
|
|
48
|
+
dict
|
|
49
|
+
The metadata dictionary.
|
|
50
|
+
"""
|
|
29
51
|
assert isinstance(variables, tuple), variables
|
|
30
52
|
|
|
31
|
-
KNOWN = {
|
|
53
|
+
KNOWN: Dict[str, Dict[str, bool]] = {
|
|
32
54
|
"cos_julian_day": dict(computed_forcing=True, constant_in_time=False),
|
|
33
55
|
"cos_latitude": dict(computed_forcing=True, constant_in_time=True),
|
|
34
56
|
"cos_local_time": dict(computed_forcing=True, constant_in_time=False),
|
|
@@ -43,9 +65,9 @@ def _fields_metatata(variables, cube):
|
|
|
43
65
|
"sin_longitude": dict(computed_forcing=True, constant_in_time=True),
|
|
44
66
|
}
|
|
45
67
|
|
|
46
|
-
def _merge(md1, md2):
|
|
68
|
+
def _merge(md1: Dict[str, Any], md2: Dict[str, Any]) -> Dict[str, Any]:
|
|
47
69
|
assert set(md1.keys()) == set(md2.keys()), (set(md1.keys()), set(md2.keys()))
|
|
48
|
-
result = {}
|
|
70
|
+
result: Dict[str, Any] = {}
|
|
49
71
|
for k in md1.keys():
|
|
50
72
|
v1 = md1[k]
|
|
51
73
|
v2 = md2[k]
|
|
@@ -68,10 +90,10 @@ def _fields_metatata(variables, cube):
|
|
|
68
90
|
|
|
69
91
|
return result
|
|
70
92
|
|
|
71
|
-
mars = {}
|
|
72
|
-
other = defaultdict(dict)
|
|
73
|
-
i = -1
|
|
74
|
-
date = None
|
|
93
|
+
mars: Dict[str, Any] = {}
|
|
94
|
+
other: DefaultDict[str, Dict[str, Any]] = defaultdict(dict)
|
|
95
|
+
i: int = -1
|
|
96
|
+
date: Optional[str] = None
|
|
75
97
|
for c in cube.iterate_cubelets():
|
|
76
98
|
|
|
77
99
|
if date is None:
|
|
@@ -97,10 +119,12 @@ def _fields_metatata(variables, cube):
|
|
|
97
119
|
# assert md['param'] != 'unknown', (md, f.metadata('param'))
|
|
98
120
|
|
|
99
121
|
startStep = f.metadata("startStep", default=None)
|
|
100
|
-
|
|
122
|
+
if startStep is not None:
|
|
123
|
+
startStep = as_timedelta(startStep)
|
|
101
124
|
|
|
102
125
|
endStep = f.metadata("endStep", default=None)
|
|
103
|
-
|
|
126
|
+
if endStep is not None:
|
|
127
|
+
endStep = as_timedelta(endStep)
|
|
104
128
|
|
|
105
129
|
stepTypeForConversion = f.metadata("stepTypeForConversion", default=None)
|
|
106
130
|
typeOfStatisticalProcessing = f.metadata("typeOfStatisticalProcessing", default=None)
|
|
@@ -112,7 +136,7 @@ def _fields_metatata(variables, cube):
|
|
|
112
136
|
|
|
113
137
|
if startStep != endStep:
|
|
114
138
|
# https://codes.ecmwf.int/grib/format/grib2/ctables/4/10/
|
|
115
|
-
TYPE_OF_STATISTICAL_PROCESSING = {
|
|
139
|
+
TYPE_OF_STATISTICAL_PROCESSING: Dict[Optional[int], Optional[str]] = {
|
|
116
140
|
None: None,
|
|
117
141
|
0: "average",
|
|
118
142
|
1: "accumulation",
|
|
@@ -132,12 +156,12 @@ def _fields_metatata(variables, cube):
|
|
|
132
156
|
|
|
133
157
|
# https://codes.ecmwf.int/grib/format/grib1/ctable/5/
|
|
134
158
|
|
|
135
|
-
TIME_RANGE_INDICATOR = {
|
|
159
|
+
TIME_RANGE_INDICATOR: Dict[int, str] = {
|
|
136
160
|
4: "accumulation",
|
|
137
161
|
3: "average",
|
|
138
162
|
}
|
|
139
163
|
|
|
140
|
-
STEP_TYPE_FOR_CONVERSION = {
|
|
164
|
+
STEP_TYPE_FOR_CONVERSION: Dict[str, str] = {
|
|
141
165
|
"min": "minimum",
|
|
142
166
|
"max": "maximum",
|
|
143
167
|
"accum": "accumulation",
|
|
@@ -147,7 +171,7 @@ def _fields_metatata(variables, cube):
|
|
|
147
171
|
# A few patches
|
|
148
172
|
#
|
|
149
173
|
|
|
150
|
-
PATCHES = {
|
|
174
|
+
PATCHES: Dict[str, str] = {
|
|
151
175
|
"10fg6": "maximum",
|
|
152
176
|
"mntpr3": "minimum", # Not in param db
|
|
153
177
|
"mntpr6": "minimum", # Not in param db
|
|
@@ -186,7 +210,7 @@ def _fields_metatata(variables, cube):
|
|
|
186
210
|
else:
|
|
187
211
|
mars[variables[i]] = md
|
|
188
212
|
|
|
189
|
-
result = {}
|
|
213
|
+
result: Dict[str, Dict[str, Any]] = {}
|
|
190
214
|
for k, v in mars.items():
|
|
191
215
|
result[k] = dict(mars=v) if v else {}
|
|
192
216
|
result[k].update(other[k])
|
|
@@ -197,12 +221,25 @@ def _fields_metatata(variables, cube):
|
|
|
197
221
|
return result
|
|
198
222
|
|
|
199
223
|
|
|
200
|
-
def _data_request(data):
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
224
|
+
def _data_request(data: Any) -> Dict[str, Any]:
|
|
225
|
+
"""Build a data request dictionary from the given data.
|
|
226
|
+
|
|
227
|
+
Parameters
|
|
228
|
+
----------
|
|
229
|
+
data : Any
|
|
230
|
+
The data to build the request from.
|
|
204
231
|
|
|
205
|
-
|
|
232
|
+
Returns
|
|
233
|
+
-------
|
|
234
|
+
dict
|
|
235
|
+
The data request dictionary.
|
|
236
|
+
"""
|
|
237
|
+
date: Optional[Any] = None
|
|
238
|
+
params_levels: DefaultDict[str, set] = defaultdict(set)
|
|
239
|
+
params_steps: DefaultDict[str, set] = defaultdict(set)
|
|
240
|
+
|
|
241
|
+
area: Optional[Any] = None
|
|
242
|
+
grid: Optional[Any] = None
|
|
206
243
|
|
|
207
244
|
for field in data:
|
|
208
245
|
try:
|
|
@@ -232,8 +269,8 @@ def _data_request(data):
|
|
|
232
269
|
except Exception:
|
|
233
270
|
LOG.error(f"Error in retrieving metadata (cannot build data request info) for {field}", exc_info=True)
|
|
234
271
|
|
|
235
|
-
def sort(old_dic):
|
|
236
|
-
new_dic = {}
|
|
272
|
+
def sort(old_dic: DefaultDict[str, set]) -> Dict[str, List[Any]]:
|
|
273
|
+
new_dic: Dict[str, List[Any]] = {}
|
|
237
274
|
for k, v in old_dic.items():
|
|
238
275
|
new_dic[k] = sorted(list(v))
|
|
239
276
|
return new_dic
|
|
@@ -245,48 +282,67 @@ def _data_request(data):
|
|
|
245
282
|
|
|
246
283
|
|
|
247
284
|
class Result:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
285
|
+
"""Class to represent the result of an action in the dataset creation process."""
|
|
286
|
+
|
|
287
|
+
empty: bool = False
|
|
288
|
+
_coords_already_built: bool = False
|
|
289
|
+
|
|
290
|
+
def __init__(self, context: ActionContext, action_path: List[str], dates: Any) -> None:
|
|
291
|
+
"""Initialize a Result instance.
|
|
292
|
+
|
|
293
|
+
Parameters
|
|
294
|
+
----------
|
|
295
|
+
context : ActionContext
|
|
296
|
+
The context in which the result exists.
|
|
297
|
+
action_path : list of str
|
|
298
|
+
The action path.
|
|
299
|
+
dates : Any
|
|
300
|
+
The dates associated with the result.
|
|
301
|
+
"""
|
|
252
302
|
from anemoi.datasets.dates.groups import GroupOfDates
|
|
253
303
|
|
|
254
|
-
from .action import ActionContext
|
|
255
|
-
|
|
256
304
|
assert isinstance(dates, GroupOfDates), dates
|
|
257
305
|
|
|
258
306
|
assert isinstance(context, ActionContext), type(context)
|
|
259
307
|
assert isinstance(action_path, list), action_path
|
|
260
308
|
|
|
261
|
-
self.context = context
|
|
262
|
-
self.group_of_dates = dates
|
|
263
|
-
self.action_path = action_path
|
|
309
|
+
self.context: Any = context
|
|
310
|
+
self.group_of_dates: Any = dates
|
|
311
|
+
self.action_path: List[str] = action_path
|
|
264
312
|
|
|
265
313
|
@property
|
|
266
314
|
@trace_datasource
|
|
267
|
-
def datasource(self):
|
|
315
|
+
def datasource(self) -> Any:
|
|
316
|
+
"""Retrieve the data source for the result."""
|
|
268
317
|
self._raise_not_implemented()
|
|
269
318
|
|
|
270
319
|
@property
|
|
271
|
-
def data_request(self):
|
|
320
|
+
def data_request(self) -> Dict[str, Any]:
|
|
272
321
|
"""Returns a dictionary with the parameters needed to retrieve the data."""
|
|
273
322
|
return _data_request(self.datasource)
|
|
274
323
|
|
|
275
|
-
def get_cube(self):
|
|
324
|
+
def get_cube(self) -> Any:
|
|
325
|
+
"""Retrieve the data cube for the result.
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
Any
|
|
330
|
+
The data cube.
|
|
331
|
+
"""
|
|
276
332
|
trace("🧊", f"getting cube from {self.__class__.__name__}")
|
|
277
|
-
ds = self.datasource
|
|
333
|
+
ds: Any = self.datasource
|
|
278
334
|
|
|
279
|
-
remapping = self.context.remapping
|
|
280
|
-
order_by = self.context.order_by
|
|
281
|
-
flatten_grid = self.context.flatten_grid
|
|
282
|
-
start = time.time()
|
|
335
|
+
remapping: Any = self.context.remapping
|
|
336
|
+
order_by: Any = self.context.order_by
|
|
337
|
+
flatten_grid: Any = self.context.flatten_grid
|
|
338
|
+
start: float = time.time()
|
|
283
339
|
LOG.debug("Sorting dataset %s %s", dict(order_by), remapping)
|
|
284
340
|
assert order_by, order_by
|
|
285
341
|
|
|
286
|
-
patches = {"number": {None: 0}}
|
|
342
|
+
patches: Dict[str, Dict[Optional[Any], int]] = {"number": {None: 0}}
|
|
287
343
|
|
|
288
344
|
try:
|
|
289
|
-
cube = ds.cube(
|
|
345
|
+
cube: Any = ds.cube(
|
|
290
346
|
order_by,
|
|
291
347
|
remapping=remapping,
|
|
292
348
|
flatten_values=flatten_grid,
|
|
@@ -306,9 +362,21 @@ class Result:
|
|
|
306
362
|
|
|
307
363
|
return cube
|
|
308
364
|
|
|
309
|
-
def explain(self, ds, *args, remapping, patches):
|
|
310
|
-
|
|
311
|
-
|
|
365
|
+
def explain(self, ds: Any, *args: Any, remapping: Any, patches: Any) -> None:
|
|
366
|
+
"""Explain the data cube creation process.
|
|
367
|
+
|
|
368
|
+
Parameters
|
|
369
|
+
----------
|
|
370
|
+
ds : Any
|
|
371
|
+
The data source.
|
|
372
|
+
args : Any
|
|
373
|
+
Additional arguments.
|
|
374
|
+
remapping : Any
|
|
375
|
+
The remapping configuration.
|
|
376
|
+
patches : Any
|
|
377
|
+
The patches configuration.
|
|
378
|
+
"""
|
|
379
|
+
METADATA: Tuple[str, ...] = (
|
|
312
380
|
"date",
|
|
313
381
|
"time",
|
|
314
382
|
"step",
|
|
@@ -333,7 +401,7 @@ class Result:
|
|
|
333
401
|
# print("Executing", self.action_path)
|
|
334
402
|
# print("Dates:", compress_dates(self.dates))
|
|
335
403
|
|
|
336
|
-
names = []
|
|
404
|
+
names: List[str] = []
|
|
337
405
|
for a in args:
|
|
338
406
|
if isinstance(a, str):
|
|
339
407
|
names.append(a)
|
|
@@ -349,7 +417,7 @@ class Result:
|
|
|
349
417
|
for k, v in user_coords.items():
|
|
350
418
|
print(f" {k:20}:", len(v), shorten_list(v, max_length=10))
|
|
351
419
|
print()
|
|
352
|
-
user_shape = tuple(len(v) for k, v in user_coords.items())
|
|
420
|
+
user_shape: Tuple[int, ...] = tuple(len(v) for k, v in user_coords.items())
|
|
353
421
|
print("Shape of the hypercube :", user_shape)
|
|
354
422
|
print(
|
|
355
423
|
"Number of expected fields :", math.prod(user_shape), "=", " x ".join([str(i) for i in user_shape])
|
|
@@ -451,11 +519,27 @@ class Result:
|
|
|
451
519
|
print()
|
|
452
520
|
exit(1)
|
|
453
521
|
|
|
454
|
-
def
|
|
455
|
-
|
|
522
|
+
def _repr(self, *args: Any, _indent_: str = "\n", **kwargs: Any) -> str:
|
|
523
|
+
"""Return the string representation of the Result instance.
|
|
524
|
+
|
|
525
|
+
Parameters
|
|
526
|
+
----------
|
|
527
|
+
args : Any
|
|
528
|
+
Additional positional arguments.
|
|
529
|
+
_indent_ : str
|
|
530
|
+
Indentation string.
|
|
531
|
+
kwargs : Any
|
|
532
|
+
Additional keyword arguments.
|
|
533
|
+
|
|
534
|
+
Returns
|
|
535
|
+
-------
|
|
536
|
+
str
|
|
537
|
+
The string representation.
|
|
538
|
+
"""
|
|
539
|
+
more: str = ",".join([str(a)[:5000] for a in args])
|
|
456
540
|
more += ",".join([f"{k}={v}"[:5000] for k, v in kwargs.items()])
|
|
457
541
|
|
|
458
|
-
dates = " no-dates"
|
|
542
|
+
dates: str = " no-dates"
|
|
459
543
|
if self.group_of_dates is not None:
|
|
460
544
|
dates = f" {len(self.group_of_dates)} dates"
|
|
461
545
|
dates += " ("
|
|
@@ -465,32 +549,52 @@ class Result:
|
|
|
465
549
|
dates += ")"
|
|
466
550
|
|
|
467
551
|
more = more[:5000]
|
|
468
|
-
txt = f"{self.__class__.__name__}:{dates}{_indent_}{more}"
|
|
552
|
+
txt: str = f"{self.__class__.__name__}:{dates}{_indent_}{more}"
|
|
469
553
|
if _indent_:
|
|
470
554
|
txt = txt.replace("\n", "\n ")
|
|
471
555
|
return txt
|
|
472
556
|
|
|
473
|
-
def
|
|
557
|
+
def __repr__(self) -> str:
|
|
558
|
+
"""Return the string representation of the Result instance."""
|
|
559
|
+
return self._repr()
|
|
560
|
+
|
|
561
|
+
def _raise_not_implemented(self) -> None:
|
|
562
|
+
"""Raise a NotImplementedError indicating the method is not implemented."""
|
|
474
563
|
raise NotImplementedError(f"Not implemented in {self.__class__.__name__}")
|
|
475
564
|
|
|
476
|
-
def _trace_datasource(self, *args, **kwargs):
|
|
565
|
+
def _trace_datasource(self, *args: Any, **kwargs: Any) -> str:
|
|
566
|
+
"""Trace the data source for the result.
|
|
567
|
+
|
|
568
|
+
Parameters
|
|
569
|
+
----------
|
|
570
|
+
args : Any
|
|
571
|
+
Additional positional arguments.
|
|
572
|
+
kwargs : Any
|
|
573
|
+
Additional keyword arguments.
|
|
574
|
+
|
|
575
|
+
Returns
|
|
576
|
+
-------
|
|
577
|
+
str
|
|
578
|
+
The trace string.
|
|
579
|
+
"""
|
|
477
580
|
return f"{self.__class__.__name__}({self.group_of_dates})"
|
|
478
581
|
|
|
479
|
-
def build_coords(self):
|
|
582
|
+
def build_coords(self) -> None:
|
|
583
|
+
"""Build the coordinates for the result."""
|
|
480
584
|
if self._coords_already_built:
|
|
481
585
|
return
|
|
482
586
|
|
|
483
|
-
cube = self.get_cube()
|
|
587
|
+
cube: Any = self.get_cube()
|
|
484
588
|
|
|
485
|
-
from_data = cube.user_coords
|
|
486
|
-
from_config = self.context.order_by
|
|
589
|
+
from_data: Any = cube.user_coords
|
|
590
|
+
from_config: Any = self.context.order_by
|
|
487
591
|
|
|
488
|
-
keys_from_config = list(from_config.keys())
|
|
489
|
-
keys_from_data = list(from_data.keys())
|
|
592
|
+
keys_from_config: list = list(from_config.keys())
|
|
593
|
+
keys_from_data: list = list(from_data.keys())
|
|
490
594
|
assert keys_from_data == keys_from_config, f"Critical error: {keys_from_data=} != {keys_from_config=}. {self=}"
|
|
491
595
|
|
|
492
|
-
variables_key = list(from_config.keys())[1]
|
|
493
|
-
ensembles_key = list(from_config.keys())[2]
|
|
596
|
+
variables_key: str = list(from_config.keys())[1]
|
|
597
|
+
ensembles_key: str = list(from_config.keys())[2]
|
|
494
598
|
|
|
495
599
|
if isinstance(from_config[variables_key], (list, tuple)):
|
|
496
600
|
assert all([v == w for v, w in zip(from_data[variables_key], from_config[variables_key])]), (
|
|
@@ -498,21 +602,22 @@ class Result:
|
|
|
498
602
|
from_config[variables_key],
|
|
499
603
|
)
|
|
500
604
|
|
|
501
|
-
self._variables = from_data[variables_key] # "param_level"
|
|
502
|
-
self._ensembles = from_data[ensembles_key] # "number"
|
|
605
|
+
self._variables: Any = from_data[variables_key] # "param_level"
|
|
606
|
+
self._ensembles: Any = from_data[ensembles_key] # "number"
|
|
503
607
|
|
|
504
|
-
first_field = self.datasource[0]
|
|
505
|
-
grid_points = first_field.grid_points()
|
|
608
|
+
first_field: Any = self.datasource[0]
|
|
609
|
+
grid_points: Any = first_field.grid_points()
|
|
506
610
|
|
|
507
|
-
lats
|
|
611
|
+
lats: Any = grid_points[0]
|
|
612
|
+
lons: Any = grid_points[1]
|
|
508
613
|
|
|
509
614
|
assert len(lats) == len(lons), (len(lats), len(lons), first_field)
|
|
510
615
|
assert len(lats) == math.prod(first_field.shape), (len(lats), first_field.shape, first_field)
|
|
511
616
|
|
|
512
|
-
north = np.amax(lats)
|
|
513
|
-
south = np.amin(lats)
|
|
514
|
-
east = np.amax(lons)
|
|
515
|
-
west = np.amin(lons)
|
|
617
|
+
north: float = np.amax(lats)
|
|
618
|
+
south: float = np.amin(lats)
|
|
619
|
+
east: float = np.amax(lons)
|
|
620
|
+
west: float = np.amin(lons)
|
|
516
621
|
|
|
517
622
|
assert -90 <= south <= north <= 90, (south, north, first_field)
|
|
518
623
|
assert (-180 <= west <= east <= 180) or (0 <= west <= east <= 360), (
|
|
@@ -521,59 +626,68 @@ class Result:
|
|
|
521
626
|
first_field,
|
|
522
627
|
)
|
|
523
628
|
|
|
524
|
-
grid_values = list(range(len(grid_points[0])))
|
|
629
|
+
grid_values: list = list(range(len(grid_points[0])))
|
|
525
630
|
|
|
526
|
-
self._grid_points = grid_points
|
|
527
|
-
self._resolution = first_field.resolution
|
|
528
|
-
self._grid_values = grid_values
|
|
529
|
-
self._field_shape = first_field.shape
|
|
530
|
-
self._proj_string = first_field.proj_string if hasattr(first_field, "proj_string") else None
|
|
631
|
+
self._grid_points: Any = grid_points
|
|
632
|
+
self._resolution: Any = first_field.resolution
|
|
633
|
+
self._grid_values: Any = grid_values
|
|
634
|
+
self._field_shape: Any = first_field.shape
|
|
635
|
+
self._proj_string: Any = first_field.proj_string if hasattr(first_field, "proj_string") else None
|
|
531
636
|
|
|
532
|
-
self._cube = cube
|
|
637
|
+
self._cube: Any = cube
|
|
533
638
|
|
|
534
|
-
self._coords_already_built = True
|
|
639
|
+
self._coords_already_built: bool = True
|
|
535
640
|
|
|
536
641
|
@property
|
|
537
|
-
def variables(self):
|
|
642
|
+
def variables(self) -> List[str]:
|
|
643
|
+
"""Retrieve the variables for the result."""
|
|
538
644
|
self.build_coords()
|
|
539
645
|
return self._variables
|
|
540
646
|
|
|
541
647
|
@property
|
|
542
|
-
def variables_metadata(self):
|
|
648
|
+
def variables_metadata(self) -> Dict[str, Any]:
|
|
649
|
+
"""Retrieve the metadata for the variables."""
|
|
543
650
|
return _fields_metatata(self.variables, self._cube)
|
|
544
651
|
|
|
545
652
|
@property
|
|
546
|
-
def ensembles(self):
|
|
653
|
+
def ensembles(self) -> Any:
|
|
654
|
+
"""Retrieve the ensembles for the result."""
|
|
547
655
|
self.build_coords()
|
|
548
656
|
return self._ensembles
|
|
549
657
|
|
|
550
658
|
@property
|
|
551
|
-
def resolution(self):
|
|
659
|
+
def resolution(self) -> Any:
|
|
660
|
+
"""Retrieve the resolution for the result."""
|
|
552
661
|
self.build_coords()
|
|
553
662
|
return self._resolution
|
|
554
663
|
|
|
555
664
|
@property
|
|
556
|
-
def grid_values(self):
|
|
665
|
+
def grid_values(self) -> Any:
|
|
666
|
+
"""Retrieve the grid values for the result."""
|
|
557
667
|
self.build_coords()
|
|
558
668
|
return self._grid_values
|
|
559
669
|
|
|
560
670
|
@property
|
|
561
|
-
def grid_points(self):
|
|
671
|
+
def grid_points(self) -> Any:
|
|
672
|
+
"""Retrieve the grid points for the result."""
|
|
562
673
|
self.build_coords()
|
|
563
674
|
return self._grid_points
|
|
564
675
|
|
|
565
676
|
@property
|
|
566
|
-
def field_shape(self):
|
|
677
|
+
def field_shape(self) -> Any:
|
|
678
|
+
"""Retrieve the field shape for the result."""
|
|
567
679
|
self.build_coords()
|
|
568
680
|
return self._field_shape
|
|
569
681
|
|
|
570
682
|
@property
|
|
571
|
-
def proj_string(self):
|
|
683
|
+
def proj_string(self) -> Any:
|
|
684
|
+
"""Retrieve the projection string for the result."""
|
|
572
685
|
self.build_coords()
|
|
573
686
|
return self._proj_string
|
|
574
687
|
|
|
575
688
|
@cached_property
|
|
576
|
-
def shape(self):
|
|
689
|
+
def shape(self) -> List[int]:
|
|
690
|
+
"""Retrieve the shape of the result."""
|
|
577
691
|
return [
|
|
578
692
|
len(self.group_of_dates),
|
|
579
693
|
len(self.variables),
|
|
@@ -582,7 +696,8 @@ class Result:
|
|
|
582
696
|
]
|
|
583
697
|
|
|
584
698
|
@cached_property
|
|
585
|
-
def coords(self):
|
|
699
|
+
def coords(self) -> Dict[str, Any]:
|
|
700
|
+
"""Retrieve the coordinates of the result."""
|
|
586
701
|
return {
|
|
587
702
|
"dates": list(self.group_of_dates),
|
|
588
703
|
"variables": self.variables,
|