anemoi-utils 0.1.7__tar.gz → 0.1.8__tar.gz
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.
Potentially problematic release.
This version of anemoi-utils might be problematic. Click here for more details.
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/PKG-INFO +1 -1
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/_version.py +2 -2
- anemoi_utils-0.1.8/src/anemoi/utils/caching.py +59 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/grib.py +56 -3
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi_utils.egg-info/PKG-INFO +1 -1
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi_utils.egg-info/SOURCES.txt +1 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/tests/test_utils.py +8 -1
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/.github/workflows/python-publish.yml +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/.gitignore +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/.pre-commit-config.yaml +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/.readthedocs.yaml +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/LICENSE +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/README.md +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/Makefile +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/_static/logo.png +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/_static/style.css +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/_templates/.gitkeep +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/conf.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/index.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/installing.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/modules/checkpoints.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/modules/config.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/modules/dates.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/modules/grib.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/modules/humanize.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/modules/provenance.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/modules/text.rst +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/docs/requirements.txt +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/pyproject.toml +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/setup.cfg +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/__init__.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/checkpoints.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/config.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/dates.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/humanize.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/provenance.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi/utils/text.py +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi_utils.egg-info/dependency_links.txt +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi_utils.egg-info/requires.txt +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/src/anemoi_utils.egg-info/top_level.txt +0 -0
- {anemoi_utils-0.1.7 → anemoi_utils-0.1.8}/tests/requirements.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: A package to hold various functions to support training of ML models on ECMWF data.
|
|
5
5
|
Author-email: "European Centre for Medium-Range Weather Forecasts (ECMWF)" <software.support@ecmwf.int>
|
|
6
6
|
License: Apache License
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# (C) Copyright 2024 European Centre for Medium-Range Weather Forecasts.
|
|
2
|
+
# This software is licensed under the terms of the Apache Licence Version 2.0
|
|
3
|
+
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
|
|
4
|
+
# In applying this licence, ECMWF does not waive the privileges and immunities
|
|
5
|
+
# granted to it by virtue of its status as an intergovernmental organisation
|
|
6
|
+
# nor does it submit to any jurisdiction.
|
|
7
|
+
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import time
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def cache(key, proc, collection="default", expires=None):
|
|
15
|
+
path = os.path.join(os.path.expanduser("~"), ".cache", "anemoi", collection)
|
|
16
|
+
os.makedirs(path, exist_ok=True)
|
|
17
|
+
|
|
18
|
+
key = json.dumps(key, sort_keys=True)
|
|
19
|
+
m = hashlib.md5()
|
|
20
|
+
m.update(key.encode("utf-8"))
|
|
21
|
+
|
|
22
|
+
filename = os.path.join(path, m.hexdigest())
|
|
23
|
+
if os.path.exists(filename):
|
|
24
|
+
with open(filename, "r") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
if expires is None or data["expires"] > time.time():
|
|
27
|
+
if data["key"] == key:
|
|
28
|
+
return data["value"]
|
|
29
|
+
|
|
30
|
+
value = proc()
|
|
31
|
+
data = {"key": key, "value": value}
|
|
32
|
+
if expires is not None:
|
|
33
|
+
data["expires"] = time.time() + expires
|
|
34
|
+
|
|
35
|
+
with open(filename, "w") as f:
|
|
36
|
+
json.dump(data, f)
|
|
37
|
+
|
|
38
|
+
return value
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class cached:
|
|
42
|
+
|
|
43
|
+
def __init__(self, collection="default", expires=None):
|
|
44
|
+
self.collection = collection
|
|
45
|
+
self.expires = expires
|
|
46
|
+
|
|
47
|
+
def __call__(self, func):
|
|
48
|
+
|
|
49
|
+
full = f"{func.__module__}.{func.__name__}"
|
|
50
|
+
|
|
51
|
+
def wrapped(*args, **kwargs):
|
|
52
|
+
return cache(
|
|
53
|
+
(full, args, kwargs),
|
|
54
|
+
lambda: func(*args, **kwargs),
|
|
55
|
+
self.collection,
|
|
56
|
+
self.expires,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return wrapped
|
|
@@ -16,10 +16,21 @@ import re
|
|
|
16
16
|
|
|
17
17
|
import requests
|
|
18
18
|
|
|
19
|
+
from .caching import cached
|
|
20
|
+
|
|
19
21
|
LOG = logging.getLogger(__name__)
|
|
20
22
|
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
@cached(collection="grib", expires=30 * 24 * 60 * 60)
|
|
25
|
+
def _units():
|
|
26
|
+
r = requests.get("https://codes.ecmwf.int/parameter-database/api/v1/unit/")
|
|
27
|
+
r.raise_for_status()
|
|
28
|
+
units = r.json()
|
|
29
|
+
return {str(u["id"]): u["name"] for u in units}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@cached(collection="grib", expires=30 * 24 * 60 * 60)
|
|
33
|
+
def _search_param(name):
|
|
23
34
|
name = re.escape(name)
|
|
24
35
|
r = requests.get(f"https://codes.ecmwf.int/parameter-database/api/v1/param/?search=^{name}$®ex=true")
|
|
25
36
|
r.raise_for_status()
|
|
@@ -56,7 +67,7 @@ def shortname_to_paramid(shortname: str) -> int:
|
|
|
56
67
|
167
|
|
57
68
|
|
|
58
69
|
"""
|
|
59
|
-
return
|
|
70
|
+
return _search_param(shortname)["id"]
|
|
60
71
|
|
|
61
72
|
|
|
62
73
|
def paramid_to_shortname(paramid: int) -> str:
|
|
@@ -76,4 +87,46 @@ def paramid_to_shortname(paramid: int) -> str:
|
|
|
76
87
|
'2t'
|
|
77
88
|
|
|
78
89
|
"""
|
|
79
|
-
return
|
|
90
|
+
return _search_param(str(paramid))["shortname"]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def units(param) -> str:
|
|
94
|
+
"""Return the units of a GRIB parameter given its name or id.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
paramid : int or str
|
|
99
|
+
Parameter id ir name.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
str
|
|
104
|
+
Parameter unit.
|
|
105
|
+
|
|
106
|
+
>>> unit(167)
|
|
107
|
+
'K'
|
|
108
|
+
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
unit_id = str(_search_param(str(param))["unit_id"])
|
|
112
|
+
return _units()[unit_id]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def must_be_positive(param):
|
|
116
|
+
"""Check if a parameter must be positive.
|
|
117
|
+
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
param : int or str
|
|
121
|
+
Parameter id or shortname.
|
|
122
|
+
|
|
123
|
+
Returns
|
|
124
|
+
-------
|
|
125
|
+
bool
|
|
126
|
+
True if the parameter must be positive.
|
|
127
|
+
|
|
128
|
+
>>> must_be_positive("tp")
|
|
129
|
+
True
|
|
130
|
+
|
|
131
|
+
"""
|
|
132
|
+
return units(param) in ["m", "kg kg**-1", "m of water equivalent"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: anemoi-utils
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: A package to hold various functions to support training of ML models on ECMWF data.
|
|
5
5
|
Author-email: "European Centre for Medium-Range Weather Forecasts (ECMWF)" <software.support@ecmwf.int>
|
|
6
6
|
License: Apache License
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
from anemoi.utils.config import DotDict
|
|
10
|
+
from anemoi.utils.grib import paramid_to_shortname
|
|
11
|
+
from anemoi.utils.grib import shortname_to_paramid
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def test_dotdict():
|
|
@@ -26,5 +28,10 @@ def test_dotdict():
|
|
|
26
28
|
assert d.d.x == 6
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
def test_grib():
|
|
32
|
+
assert shortname_to_paramid("2t") == 167
|
|
33
|
+
assert paramid_to_shortname(167) == "2t"
|
|
34
|
+
|
|
35
|
+
|
|
29
36
|
if __name__ == "__main__":
|
|
30
|
-
|
|
37
|
+
test_grib()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|