anemoi-datasets 0.5.7__py3-none-any.whl → 0.5.11__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 +3 -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 +62 -12
  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 -11
  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 +8 -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 -3
  54. anemoi/datasets/create/functions/sources/xarray/coordinates.py +3 -2
  55. anemoi/datasets/create/functions/sources/xarray/field.py +6 -5
  56. anemoi/datasets/create/functions/sources/xarray/fieldlist.py +12 -4
  57. anemoi/datasets/create/functions/sources/xarray/flavour.py +2 -2
  58. anemoi/datasets/create/functions/sources/xarray/grid.py +2 -2
  59. anemoi/datasets/create/functions/sources/xarray/metadata.py +3 -2
  60. anemoi/datasets/create/functions/sources/xarray/time.py +2 -2
  61. anemoi/datasets/create/functions/sources/xarray/variable.py +6 -9
  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 -8
  67. anemoi/datasets/create/input/concat.py +3 -2
  68. anemoi/datasets/create/input/context.py +3 -8
  69. anemoi/datasets/create/input/data_sources.py +3 -9
  70. anemoi/datasets/create/input/empty.py +3 -9
  71. anemoi/datasets/create/input/filter.py +3 -9
  72. anemoi/datasets/create/input/function.py +3 -9
  73. anemoi/datasets/create/input/join.py +3 -2
  74. anemoi/datasets/create/input/misc.py +3 -8
  75. anemoi/datasets/create/input/pipe.py +9 -3
  76. anemoi/datasets/create/input/repeated_dates.py +14 -8
  77. anemoi/datasets/create/input/result.py +154 -12
  78. anemoi/datasets/create/input/step.py +4 -9
  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 +3 -2
  83. anemoi/datasets/create/size.py +3 -2
  84. anemoi/datasets/create/statistics/__init__.py +3 -2
  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 +3 -2
  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 +23 -1
  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 +12 -9
  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 +4 -1
  106. anemoi/datasets/data/statistics.py +4 -1
  107. anemoi/datasets/data/stores.py +66 -3
  108. anemoi/datasets/data/subset.py +6 -1
  109. anemoi/datasets/data/unchecked.py +4 -1
  110. anemoi/datasets/data/xy.py +20 -5
  111. anemoi/datasets/dates/__init__.py +9 -7
  112. anemoi/datasets/dates/groups.py +4 -2
  113. anemoi/datasets/grids.py +86 -2
  114. anemoi/datasets/testing.py +3 -2
  115. anemoi/datasets/utils/__init__.py +8 -0
  116. anemoi/datasets/utils/fields.py +2 -2
  117. {anemoi_datasets-0.5.7.dist-info → anemoi_datasets-0.5.11.dist-info}/METADATA +11 -29
  118. anemoi_datasets-0.5.11.dist-info/RECORD +123 -0
  119. {anemoi_datasets-0.5.7.dist-info → anemoi_datasets-0.5.11.dist-info}/WHEEL +1 -1
  120. anemoi/datasets/fields.py +0 -66
  121. anemoi_datasets-0.5.7.dist-info/RECORD +0 -122
  122. {anemoi_datasets-0.5.7.dist-info → anemoi_datasets-0.5.11.dist-info}/LICENSE +0 -0
  123. {anemoi_datasets-0.5.7.dist-info → anemoi_datasets-0.5.11.dist-info}/entry_points.txt +0 -0
  124. {anemoi_datasets-0.5.7.dist-info → anemoi_datasets-0.5.11.dist-info}/top_level.txt +0 -0
@@ -1,19 +1,27 @@
1
- # (C) Copyright 2023 European Centre for Medium-Range Weather Forecasts.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
+ #
2
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
3
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
4
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
5
7
  # granted to it by virtue of its status as an intergovernmental organisation
6
8
  # nor does it submit to any jurisdiction.
7
9
 
8
- from ._version import __version__
9
10
  from .data import MissingDateError
10
11
  from .data import add_dataset_path
11
12
  from .data import add_named_dataset
