anemoi-datasets 0.5.6__py3-none-any.whl → 0.5.10__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.
Files changed (124) hide show
  1. anemoi/datasets/__init__.py +11 -3
  2. anemoi/datasets/__main__.py +2 -3
  3. anemoi/datasets/_version.py +2 -2
  4. anemoi/datasets/commands/__init__.py +2 -3
  5. anemoi/datasets/commands/cleanup.py +9 -0
  6. anemoi/datasets/commands/compare.py +3 -3
  7. anemoi/datasets/commands/copy.py +38 -68
  8. anemoi/datasets/commands/create.py +20 -5
  9. anemoi/datasets/commands/finalise-additions.py +9 -0
  10. anemoi/datasets/commands/finalise.py +9 -0
  11. anemoi/datasets/commands/init-additions.py +9 -0
  12. anemoi/datasets/commands/init.py +9 -0
  13. anemoi/datasets/commands/inspect.py +7 -1
  14. anemoi/datasets/commands/load-additions.py +9 -0
  15. anemoi/datasets/commands/load.py +9 -0
  16. anemoi/datasets/commands/patch.py +9 -0
  17. anemoi/datasets/commands/publish.py +9 -0
  18. anemoi/datasets/commands/scan.py +9 -0
  19. anemoi/datasets/compute/__init__.py +8 -0
  20. anemoi/datasets/compute/recentre.py +3 -2
  21. anemoi/datasets/create/__init__.py +64 -48
  22. anemoi/datasets/create/check.py +4 -3
  23. anemoi/datasets/create/chunks.py +3 -2
  24. anemoi/datasets/create/config.py +5 -5
  25. anemoi/datasets/create/functions/__init__.py +22 -7
  26. anemoi/datasets/create/functions/filters/__init__.py +2 -1
  27. anemoi/datasets/create/functions/filters/empty.py +3 -2
  28. anemoi/datasets/create/functions/filters/noop.py +2 -2
  29. anemoi/datasets/create/functions/filters/pressure_level_relative_humidity_to_specific_humidity.py +3 -2
  30. anemoi/datasets/create/functions/filters/pressure_level_specific_humidity_to_relative_humidity.py +3 -2
  31. anemoi/datasets/create/functions/filters/rename.py +16 -10
  32. anemoi/datasets/create/functions/filters/rotate_winds.py +3 -2
  33. anemoi/datasets/create/functions/filters/single_level_dewpoint_to_relative_humidity.py +3 -2
  34. anemoi/datasets/create/functions/filters/single_level_relative_humidity_to_dewpoint.py +3 -2
  35. anemoi/datasets/create/functions/filters/single_level_relative_humidity_to_specific_humidity.py +2 -2
  36. anemoi/datasets/create/functions/filters/single_level_specific_humidity_to_relative_humidity.py +2 -2
  37. anemoi/datasets/create/functions/filters/speeddir_to_uv.py +3 -2
  38. anemoi/datasets/create/functions/filters/unrotate_winds.py +3 -2
  39. anemoi/datasets/create/functions/filters/uv_to_speeddir.py +3 -2
  40. anemoi/datasets/create/functions/sources/__init__.py +2 -2
  41. anemoi/datasets/create/functions/sources/accumulations.py +10 -4
  42. anemoi/datasets/create/functions/sources/constants.py +3 -2
  43. anemoi/datasets/create/functions/sources/empty.py +3 -2
  44. anemoi/datasets/create/functions/sources/forcings.py +3 -2
  45. anemoi/datasets/create/functions/sources/grib.py +2 -2
  46. anemoi/datasets/create/functions/sources/hindcasts.py +3 -2
  47. anemoi/datasets/create/functions/sources/mars.py +97 -17
  48. anemoi/datasets/create/functions/sources/netcdf.py +3 -2
  49. anemoi/datasets/create/functions/sources/opendap.py +2 -2
  50. anemoi/datasets/create/functions/sources/recentre.py +3 -2
  51. anemoi/datasets/create/functions/sources/source.py +3 -2
  52. anemoi/datasets/create/functions/sources/tendencies.py +3 -2
  53. anemoi/datasets/create/functions/sources/xarray/__init__.py +8 -2
  54. anemoi/datasets/create/functions/sources/xarray/coordinates.py +5 -2
  55. anemoi/datasets/create/functions/sources/xarray/field.py +3 -2
  56. anemoi/datasets/create/functions/sources/xarray/fieldlist.py +12 -2
  57. anemoi/datasets/create/functions/sources/xarray/flavour.py +21 -16
  58. anemoi/datasets/create/functions/sources/xarray/grid.py +3 -2
  59. anemoi/datasets/create/functions/sources/xarray/metadata.py +3 -2
  60. anemoi/datasets/create/functions/sources/xarray/time.py +39 -4
  61. anemoi/datasets/create/functions/sources/xarray/variable.py +6 -6
  62. anemoi/datasets/create/functions/sources/xarray_kerchunk.py +2 -2
  63. anemoi/datasets/create/functions/sources/xarray_zarr.py +2 -2
  64. anemoi/datasets/create/functions/sources/zenodo.py +2 -2
  65. anemoi/datasets/create/input/__init__.py +3 -17
  66. anemoi/datasets/create/input/action.py +3 -2
  67. anemoi/datasets/create/input/concat.py +3 -2
  68. anemoi/datasets/create/input/context.py +3 -2
  69. anemoi/datasets/create/input/data_sources.py +3 -2
  70. anemoi/datasets/create/input/empty.py +3 -2
  71. anemoi/datasets/create/input/filter.py +3 -2
  72. anemoi/datasets/create/input/function.py +3 -2
  73. anemoi/datasets/create/input/join.py +3 -2
  74. anemoi/datasets/create/input/misc.py +3 -2
  75. anemoi/datasets/create/input/pipe.py +3 -2
  76. anemoi/datasets/create/input/repeated_dates.py +3 -2
  77. anemoi/datasets/create/input/result.py +187 -3
  78. anemoi/datasets/create/input/step.py +4 -2
  79. anemoi/datasets/create/input/template.py +3 -2
  80. anemoi/datasets/create/input/trace.py +3 -2
  81. anemoi/datasets/create/patch.py +9 -1
  82. anemoi/datasets/create/persistent.py +7 -3
  83. anemoi/datasets/create/size.py +3 -2
  84. anemoi/datasets/create/statistics/__init__.py +7 -3
  85. anemoi/datasets/create/statistics/summary.py +3 -2
  86. anemoi/datasets/create/utils.py +15 -2
  87. anemoi/datasets/create/writer.py +3 -2
  88. anemoi/datasets/create/zarr.py +8 -3
  89. anemoi/datasets/data/__init__.py +27 -1
  90. anemoi/datasets/data/concat.py +5 -1
  91. anemoi/datasets/data/dataset.py +216 -37
  92. anemoi/datasets/data/debug.py +4 -1
  93. anemoi/datasets/data/ensemble.py +4 -1
  94. anemoi/datasets/data/fill_missing.py +165 -0
  95. anemoi/datasets/data/forwards.py +27 -2
  96. anemoi/datasets/data/grids.py +236 -58
  97. anemoi/datasets/data/indexing.py +4 -1
  98. anemoi/datasets/data/interpolate.py +4 -1
  99. anemoi/datasets/data/join.py +17 -1
  100. anemoi/datasets/data/masked.py +36 -10
  101. anemoi/datasets/data/merge.py +180 -0
  102. anemoi/datasets/data/misc.py +18 -3
  103. anemoi/datasets/data/missing.py +4 -1
  104. anemoi/datasets/data/rescale.py +4 -1
  105. anemoi/datasets/data/select.py +15 -1
  106. anemoi/datasets/data/statistics.py +4 -1
  107. anemoi/datasets/data/stores.py +70 -3
  108. anemoi/datasets/data/subset.py +6 -1
  109. anemoi/datasets/data/unchecked.py +9 -1
  110. anemoi/datasets/data/xy.py +20 -5
  111. anemoi/datasets/dates/__init__.py +9 -7
  112. anemoi/datasets/dates/groups.py +3 -1
  113. anemoi/datasets/fields.py +3 -1
  114. anemoi/datasets/grids.py +86 -2
  115. anemoi/datasets/testing.py +60 -0
  116. anemoi/datasets/utils/__init__.py +8 -0
  117. anemoi/datasets/utils/fields.py +2 -2
  118. {anemoi_datasets-0.5.6.dist-info → anemoi_datasets-0.5.10.dist-info}/METADATA +11 -29
  119. anemoi_datasets-0.5.10.dist-info/RECORD +124 -0
  120. {anemoi_datasets-0.5.6.dist-info → anemoi_datasets-0.5.10.dist-info}/WHEEL +1 -1
  121. anemoi_datasets-0.5.6.dist-info/RECORD +0 -121
  122. {anemoi_datasets-0.5.6.dist-info → anemoi_datasets-0.5.10.dist-info}/LICENSE +0 -0
  123. {anemoi_datasets-0.5.6.dist-info → anemoi_datasets-0.5.10.dist-info}/entry_points.txt +0 -0
  124. {anemoi_datasets-0.5.6.dist-info → anemoi_datasets-0.5.10.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from copy import deepcopy
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from copy import deepcopy
11
12
  from functools import cached_property
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  import textwrap
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from functools import cached_property
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from functools import cached_property
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from functools import cached_property
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from functools import cached_property
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from functools import cached_property
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from functools import wraps
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
 
11
12
  from .action import Action
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2023 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
 
10
11
  import logging
11
12
  from collections import defaultdict
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import itertools
10
11
  import logging
11
12
  import math
@@ -30,6 +31,178 @@ from .trace import trace_datasource
30
31
  LOG = logging.getLogger(__name__)
31
32
 
32
33
 
34
+ def _fields_metatata(variables, cube):
35
+ assert isinstance(variables, tuple), variables
36
+
37
+ KNOWN = {
38
+ "cos_julian_day": dict(computed_forcing=True, constant_in_time=False),
39
+ "cos_latitude": dict(computed_forcing=True, constant_in_time=True),
40
+ "cos_local_time": dict(computed_forcing=True, constant_in_time=False),
41
+ "cos_longitude": dict(computed_forcing=True, constant_in_time=True),
42
+ "cos_solar_zenith_angle": dict(computed_forcing=True, constant_in_time=False),
43
+ "insolation": dict(computed_forcing=True, constant_in_time=False),
44
+ "latitude": dict(computed_forcing=True, constant_in_time=True),
45
+ "longitude": dict(computed_forcing=True, constant_in_time=True),
46
+ "sin_julian_day": dict(computed_forcing=True, constant_in_time=False),
47
+ "sin_latitude": dict(computed_forcing=True, constant_in_time=True),
48
+ "sin_local_time": dict(computed_forcing=True, constant_in_time=False),
49
+ "sin_longitude": dict(computed_forcing=True, constant_in_time=True),
50
+ }
51
+
52
+ def _merge(md1, md2):
53
+ assert set(md1.keys()) == set(md2.keys()), (set(md1.keys()), set(md2.keys()))
54
+ result = {}
55
+ for k in md1.keys():
56
+ v1 = md1[k]
57
+ v2 = md2[k]
58
+
59
+ if v1 == v2:
60
+ result[k] = v1
61
+ continue
62
+
63
+ if isinstance(v1, list):
64
+ assert v2 not in v1, (v1, v2)
65
+ result[k] = sorted(v1 + [v2])
66
+ continue
67
+
68
+ if isinstance(v2, list):
69
+ assert v1 not in v2, (v1, v2)
70
+ result[k] = sorted(v2 + [v1])
71
+ continue
72
+
73
+ result[k] = sorted([v1, v2])
74
+
75
+ return result
76
+
77
+ mars = {}
78
+ other = defaultdict(dict)
79
+ i = -1
80
+ date = None
81
+ for c in cube.iterate_cubelets():
82
+
83
+ if date is None:
84
+ date = c._coords_names[0]
85
+
86
+ if date != c._coords_names[0]:
87
+ continue
88
+
89
+ if i == -1 or c._coords_names[1] != variables[i]:
90
+ i += 1
91
+
92
+ f = cube[c.coords]
93
+ md = f.metadata(namespace="mars")
94
+ if not md:
95
+ md = f.metadata(namespace="default")
96
+
97
+ if md.get("param") == "~":
98
+ md["param"] = f.metadata("param")
99
+ assert md["param"] not in ("~", "unknown"), (md, f.metadata("param"))
100
+
101
+ if md.get("param") == "unknown":
102
+ md["param"] = str(f.metadata("paramId", default="unknown"))
103
+ # assert md['param'] != 'unknown', (md, f.metadata('param'))
104
+
105
+ startStep = f.metadata("startStep", default=None)
106
+ assert startStep is None or isinstance(startStep, int), (startStep, type(f))
107
+
108
+ endStep = f.metadata("endStep", default=None)
109
+ assert endStep is None or isinstance(endStep, int), endStep
110
+
111
+ stepTypeForConversion = f.metadata("stepTypeForConversion", default=None)
112
+ typeOfStatisticalProcessing = f.metadata("typeOfStatisticalProcessing", default=None)
113
+ timeRangeIndicator = f.metadata("timeRangeIndicator", default=None)
114
+
115
+ # GRIB1 precipitation accumulations are not correctly encoded
116
+ if startStep == endStep and stepTypeForConversion == "accum":
117
+ startStep = 0
118
+
119
+ if startStep != endStep:
120
+ # https://codes.ecmwf.int/grib/format/grib2/ctables/4/10/
121
+ TYPE_OF_STATISTICAL_PROCESSING = {
122
+ None: None,
123
+ 0: "average",
124
+ 1: "accumulation",
125
+ 2: "maximum",
126
+ 3: "minimum",
127
+ 4: "difference(end-start)",
128
+ 5: "root_mean_square",
129
+ 6: "standard_deviation",
130
+ 7: "covariance",
131
+ 8: "difference(start-end)",
132
+ 9: "ratio",
133
+ 10: "standardized_anomaly",
134
+ 11: "summation",
135
+ 100: "severity",
136
+ 101: "mode",
137
+ }
138
+
139
+ # https://codes.ecmwf.int/grib/format/grib1/ctable/5/
140
+
141
+ TIME_RANGE_INDICATOR = {
142
+ 4: "accumulation",
143
+ 3: "average",
144
+ }
145
+
146
+ STEP_TYPE_FOR_CONVERSION = {
147
+ "min": "minimum",
148
+ "max": "maximum",
149
+ "accum": "accumulation",
150
+ }
151
+
152
+ #
153
+ # A few patches
154
+ #
155
+
156
+ PATCHES = {
157
+ "10fg6": "maximum",
158
+ "mntpr3": "minimum", # Not in param db
159
+ "mntpr6": "minimum", # Not in param db
160
+ "mxtpr3": "maximum", # Not in param db
161
+ "mxtpr6": "maximum", # Not in param db
162
+ }
163
+
164
+ process = TYPE_OF_STATISTICAL_PROCESSING.get(typeOfStatisticalProcessing)
165
+ if process is None:
166
+ process = TIME_RANGE_INDICATOR.get(timeRangeIndicator)
167
+ if process is None:
168
+ process = STEP_TYPE_FOR_CONVERSION.get(stepTypeForConversion)
169
+ if process is None:
170
+ process = PATCHES.get(md["param"])
171
+ if process is not None:
172
+ LOG.error(f"Unknown process {stepTypeForConversion} for {md['param']}, using {process} instead")
173
+
174
+ if process is None:
175
+ raise ValueError(
176
+ f"Unknown for {md['param']}:"
177
+ f" {stepTypeForConversion=} ({STEP_TYPE_FOR_CONVERSION.get('stepTypeForConversion')}),"
178
+ f" {typeOfStatisticalProcessing=} ({TYPE_OF_STATISTICAL_PROCESSING.get(typeOfStatisticalProcessing)}),"
179
+ f" {timeRangeIndicator=} ({TIME_RANGE_INDICATOR.get(timeRangeIndicator)})"
180
+ )
181
+
182
+ # print(md["param"], "startStep", startStep, "endStep", endStep, "process", process, "typeOfStatisticalProcessing", typeOfStatisticalProcessing)
183
+ other[variables[i]]["process"] = process
184
+ other[variables[i]]["period"] = (startStep, endStep)
185
+
186
+ for k in md.copy().keys():
187
+ if k.startswith("_"):
188
+ md.pop(k)
189
+
190
+ if variables[i] in mars:
191
+ mars[variables[i]] = _merge(md, mars[variables[i]])
192
+ else:
193
+ mars[variables[i]] = md
194
+
195
+ result = {}
196
+ for k, v in mars.items():
197
+ result[k] = dict(mars=v) if v else {}
198
+ result[k].update(other[k])
199
+ result[k].update(KNOWN.get(k, {}))
200
+ assert result[k], k
201
+
202
+ assert i + 1 == len(variables), (i + 1, len(variables))
203
+ return result
204
+
205
+
33
206
  def _data_request(data):
34
207
  date = None
35
208
  params_levels = defaultdict(set)
@@ -312,7 +485,10 @@ class Result:
312
485
  def build_coords(self):
313
486
  if self._coords_already_built:
314
487
  return
315
- from_data = self.get_cube().user_coords
488
+
489
+ cube = self.get_cube()
490
+
491
+ from_data = cube.user_coords
316
492
  from_config = self.context.order_by
317
493
 
318
494
  keys_from_config = list(from_config.keys())
@@ -359,11 +535,19 @@ class Result:
359
535
  self._field_shape = first_field.shape
360
536
  self._proj_string = first_field.proj_string if hasattr(first_field, "proj_string") else None
361
537
 
538
+ self._cube = cube
539
+
540
+ self._coords_already_built = True
541
+
362
542
  @property
363
543
  def variables(self):
364
544
  self.build_coords()
365
545
  return self._variables
366
546
 
547
+ @property
548
+ def variables_metadata(self):
549
+ return _fields_metatata(self.variables, self._cube)
550
+
367
551
  @property
368
552
  def ensembles(self):
369
553
  self.build_coords()
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import logging
10
11
  from copy import deepcopy
11
12
 
@@ -59,6 +60,7 @@ class StepAction(Action):
59
60
  )
