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
@@ -0,0 +1,87 @@
1
+ """
2
+ Usage of the TNT package.
3
+ """
4
+
5
+ import codecs
6
+ import io
7
+
8
+ from bronx.fancies import loggers
9
+ from bronx.syntax.externalcode import ExternalCodeImportChecker
10
+
11
+ from vortex import sessions
12
+ from vortex.data.stores import FunctionStoreCallbackError
13
+ from vortex.util.roles import setrole
14
+
15
+ logger = loggers.getLogger(__name__)
16
+
17
+ tnt_checker = ExternalCodeImportChecker('thenamelisttool')
18
+ with tnt_checker as tnt_register:
19
+ import thenamelisttool
20
+
21
+ __all__ = []
22
+
23
+
24
+ @tnt_checker.disabled_if_unavailable
25
+ def compose_nam(options):
26
+ """Use a TNT recipe in order to build a namelist file.
27
+
28
+ This function is designed to be executed by a
29
+ :obj:`vortex.data.stores.FunctionStore` object.
30
+
31
+ In order to "execute" the TNT recipe, this function requires a namelist
32
+ pack to be available in the inputs sequence. By default, this namelist
33
+ pack should have the "MainNamelistPack" role. This default value can
34
+ be overriden using the `nampack` attribute of the URI query.
35
+
36
+ The recipe file should be named `[source].yaml` where `[source]` stands
37
+ for the `source` attribute of the obj:`~nwp.data.namelists.Namelist`
38
+ resource object.
39
+
40
+ By defaut, the recipe file is looked for in the namelist pack mentioned
41
+ above. The role of an alternative pack can be designated using the
42
+ `dirpack` attribute of the URI.
43
+
44
+ :param dict options: All the options passed to the store plus anything from
45
+ the query part of the URI.
46
+
47
+ :return: Content of a :obj:`nwp.data.namelists.Namelist` resource
48
+
49
+ :rtype: A file like object
50
+ """
51
+ rhdict = options.get('rhandler', None)
52
+ source = rhdict['resource'].get('source', None)
53
+ if source is None:
54
+ logger.error("Inapropriate type of resource. Got:\n%s", rhdict)
55
+ raise FunctionStoreCallbackError('Inapropriate type of resources.')
56
+
57
+ t = sessions.current()
58
+
59
+ def _get_pack_adress(role):
60
+ role = setrole(role)
61
+ packlist = [sec.rh for sec in t.context.sequence.filtered_inputs(role=role)]
62
+ if len(packlist) != 1:
63
+ logger.error("The number of namelist packs with role=%s is not 1.")
64
+ raise FunctionStoreCallbackError('Incorrect number of namelist packs.')
65
+ packrh = packlist[0]
66
+ if packrh.resource.realkind != 'namelistpack':
67
+ logger.error("Incorrect resource type for role %s. Resource handler:\n%s",
68
+ role, packrh.icdard())
69
+ raise FunctionStoreCallbackError('Incorrect resource type.')
70
+ if not packrh.container.filled:
71
+ logger.error("The resource handler's container is not filled for role %s", role)
72
+ raise FunctionStoreCallbackError('RH container is not filled.')
73
+ return packrh.container.abspath
74
+
75
+ nampack_path = _get_pack_adress(options.get('nampack', 'Main Namelist Pack'))
76
+ dirpack_role = options.get('dirpack', None)
77
+ dirpack_path = _get_pack_adress(dirpack_role) if dirpack_role else nampack_path
78
+
79
+ out_io = io.BytesIO()
80
+ thenamelisttool.util.compose_namelist(
81
+ t.sh.path.join(dirpack_path, source + '.yaml'),
82
+ sourcenam_directory=nampack_path,
83
+ sorting=thenamelisttool.namadapter.FIRST_ORDER_SORTING,
84
+ squeeze=False,
85
+ fhoutput=codecs.getwriter('utf-8')(out_io)
86
+ )
87
+ return out_io
vortex/proxy.py ADDED
@@ -0,0 +1,6 @@
1
+ """
2
+ Fake module to be populated dynamically, eg. by footprints shortcuts to catalogs.
3
+ """
4
+
5
+ #: No automatic export
6
+ __all__ = []
vortex/sessions.py ADDED
@@ -0,0 +1,341 @@
1
+ """
2
+ Vortex Sessions Handling
3
+
4
+ A :mod:`vortex` session is a virtual identifier gathering information on the current
5
+ #usage of the toolbox. A session has a starting time, and possibly a closing
6
+ time. A session also defines the level of the internal logging used in all
7
+ the vortex modules.
8
+ """
9
+
10
+ import logging
11
+
12
+ from bronx.fancies import loggers
13
+ from bronx.datagrip.datastore import DataStore
14
+ from bronx.patterns import getbytag
15
+ from bronx.stdtypes import date
16
+ import footprints
17
+
18
+ from vortex.tools.env import Environment
19
+
20
+ from vortex import gloves # @UnusedImport
21
+ from vortex.layout import contexts
22
+
23
+ #: No automatic export
24
+ __all__ = []
25
+
26
+ logger = loggers.getLogger(__name__)
27
+
28
+
29
+ # Module Interface
30
+
31
+ def get(**kw):
32
+ """Return actual session ticket object matching description."""
33
+ if kw.get('tag', 'current') == 'current' and Ticket.tag_focus() is not None:
34
+ return current()
35
+ else:
36
+ return Ticket(**kw)
37
+
38
+
39
+ def keys():
40
+ """Return the list of current session tickets names collected."""
41
+ return Ticket.tag_keys()
42
+
43
+
44
+ def values():
45
+ """Return the list of current session ticket values collected."""
46
+ return Ticket.tag_values()
47
+
48
+
49
+ def items():
50
+ """Return the items of the session tickets table."""
51
+ return Ticket.tag_items()
52
+
53
+
54
+ def current():
55
+ """Return the current active session."""
56
+ return get(tag=Ticket.tag_focus())
57
+
58
+
59
+ def prompt():
60
+ """Returns a built string that could be used as a prompt for reporting."""
61
+ return current().prompt
62
+
63
+
64
+ def switch(tag=None):
65
+ """Set the session associated to the actual ``tag`` as active."""
66
+ return current().switch(tag=tag)
67
+
68
+
69
+ def getglove(**kw):
70
+ """Proxy to :mod:`gloves` collector."""
71
+ return footprints.proxy.gloves.default(**kw)
72
+
73
+
74
+ def system(**kw):
75
+ """Returns the system associated to the current ticket."""
76
+ return get(tag=kw.pop('tag', Ticket.tag_focus())).system(**kw)
77
+
78
+
79
+ # noinspection PyShadowingBuiltins
80
+ def exit():
81
+ """Ask all inactive sessions to close, then close the active one."""
82
+ tags = keys()
83
+ xtag = Ticket.tag_focus()
84
+ tags.remove(xtag)
85
+ tags.append(xtag)
86
+ ok = True
87
+ for s in [get(tag=x) for x in tags]:
88
+ ok = s.exit() and ok
89
+ return ok
90
+
91
+
92
+ class Ticket(getbytag.GetByTag):
93
+ """
94
+ Default session ticket class, defined by tag.
95
+ """
96
+
97
+ _tag_default = 'root'
98
+
99
+ def __init__(self,
100
+ active=False,
101
+ topenv=None,
102
+ glove=None,
103
+ context=None,
104
+ datastore=None,
105
+ prompt='Vortex:'):
106
+ self.prompt = prompt
107
+ self.line = "\n" + '-' * 100 + "\n"
108
+
109
+ self._started = date.now()
110
+ self._closed = 0
111
+ self._system = None
112
+
113
+ if topenv:
114
+ self._topenv = topenv
115
+ else:
116
+ self._topenv = Environment()
117
+
118
+ if glove:
119
+ self._glove = glove
120
+ else:
121
+ self._glove = getglove()
122
+
123
+ logger.debug('New session system is %s', self.system())
124
+
125
+ self._rundir = self.sh.getcwd()
126
+
127
+ logger.debug('Open session %s %s', self.tag, self)
128
+
129
+ if datastore is None:
130
+ datastore = DataStore(default_picklefile='{:s}_session_datastore.pickled'.format(self.tag))
131
+ self._dstore = datastore
132
+
133
+ if context is None:
134
+ context = contexts.Context(tag=self.tag, topenv=self._topenv, path=self.path)
135
+ self._last_context = context
136
+
137
+ if active:
138
+ self.catch_focus()
139
+
140
+ def _get_rundir(self):
141
+ """Return the path of the directory associated to current session."""
142
+ return self._rundir
143
+
144
+ def _set_rundir(self, path):
145
+ """Set a new default rundir for this session."""
146
+ if self._rundir:
147
+ logger.warning('Session <%s> is changing its working directory <%s>', self.tag, self._rundir)
148
+ if self.sh.path.isdir(path):
149
+ self._rundir = path
150
+ logger.info('Session <%s> set rundir <%s>', self.tag, self._rundir)
151
+ else:
152
+ logger.error('Try to change session <%s> to invalid path <%s>', self.tag, path)
153
+
154
+ rundir = property(_get_rundir, _set_rundir)
155
+
156
+ @property
157
+ def active(self):
158
+ """Return whether this session is active or not."""
159
+ return self.has_focus()
160
+
161
+ @property
162
+ def started(self):
163
+ """Return opening time stamp."""
164
+ return self._started
165
+
166
+ @property
167
+ def closed(self):
168
+ """Return closing time stamp if any."""
169
+ return self._closed
170
+
171
+ @property
172
+ def opened(self):
173
+ """Boolean. True if the session is not closed."""
174
+ return not bool(self.closed)
175
+
176
+ @property
177
+ def topenv(self):
178
+ """Return top environment binded to this session."""
179
+ return self._topenv
180
+
181
+ @property
182
+ def env(self):
183
+ """Return environment binded to current active context."""
184
+ return self.context.env
185
+
186
+ @property
187
+ def sh(self):
188
+ """Return shell interface binded to current active context."""
189
+ return self._system
190
+
191
+ @property
192
+ def glove(self):
193
+ """Return the default glove associated to this session."""
194
+ return self._glove
195
+
196
+ @property
197
+ def context(self):
198
+ """Returns the active or latest context binded to this section."""
199
+ if self.active:
200
+ return contexts.current()
201
+ else:
202
+ return self._last_context
203
+
204
+ @property
205
+ def datastore(self):
206
+ return self._dstore
207
+
208
+ def system(self, **kw):
209
+ """
210
+ Returns the current OS handler used or set a new one according
211
+ to ``kw`` dictionary-like arguments.
212
+ """
213
+ refill = kw.pop('refill', False)
214
+ if not self._system or kw or refill:
215
+ self._system = footprints.proxy.system(glove=self.glove, **kw)
216
+ if not self._system:
217
+ logger.critical('Could not load a system object with description %s', str(kw))
218
+ return self._system
219
+
220
+ def duration(self):
221
+ """
222
+ Time since the opening of the session if still opened
223
+ or complete duration time if closed.
224
+ """
225
+ if self.closed:
226
+ return self.closed - self.started
227
+ else:
228
+ return date.now() - self.started
229
+
230
+ def activate(self):
231
+ """Force the current session as active."""
232
+ if self.opened:
233
+ return self.switch(self.tag)
234
+ else:
235
+ return False
236
+
237
+ def close(self):
238
+ """Closes the current session."""
239
+ if self.closed:
240
+ logger.warning('Session %s already closed at %s', self.tag, self.closed)
241
+ else:
242
+ self._closed = date.now()
243
+ logger.debug('Close session %s ( time = %s )', self.tag, self.duration())
244
+
245
+ @property
246
+ def path(self):
247
+ return '/' + self.tag
248
+
249
+ @property
250
+ def subcontexts(self):
251
+ """The current contexts binded to this session."""
252
+ rootpath = self.path + '/'
253
+ return [x for x in contexts.values() if x.path.startswith(rootpath)]
254
+
255
+ def exit(self):
256
+ """Exit from the current session."""
257
+ ok = True
258
+ logger.debug('Exit session %s %s', self.tag, self)
259
+ for kid in self.subcontexts:
260
+ logger.debug('Exit from context %s', kid)
261
+ ok = ok and kid.exit()
262
+ if self.opened:
263
+ self.close()
264
+ return ok
265
+
266
+ def warning(self):
267
+ """Switch current loglevel to WARNING."""
268
+ self.setloglevel(logging.WARNING)
269
+
270
+ def debug(self):
271
+ """Switch current loglevel to DEBUG."""
272
+ self.setloglevel(logging.DEBUG)
273
+
274
+ def info(self):
275
+ """Switch current loglevel to INFO."""
276
+ self.setloglevel(logging.INFO)
277
+
278
+ def error(self):
279
+ """Switch current loglevel to ERROR."""
280
+ self.setloglevel(logging.ERROR)
281
+
282
+ def critical(self):
283
+ """Switch current loglevel to CRITICAL."""
284
+ self.setloglevel(logging.CRITICAL)
285
+
286
+ def setloglevel(self, level):
287
+ """
288
+ Explicitly sets the logging level to the ``level`` value.
289
+ Shortcuts such as :method::`debug' or :method:`error` should be used.
290
+ """
291
+ loggers.setGlobalLevel(level)
292
+
293
+ @property
294
+ def loglevel(self):
295
+ """
296
+ Returns the logging level.
297
+ """
298
+ v_logger = loggers.getLogger('vortex')
299
+ return logging.getLevelName(v_logger.getEffectiveLevel())
300
+
301
+ def idcard(self, indent='+ '):
302
+ """Returns a printable description of the current session."""
303
+ card = "\n".join((
304
+ '{0}Name = {1:s}',
305
+ '{0}Started = {2!s}',
306
+ '{0}Opened = {3!s}',
307
+ '{0}Duration = {4!s}',
308
+ '{0}Loglevel = {5:s}'
309
+ )).format(
310
+ indent,
311
+ self.tag, self.started, self.opened, self.duration(), self.loglevel
312
+ )
313
+ return card
314
+
315
+ def focus_gain_hook(self):
316
+ """Activate the appropriate context."""
317
+ super().focus_gain_hook()
318
+ self._last_context.catch_focus()
319
+
320
+ def focus_loose_hook(self):
321
+ """Keep track of the latest context."""
322
+ super().focus_loose_hook()
323
+ self._last_context = self.context
324
+
325
+ @classmethod
326
+ def switch(cls, tag=None):
327
+ """
328
+ Allows the user to switch to an other session,
329
+ assuming that the provided tag is already known.
330
+ """
331
+ if tag in cls.tag_keys():
332
+ obj = Ticket(tag=tag)
333
+ obj.catch_focus()
334
+ return obj
335
+ else:
336
+ logger.error('Try to switch to an undefined session: %s', tag)
337
+ return None
338
+
339
+ def __del__(self):
340
+ if self.opened:
341
+ self.close()
@@ -0,0 +1,9 @@
1
+ """
2
+ The :mod:`vortex` syntax mostly deals with attributes resolution and arguments expansion.
3
+ The most important usage is done by :class:`FootprintBase` derivated objects.
4
+ """
5
+
6
+ #: No automatic export
7
+ __all__ = []
8
+
9
+ __tocinfoline__ = 'VORTEX package where standard attributes are defined.'