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
vortex/nwp/data/eps.py ADDED
@@ -0,0 +1,432 @@
1
+ """
2
+ Resources needed to build the Ensemble Prediction System.
3
+ """
4
+
5
+ import copy
6
+
7
+ from bronx.fancies import loggers
8
+ import footprints
9
+
10
+ from bronx.stdtypes.date import Date, Time
11
+ from bronx.syntax.decorators import secure_getattr
12
+ from vortex.data.flow import FlowResource
13
+ from vortex.data.contents import JsonDictContent, TextContent
14
+ from vortex.syntax.stdattrs import number_deco
15
+ from vortex.syntax.stddeco import namebuilding_delete, namebuilding_insert
16
+ from .logs import use_flow_logs_stack
17
+ from .modelstates import Historic
18
+
19
+ #: No automatic export
20
+ __all__ = []
21
+
22
+ logger = loggers.getLogger(__name__)
23
+
24
+
25
+ @namebuilding_insert(
26
+ "radical",
27
+ lambda s: {"unit": "u", "normed": "n"}.get(s.processing, "") + s.realkind,
28
+ )
29
+ class PerturbedState(Historic):
30
+ """
31
+ Class for numbered historic resources, for example perturbations or perturbed states of the EPS.
32
+ """
33
+
34
+ _footprint = [
35
+ number_deco,
36
+ dict(
37
+ info="Perturbation or perturbed state",
38
+ attr=dict(
39
+ kind=dict(
40
+ values=[
41
+ "perturbation",
42
+ "perturbed_historic",
43
+ "perturbed_state",
44
+ "pert",
45
+ ],
46
+ remap=dict(autoremap="first"),
47
+ ),
48
+ term=dict(optional=True, default=Time(0)),
49
+ processing=dict(
50
+ values=["unit", "normed"],
51
+ optional=True,
52
+ ),
53
+ ),
54
+ ),
55
+ ]
56
+
57
+ @property
58
+ def realkind(self):
59
+ return "pert"
60
+
61
+ def olive_basename(self):
62
+ """OLIVE specific naming convention."""
63
+ raise NotImplementedError(
64
+ "Perturbations were previously tar files, not supported yet."
65
+ )
66
+
67
+ def archive_basename(self):
68
+ """OP ARCHIVE specific naming convention."""
69
+ raise NotImplementedError(
70
+ "Perturbations were previously tar files, not supported yet."
71
+ )
72
+
73
+
74
+ @namebuilding_insert("radical", lambda s: s.realkind + "-" + s.zone)
75
+ class SingularVector(Historic):
76
+ """
77
+ Generic class for resources internal to singular vectors.
78
+ """
79
+
80
+ _footprint = [
81
+ number_deco,
82
+ dict(
83
+ info="Singular vector",
84
+ attr=dict(
85
+ kind=dict(
86
+ values=["svector"],
87
+ ),
88
+ zone=dict(
89
+ values=[
90
+ "ateur",
91
+ "hnc",
92
+ "hs",
93
+ "pno",
94
+ "oise",
95
+ "an",
96
+ "pne",
97
+ "oiso",
98
+ "ps",
99
+ "oin",
100
+ "trop1",
101
+ "trop2",
102
+ "trop3",
103
+ "trop4",
104
+ ],
105
+ ),
106
+ term=dict(optional=True, default=Time(0)),
107
+ optime=dict(
108
+ type=Time,
109
+ optional=True,
110
+ ),
111
+ ),
112
+ ),
113
+ ]
114
+
115
+ @property
116
+ def realkind(self):
117
+ return "svector"
118
+
119
+ def olive_basename(self):
120
+ """OLIVE specific naming convention."""
121
+ return "SVARPE" + "{:03d}".format(self.number) + "+0000"
122
+
123
+ def archive_basename(self):
124
+ """OP ARCHIVE specific naming convention."""
125
+ return "SVARPE" + "{:03d}".format(self.number) + "+0000"
126
+
127
+
128
+ @use_flow_logs_stack
129
+ class NormCoeff(FlowResource):
130
+ """
131
+ Coefficient used to normalize the singular vectors or the bred modes.
132
+ """
133
+
134
+ _footprint = dict(
135
+ info="Perturbations coefficient",
136
+ attr=dict(
137
+ kind=dict(
138
+ values=["coeffnorm", "coeffpert"],
139
+ remap=dict(autoremap="first"),
140
+ ),
141
+ clscontents=dict(
142
+ default=JsonDictContent,
143
+ ),
144
+ nativefmt=dict(
145
+ values=["json"],
146
+ default="json",
147
+ ),
148
+ pertkind=dict(
149
+ values=["sv", "bd"],
150
+ optional=True,
151
+ default="sv",
152
+ ),
153
+ ),
154
+ )
155
+
156
+ @property
157
+ def realkind(self):
158
+ return "coeff" + self.pertkind
159
+
160
+
161
+ class SampleContent(JsonDictContent):
162
+ """Specialisation of the JSONDictContent to deal with drawing lots."""
163
+
164
+ def drawing(self, g, x):
165
+ """Return the number of a sampled element according to the local number."""
166
+ n = g.get("number", x.get("number", None))
167
+ virgin = g.get(
168
+ "untouched",
169
+ x.get(
170
+ "untouched",
171
+ [
172
+ 0,
173
+ ],
174
+ ),
175
+ )
176
+ if n is None:
177
+ return None
178
+ else:
179
+ try:
180
+ if not isinstance(virgin, list):
181
+ virgin = [int(virgin)]
182
+ else:
183
+ virgin = map(int, virgin)
184
+ n = int(n)
185
+ except TypeError:
186
+ return None
187
+ if n in virgin:
188
+ return n
189
+ else:
190
+ try:
191
+ return self.data["drawing"][n - 1]
192
+ except KeyError:
193
+ return None
194
+
195
+ @secure_getattr
196
+ def __getattr__(self, attr):
197
+ # Return an access function that corresponds to the key in "drawing"
198
+ drawing_keys = {
199
+ item
200
+ for d in self.data.get("drawing", [])
201
+ if isinstance(d, dict)
202
+ for item in d.keys()
203
+ }
204
+ if attr in drawing_keys:
205
+
206
+ def _attr_access(g, x):
207
+ elt = self.drawing(g, x)
208
+ # drawing may returns
209
+ # * None (if the 'number' attribute is incorrect or missing)
210
+ # * An integer if 'number' is in the 'untouched' list
211
+ # * A dictionary
212
+ if elt is None:
213
+ choices = {d[attr] for d in self.data["drawing"]}
214
+ return None if len(choices) > 1 else choices.pop()
215
+ else:
216
+ return elt[attr] if isinstance(elt, dict) else None
217
+
218
+ return _attr_access
219
+ # Return an access function that corresponds to the key in "population"
220
+ population_keys = {
221
+ item
222
+ for d in self.data.get("population", [])
223
+ if isinstance(d, dict)
224
+ for item in d.keys()
225
+ }
226
+ if attr in population_keys:
227
+
228
+ def _attr_access(g, x):
229
+ n = g.get("number", x.get("number", None))
230
+ if n is None:
231
+ return None
232
+ else:
233
+ return self.data["population"][n - 1][attr]
234
+
235
+ return _attr_access
236
+ # Returns the list of drawn keys
237
+ listing_keys = {
238
+ item + "s"
239
+ for d in self.data.get("drawing", [])
240
+ if isinstance(d, dict)
241
+ for item in d.keys()
242
+ }
243
+ if attr in listing_keys:
244
+ return [d[attr[:-1]] for d in self.data["drawing"]]
245
+ # Return the list of available keys
246
+ listing_keys = {
247
+ item + "s"
248
+ for d in self.data["population"]
249
+ if isinstance(d, dict)
250
+ for item in d.keys()
251
+ }
252
+ if attr in listing_keys:
253
+ return [d[attr[:-1]] for d in self.data["population"]]
254
+ raise AttributeError()
255
+
256
+ def targetdate(self, g, x):
257
+ targetdate = g.get("targetdate", x.get("targetdate", None))
258
+ if targetdate is None:
259
+ raise ValueError(
260
+ "A targetdate attribute must be present if targetdate is used"
261
+ )
262
+ return Date(targetdate)
263
+
264
+ def targetterm(self, g, x):
265
+ targetterm = g.get("targetterm", x.get("targetterm", None))
266
+ if targetterm is None:
267
+ raise ValueError(
268
+ "A targetterm attribute must be present if targetterm is used"
269
+ )
270
+ return Time(targetterm)
271
+
272
+ def timedelta(self, g, x):
273
+ """Find the time difference between the resource's date and the targetdate."""
274
+ targetterm = Time(g.get("targetterm", x.get("targetterm", 0)))
275
+ thedate = Date(self.date(g, x))
276
+ period = (self.targetdate(g, x) + targetterm) - thedate
277
+ return period.time()
278
+
279
+ def _actual_diff(self, ref):
280
+ me = copy.copy(self.data)
281
+ other = copy.copy(ref.data)
282
+ me.pop(
283
+ "experiment", None
284
+ ) # Do not compare the experiment ID (if present)
285
+ other.pop("experiment", None)
286
+ return me == other
287
+
288
+
289
+ @use_flow_logs_stack
290
+ @namebuilding_delete("src")
291
+ class PopulationList(FlowResource):
292
+ """
293
+ Description of available data
294
+ """
295
+
296
+ _abstract = True
297
+ _footprint = dict(
298
+ info="A Population List",
299
+ attr=dict(
300
+ clscontents=dict(
301
+ default=SampleContent,
302
+ ),
303
+ nativefmt=dict(
304
+ values=["json"],
305
+ default="json",
306
+ ),
307
+ nbsample=dict(
308
+ optional=True,
309
+ type=int,
310
+ ),
311
+ checkrole=dict(optional=True),
312
+ ),
313
+ )
314
+
315
+
316
+ class MembersPopulation(PopulationList):
317
+ _footprint = dict(
318
+ info="Members population",
319
+ attr=dict(
320
+ kind=dict(
321
+ values=[
322
+ "mbpopulation",
323
+ ],
324
+ ),
325
+ ),
326
+ )
327
+
328
+ @property
329
+ def realkind(self):
330
+ return "mbpopulation"
331
+
332
+
333
+ @namebuilding_insert(
334
+ "radical", lambda s: "{:s}of{:d}".format(s.realkind, s.nbsample)
335
+ )
336
+ class Sample(PopulationList):
337
+ """
338
+ Lot drawn out of a set.
339
+ """
340
+
341
+ _abstract = (True,)
342
+ _footprint = dict(
343
+ info="Sample",
344
+ attr=dict(
345
+ nbsample=dict(
346
+ optional=False,
347
+ ),
348
+ population=dict(type=footprints.stdtypes.FPList, optional=True),
349
+ ),
350
+ )
351
+
352
+
353
+ class MembersSample(Sample):
354
+ """
355
+ List of members selected among a set.
356
+ """
357
+
358
+ _footprint = dict(
359
+ info="Members sample",
360
+ attr=dict(
361
+ kind=dict(
362
+ values=["mbsample", "mbselect", "mbdrawing", "members_select"],
363
+ remap=dict(autoremap="first"),
364
+ ),
365
+ ),
366
+ )
367
+
368
+ @property
369
+ def realkind(self):
370
+ return "mbsample"
371
+
372
+
373
+ class MultiphysicsSample(Sample):
374
+ """
375
+ List of physical packages selected among a set.
376
+ """
377
+
378
+ _footprint = dict(
379
+ info="Physical packages sample",
380
+ attr=dict(
381
+ kind=dict(
382
+ values=["physample", "physelect", "phydrawing"],
383
+ remap=dict(autoremap="first"),
384
+ ),
385
+ ),
386
+ )
387
+
388
+ @property
389
+ def realkind(self):
390
+ return "physample"
391
+
392
+
393
+ class ClustContent(TextContent):
394
+ """Specialisation of the TextContent to deal with clustering outputs."""
395
+
396
+ def getNumber(self, idx):
397
+ return self.data[idx - 1]
398
+
399
+
400
+ @use_flow_logs_stack
401
+ @namebuilding_delete("src")
402
+ class GeneralCluster(FlowResource):
403
+ """
404
+ Files produced by the clustering step of the LAM PE.
405
+ """
406
+
407
+ _footprint = dict(
408
+ info="Clustering stuff",
409
+ attr=dict(
410
+ kind=dict(
411
+ values=["clustering", "clust", "members_select"],
412
+ remap=dict(autoremap="first"),
413
+ ),
414
+ clscontents=dict(
415
+ default=ClustContent,
416
+ ),
417
+ nativefmt=dict(
418
+ values=["ascii", "txt"],
419
+ default="txt",
420
+ remap=dict(ascii="txt"),
421
+ ),
422
+ filling=dict(
423
+ values=["population", "pop", "members", "full"],
424
+ remap=dict(population="pop"),
425
+ default="",
426
+ ),
427
+ ),
428
+ )
429
+
430
+ @property
431
+ def realkind(self):
432
+ return "clustering" + "_" + self.filling