60
61
 
61
62
  def __repr__(self):
63
+ # raise NotImplementedError(f"Not implemented in {self.__class__.__name__}")
62
64
  return super().__repr__(self.previous_step, _inline_=str(self.kwargs))
63
65
 
64
66
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2023 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
 
10
11
  import logging
11
12
  import re
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
 
10
11
  import logging
11
12
  import textwrap
@@ -1,4 +1,12 @@
1
- #!/usr/bin/env python3
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
+
2
10
  import json
3
11
  import logging
4
12
  import os
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2023 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
 
10
11
  import glob
11
12
  import hashlib
@@ -56,8 +57,11 @@ class PersistentDict:
56
57
  yield pickle.load(f)
57
58
 
58
59
  def add_provenance(self, **kwargs):
60
+ path = os.path.join(self.dirname, "provenance.json")
61
+ if os.path.exists(path):
62
+ return
59
63
  out = dict(provenance=gather_provenance_info(), **kwargs)
60
- with open(os.path.join(self.dirname, "provenance.json"), "w") as f:
64
+ with open(path, "w") as f:
61
65
  json.dump(out, f)
62
66
 
63
67
  def add(self, elt, *, key):
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2023 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
 
10
11
  import logging
11
12
  import os
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import datetime
10
11
  import glob
