vortex-nwp 2.0.0b1__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 (146) hide show
  1. vortex/__init__.py +135 -0
  2. vortex/algo/__init__.py +12 -0
  3. vortex/algo/components.py +2136 -0
  4. vortex/algo/mpitools.py +1648 -0
  5. vortex/algo/mpitools_templates/envelope_wrapper_default.tpl +27 -0
  6. vortex/algo/mpitools_templates/envelope_wrapper_mpiauto.tpl +29 -0
  7. vortex/algo/mpitools_templates/wrapstd_wrapper_default.tpl +18 -0
  8. vortex/algo/serversynctools.py +170 -0
  9. vortex/config.py +115 -0
  10. vortex/data/__init__.py +13 -0
  11. vortex/data/abstractstores.py +1572 -0
  12. vortex/data/containers.py +780 -0
  13. vortex/data/contents.py +596 -0
  14. vortex/data/executables.py +284 -0
  15. vortex/data/flow.py +113 -0
  16. vortex/data/geometries.ini +2689 -0
  17. vortex/data/geometries.py +703 -0
  18. vortex/data/handlers.py +1021 -0
  19. vortex/data/outflow.py +67 -0
  20. vortex/data/providers.py +465 -0
  21. vortex/data/resources.py +201 -0
  22. vortex/data/stores.py +1271 -0
  23. vortex/gloves.py +282 -0
  24. vortex/layout/__init__.py +27 -0
  25. vortex/layout/appconf.py +109 -0
  26. vortex/layout/contexts.py +511 -0
  27. vortex/layout/dataflow.py +1069 -0
  28. vortex/layout/jobs.py +1276 -0
  29. vortex/layout/monitor.py +833 -0
  30. vortex/layout/nodes.py +1424 -0
  31. vortex/layout/subjobs.py +464 -0
  32. vortex/nwp/__init__.py +11 -0
  33. vortex/nwp/algo/__init__.py +12 -0
  34. vortex/nwp/algo/assim.py +483 -0
  35. vortex/nwp/algo/clim.py +920 -0
  36. vortex/nwp/algo/coupling.py +609 -0
  37. vortex/nwp/algo/eda.py +632 -0
  38. vortex/nwp/algo/eps.py +613 -0
  39. vortex/nwp/algo/forecasts.py +745 -0
  40. vortex/nwp/algo/fpserver.py +927 -0
  41. vortex/nwp/algo/ifsnaming.py +403 -0
  42. vortex/nwp/algo/ifsroot.py +311 -0
  43. vortex/nwp/algo/monitoring.py +202 -0
  44. vortex/nwp/algo/mpitools.py +554 -0
  45. vortex/nwp/algo/odbtools.py +974 -0
  46. vortex/nwp/algo/oopsroot.py +735 -0
  47. vortex/nwp/algo/oopstests.py +186 -0
  48. vortex/nwp/algo/request.py +579 -0
  49. vortex/nwp/algo/stdpost.py +1285 -0
  50. vortex/nwp/data/__init__.py +12 -0
  51. vortex/nwp/data/assim.py +392 -0
  52. vortex/nwp/data/boundaries.py +261 -0
  53. vortex/nwp/data/climfiles.py +539 -0
  54. vortex/nwp/data/configfiles.py +149 -0
  55. vortex/nwp/data/consts.py +929 -0
  56. vortex/nwp/data/ctpini.py +133 -0
  57. vortex/nwp/data/diagnostics.py +181 -0
  58. vortex/nwp/data/eda.py +148 -0
  59. vortex/nwp/data/eps.py +383 -0
  60. vortex/nwp/data/executables.py +1039 -0
  61. vortex/nwp/data/fields.py +96 -0
  62. vortex/nwp/data/gridfiles.py +308 -0
  63. vortex/nwp/data/logs.py +551 -0
  64. vortex/nwp/data/modelstates.py +334 -0
  65. vortex/nwp/data/monitoring.py +220 -0
  66. vortex/nwp/data/namelists.py +644 -0
  67. vortex/nwp/data/obs.py +748 -0
  68. vortex/nwp/data/oopsexec.py +72 -0
  69. vortex/nwp/data/providers.py +182 -0
  70. vortex/nwp/data/query.py +217 -0
  71. vortex/nwp/data/stores.py +147 -0
  72. vortex/nwp/data/surfex.py +338 -0
  73. vortex/nwp/syntax/__init__.py +9 -0
  74. vortex/nwp/syntax/stdattrs.py +375 -0
  75. vortex/nwp/tools/__init__.py +10 -0
  76. vortex/nwp/tools/addons.py +35 -0
  77. vortex/nwp/tools/agt.py +55 -0
  78. vortex/nwp/tools/bdap.py +48 -0
  79. vortex/nwp/tools/bdcp.py +38 -0
  80. vortex/nwp/tools/bdm.py +21 -0
  81. vortex/nwp/tools/bdmp.py +49 -0
  82. vortex/nwp/tools/conftools.py +1311 -0
  83. vortex/nwp/tools/drhook.py +62 -0
  84. vortex/nwp/tools/grib.py +268 -0
  85. vortex/nwp/tools/gribdiff.py +99 -0
  86. vortex/nwp/tools/ifstools.py +163 -0
  87. vortex/nwp/tools/igastuff.py +249 -0
  88. vortex/nwp/tools/mars.py +56 -0
  89. vortex/nwp/tools/odb.py +548 -0
  90. vortex/nwp/tools/partitioning.py +234 -0
  91. vortex/nwp/tools/satrad.py +56 -0
  92. vortex/nwp/util/__init__.py +6 -0
  93. vortex/nwp/util/async.py +184 -0
  94. vortex/nwp/util/beacon.py +40 -0
  95. vortex/nwp/util/diffpygram.py +359 -0
  96. vortex/nwp/util/ens.py +198 -0
  97. vortex/nwp/util/hooks.py +128 -0
  98. vortex/nwp/util/taskdeco.py +81 -0
  99. vortex/nwp/util/usepygram.py +591 -0
  100. vortex/nwp/util/usetnt.py +87 -0
  101. vortex/proxy.py +6 -0
  102. vortex/sessions.py +341 -0
  103. vortex/syntax/__init__.py +9 -0
  104. vortex/syntax/stdattrs.py +628 -0
  105. vortex/syntax/stddeco.py +176 -0
  106. vortex/toolbox.py +982 -0
  107. vortex/tools/__init__.py +11 -0
  108. vortex/tools/actions.py +457 -0
  109. vortex/tools/addons.py +297 -0
  110. vortex/tools/arm.py +76 -0
  111. vortex/tools/compression.py +322 -0
  112. vortex/tools/date.py +20 -0
  113. vortex/tools/ddhpack.py +10 -0
  114. vortex/tools/delayedactions.py +672 -0
  115. vortex/tools/env.py +513 -0
  116. vortex/tools/folder.py +663 -0
  117. vortex/tools/grib.py +559 -0
  118. vortex/tools/lfi.py +746 -0
  119. vortex/tools/listings.py +354 -0
  120. vortex/tools/names.py +575 -0
  121. vortex/tools/net.py +1790 -0
  122. vortex/tools/odb.py +10 -0
  123. vortex/tools/parallelism.py +336 -0
  124. vortex/tools/prestaging.py +186 -0
  125. vortex/tools/rawfiles.py +10 -0
  126. vortex/tools/schedulers.py +413 -0
  127. vortex/tools/services.py +871 -0
  128. vortex/tools/storage.py +1061 -0
  129. vortex/tools/surfex.py +61 -0
  130. vortex/tools/systems.py +3396 -0
  131. vortex/tools/targets.py +384 -0
  132. vortex/util/__init__.py +9 -0
  133. vortex/util/config.py +1071 -0
  134. vortex/util/empty.py +24 -0
  135. vortex/util/helpers.py +184 -0
  136. vortex/util/introspection.py +63 -0
  137. vortex/util/iosponge.py +76 -0
  138. vortex/util/roles.py +51 -0
  139. vortex/util/storefunctions.py +103 -0
  140. vortex/util/structs.py +26 -0
  141. vortex/util/worker.py +150 -0
  142. vortex_nwp-2.0.0b1.dist-info/LICENSE +517 -0
  143. vortex_nwp-2.0.0b1.dist-info/METADATA +50 -0
  144. vortex_nwp-2.0.0b1.dist-info/RECORD +146 -0
  145. vortex_nwp-2.0.0b1.dist-info/WHEEL +5 -0
  146. vortex_nwp-2.0.0b1.dist-info/top_level.txt +1 -0