12
13
  from .data import list_dataset_names
13
14
  from .data import open_dataset
14
15
 
16
+ try:
17
+ # NOTE: the `_version.py` file must not be present in the git repository
18
+ # as it is generated by setuptools at install time
19
+ from ._version import __version__ # type: ignore
20
+ except ImportError: # pragma: no cover
21
+ # Local copy or not installed with setuptools
22
+ __version__ = "999"
23
+
15
24
  __all__ = [
16
- "__version__",
17
25
  "add_dataset_path",
18
26
  "add_named_dataset",
19
27
  "list_dataset_names",
@@ -1,12 +1,11 @@
1
- #!/usr/bin/env python
2
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
3
2
  #
4
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
5
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
6
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
7
7
  # granted to it by virtue of its status as an intergovernmental organisation
8
8
  # nor does it submit to any jurisdiction.
9
- #
10
9
 
11
10
  from anemoi.utils.cli import cli_main
12
11
  from anemoi.utils.cli import make_parser
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.5.7'
16
- __version_tuple__ = version_tuple = (0, 5, 7)
15
+ __version__ = version = '0.5.11'
16
+ __version_tuple__ = version_tuple = (0, 5, 11)
@@ -1,12 +1,11 @@
1
- #!/usr/bin/env python
2
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
3
2
  #
4
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
5
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
6
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
7
7
  # granted to it by virtue of its status as an intergovernmental organisation
8
8
  # nor does it submit to any jurisdiction.
9
- #
10
9
 
11
10
  import os
12
11
 
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,12 +1,12 @@
1
- #!/usr/bin/env python
2
- # (C) Copyright 2024 ECMWF.
1
+ # (C) Copyright 2024 Anemoi contributors.
3
2
  #
4
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
5
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
6
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
7
7
  # granted to it by virtue of its status as an intergovernmental organisation
8
8
  # nor does it submit to any jurisdiction.
9
- #
9
+
10
10
 
11
11
  import numpy as np
12
12
  import tqdm
@@ -1,20 +1,22 @@
1
- # (C) Copyright 2023 European Centre for Medium-Range Weather Forecasts.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
+ #
2
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
3
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
4
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
5
7
  # granted to it by virtue of its status as an intergovernmental organisation
6
8
  # nor does it submit to any jurisdiction.
7
9
 
10
+
8
11
  import logging
9
12
  import os
10
- import shutil
11
13
  import sys
12
14
  from concurrent.futures import ThreadPoolExecutor
13
15
  from concurrent.futures import as_completed
14
16
 
15
17
  import tqdm
16
- from anemoi.utils.s3 import download
17
- from anemoi.utils.s3 import upload
18
+ from anemoi.utils.remote import Transfer
19
+ from anemoi.utils.remote import TransferMethodNotImplementedError
18
20
 
19
21
  from . import Command
20
22
 
@@ -26,54 +28,7 @@ except AttributeError:
26
28
  isatty = False
27
29
 
28
30
 
29
- class S3Downloader:
30
- def __init__(self, source, target, transfers, overwrite, resume, verbosity, **kwargs):
31
- self.source = source
32
- self.target = target
33
- self.transfers = transfers
34
- self.overwrite = overwrite
35
- self.resume = resume
36
- self.verbosity = verbosity
37
-
38
- def run(self):
39
- if self.target == ".":
40
- self.target = os.path.basename(self.source)
41
-
42
- if self.overwrite and os.path.exists(self.target):
43
- LOG.info(f"Deleting {self.target}")
44
- shutil.rmtree(self.target)
45
-
46
- download(
47
- self.source + "/" if not self.source.endswith("/") else self.source,
48
- self.target,
49
- overwrite=self.overwrite,
50
- resume=self.resume,
51
- verbosity=self.verbosity,
52
- threads=self.transfers,
53
- )
54
-
55
-
56
- class S3Uploader:
57
- def __init__(self, source, target, transfers, overwrite, resume, verbosity, **kwargs):
58
- self.source = source
59
- self.target = target
60
- self.transfers = transfers
61
- self.overwrite = overwrite
62
- self.resume = resume
63
- self.verbosity = verbosity
64
-
65
- def run(self):
66
- upload(
67
- self.source,
68
- self.target,
69
- overwrite=self.overwrite,
70
- resume=self.resume,
71
- verbosity=self.verbosity,
72
- threads=self.transfers,
73
- )
74
-
75
-
76
- class DefaultCopier:
31
+ class ZarrCopier:
77
32
  def __init__(self, source, target, transfers, block_size, overwrite, resume, verbosity, nested, rechunk, **kwargs):
78
33
  self.source = source
79
34
  self.target = target
@@ -87,6 +42,14 @@ class DefaultCopier:
87
42
 
88
43
  self.rechunking = rechunk.split(",") if rechunk else []
89
44
 
45
+ source_is_ssh = self.source.startswith("ssh://")
46
+ target_is_ssh = self.target.startswith("ssh://")
47
+
48
+ if source_is_ssh or target_is_ssh:
49
+ if self.rechunk:
50
+ raise NotImplementedError("Rechunking with SSH not implemented.")
51
+ assert NotImplementedError("SSH not implemented.")
52
+
90
53
  def _store(self, path, nested=False):
91
54
  if nested:
92
55
  import zarr
@@ -334,26 +297,33 @@ class CopyMixin:
334
297
  if args.source == args.target:
335
298
  raise ValueError("Source and target are the same.")
336
299
 
337
- kwargs = vars(args)
338
-
339
300
  if args.overwrite and args.resume:
340
301
  raise ValueError("Cannot use --overwrite and --resume together.")
341
302
 
342
- source_in_s3 = args.source.startswith("s3://")
343
- target_in_s3 = args.target.startswith("s3://")
344
-
345
- copier = None
346
-
347
- if args.rechunk or (source_in_s3 and target_in_s3):
348
- copier = DefaultCopier(**kwargs)
349
- else:
350
- if source_in_s3:
351
- copier = S3Downloader(**kwargs)
352
-
353
- if target_in_s3:
354
- copier = S3Uploader(**kwargs)
355
-
303
+ if not args.rechunk:
304
+ # rechunking is only supported for ZARR datasets, it is implemented in this package
305
+ try:
306
+ if args.source.startswith("s3://") and not args.source.endswith("/"):
307
+ args.source = args.source + "/"
308
+ copier = Transfer(
309
+ args.source,
310
+ args.target,
311
+ overwrite=args.overwrite,
312
+ resume=args.resume,
313
+ verbosity=args.verbosity,
314
+ threads=args.transfers,
315
+ )
316
+ copier.run()
317
+ return
318
+ except TransferMethodNotImplementedError:
319
+ # DataTransfer relies on anemoi-utils which is agnostic to the source and target format
320
+ # it transfers file and folders, ignoring that it is zarr data
321
+ # if it is not implemented, we fallback to the ZarrCopier
322
+ pass
323
+
324
+ copier = ZarrCopier(**vars(args))
356
325
  copier.run()
326
+ return
357
327
 
358
328
 
359
329
  class Copy(CopyMixin, Command):
@@ -1,3 +1,12 @@
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
+
1
10
  import datetime
2
11
  import logging
3
12
  import time
@@ -14,9 +23,7 @@ LOG = logging.getLogger(__name__)
14
23
 
15
24
 
16
25
  def task(what, options, *args, **kwargs):
17
- """
18
- Make sure `import Creator` is done in the sub-processes, and not in the main one.
19
- """
26
+ """Make sure `import Creator` is done in the sub-processes, and not in the main one."""
20
27
 
21
28
  now = datetime.datetime.now()
22
29
  LOG.info(f"🎬 Task {what}({args},{kwargs}) starting")
@@ -117,7 +124,9 @@ class Create(Command):
117
124
  opt["parts"] = f"{n+1}/{total}"
118
125
  futures.append(executor.submit(task, "load", opt))
119
126
 
120
- for future in tqdm.tqdm(as_completed(futures), desc="Loading", total=len(futures), colour="green", position=parallel + 1): # fmt: skip
127
+ for future in tqdm.tqdm(
128
+ as_completed(futures), desc="Loading", total=len(futures), colour="green", position=parallel + 1
129
+ ):
121
130
  future.result()
122
131
 
123
132
  with ExecutorClass(max_workers=1) as executor:
@@ -133,7 +142,13 @@ class Create(Command):
133
142
  for n in range(total):
134
143
  futures.append(executor.submit(task, "load-additions", opt))
135
144
 
136
- for future in tqdm.tqdm(as_completed(futures), desc="Computing additions", total=len(futures), colour="green", position=parallel + 1): # fmt: skip
145
+ for future in tqdm.tqdm(
146
+ as_completed(futures),
147
+ desc="Computing additions",
148
+ total=len(futures),
149
+ colour="green",
150
+ position=parallel + 1,
151
+ ):
137
152
  future.result()
138
153
 
139
154
  with ExecutorClass(max_workers=1) as executor:
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,6 +1,8 @@
1
- # (C) Copyright 2023 European Centre for Medium-Range Weather Forecasts.
1
+ # (C) Copyright 2024 Anemoi contributors.
2
+ #
2
3
  # This software is licensed under the terms of the Apache Licence Version 2.0
3
4
  # which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5
+ #
4
6
  # In applying this licence, ECMWF does not waive the privileges and immunities
5
7
  # granted to it by virtue of its status as an intergovernmental organisation
6
8
  # nor does it submit to any jurisdiction.
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
  import time
3
12
 
@@ -1,3 +1,12 @@
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
+
1
10
  import logging
2
11
 
3
12
  from . import Command
@@ -1,3 +1,12 @@
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
+
1
10
  import fnmatch
2
11
  import os
3
12
  import sys
@@ -0,0 +1,8 @@
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.
@@ -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
 
@@ -1,11 +1,11 @@
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
  import datetime
11
11
  import json
@@ -14,12 +14,11 @@ import os
14
14
  import time
15
15
  import uuid
16
16
  import warnings
17
- from copy import deepcopy
18
17
  from functools import cached_property
19
18
 
19
+ import cftime
20
20
  import numpy as np
21
21
  import tqdm
22
- from anemoi.utils.config import DotDict as DotDict
23
22
  from anemoi.utils.dates import as_datetime
24
23
  from anemoi.utils.dates import frequency_to_string
25
24
  from anemoi.utils.dates import frequency_to_timedelta
@@ -67,6 +66,19 @@ def json_tidy(o):
67
66
  if isinstance(o, datetime.timedelta):
68
67
  return frequency_to_string(o)
69
68
 
69
+ if isinstance(o, cftime.DatetimeJulian):
70
+ import pandas as pd
71
+
72
+ o = pd.Timestamp(
73
+ o.year,
74
+ o.month,
75
+ o.day,
76
+ o.hour,
77
+ o.minute,
78
+ o.second,
79
+ )
80
+ return o.isoformat()
81
+
70
82
  raise TypeError(repr(o) + " is not JSON serializable")
71
83
 
72
84
 
@@ -94,10 +106,6 @@ def build_statistics_dates(dates, start, end):
94
106
  return (start.isoformat(), end.isoformat())
95
107
 
96
108
 
97
- def _ignore(*args, **kwargs):
98
- pass
99
-
100
-
101
109
  def _path_readable(path):
102
110
  import zarr
103
111
 
@@ -278,6 +286,16 @@ class Size(Actor):
278
286
  metadata = compute_directory_sizes(self.path)
279
287
  self.update_metadata(**metadata)
280
288
 
289
+ # Look for constant fields
290
+ ds = open_dataset(self.path)
291
+ constants = ds.computed_constant_fields()
292
+
293
+ variables_metadata = self.dataset.zarr_metadata.get("variables_metadata", {}).copy()
294
+ for k in constants:
295
+ variables_metadata[k]["constant_in_time"] = True
296
+
297
+ self.update_metadata(constant_fields=constants, variables_metadata=variables_metadata)
298
+
281
299
 
282
300
  class HasRegistryMixin:
283
301
  @cached_property
@@ -308,7 +326,7 @@ class HasElementForDataMixin:
308
326
  self.output = build_output(config.output, parent=self)
309
327
 
310
328
  self.input = build_input_(main_config=config, output_config=self.output)
311
- LOG.info(self.input)
329
+ LOG.info("%s", self.input)
312
330
 
313
331
 
314
332
  def build_input_(main_config, output_config):
@@ -328,7 +346,20 @@ def build_input_(main_config, output_config):
328
346
 
329
347
  class Init(Actor, HasRegistryMixin, HasStatisticTempMixin, HasElementForDataMixin):
330
348
  dataset_class = NewDataset
331
- def __init__(self, path, config, check_name=False, overwrite=False, use_threads=False, statistics_temp_dir=None, progress=None, test=False, cache=None, **kwargs): # fmt: skip
349
+
350
+ def __init__(
351
+ self,
352
+ path,
353
+ config,
354
+ check_name=False,
355
+ overwrite=False,
356
+ use_threads=False,
357
+ statistics_temp_dir=None,
358
+ progress=None,
359
+ test=False,
360
+ cache=None,
361
+ **kwargs,
362
+ ):
332
363
  if _path_readable(path) and not overwrite:
333
364
  raise Exception(f"{path} already exists. Use overwrite=True to overwrite.")
334
365
 
@@ -412,7 +443,24 @@ class Init(Actor, HasRegistryMixin, HasStatisticTempMixin, HasElementForDataMixi
412
443
  metadata.update(self.main_config.get("add_metadata", {}))
413
444
 
414
445
  metadata["_create_yaml_config"] = self.main_config.get_serialisable_dict()
415
- metadata["recipe"] = sanitise(self.main_config.get_serialisable_dict())
446
+
447
+ recipe = sanitise(self.main_config.get_serialisable_dict())
448
+
449
+ # Remove stuff added by prepml
450
+ for k in [
451
+ "build_dataset",
452
+ "config_format_version",
453
+ "config_path",
454
+ "dataset_status",
455
+ "ecflow",
456
+ "metadata",
457
+ "platform",
458
+ "reading_chunks",
459
+ "upload",
460
+ ]:
461
+ recipe.pop(k, None)
462
+
463
+ metadata["recipe"] = recipe
416
464
 
417
465
  metadata["description"] = self.main_config.description
418
466
  metadata["licence"] = self.main_config["licence"]
@@ -496,7 +544,9 @@ class Init(Actor, HasRegistryMixin, HasStatisticTempMixin, HasElementForDataMixi
496
544
 
497
545
 
498
546
  class Load(Actor, HasRegistryMixin, HasStatisticTempMixin, HasElementForDataMixin):
499
- def __init__(self, path, parts=None, use_threads=False, statistics_temp_dir=None, progress=None, cache=None, **kwargs): # fmt: skip
547
+ def __init__(
548
+ self, path, parts=None, use_threads=False, statistics_temp_dir=None, progress=None, cache=None, **kwargs
549
+ ):
500
550
  super().__init__(path, cache=cache)
501
551
  self.use_threads = use_threads
502
552
  self.statistics_temp_dir = statistics_temp_dir
@@ -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
@@ -88,7 +89,7 @@ class DatasetName:
88
89
  self.messages.append(
89
90
  f"the dataset name {self} does not follow naming convention. "
90
91
  "See here for details: "
91
- "https://confluence.ecmwf.int/display/DWF/Datasets+available+as+zarr"
92
+ "https://anemoi-registry.readthedocs.io/en/latest/naming-conventions.html"
92
93
  )
93
94
 
94
95
  def check_resolution(self, resolution):
@@ -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 warnings
11
12