vortex-nwp 2.0.0__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.
- vortex/__init__.py +159 -0
- vortex/algo/__init__.py +13 -0
- vortex/algo/components.py +2462 -0
- vortex/algo/mpitools.py +1953 -0
- vortex/algo/mpitools_templates/__init__.py +1 -0
- vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
- vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
- vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
- vortex/algo/serversynctools.py +171 -0
- vortex/config.py +112 -0
- vortex/data/__init__.py +19 -0
- vortex/data/abstractstores.py +1510 -0
- vortex/data/containers.py +835 -0
- vortex/data/contents.py +622 -0
- vortex/data/executables.py +275 -0
- vortex/data/flow.py +119 -0
- vortex/data/geometries.ini +2689 -0
- vortex/data/geometries.py +799 -0
- vortex/data/handlers.py +1230 -0
- vortex/data/outflow.py +67 -0
- vortex/data/providers.py +487 -0
- vortex/data/resources.py +207 -0
- vortex/data/stores.py +1390 -0
- vortex/data/sync_templates/__init__.py +0 -0
- vortex/gloves.py +309 -0
- vortex/layout/__init__.py +20 -0
- vortex/layout/contexts.py +577 -0
- vortex/layout/dataflow.py +1220 -0
- vortex/layout/monitor.py +969 -0
- vortex/nwp/__init__.py +14 -0
- vortex/nwp/algo/__init__.py +21 -0
- vortex/nwp/algo/assim.py +537 -0
- vortex/nwp/algo/clim.py +1086 -0
- vortex/nwp/algo/coupling.py +831 -0
- vortex/nwp/algo/eda.py +840 -0
- vortex/nwp/algo/eps.py +785 -0
- vortex/nwp/algo/forecasts.py +886 -0
- vortex/nwp/algo/fpserver.py +1303 -0
- vortex/nwp/algo/ifsnaming.py +463 -0
- vortex/nwp/algo/ifsroot.py +404 -0
- vortex/nwp/algo/monitoring.py +263 -0
- vortex/nwp/algo/mpitools.py +694 -0
- vortex/nwp/algo/odbtools.py +1258 -0
- vortex/nwp/algo/oopsroot.py +916 -0
- vortex/nwp/algo/oopstests.py +220 -0
- vortex/nwp/algo/request.py +660 -0
- vortex/nwp/algo/stdpost.py +1641 -0
- vortex/nwp/data/__init__.py +30 -0
- vortex/nwp/data/assim.py +380 -0
- vortex/nwp/data/boundaries.py +314 -0
- vortex/nwp/data/climfiles.py +521 -0
- vortex/nwp/data/configfiles.py +153 -0
- vortex/nwp/data/consts.py +954 -0
- vortex/nwp/data/ctpini.py +149 -0
- vortex/nwp/data/diagnostics.py +209 -0
- vortex/nwp/data/eda.py +147 -0
- vortex/nwp/data/eps.py +432 -0
- vortex/nwp/data/executables.py +1045 -0
- vortex/nwp/data/fields.py +111 -0
- vortex/nwp/data/gridfiles.py +380 -0
- vortex/nwp/data/logs.py +584 -0
- vortex/nwp/data/modelstates.py +363 -0
- vortex/nwp/data/monitoring.py +193 -0
- vortex/nwp/data/namelists.py +696 -0
- vortex/nwp/data/obs.py +840 -0
- vortex/nwp/data/oopsexec.py +74 -0
- vortex/nwp/data/providers.py +207 -0
- vortex/nwp/data/query.py +206 -0
- vortex/nwp/data/stores.py +160 -0
- vortex/nwp/data/surfex.py +337 -0
- vortex/nwp/syntax/__init__.py +9 -0
- vortex/nwp/syntax/stdattrs.py +437 -0
- vortex/nwp/tools/__init__.py +10 -0
- vortex/nwp/tools/addons.py +40 -0
- vortex/nwp/tools/agt.py +67 -0
- vortex/nwp/tools/bdap.py +59 -0
- vortex/nwp/tools/bdcp.py +41 -0
- vortex/nwp/tools/bdm.py +24 -0
- vortex/nwp/tools/bdmp.py +54 -0
- vortex/nwp/tools/conftools.py +1661 -0
- vortex/nwp/tools/drhook.py +66 -0
- vortex/nwp/tools/grib.py +294 -0
- vortex/nwp/tools/gribdiff.py +104 -0
- vortex/nwp/tools/ifstools.py +203 -0
- vortex/nwp/tools/igastuff.py +273 -0
- vortex/nwp/tools/mars.py +68 -0
- vortex/nwp/tools/odb.py +657 -0
- vortex/nwp/tools/partitioning.py +258 -0
- vortex/nwp/tools/satrad.py +71 -0
- vortex/nwp/util/__init__.py +6 -0
- vortex/nwp/util/async.py +212 -0
- vortex/nwp/util/beacon.py +40 -0
- vortex/nwp/util/diffpygram.py +447 -0
- vortex/nwp/util/ens.py +279 -0
- vortex/nwp/util/hooks.py +139 -0
- vortex/nwp/util/taskdeco.py +85 -0
- vortex/nwp/util/usepygram.py +697 -0
- vortex/nwp/util/usetnt.py +101 -0
- vortex/proxy.py +6 -0
- vortex/sessions.py +374 -0
- vortex/syntax/__init__.py +9 -0
- vortex/syntax/stdattrs.py +867 -0
- vortex/syntax/stddeco.py +185 -0
- vortex/toolbox.py +1117 -0
- vortex/tools/__init__.py +20 -0
- vortex/tools/actions.py +523 -0
- vortex/tools/addons.py +316 -0
- vortex/tools/arm.py +96 -0
- vortex/tools/compression.py +325 -0
- vortex/tools/date.py +27 -0
- vortex/tools/ddhpack.py +10 -0
- vortex/tools/delayedactions.py +782 -0
- vortex/tools/env.py +541 -0
- vortex/tools/folder.py +834 -0
- vortex/tools/grib.py +738 -0
- vortex/tools/lfi.py +953 -0
- vortex/tools/listings.py +423 -0
- vortex/tools/names.py +637 -0
- vortex/tools/net.py +2124 -0
- vortex/tools/odb.py +10 -0
- vortex/tools/parallelism.py +368 -0
- vortex/tools/prestaging.py +210 -0
- vortex/tools/rawfiles.py +10 -0
- vortex/tools/schedulers.py +480 -0
- vortex/tools/services.py +940 -0
- vortex/tools/storage.py +996 -0
- vortex/tools/surfex.py +61 -0
- vortex/tools/systems.py +3976 -0
- vortex/tools/targets.py +440 -0
- vortex/util/__init__.py +9 -0
- vortex/util/config.py +1122 -0
- vortex/util/empty.py +24 -0
- vortex/util/helpers.py +216 -0
- vortex/util/introspection.py +69 -0
- vortex/util/iosponge.py +80 -0
- vortex/util/roles.py +49 -0
- vortex/util/storefunctions.py +129 -0
- vortex/util/structs.py +26 -0
- vortex/util/worker.py +162 -0
- vortex_nwp-2.0.0.dist-info/METADATA +67 -0
- vortex_nwp-2.0.0.dist-info/RECORD +144 -0
- vortex_nwp-2.0.0.dist-info/WHEEL +5 -0
- vortex_nwp-2.0.0.dist-info/licenses/LICENSE +517 -0
- vortex_nwp-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,867 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides some pre-defined attributes descriptions or combined sets
|
|
3
|
+
of attributes description that could be used in the footprint definition of any
|
|
4
|
+
class which follow the :class:`footprints.Footprint` syntax.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import copy
|
|
8
|
+
import re
|
|
9
|
+
|
|
10
|
+
import footprints
|
|
11
|
+
from bronx.stdtypes.date import Date, Month, Time
|
|
12
|
+
from bronx.syntax.decorators import secure_getattr
|
|
13
|
+
from bronx.system import hash as hashutils
|
|
14
|
+
from vortex.tools import env
|
|
15
|
+
|
|
16
|
+
from .stddeco import (
|
|
17
|
+
generic_pathname_insert,
|
|
18
|
+
namebuilding_append,
|
|
19
|
+
namebuilding_insert,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
#: Export a set of attributes :data:`a_model`, :data:`a_date`, etc..
|
|
23
|
+
__all__ = [
|
|
24
|
+
"a_xpid",
|
|
25
|
+
"a_month",
|
|
26
|
+
"a_domain",
|
|
27
|
+
"a_truncation",
|
|
28
|
+
"a_model",
|
|
29
|
+
"a_member",
|
|
30
|
+
"a_date",
|
|
31
|
+
"a_cutoff",
|
|
32
|
+
"a_term",
|
|
33
|
+
"a_nativefmt",
|
|
34
|
+
"a_actualfmt",
|
|
35
|
+
"a_suite",
|
|
36
|
+
"a_namespace",
|
|
37
|
+
"a_hashalgo",
|
|
38
|
+
"a_compressionpipeline",
|
|
39
|
+
"a_block",
|
|
40
|
+
"a_number",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
#: Possible values for the *model* attribute.
|
|
44
|
+
models = {
|
|
45
|
+
"arpege",
|
|
46
|
+
"arp",
|
|
47
|
+
"arp_court",
|
|
48
|
+
"aladin",
|
|
49
|
+
"ald",
|
|
50
|
+
"arome",
|
|
51
|
+
"aro",
|
|
52
|
+
"aearp",
|
|
53
|
+
"pearp",
|
|
54
|
+
"mocage",
|
|
55
|
+
"mesonh",
|
|
56
|
+
"surfex",
|
|
57
|
+
"hycom",
|
|
58
|
+
"psy4",
|
|
59
|
+
"mercator_global",
|
|
60
|
+
"glo12",
|
|
61
|
+
"safran",
|
|
62
|
+
"ifs",
|
|
63
|
+
"aroifs",
|
|
64
|
+
"cifs",
|
|
65
|
+
"mfwam",
|
|
66
|
+
"pg1",
|
|
67
|
+
"alpha",
|
|
68
|
+
"eps",
|
|
69
|
+
"postproc",
|
|
70
|
+
"ww3",
|
|
71
|
+
"sympo",
|
|
72
|
+
"psym",
|
|
73
|
+
"petaroute",
|
|
74
|
+
"promethee",
|
|
75
|
+
"hycom3d",
|
|
76
|
+
"croco",
|
|
77
|
+
"alaro",
|
|
78
|
+
"harmoniearome",
|
|
79
|
+
"nemo",
|
|
80
|
+
"oasis",
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#: Possible values for the most common binaries.
|
|
84
|
+
binaries = {
|
|
85
|
+
"arpege",
|
|
86
|
+
"aladin",
|
|
87
|
+
"arome",
|
|
88
|
+
"aromeom_common",
|
|
89
|
+
"batodb",
|
|
90
|
+
"peace",
|
|
91
|
+
"mocage",
|
|
92
|
+
"sumo",
|
|
93
|
+
"corromegasurf",
|
|
94
|
+
"mesonh",
|
|
95
|
+
"safran",
|
|
96
|
+
"surfex",
|
|
97
|
+
"macc",
|
|
98
|
+
"mktopbd",
|
|
99
|
+
"ifs",
|
|
100
|
+
"oops",
|
|
101
|
+
"assistance",
|
|
102
|
+
"arpifs",
|
|
103
|
+
"mfwam",
|
|
104
|
+
"mfwam_interp",
|
|
105
|
+
"mfwam_interpbc",
|
|
106
|
+
"ww3",
|
|
107
|
+
"ww3_prnc",
|
|
108
|
+
"ww3_bound",
|
|
109
|
+
"ww3_ncgrb",
|
|
110
|
+
"ial",
|
|
111
|
+
"alaro",
|
|
112
|
+
"harmoniearome",
|
|
113
|
+
"nemo",
|
|
114
|
+
"oasis",
|
|
115
|
+
"arobase",
|
|
116
|
+
"xios",
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#: Possible values for the most common utility programs.
|
|
120
|
+
utilities = {"batodb"}
|
|
121
|
+
|
|
122
|
+
#: Known formats
|
|
123
|
+
knownfmt = {
|
|
124
|
+
"auto",
|
|
125
|
+
"autoconfig",
|
|
126
|
+
"unknown",
|
|
127
|
+
"foo",
|
|
128
|
+
"arpifslist",
|
|
129
|
+
"bdmbufr_listing",
|
|
130
|
+
"ascii",
|
|
131
|
+
"txt",
|
|
132
|
+
"json",
|
|
133
|
+
"fa",
|
|
134
|
+
"lfi",
|
|
135
|
+
"lfa",
|
|
136
|
+
"netcdf",
|
|
137
|
+
"grib",
|
|
138
|
+
"grib1",
|
|
139
|
+
"grib2",
|
|
140
|
+
"bufr",
|
|
141
|
+
"hdf5",
|
|
142
|
+
"obsoul",
|
|
143
|
+
"odb",
|
|
144
|
+
"ecma",
|
|
145
|
+
"ccma",
|
|
146
|
+
"bullx",
|
|
147
|
+
"sx",
|
|
148
|
+
"ddhpack",
|
|
149
|
+
"tar",
|
|
150
|
+
"tgz",
|
|
151
|
+
"rawfiles",
|
|
152
|
+
"binary",
|
|
153
|
+
"bin",
|
|
154
|
+
"obslocationpack",
|
|
155
|
+
"obsfirepack",
|
|
156
|
+
"wbcpack",
|
|
157
|
+
"geo",
|
|
158
|
+
"nam",
|
|
159
|
+
"png",
|
|
160
|
+
"pdf",
|
|
161
|
+
"dir/hdr",
|
|
162
|
+
"yml",
|
|
163
|
+
"yaml",
|
|
164
|
+
"ini",
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#: Default attributes excluded from `repr` display
|
|
168
|
+
notinrepr = {"kind", "unknown", "clscontents", "gvar", "nativefmt"}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class DelayedEnvValue:
|
|
172
|
+
"""
|
|
173
|
+
Store an environment variable name and compute its value when needed,
|
|
174
|
+
*e.g.* in a footprint evaluation.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def __init__(self, varname, default=None, refresh=False):
|
|
178
|
+
self.varname = varname
|
|
179
|
+
self.default = default
|
|
180
|
+
self.refresh = refresh
|
|
181
|
+
self._value = None
|
|
182
|
+
self._frozen = False
|
|
183
|
+
|
|
184
|
+
def as_dump(self):
|
|
185
|
+
return "varname={},default={}".format(self.varname, self.default)
|
|
186
|
+
|
|
187
|
+
def footprint_value(self):
|
|
188
|
+
"""
|
|
189
|
+
Return the actual env value of the ``varname`` variable.
|
|
190
|
+
Optional argument ``refresh`` set to ``True`` do not store this value.
|
|
191
|
+
"""
|
|
192
|
+
if not self._frozen:
|
|
193
|
+
self._value = env.current().get(self.varname, self.default)
|
|
194
|
+
if not self.refresh:
|
|
195
|
+
self._frozen = True
|
|
196
|
+
return self._value
|
|
197
|
+
|
|
198
|
+
def export_dict(self):
|
|
199
|
+
"""The pure dict/json value is the actual value."""
|
|
200
|
+
return self.footprint_value()
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class DelayedInit:
|
|
204
|
+
"""
|
|
205
|
+
Delays the proxied object creation until it's actually accessed.
|
|
206
|
+
*e.g.* in a footprint evaluation.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
def __init__(self, proxied, initializer):
|
|
210
|
+
self.__proxied = proxied
|
|
211
|
+
self.__initializer = initializer
|
|
212
|
+
|
|
213
|
+
@secure_getattr
|
|
214
|
+
def __getattr__(self, name):
|
|
215
|
+
if self.__proxied is None:
|
|
216
|
+
self.__proxied = self.__initializer()
|
|
217
|
+
return getattr(self.__proxied, name)
|
|
218
|
+
|
|
219
|
+
def __repr__(self):
|
|
220
|
+
orig = re.sub("^<(.*)>$", r"\1", super().__repr__())
|
|
221
|
+
return "<{:s} | proxied={:s}>".format(
|
|
222
|
+
orig,
|
|
223
|
+
"Not yet Initialised"
|
|
224
|
+
if self.__proxied is None
|
|
225
|
+
else repr(self.__proxied),
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
def __str__(self):
|
|
229
|
+
return repr(self) if self.__proxied is None else str(self.__proxied)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class FmtInt(int):
|
|
233
|
+
"""Formated integer."""
|
|
234
|
+
|
|
235
|
+
def __new__(cls, value, fmt="02"):
|
|
236
|
+
obj = int.__new__(cls, value)
|
|
237
|
+
obj._fmt = fmt
|
|
238
|
+
return obj
|
|
239
|
+
|
|
240
|
+
def __str__(self):
|
|
241
|
+
return "{0:{fmt}d}".format(self.__int__(), fmt=self._fmt)
|
|
242
|
+
|
|
243
|
+
def export_dict(self):
|
|
244
|
+
"""The pure dict/json output is the raw integer"""
|
|
245
|
+
return int(self)
|
|
246
|
+
|
|
247
|
+
def nice(self, value):
|
|
248
|
+
"""Returns the specified ``value`` with the format of the current object."""
|
|
249
|
+
return "{0:{fmt}d}".format(value, fmt=self._fmt)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class XPid(str):
|
|
253
|
+
"""Basestring wrapper for experiment ids (abstract)."""
|
|
254
|
+
|
|
255
|
+
pass
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class LegacyXPid(XPid):
|
|
259
|
+
"""Basestring wrapper for experiment ids (Olive/Oper convention)."""
|
|
260
|
+
|
|
261
|
+
def __new__(cls, value):
|
|
262
|
+
if len(value) != 4 or "@" in value:
|
|
263
|
+
raise ValueError("XPid should be a 4 digits string")
|
|
264
|
+
return str.__new__(cls, value.upper())
|
|
265
|
+
|
|
266
|
+
def isoper(self):
|
|
267
|
+
"""Return true if current value looks like an op id."""
|
|
268
|
+
return str(self) in opsuites
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class FreeXPid(XPid):
|
|
272
|
+
"""Basestring wrapper for experiment ids (User defined)."""
|
|
273
|
+
|
|
274
|
+
_re_valid = re.compile(r"^\S+@[-\w]+$")
|
|
275
|
+
|
|
276
|
+
def __new__(cls, value):
|
|
277
|
+
if not cls._re_valid.match(value):
|
|
278
|
+
raise ValueError(
|
|
279
|
+
'XPid should be something like "id@location" (not "{:s}")'.format(
|
|
280
|
+
value
|
|
281
|
+
)
|
|
282
|
+
)
|
|
283
|
+
return str.__new__(cls, value)
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def id(self):
|
|
287
|
+
return self.split("@")[0]
|
|
288
|
+
|
|
289
|
+
@property
|
|
290
|
+
def location(self):
|
|
291
|
+
return self.split("@")[1]
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def any_vortex_xpid(xpidguess):
|
|
295
|
+
"""Try to reclass *xpidquess* as a Legacy or Free XPid"""
|
|
296
|
+
try:
|
|
297
|
+
try:
|
|
298
|
+
xp = LegacyXPid(xpidguess)
|
|
299
|
+
except ValueError:
|
|
300
|
+
xp = FreeXPid(xpidguess)
|
|
301
|
+
except ValueError:
|
|
302
|
+
raise ValueError(
|
|
303
|
+
"'{:s}' could not be reclassed as a LegacyXPid or a FreeXPid"
|
|
304
|
+
)
|
|
305
|
+
return xp
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
#: The list of operational experiment names.
|
|
309
|
+
opsuites = {
|
|
310
|
+
LegacyXPid(x)
|
|
311
|
+
for x in (
|
|
312
|
+
["OPER", "DBLE", "TEST", "MIRR"]
|
|
313
|
+
+ ["OP{:02d}".format(i) for i in range(100)]
|
|
314
|
+
)
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
#: The list of experiemnt names dedicated to Vortex' demos
|
|
318
|
+
demosuites = {LegacyXPid("DEMO"), LegacyXPid("DREF")}
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class Namespace(str):
|
|
322
|
+
"""Basestring wrapper for namespaces (as net domains)."""
|
|
323
|
+
|
|
324
|
+
def __new__(cls, value):
|
|
325
|
+
value = value.lower()
|
|
326
|
+
full = value
|
|
327
|
+
if "@" in value:
|
|
328
|
+
netuser, value = value.split("@")
|
|
329
|
+
if ":" in netuser:
|
|
330
|
+
netuser, netpass = netuser.split(":")
|
|
331
|
+
else:
|
|
332
|
+
netpass = None
|
|
333
|
+
else:
|
|
334
|
+
netuser, netpass = None, None
|
|
335
|
+
if ":" in value:
|
|
336
|
+
value, port = value.split(":")
|
|
337
|
+
else:
|
|
338
|
+
port = None
|
|
339
|
+
if 0 < value.count(".") < 2:
|
|
340
|
+
raise ValueError(
|
|
341
|
+
"Namespace should contain one or at least 3 fields"
|
|
342
|
+
)
|
|
343
|
+
thisns = str.__new__(cls, value)
|
|
344
|
+
thisns._port = int(port) if port else None
|
|
345
|
+
thisns._user = netuser
|
|
346
|
+
thisns._pass = netpass
|
|
347
|
+
thisns._full = full
|
|
348
|
+
return thisns
|
|
349
|
+
|
|
350
|
+
@property
|
|
351
|
+
def firstname(self):
|
|
352
|
+
return self.split(".", 1)[0]
|
|
353
|
+
|
|
354
|
+
@property
|
|
355
|
+
def domain(self):
|
|
356
|
+
if "." in self.netloc:
|
|
357
|
+
return self.split(".", 1)[1]
|
|
358
|
+
else:
|
|
359
|
+
return self.netloc
|
|
360
|
+
|
|
361
|
+
@property
|
|
362
|
+
def netuser(self):
|
|
363
|
+
return self._user
|
|
364
|
+
|
|
365
|
+
@property
|
|
366
|
+
def netpass(self):
|
|
367
|
+
return self._pass
|
|
368
|
+
|
|
369
|
+
@property
|
|
370
|
+
def netport(self):
|
|
371
|
+
return self._port
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def netloc(self):
|
|
375
|
+
return self._full
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class Latitude(float):
|
|
379
|
+
"""Bounded floating point value with N-S nice representation."""
|
|
380
|
+
|
|
381
|
+
def __new__(cls, value):
|
|
382
|
+
value = str(value).lower()
|
|
383
|
+
if value.endswith("n"):
|
|
384
|
+
value = value[:-1]
|
|
385
|
+
elif value.endswith("s"):
|
|
386
|
+
value = value[:-1]
|
|
387
|
+
if not value.startswith("-"):
|
|
388
|
+
value = "-" + value
|
|
389
|
+
if not -90 <= float(value) <= 90:
|
|
390
|
+
raise ValueError("Latitude out of bounds: " + value)
|
|
391
|
+
return float.__new__(cls, value)
|
|
392
|
+
|
|
393
|
+
def nice(self):
|
|
394
|
+
ns = "N" if self >= 0 else "S"
|
|
395
|
+
return str(self).strip("-") + ns
|
|
396
|
+
|
|
397
|
+
@property
|
|
398
|
+
def hemisphere(self):
|
|
399
|
+
return "North" if self >= 0 else "South"
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
class Longitude(float):
|
|
403
|
+
"""Bounded floating point value with E-W nice representation."""
|
|
404
|
+
|
|
405
|
+
def __new__(cls, value):
|
|
406
|
+
value = str(value).lower()
|
|
407
|
+
if value.endswith("e"):
|
|
408
|
+
value = value[:-1]
|
|
409
|
+
elif value.endswith("w"):
|
|
410
|
+
value = value[:-1]
|
|
411
|
+
if not value.startswith("-"):
|
|
412
|
+
value = "-" + value
|
|
413
|
+
if not -180 <= float(value) <= 180:
|
|
414
|
+
raise ValueError("Longitude out of bounds: " + value)
|
|
415
|
+
return float.__new__(cls, value)
|
|
416
|
+
|
|
417
|
+
def nice(self):
|
|
418
|
+
ns = "E" if self >= 0 else "W"
|
|
419
|
+
return str(self).strip("-") + ns
|
|
420
|
+
|
|
421
|
+
@property
|
|
422
|
+
def hemisphere(self):
|
|
423
|
+
return "East" if self >= 0 else "West"
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
# predefined attributes
|
|
427
|
+
|
|
428
|
+
#: Usual definition for the ``xpid`` (*e.g.* experiment name).
|
|
429
|
+
a_xpid = dict(
|
|
430
|
+
info="The experiment's identifier.",
|
|
431
|
+
type=XPid,
|
|
432
|
+
optional=False,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
xpid = footprints.Footprint(
|
|
436
|
+
info="Abstract experiment id", attr=dict(experiment=a_xpid)
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
#: Usual definition for an Olive/Oper ``xpid`` (*e.g.* experiment name).
|
|
440
|
+
a_legacy_xpid = copy.copy(a_xpid)
|
|
441
|
+
a_legacy_xpid["type"] = LegacyXPid
|
|
442
|
+
|
|
443
|
+
legacy_xpid = footprints.Footprint(
|
|
444
|
+
info="Abstract experiment id", attr=dict(experiment=a_legacy_xpid)
|
|
445
|
+
)
|
|
446
|
+
|
|
447
|
+
#: Usual definition for a user-defined ``xpid`` (*e.g.* experiment name).
|
|
448
|
+
a_free_xpid = copy.copy(a_xpid)
|
|
449
|
+
a_free_xpid["type"] = FreeXPid
|
|
450
|
+
|
|
451
|
+
free_xpid = footprints.Footprint(
|
|
452
|
+
info="Abstract experiment id", attr=dict(experiment=a_free_xpid)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
#: Usual definition of the ``nativefmt`` attribute.
|
|
456
|
+
a_nativefmt = dict(
|
|
457
|
+
info="The resource's storage format.",
|
|
458
|
+
optional=True,
|
|
459
|
+
default="foo",
|
|
460
|
+
values=knownfmt,
|
|
461
|
+
remap=dict(auto="foo"),
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
nativefmt = footprints.Footprint(
|
|
465
|
+
info="Native format", attr=dict(nativefmt=a_nativefmt)
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def _namebuilding_insert_nativefmt(cls):
|
|
470
|
+
if hasattr(cls, "namebuilding_info"):
|
|
471
|
+
original_namebuilding_info = cls.namebuilding_info
|
|
472
|
+
|
|
473
|
+
def namebuilding_info(self):
|
|
474
|
+
vinfo = original_namebuilding_info(self)
|
|
475
|
+
ext_remap = getattr(self, "_extension_remap", dict())
|
|
476
|
+
ext_value = ext_remap.get(self.nativefmt, self.nativefmt)
|
|
477
|
+
if ext_value is not None:
|
|
478
|
+
vinfo.setdefault(
|
|
479
|
+
"fmt", ext_remap.get(self.nativefmt, self.nativefmt)
|
|
480
|
+
)
|
|
481
|
+
return vinfo
|
|
482
|
+
|
|
483
|
+
namebuilding_info.__doc__ = original_namebuilding_info.__doc__
|
|
484
|
+
cls.namebuilding_info = namebuilding_info
|
|
485
|
+
|
|
486
|
+
return cls
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
nativefmt_deco = footprints.DecorativeFootprint(
|
|
490
|
+
nativefmt,
|
|
491
|
+
decorator=[
|
|
492
|
+
_namebuilding_insert_nativefmt,
|
|
493
|
+
generic_pathname_insert(
|
|
494
|
+
"nativefmt", lambda self: self.nativefmt, setdefault=True
|
|
495
|
+
),
|
|
496
|
+
],
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
#: Usual definition of the ``actualfmt`` attribute.
|
|
500
|
+
a_actualfmt = dict(
|
|
501
|
+
info="The resource's format.",
|
|
502
|
+
optional=True,
|
|
503
|
+
default="[nativefmt#unknown]",
|
|
504
|
+
alias=("format",),
|
|
505
|
+
values=knownfmt,
|
|
506
|
+
remap=dict(auto="foo"),
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
actualfmt = footprints.Footprint(
|
|
510
|
+
info="Actual data format", attr=dict(actualfmt=a_actualfmt)
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
#: Usual definition of the ``cutoff`` attribute.
|
|
514
|
+
a_cutoff = dict(
|
|
515
|
+
info="The cutoff type of the generating process.",
|
|
516
|
+
optional=False,
|
|
517
|
+
alias=("cut",),
|
|
518
|
+
values=[
|
|
519
|
+
"a",
|
|
520
|
+
"assim",
|
|
521
|
+
"assimilation",
|
|
522
|
+
"long",
|
|
523
|
+
"p",
|
|
524
|
+
"prod",
|
|
525
|
+
"production",
|
|
526
|
+
"short",
|
|
527
|
+
],
|
|
528
|
+
remap=dict(
|
|
529
|
+
a="assim",
|
|
530
|
+
p="production",
|
|
531
|
+
prod="production",
|
|
532
|
+
long="assim",
|
|
533
|
+
assimilation="assim",
|
|
534
|
+
),
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
cutoff = footprints.Footprint(
|
|
538
|
+
info="Abstract cutoff", attr=dict(cutoff=a_cutoff)
|
|
539
|
+
)
|
|
540
|
+
|
|
541
|
+
cutoff_deco = footprints.DecorativeFootprint(
|
|
542
|
+
cutoff,
|
|
543
|
+
decorator=[
|
|
544
|
+
namebuilding_append(
|
|
545
|
+
"flow",
|
|
546
|
+
lambda self: None
|
|
547
|
+
if self.cutoff is None
|
|
548
|
+
else {"shortcutoff": self.cutoff},
|
|
549
|
+
none_discard=True,
|
|
550
|
+
),
|
|
551
|
+
generic_pathname_insert(
|
|
552
|
+
"cutoff", lambda self: self.cutoff, setdefault=True
|
|
553
|
+
),
|
|
554
|
+
],
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
#: Usual definition of the ``model`` attribute.
|
|
558
|
+
a_model = dict(
|
|
559
|
+
info="The model name (from a source code perspective).",
|
|
560
|
+
alias=("turtle",),
|
|
561
|
+
optional=False,
|
|
562
|
+
values=models,
|
|
563
|
+
remap=dict(arp="arpege", ald="aladin", aro="arome"),
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
model = footprints.Footprint(info="Abstract model", attr=dict(model=a_model))
|
|
567
|
+
|
|
568
|
+
model_deco = footprints.DecorativeFootprint(
|
|
569
|
+
model,
|
|
570
|
+
decorator=[
|
|
571
|
+
namebuilding_append(
|
|
572
|
+
"src",
|
|
573
|
+
lambda self: [
|
|
574
|
+
self.model,
|
|
575
|
+
],
|
|
576
|
+
),
|
|
577
|
+
generic_pathname_insert(
|
|
578
|
+
"model", lambda self: self.model, setdefault=True
|
|
579
|
+
),
|
|
580
|
+
],
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
#: Usual definition of the ``date`` attribute.
|
|
584
|
+
a_date = dict(
|
|
585
|
+
info="The generating process run date.",
|
|
586
|
+
type=Date,
|
|
587
|
+
optional=False,
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
date = footprints.Footprint(info="Abstract date", attr=dict(date=a_date))
|
|
591
|
+
|
|
592
|
+
date_deco = footprints.DecorativeFootprint(
|
|
593
|
+
date,
|
|
594
|
+
decorator=[
|
|
595
|
+
namebuilding_append("flow", lambda self: {"date": self.date}),
|
|
596
|
+
generic_pathname_insert(
|
|
597
|
+
"date", lambda self: self.date, setdefault=True
|
|
598
|
+
),
|
|
599
|
+
],
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
#: Usual definition of the ``begindate`` and ``enddate`` attributes.
|
|
603
|
+
|
|
604
|
+
dateperiod = footprints.Footprint(
|
|
605
|
+
info="Abstract date period",
|
|
606
|
+
attr=dict(
|
|
607
|
+
begindate=dict(
|
|
608
|
+
info="The resource's begin date.", type=Date, optional=False
|
|
609
|
+
),
|
|
610
|
+
enddate=dict(
|
|
611
|
+
info="The resource's end date.", type=Date, optional=False
|
|
612
|
+
),
|
|
613
|
+
),
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
dateperiod_deco = footprints.DecorativeFootprint(
|
|
617
|
+
dateperiod,
|
|
618
|
+
decorator=[
|
|
619
|
+
namebuilding_append(
|
|
620
|
+
"flow",
|
|
621
|
+
lambda self: [
|
|
622
|
+
{"begindate": self.begindate},
|
|
623
|
+
{"enddate": self.enddate},
|
|
624
|
+
],
|
|
625
|
+
),
|
|
626
|
+
generic_pathname_insert(
|
|
627
|
+
"begindate", lambda self: self.begindate, setdefault=True
|
|
628
|
+
),
|
|
629
|
+
generic_pathname_insert(
|
|
630
|
+
"enddate", lambda self: self.enddate, setdefault=True
|
|
631
|
+
),
|
|
632
|
+
],
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
#: Usual definition of the ``month`` attribute.
|
|
636
|
+
a_month = dict(
|
|
637
|
+
info="The generating process run month.",
|
|
638
|
+
type=Month,
|
|
639
|
+
args=dict(year=0),
|
|
640
|
+
optional=False,
|
|
641
|
+
values=range(1, 13),
|
|
642
|
+
)
|
|
643
|
+
|
|
644
|
+
month = footprints.Footprint(info="Abstract month", attr=dict(month=a_month))
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
def _add_month2gget_basename(cls):
|
|
648
|
+
"""Decorator that appends the month's number at the end of the gget_basename"""
|
|
649
|
+
original_gget_basename = getattr(cls, "gget_basename", None)
|
|
650
|
+
if original_gget_basename is not None:
|
|
651
|
+
|
|
652
|
+
def gget_basename(self):
|
|
653
|
+
"""GGET specific naming convention."""
|
|
654
|
+
b_dict = original_gget_basename(self)
|
|
655
|
+
b_dict["suffix"] = b_dict.get("suffix", "") + ".m{!s}".format(
|
|
656
|
+
self.month
|
|
657
|
+
)
|
|
658
|
+
return b_dict
|
|
659
|
+
|
|
660
|
+
cls.gget_basename = gget_basename
|
|
661
|
+
return cls
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
def _add_month2olive_basename(cls):
|
|
665
|
+
"""Decorator that appends the month's number at the end of the olive_basename."""
|
|
666
|
+
original_olive_basename = getattr(cls, "olive_basename", None)
|
|
667
|
+
if original_olive_basename is not None:
|
|
668
|
+
|
|
669
|
+
def olive_basename(self):
|
|
670
|
+
"""GGET specific naming convention."""
|
|
671
|
+
return original_olive_basename(self) + ".{!s}".format(self.month)
|
|
672
|
+
|
|
673
|
+
cls.olive_basename = olive_basename
|
|
674
|
+
return cls
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
month_deco = footprints.DecorativeFootprint(
|
|
678
|
+
month,
|
|
679
|
+
decorator=[
|
|
680
|
+
namebuilding_append("suffix", lambda self: {"month": self.month}),
|
|
681
|
+
_add_month2gget_basename,
|
|
682
|
+
_add_month2olive_basename,
|
|
683
|
+
],
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
#: Usual definition of the ``truncation`` attribute.
|
|
687
|
+
a_truncation = dict(
|
|
688
|
+
info="The resource's truncation.",
|
|
689
|
+
type=int,
|
|
690
|
+
optional=False,
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
truncation = footprints.Footprint(
|
|
694
|
+
info="Abstract truncation", attr=dict(truncation=a_truncation)
|
|
695
|
+
)
|
|
696
|
+
|
|
697
|
+
#: Usual definition of the ``domain`` attribute.
|
|
698
|
+
a_domain = dict(
|
|
699
|
+
info="The resource's geographical domain.",
|
|
700
|
+
optional=False,
|
|
701
|
+
)
|
|
702
|
+
|
|
703
|
+
domain = footprints.Footprint(
|
|
704
|
+
info="Abstract domain", attr=dict(domain=a_domain)
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
#: Usual definition of the ``term`` attribute.
|
|
708
|
+
a_term = dict(
|
|
709
|
+
info="The resource's forecast term.",
|
|
710
|
+
type=Time,
|
|
711
|
+
optional=False,
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
term = footprints.Footprint(info="Abstract term", attr=dict(term=a_term))
|
|
715
|
+
|
|
716
|
+
term_deco = footprints.DecorativeFootprint(
|
|
717
|
+
term,
|
|
718
|
+
decorator=[
|
|
719
|
+
namebuilding_insert(
|
|
720
|
+
"term",
|
|
721
|
+
lambda self: None if self.term is None else self.term.fmthm,
|
|
722
|
+
none_discard=True,
|
|
723
|
+
setdefault=True,
|
|
724
|
+
),
|
|
725
|
+
],
|
|
726
|
+
)
|
|
727
|
+
|
|
728
|
+
#: Usual definition of the ``begintime`` and ``endtime`` attributes.
|
|
729
|
+
|
|
730
|
+
timeperiod = footprints.Footprint(
|
|
731
|
+
info="Abstract Time Period",
|
|
732
|
+
attr=dict(
|
|
733
|
+
begintime=dict(
|
|
734
|
+
info="The resource's begin forecast term.",
|
|
735
|
+
type=Time,
|
|
736
|
+
optional=False,
|
|
737
|
+
),
|
|
738
|
+
endtime=dict(
|
|
739
|
+
info="The resource's end forecast term.", type=Time, optional=False
|
|
740
|
+
),
|
|
741
|
+
),
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
timeperiod_deco = footprints.DecorativeFootprint(
|
|
745
|
+
timeperiod,
|
|
746
|
+
decorator=[
|
|
747
|
+
namebuilding_insert(
|
|
748
|
+
"period",
|
|
749
|
+
lambda self: [
|
|
750
|
+
{"begintime": self.begintime},
|
|
751
|
+
{"endtime": self.endtime},
|
|
752
|
+
],
|
|
753
|
+
),
|
|
754
|
+
],
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
#: Usual definition of operational suite
|
|
758
|
+
a_suite = dict(
|
|
759
|
+
info="The operational suite identifier.",
|
|
760
|
+
values=["oper", "dble", "dbl", "test", "mirr", "miroir"],
|
|
761
|
+
remap=dict(
|
|
762
|
+
dbl="dble",
|
|
763
|
+
miroir="mirr",
|
|
764
|
+
),
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
#: Usual definition of the ``member`` attribute
|
|
768
|
+
a_member = dict(
|
|
769
|
+
info="The member's number (`None` for a deterministic configuration).",
|
|
770
|
+
type=int,
|
|
771
|
+
optional=True,
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
member = footprints.Footprint(
|
|
775
|
+
info="Abstract member", attr=dict(member=a_member)
|
|
776
|
+
)
|
|
777
|
+
|
|
778
|
+
#: Usual definition of the ``scenario`` attribute
|
|
779
|
+
a_scenario = dict(
|
|
780
|
+
info="The scenario identifier of the climate simulation (optional, especially in an NWP context).",
|
|
781
|
+
optional=True,
|
|
782
|
+
)
|
|
783
|
+
|
|
784
|
+
scenario = footprints.Footprint(
|
|
785
|
+
info="Abstract scenario", attr=dict(scenario=a_scenario)
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
#: Usual definition of the ``number`` attribute (e.g. a perturbation number)
|
|
789
|
+
a_number = dict(
|
|
790
|
+
info="Any kind of numbering...",
|
|
791
|
+
type=FmtInt,
|
|
792
|
+
args=dict(fmt="03"),
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
number = footprints.Footprint(
|
|
796
|
+
info="Abstract number", attr=dict(number=a_number)
|
|
797
|
+
)
|
|
798
|
+
|
|
799
|
+
number_deco = footprints.DecorativeFootprint(
|
|
800
|
+
number,
|
|
801
|
+
decorator=[
|
|
802
|
+
namebuilding_insert(
|
|
803
|
+
"number", lambda self: self.number, setdefault=True
|
|
804
|
+
),
|
|
805
|
+
],
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
#: Usual definition of the ``block`` attribute
|
|
809
|
+
a_block = dict(
|
|
810
|
+
info="The subpath where to store the data.",
|
|
811
|
+
)
|
|
812
|
+
|
|
813
|
+
block = footprints.Footprint(info="Abstract block", attr=dict(block=a_block))
|
|
814
|
+
|
|
815
|
+
#: Usual definition of the ``namespace`` attribute
|
|
816
|
+
a_namespace = dict(
|
|
817
|
+
info="The namespace where to store the data.",
|
|
818
|
+
type=Namespace,
|
|
819
|
+
optional=True,
|
|
820
|
+
)
|
|
821
|
+
|
|
822
|
+
namespacefp = footprints.Footprint(
|
|
823
|
+
info="Abstract namespace", attr=dict(namespace=a_namespace)
|
|
824
|
+
)
|
|
825
|
+
|
|
826
|
+
#: Usual definition of the ``storehash`` attribute
|
|
827
|
+
a_hashalgo = dict(
|
|
828
|
+
info="The hash algorithm used to check data integrity",
|
|
829
|
+
optional=True,
|
|
830
|
+
values=[
|
|
831
|
+
None,
|
|
832
|
+
],
|
|
833
|
+
)
|
|
834
|
+
|
|
835
|
+
hashalgo = footprints.Footprint(
|
|
836
|
+
info="Abstract Hash Algo", attr=dict(storehash=a_hashalgo)
|
|
837
|
+
)
|
|
838
|
+
|
|
839
|
+
hashalgo_avail_list = hashutils.HashAdapter.algorithms()
|
|
840
|
+
|
|
841
|
+
#: Usual definition of the ``store_compressed`` attribute
|
|
842
|
+
a_compressionpipeline = dict(
|
|
843
|
+
info="The compression pipeline used for this store",
|
|
844
|
+
optional=True,
|
|
845
|
+
)
|
|
846
|
+
|
|
847
|
+
compressionpipeline = footprints.Footprint(
|
|
848
|
+
info="Abstract Compression Pipeline",
|
|
849
|
+
attr=dict(store_compressed=a_compressionpipeline),
|
|
850
|
+
)
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def show():
|
|
854
|
+
"""Returns available items and their type."""
|
|
855
|
+
dmod = globals()
|
|
856
|
+
for stda in sorted(
|
|
857
|
+
filter(
|
|
858
|
+
lambda x: x.startswith("a_")
|
|
859
|
+
or isinstance(dmod[x], footprints.Footprint),
|
|
860
|
+
dmod.keys(),
|
|
861
|
+
)
|
|
862
|
+
):
|
|
863
|
+
print(
|
|
864
|
+
"{} ( {} ) :\n {}\n".format(
|
|
865
|
+
stda, type(dmod[stda]).__name__, dmod[stda]
|
|
866
|
+
)
|
|
867
|
+
)
|