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/gloves.py ADDED
@@ -0,0 +1,282 @@
1
+ """
2
+ GLObal Versatile Environment classes are responsible for session-wide
3
+ configuration (username, emil adress, ...)
4
+ """
5
+
6
+ from bronx.fancies import loggers
7
+ import footprints
8
+
9
+ from vortex.tools.env import Environment
10
+
11
+ #: No automatic export
12
+ __all__ = []
13
+
14
+ logger = loggers.getLogger(__name__)
15
+
16
+
17
+ class Glove(footprints.FootprintBase):
18
+ """Base class for GLObal Versatile Environment."""
19
+
20
+ _abstract = True
21
+ _collector = ('glove',)
22
+ _footprint = dict(
23
+ info = 'Abstract glove',
24
+ attr = dict(
25
+ email = dict(
26
+ alias = ['address'],
27
+ optional = True,
28
+ default = Environment(active=False)['email'],
29
+ access = 'rwx',
30
+ ),
31
+ vapp = dict(
32
+ optional = True,
33
+ default = 'play',
34
+ access = 'rwx',
35
+ ),
36
+ vconf = dict(
37
+ optional = True,
38
+ default = 'sandbox',
39
+ access = 'rwx',
40
+ ),
41
+ tag = dict(
42
+ optional = True,
43
+ default = 'default',
44
+ ),
45
+ user = dict(
46
+ alias = ('logname', 'username'),
47
+ optional = True,
48
+ default = Environment(active=False)['logname']
49
+ ),
50
+ profile = dict(
51
+ alias = ('kind', 'membership'),
52
+ values = ['oper', 'dble', 'test', 'research', 'tourist'],
53
+ remap = dict(tourist = 'research')
54
+ )
55
+ )
56
+ )
57
+
58
+ def __init__(self, *args, **kw):
59
+ logger.debug('Glove abstract %s init', self.__class__)
60
+ super().__init__(*args, **kw)
61
+ self._rmdepthmin = 3
62
+ self._siteroot = None
63
+ self._siteconf = None
64
+ self._sitedoc = None
65
+ self._sitesrc = None
66
+ self._ftdhost = None
67
+ self._ftduser = None
68
+ self._ftusers = dict()
69
+
70
+ @property
71
+ def realkind(self):
72
+ """Returns the litteral string identity of the current glove."""
73
+ return 'glove'
74
+
75
+ @property
76
+ def configrc(self):
77
+ """Returns the path of the default directory where ``.ini`` files are stored."""
78
+ return Environment(active=False).HOME + '/.vortexrc'
79
+
80
+ @property
81
+ def siteroot(self):
82
+ """Returns the path of the vortex install directory."""
83
+ if not self._siteroot:
84
+ self._siteroot = '/'.join(__file__.split('/')[0:-3])
85
+ return self._siteroot
86
+
87
+ @property
88
+ def siteconf(self):
89
+ """Returns the path of the default directory where ``.ini`` files are stored."""
90
+ if not self._siteconf:
91
+ self._siteconf = '/'.join((self.siteroot, 'conf'))
92
+ return self._siteconf
93
+
94
+ @property
95
+ def sitedoc(self):
96
+ """Returns the path of the default directory where ``.ini`` files are stored."""
97
+ if not self._sitedoc:
98
+ self._sitedoc = '/'.join((self.siteroot, 'sphinx'))
99
+ return self._sitedoc
100
+
101
+ @property
102
+ def sitesrc(self):
103
+ """Returns the path of the default directory where ``.ini`` files are stored."""
104
+ if not self._sitesrc:
105
+ self._sitesrc = (
106
+ '/'.join((self.siteroot, 'site')),
107
+ '/'.join((self.siteroot, 'src'))
108
+ )
109
+ return self._sitesrc
110
+
111
+ def setenv(self, app=None, conf=None):
112
+ """Change ``vapp`` or/and ``vconf`` in one call."""
113
+ if app is not None:
114
+ self.vapp = app
115
+ if conf is not None:
116
+ self.vconf = conf
117
+ return (self.vapp, self.vconf)
118
+
119
+ def setmail(self, domain=None):
120
+ """Refresh actual email with current username and provided ``domain``."""
121
+ if domain is None:
122
+ from vortex import sessions
123
+ domain = sessions.system().getfqdn()
124
+ return '@'.join((self.user, domain))
125
+
126
+ @property
127
+ def xmail(self):
128
+ if self.email is None:
129
+ return self.setmail()
130
+ else:
131
+ return self.email
132
+
133
+ def safedirs(self):
134
+ """Protected paths as a list a tuples (path, depth)."""
135
+ e = Environment(active=False)
136
+ return [(e.HOME, 2), (e.TMPDIR, 1)]
137
+
138
+ def setftuser(self, user, hostname=None):
139
+ """Register a default username for *hostname*.
140
+
141
+ If *hostname* is omitted the default username is set.
142
+ """
143
+ if hostname is None:
144
+ self._ftduser = user
145
+ else:
146
+ if not user:
147
+ del self._ftusers[hostname]
148
+ else:
149
+ self._ftusers[hostname] = user
150
+
151
+ def getftuser(self, hostname, defaults_to_user=True):
152
+ """Get the default username for a given *hostname*."""
153
+ if self._ftusers.get(hostname, None):
154
+ return self._ftusers[hostname]
155
+ else:
156
+ if self._ftduser:
157
+ return self._ftduser
158
+ else:
159
+ return Environment.current().get('VORTEX_ARCHIVE_USER',
160
+ self.user if defaults_to_user else None)
161
+
162
+ def _get_default_fthost(self):
163
+ if self._ftdhost:
164
+ return self._ftdhost
165
+ else:
166
+ return Environment.current().get('VORTEX_ARCHIVE_HOST', None)
167
+
168
+ def _set_default_fthost(self, value):
169
+ self._ftdhost = value
170
+
171
+ def _del_default_fthost(self):
172
+ self._ftdhost = None
173
+
174
+ default_fthost = property(_get_default_fthost, _set_default_fthost, _del_default_fthost)
175
+
176
+ def describeftsettings(self, indent='+ '):
177
+ """Returns a printable description of default file transfert usernames."""
178
+ card = "\n".join(
179
+ ['{0}{3:48s} = {4:s}', ] +
180
+ ['{0}{1:48s} = {2:s}', ] +
181
+ (['{0}Host specific FT users:', ] if self._ftusers else []) +
182
+ ['{0}' + ' {:46s} = {:s}'.format(k, v) for k, v in self._ftusers.items() if v]
183
+ ).format(indent,
184
+ 'Default FT User', str(self._ftduser),
185
+ 'Default FT Host', str(self._ftdhost))
186
+ return card
187
+
188
+ def idcard(self, indent='+ '):
189
+ """Returns a printable description of the current glove."""
190
+ card = "\n".join((
191
+ '{0}User = {1:s}',
192
+ '{0}Profile = {2!s}',
193
+ '{0}Vapp = {3:s}',
194
+ '{0}Vconf = {4:s}',
195
+ '{0}Configrc = {5:s}'
196
+ )).format(
197
+ indent,
198
+ self.user, self.profile, self.vapp, self.vconf, self.configrc
199
+ )
200
+ return card
201
+
202
+
203
+ class ResearchGlove(Glove):
204
+ """
205
+ The default glove as long as you do not need operational privileges.
206
+ Optional arguments are:
207
+
208
+ * mail
209
+ * profile (default is research)
210
+ """
211
+
212
+ _explicit = False
213
+ _footprint = dict(
214
+ info = 'Research glove',
215
+ attr = dict(
216
+ profile = dict(
217
+ optional = True,
218
+ values = ['research', 'tourist'],
219
+ default = 'research',
220
+ )
221
+ )
222
+ )
223
+
224
+ @property
225
+ def realkind(self):
226
+ return 'research'
227
+
228
+
229
+ class OperGlove(Glove):
230
+ """
231
+ The default glove if you need operational privileges.
232
+ Mandatory arguments are:
233
+
234
+ * user
235
+ * profile
236
+ """
237
+
238
+ _footprint = dict(
239
+ info = 'Operational glove',
240
+ attr = dict(
241
+ user = dict(
242
+ values = ['mxpt001']
243
+ ),
244
+ profile = dict(
245
+ optional = False,
246
+ values = ['oper', 'dble', 'test', 'miroir'],
247
+ )
248
+ )
249
+ )
250
+
251
+ @property
252
+ def realkind(self):
253
+ return 'opuser'
254
+
255
+
256
+ class UnitTestGlove(ResearchGlove):
257
+ """A very special glove for unit-tests."""
258
+
259
+ _footprint = dict(
260
+ info = 'Unit-Test Glove',
261
+ attr = dict(
262
+ profile = dict(
263
+ optional = False,
264
+ values = ['utest'],
265
+ ),
266
+ test_configrc = dict(
267
+ optional = False,
268
+ ),
269
+ test_siteroot = dict(
270
+ optional = False,
271
+ ),
272
+ )
273
+ )
274
+
275
+ def __init__(self, *args, **kw):
276
+ super().__init__(*args, **kw)
277
+ self._siteroot = self.test_siteroot
278
+
279
+ @property
280
+ def configrc(self):
281
+ """Returns the path of the default directory where ``.ini`` files are stored."""
282
+ return self.test_configrc
@@ -0,0 +1,27 @@
1
+ """
2
+ Package dealing with various aspects of the VORTEX session organisation/layout.
3
+
4
+ It provides modules to keep track of all the input/output data handled during
5
+ a VORTEX session:
6
+
7
+ * the :mod:`dataflow` module defines the :class:`~dataflow.Section` class
8
+ and all the necessary class to gather and manipulate :class:`~dataflow.Section`
9
+ objects ;
10
+ * the :mod:`contexts` module is dedicated to the :class:`~contexts.Context`
11
+ class that provide a logical separation within VORTEX sessions. It mantains
12
+ the list of sections and environment variables ;
13
+ * the :mod:`monitor` module defines utility classes to monitor the state of an
14
+ ensemble of :class:`~dataflow.Section` objects.
15
+
16
+ It also provides modules that allows to create "standard" VORTEX's jobs:
17
+
18
+ * the :mod:`nodes` modules defines a bunch of classes that helps to organise
19
+ VORTEX jobs (creating tasks, families of tasks, ...);
20
+ * the :mod:`jobs` module focuses on the actual job generation and initialisation.
21
+
22
+ """
23
+
24
+ #: No automatic export
25
+ __all__ = []
26
+
27
+ __tocinfoline__ = 'Package that helps organising a VORTEX session.'
@@ -0,0 +1,109 @@
1
+ """
2
+ This modules defines objects that any kind of configuration data
3
+ for jobs and nodes.
4
+ """
5
+
6
+ import collections.abc
7
+ import re
8
+
9
+ from bronx.syntax.decorators import secure_getattr
10
+
11
+ from vortex.util.config import AppConfigStringDecoder
12
+
13
+
14
+ class ConfigSet(collections.abc.MutableMapping):
15
+ """Simple struct-like object that acts as a lower case dictionary.
16
+
17
+ Two syntax are available to add a new entry in a :class:`ConfigSet` object:
18
+
19
+ * ``ConfigSetObject.key = value``
20
+ * ``ConfigSetObject[key] = value``
21
+
22
+ Prior to being retrieved, entries are passed to a
23
+ :class:`vortex.util.config.AppConfigStringDecoder` object. It allows to
24
+ describe complex data types (see the :class:`vortex.util.config.AppConfigStringDecoder`
25
+ class documentation).
26
+
27
+ Some extra features are added on top of the
28
+ :class:`vortex.util.config.AppConfigStringDecoder` capabilities:
29
+
30
+ * If ``key`` ends with *_map*, ``value`` will be seen as a dictionary
31
+ * If ``key`` contains the words *geometry* or *geometries*, ``value``
32
+ will be converted to a :class:`vortex.data.geometries.Geometry` object
33
+ * If ``key`` ends with *_range*, ``value`` will be passed to the
34
+ :func:`footprints.util.rangex` function
35
+
36
+ """
37
+
38
+ def __init__(self, *kargs, **kwargs):
39
+ super().__init__(*kargs, **kwargs)
40
+ self.__dict__['_internal'] = dict()
41
+ self.__dict__['_confdecoder'] = AppConfigStringDecoder(substitution_cb=self._internal.get)
42
+
43
+ @staticmethod
44
+ def _remap_key(key):
45
+ return key.lower()
46
+
47
+ def __iter__(self):
48
+ for k in self._internal.keys():
49
+ yield self._remap_key(k)
50
+
51
+ def __getitem__(self, key):
52
+ return self._confdecoder(self._internal[self._remap_key(key)])
53
+
54
+ def __setitem__(self, key, value):
55
+ if value is not None and isinstance(value, str):
56
+ # Support for old style dictionaries (compatibility)
57
+ if (key.endswith('_map') and not re.match(r'^dict\(.*\)$', value) and
58
+ not re.match(r'^\w+\(dict\(.*\)\)$', value)):
59
+ key = key[:-4]
60
+ if re.match(r'^\w+\(.*\)$', value):
61
+ value = re.sub(r'^(\w+)\((.*)\)$', r'\1(dict(\2))', value)
62
+ else:
63
+ value = 'dict(' + value + ')'
64
+ # Support for geometries (compatibility)
65
+ if (('geometry' in key or 'geometries' in key) and
66
+ (not re.match(r'^geometry\(.*\)$', value, flags=re.IGNORECASE))):
67
+ value = 'geometry(' + value + ')'
68
+ # Support for oldstyle range (compatibility)
69
+ if (key.endswith('_range') and not re.match(r'^rangex\(.*\)$', value) and
70
+ not re.match(r'^\w+\(rangex\(.*\)\)$', value)):
71
+ key = key[:-6]
72
+ if re.match(r'^\w+\(.*\)$', value):
73
+ value = re.sub(r'^(\w+)\((.*)\)$', r'\1(rangex(\2))', value)
74
+ else:
75
+ value = 'rangex(' + value + ')'
76
+ self._internal[self._remap_key(key)] = value
77
+
78
+ def __delitem__(self, key):
79
+ del self._internal[self._remap_key(key)]
80
+
81
+ def __len__(self):
82
+ return len(self._internal)
83
+
84
+ def clear(self):
85
+ self._internal.clear()
86
+
87
+ def __contains__(self, key):
88
+ return self._remap_key(key) in self._internal
89
+
90
+ @secure_getattr
91
+ def __getattr__(self, key):
92
+ if key in self:
93
+ return self[key]
94
+ else:
95
+ raise AttributeError('No such parameter <' + key + '>')
96
+
97
+ def __setattr__(self, attr, value):
98
+ self[attr] = value
99
+
100
+ def __delattr__(self, key):
101
+ if key in self:
102
+ del self[key]
103
+ else:
104
+ raise AttributeError('No such parameter <' + key + '>')
105
+
106
+ def copy(self):
107
+ newobj = self.__class__()
108
+ newobj.update(**self._internal)
109
+ return newobj