vortex/nwp/data/eps.py ADDED
@@ -0,0 +1,383 @@
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('radical', lambda s: {'unit': 'u', 'normed': 'n'}.get(s.processing, '') + s.realkind)
26
+ class PerturbedState(Historic):
27
+ """
28
+ Class for numbered historic resources, for example perturbations or perturbed states of the EPS.
29
+ """
30
+
31
+ _footprint = [
32
+ number_deco,
33
+ dict(
34
+ info = 'Perturbation or perturbed state',
35
+ attr = dict(
36
+ kind = dict(
37
+ values = ['perturbation', 'perturbed_historic', 'perturbed_state', 'pert'],
38
+ remap = dict(autoremap = 'first')
39
+ ),
40
+ term = dict(
41
+ optional = True,
42
+ default = Time(0)
43
+ ),
44
+ processing = dict(
45
+ values = ['unit', 'normed'],
46
+ optional = True,
47
+ ),
48
+ )
49
+ )
50
+ ]
51
+
52
+ @property
53
+ def realkind(self):
54
+ return 'pert'
55
+
56
+ def olive_basename(self):
57
+ """OLIVE specific naming convention."""
58
+ raise NotImplementedError("Perturbations were previously tar files, not supported yet.")
59
+
60
+ def archive_basename(self):
61
+ """OP ARCHIVE specific naming convention."""
62
+ raise NotImplementedError("Perturbations were previously tar files, not supported yet.")
63
+
64
+
65
+ @namebuilding_insert('radical', lambda s: s.realkind + '-' + s.zone)
66
+ class SingularVector(Historic):
67
+ """
68
+ Generic class for resources internal to singular vectors.
69
+ """
70
+ _footprint = [
71
+ number_deco,
72
+ dict(
73
+ info = 'Singular vector',
74
+ attr = dict(
75
+ kind = dict(
76
+ values = ['svector'],
77
+ ),
78
+ zone = dict(
79
+ values = ['ateur', 'hnc', 'hs', 'pno', 'oise', 'an', 'pne',
80
+ 'oiso', 'ps', 'oin', 'trop1', 'trop2', 'trop3', 'trop4'],
81
+ ),
82
+ term = dict(
83
+ optional = True,
84
+ default = Time(0)
85
+ ),
86
+ optime = dict(
87
+ type = Time,
88
+ optional = True,
89
+ )
90
+ )
91
+ )
92
+ ]
93
+
94
+ @property
95
+ def realkind(self):
96
+ return 'svector'
97
+
98
+ def olive_basename(self):
99
+ """OLIVE specific naming convention."""
100
+ return 'SVARPE' + '{:03d}'.format(self.number) + '+0000'
101
+
102
+ def archive_basename(self):
103
+ """OP ARCHIVE specific naming convention."""
104
+ return 'SVARPE' + '{:03d}'.format(self.number) + '+0000'
105
+
106
+
107
+ @use_flow_logs_stack
108
+ class NormCoeff(FlowResource):
109
+ """
110
+ Coefficient used to normalize the singular vectors or the bred modes.
111
+ """
112
+
113
+ _footprint = dict(
114
+ info = 'Perturbations coefficient',
115
+ attr = dict(
116
+ kind = dict(
117
+ values = ['coeffnorm', 'coeffpert'],
118
+ remap = dict(autoremap = 'first'),
119
+ ),
120
+ clscontents = dict(
121
+ default = JsonDictContent,
122
+ ),
123
+ nativefmt = dict(
124
+ values = ['json'],
125
+ default = 'json',
126
+ ),
127
+ pertkind = dict(
128
+ values = ['sv', 'bd'],
129
+ optional = True,
130
+ default = 'sv',
131
+ ),
132
+ )
133
+ )
134
+
135
+ @property
136
+ def realkind(self):
137
+ return 'coeff' + self.pertkind
138
+
139
+
140
+ class SampleContent(JsonDictContent):
141
+ """Specialisation of the JSONDictContent to deal with drawing lots."""
142
+
143
+ def drawing(self, g, x):
144
+ """Return the number of a sampled element according to the local number."""
145
+ n = g.get('number', x.get('number', None))
146
+ virgin = g.get('untouched', x.get('untouched', [0, ]))
147
+ if n is None:
148
+ return None
149
+ else:
150
+ try:
151
+ if not isinstance(virgin, list):
152
+ virgin = [int(virgin)]
153
+ else:
154
+ virgin = map(int, virgin)
155
+ n = int(n)
156
+ except TypeError:
157
+ return None
158
+ if n in virgin:
159
+ return n
160
+ else:
161
+ try:
162
+ return self.data['drawing'][n - 1]
163
+ except KeyError:
164
+ return None
165
+
166
+ @secure_getattr
167
+ def __getattr__(self, attr):
168
+ # Return an access function that corresponds to the key in "drawing"
169
+ drawing_keys = {item
170
+ for d in self.data.get('drawing', []) if isinstance(d, dict)
171
+ for item in d.keys()}
172
+ if attr in drawing_keys:
173
+ def _attr_access(g, x):
174
+ elt = self.drawing(g, x)
175
+ # drawing may returns
176
+ # * None (if the 'number' attribute is incorrect or missing)
177
+ # * An integer if 'number' is in the 'untouched' list
178
+ # * A dictionary
179
+ if elt is None:
180
+ choices = {d[attr] for d in self.data['drawing']}
181
+ return None if len(choices) > 1 else choices.pop()
182
+ else:
183
+ return elt[attr] if isinstance(elt, dict) else None
184
+ return _attr_access
185
+ # Return an access function that corresponds to the key in "population"
186
+ population_keys = {item
187
+ for d in self.data.get('population', []) if isinstance(d, dict)
188
+ for item in d.keys()}
189
+ if attr in population_keys:
190
+ def _attr_access(g, x):
191
+ n = g.get('number', x.get('number', None))
192
+ if n is None:
193
+ return None
194
+ else:
195
+ return self.data['population'][n - 1][attr]
196
+ return _attr_access
197
+ # Returns the list of drawn keys
198
+ listing_keys = {item + 's'
199
+ for d in self.data.get('drawing', []) if isinstance(d, dict)
200
+ for item in d.keys()}
201
+ if attr in listing_keys:
202
+ return [d[attr[:-1]] for d in self.data['drawing']]
203
+ # Return the list of available keys
204
+ listing_keys = {item + 's'
205
+ for d in self.data['population'] if isinstance(d, dict)
206
+ for item in d.keys()}
207
+ if attr in listing_keys:
208
+ return [d[attr[:-1]] for d in self.data['population']]
209
+ raise AttributeError()
210
+
211
+ def targetdate(self, g, x):
212
+ targetdate = g.get('targetdate', x.get('targetdate', None))
213
+ if targetdate is None:
214
+ raise ValueError("A targetdate attribute must be present if targetdate is used")
215
+ return Date(targetdate)
216
+
217
+ def targetterm(self, g, x):
218
+ targetterm = g.get('targetterm', x.get('targetterm', None))
219
+ if targetterm is None:
220
+ raise ValueError("A targetterm attribute must be present if targetterm is used")
221
+ return Time(targetterm)
222
+
223
+ def timedelta(self, g, x):
224
+ """Find the time difference between the resource's date and the targetdate."""
225
+ targetterm = Time(g.get('targetterm', x.get('targetterm', 0)))
226
+ thedate = Date(self.date(g, x))
227
+ period = (self.targetdate(g, x) + targetterm) - thedate
228
+ return period.time()
229
+
230
+ def _actual_diff(self, ref):
231
+ me = copy.copy(self.data)
232
+ other = copy.copy(ref.data)
233
+ me.pop('experiment', None) # Do not compare the experiment ID (if present)
234
+ other.pop('experiment', None)
235
+ return me == other
236
+
237
+
238
+ @use_flow_logs_stack
239
+ @namebuilding_delete('src')
240
+ class PopulationList(FlowResource):
241
+ """
242
+ Description of available data
243
+ """
244
+
245
+ _abstract = True
246
+ _footprint = dict(
247
+ info = 'A Population List',
248
+ attr = dict(
249
+ clscontents = dict(
250
+ default = SampleContent,
251
+ ),
252
+ nativefmt = dict(
253
+ values = ['json'],
254
+ default = 'json',
255
+ ),
256
+ nbsample = dict(
257
+ optional = True,
258
+ type = int,
259
+ ),
260
+ checkrole = dict(
261
+ optional = True
262
+ )
263
+ )
264
+ )
265
+
266
+
267
+ class MembersPopulation(PopulationList):
268
+
269
+ _footprint = dict(
270
+ info = 'Members population',
271
+ attr = dict(
272
+ kind = dict(
273
+ values = ['mbpopulation', ],
274
+ ),
275
+ )
276
+ )
277
+
278
+ @property
279
+ def realkind(self):
280
+ return 'mbpopulation'
281
+
282
+
283
+ @namebuilding_insert('radical', lambda s: '{:s}of{:d}'.format(s.realkind, s.nbsample))
284
+ class Sample(PopulationList):
285
+ """
286
+ Lot drawn out of a set.
287
+ """
288
+
289
+ _abstract = True,
290
+ _footprint = dict(
291
+ info = 'Sample',
292
+ attr = dict(
293
+ nbsample = dict(
294
+ optional = False,
295
+ ),
296
+ population = dict(
297
+ type = footprints.stdtypes.FPList,
298
+ optional = True
299
+ ),
300
+ )
301
+ )
302
+
303
+
304
+ class MembersSample(Sample):
305
+ """
306
+ List of members selected among a set.
307
+ """
308
+
309
+ _footprint = dict(
310
+ info = 'Members sample',
311
+ attr = dict(
312
+ kind = dict(
313
+ values = ['mbsample', 'mbselect', 'mbdrawing', 'members_select'],
314
+ remap = dict(autoremap = 'first'),
315
+ ),
316
+ )
317
+ )
318
+
319
+ @property
320
+ def realkind(self):
321
+ return 'mbsample'
322
+
323
+
324
+ class MultiphysicsSample(Sample):
325
+ """
326
+ List of physical packages selected among a set.
327
+ """
328
+
329
+ _footprint = dict(
330
+ info = 'Physical packages sample',
331
+ attr = dict(
332
+ kind = dict(
333
+ values = ['physample', 'physelect', 'phydrawing'],
334
+ remap = dict(autoremap = 'first'),
335
+ ),
336
+ )
337
+ )
338
+
339
+ @property
340
+ def realkind(self):
341
+ return 'physample'
342
+
343
+
344
+ class ClustContent(TextContent):
345
+ """Specialisation of the TextContent to deal with clustering outputs."""
346
+
347
+ def getNumber(self, idx):
348
+ return self.data[idx - 1]
349
+
350
+
351
+ @use_flow_logs_stack
352
+ @namebuilding_delete('src')
353
+ class GeneralCluster(FlowResource):
354
+ """
355
+ Files produced by the clustering step of the LAM PE.
356
+ """
357
+
358
+ _footprint = dict(
359
+ info = 'Clustering stuff',
360
+ attr = dict(
361
+ kind = dict(
362
+ values = ['clustering', 'clust', 'members_select'],
363
+ remap = dict(autoremap = 'first'),
364
+ ),
365
+ clscontents = dict(
366
+ default = ClustContent,
367
+ ),
368
+ nativefmt = dict(
369
+ values = ['ascii', 'txt'],
370
+ default = 'txt',
371
+ remap = dict(ascii = 'txt'),
372
+ ),
373
+ filling = dict(
374
+ values = ['population', 'pop', 'members', 'full'],
375
+ remap = dict(population = 'pop'),
376
+ default = '',
377
+ ),
378
+ )
379
+ )
380
+
381
+ @property
382
+ def realkind(self):
383
+ return 'clustering' + '_' + self.filling