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.
Files changed (144) hide show
  1. vortex/__init__.py +159 -0
  2. vortex/algo/__init__.py +13 -0
  3. vortex/algo/components.py +2462 -0
  4. vortex/algo/mpitools.py +1953 -0
  5. vortex/algo/mpitools_templates/__init__.py +1 -0
  6. vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
  7. vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
  8. vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
  9. vortex/algo/serversynctools.py +171 -0
  10. vortex/config.py +112 -0
  11. vortex/data/__init__.py +19 -0
  12. vortex/data/abstractstores.py +1510 -0
  13. vortex/data/containers.py +835 -0
  14. vortex/data/contents.py +622 -0
  15. vortex/data/executables.py +275 -0
  16. vortex/data/flow.py +119 -0
  17. vortex/data/geometries.ini +2689 -0
  18. vortex/data/geometries.py +799 -0
  19. vortex/data/handlers.py +1230 -0
  20. vortex/data/outflow.py +67 -0
  21. vortex/data/providers.py +487 -0
  22. vortex/data/resources.py +207 -0
  23. vortex/data/stores.py +1390 -0
  24. vortex/data/sync_templates/__init__.py +0 -0
  25. vortex/gloves.py +309 -0
  26. vortex/layout/__init__.py +20 -0
  27. vortex/layout/contexts.py +577 -0
  28. vortex/layout/dataflow.py +1220 -0
  29. vortex/layout/monitor.py +969 -0
  30. vortex/nwp/__init__.py +14 -0
  31. vortex/nwp/algo/__init__.py +21 -0
  32. vortex/nwp/algo/assim.py +537 -0
  33. vortex/nwp/algo/clim.py +1086 -0
  34. vortex/nwp/algo/coupling.py +831 -0
  35. vortex/nwp/algo/eda.py +840 -0
  36. vortex/nwp/algo/eps.py +785 -0
  37. vortex/nwp/algo/forecasts.py +886 -0
  38. vortex/nwp/algo/fpserver.py +1303 -0
  39. vortex/nwp/algo/ifsnaming.py +463 -0
  40. vortex/nwp/algo/ifsroot.py +404 -0
  41. vortex/nwp/algo/monitoring.py +263 -0
  42. vortex/nwp/algo/mpitools.py +694 -0
  43. vortex/nwp/algo/odbtools.py +1258 -0
  44. vortex/nwp/algo/oopsroot.py +916 -0
  45. vortex/nwp/algo/oopstests.py +220 -0
  46. vortex/nwp/algo/request.py +660 -0
  47. vortex/nwp/algo/stdpost.py +1641 -0
  48. vortex/nwp/data/__init__.py +30 -0
  49. vortex/nwp/data/assim.py +380 -0
  50. vortex/nwp/data/boundaries.py +314 -0
  51. vortex/nwp/data/climfiles.py +521 -0
  52. vortex/nwp/data/configfiles.py +153 -0
  53. vortex/nwp/data/consts.py +954 -0
  54. vortex/nwp/data/ctpini.py +149 -0
  55. vortex/nwp/data/diagnostics.py +209 -0
  56. vortex/nwp/data/eda.py +147 -0
  57. vortex/nwp/data/eps.py +432 -0
  58. vortex/nwp/data/executables.py +1045 -0
  59. vortex/nwp/data/fields.py +111 -0
  60. vortex/nwp/data/gridfiles.py +380 -0
  61. vortex/nwp/data/logs.py +584 -0
  62. vortex/nwp/data/modelstates.py +363 -0
  63. vortex/nwp/data/monitoring.py +193 -0
  64. vortex/nwp/data/namelists.py +696 -0
  65. vortex/nwp/data/obs.py +840 -0
  66. vortex/nwp/data/oopsexec.py +74 -0
  67. vortex/nwp/data/providers.py +207 -0
  68. vortex/nwp/data/query.py +206 -0
  69. vortex/nwp/data/stores.py +160 -0
  70. vortex/nwp/data/surfex.py +337 -0
  71. vortex/nwp/syntax/__init__.py +9 -0
  72. vortex/nwp/syntax/stdattrs.py +437 -0
  73. vortex/nwp/tools/__init__.py +10 -0
  74. vortex/nwp/tools/addons.py +40 -0
  75. vortex/nwp/tools/agt.py +67 -0
  76. vortex/nwp/tools/bdap.py +59 -0
  77. vortex/nwp/tools/bdcp.py +41 -0
  78. vortex/nwp/tools/bdm.py +24 -0
  79. vortex/nwp/tools/bdmp.py +54 -0
  80. vortex/nwp/tools/conftools.py +1661 -0
  81. vortex/nwp/tools/drhook.py +66 -0
  82. vortex/nwp/tools/grib.py +294 -0
  83. vortex/nwp/tools/gribdiff.py +104 -0
  84. vortex/nwp/tools/ifstools.py +203 -0
  85. vortex/nwp/tools/igastuff.py +273 -0
  86. vortex/nwp/tools/mars.py +68 -0
  87. vortex/nwp/tools/odb.py +657 -0
  88. vortex/nwp/tools/partitioning.py +258 -0
  89. vortex/nwp/tools/satrad.py +71 -0
  90. vortex/nwp/util/__init__.py +6 -0
  91. vortex/nwp/util/async.py +212 -0
  92. vortex/nwp/util/beacon.py +40 -0
  93. vortex/nwp/util/diffpygram.py +447 -0
  94. vortex/nwp/util/ens.py +279 -0
  95. vortex/nwp/util/hooks.py +139 -0
  96. vortex/nwp/util/taskdeco.py +85 -0
  97. vortex/nwp/util/usepygram.py +697 -0
  98. vortex/nwp/util/usetnt.py +101 -0
  99. vortex/proxy.py +6 -0
  100. vortex/sessions.py +374 -0
  101. vortex/syntax/__init__.py +9 -0
  102. vortex/syntax/stdattrs.py +867 -0
  103. vortex/syntax/stddeco.py +185 -0
  104. vortex/toolbox.py +1117 -0
  105. vortex/tools/__init__.py +20 -0
  106. vortex/tools/actions.py +523 -0
  107. vortex/tools/addons.py +316 -0
  108. vortex/tools/arm.py +96 -0
  109. vortex/tools/compression.py +325 -0
  110. vortex/tools/date.py +27 -0
  111. vortex/tools/ddhpack.py +10 -0
  112. vortex/tools/delayedactions.py +782 -0
  113. vortex/tools/env.py +541 -0
  114. vortex/tools/folder.py +834 -0
  115. vortex/tools/grib.py +738 -0
  116. vortex/tools/lfi.py +953 -0
  117. vortex/tools/listings.py +423 -0
  118. vortex/tools/names.py +637 -0
  119. vortex/tools/net.py +2124 -0
  120. vortex/tools/odb.py +10 -0
  121. vortex/tools/parallelism.py +368 -0
  122. vortex/tools/prestaging.py +210 -0
  123. vortex/tools/rawfiles.py +10 -0
  124. vortex/tools/schedulers.py +480 -0
  125. vortex/tools/services.py +940 -0
  126. vortex/tools/storage.py +996 -0
  127. vortex/tools/surfex.py +61 -0
  128. vortex/tools/systems.py +3976 -0
  129. vortex/tools/targets.py +440 -0
  130. vortex/util/__init__.py +9 -0
  131. vortex/util/config.py +1122 -0
  132. vortex/util/empty.py +24 -0
  133. vortex/util/helpers.py +216 -0
  134. vortex/util/introspection.py +69 -0
  135. vortex/util/iosponge.py +80 -0
  136. vortex/util/roles.py +49 -0
  137. vortex/util/storefunctions.py +129 -0
  138. vortex/util/structs.py +26 -0
  139. vortex/util/worker.py +162 -0
  140. vortex_nwp-2.0.0.dist-info/METADATA +67 -0
  141. vortex_nwp-2.0.0.dist-info/RECORD +144 -0
  142. vortex_nwp-2.0.0.dist-info/WHEEL +5 -0
  143. vortex_nwp-2.0.0.dist-info/licenses/LICENSE +517 -0
  144. 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
+ )