11
12
  import hashlib
@@ -187,8 +188,11 @@ class TmpStatistics:
187
188
 
188
189
  def add_provenance(self, **kwargs):
189
190
  self.create(exist_ok=True)
191
+ path = os.path.join(self.dirname, "provenance.json")
192
+ if os.path.exists(path):
193
+ return
190
194
  out = dict(provenance=gather_provenance_info(), **kwargs)
191
- with open(os.path.join(self.dirname, "provenance.json"), "w") as f:
195
+ with open(path, "w") as f:
192
196
  json.dump(out, f)
193
197
 
194
198
  def create(self, exist_ok):
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import json
10
11
  from collections import defaultdict
11
12
 
@@ -1,14 +1,16 @@
1
- # (C) Copyright 2023 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
 
10
11
  import datetime
11
12
  import os
13
+ import warnings
12
14
  from contextlib import contextmanager
13
15
 
14
16
  import numpy as np
@@ -31,12 +33,23 @@ def cache_context(dirname):
31
33
  def to_datetime_list(*args, **kwargs):
32
34
  from earthkit.data.utils.dates import to_datetime_list as to_datetime_list_
33
35
 
36
+ warnings.warn(
37
+ "to_datetime_list() is deprecated. Call earthkit.data.utils.dates.to_datetime_list() instead.",
38
+ DeprecationWarning,
39
+ stacklevel=2,
40
+ )
34
41
  return to_datetime_list_(*args, **kwargs)
35
42
 
36
43
 
37
44
  def to_datetime(*args, **kwargs):
38
45
  from earthkit.data.utils.dates import to_datetime as to_datetime_
39
46
 
47
+ warnings.warn(
48
+ "to_datetime() is deprecated. Call earthkit.data.utils.dates.to_datetime() instead.",
49
+ DeprecationWarning,
50
+ stacklevel=2,
51
+ )
52
+
40
53
  return to_datetime_(*args, **kwargs)
41
54
 
42
55
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2023 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
 
10
11
  import logging
11
12
 
@@ -1,11 +1,12 @@
1
- # (C) Copyright 2023 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
2
  #
3
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
4
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
5
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
6
7
  # granted to it by virtue of its status as an intergovernmental organisation
7
8
  # nor does it submit to any jurisdiction.
8
- #
9
+
9
10
  import datetime
10
11
  import logging
11
12
  import shutil
@@ -168,7 +169,11 @@ class ZarrBuiltRegistry:
168
169
  return self.create(lengths, overwrite=True)
169
170
 
170
171
  def add_provenance(self, name):
172
+ z = self._open_write()
173
+
174
+ if name in z.attrs:
175
+ return
176
+
171
177
  from anemoi.utils.provenance import gather_provenance_info
172
178
 
173
- z = self._open_write()
174
179
  z.attrs[name] = gather_provenance_info()