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,27 @@
1
+ #!${python}
2
+
3
+ import os
4
+ import sys
5
+
6
+ sys.path.append('${sitepath}')
7
+ rank = os.environ['${mpirankvariable}']
8
+
9
+ todolist = {
10
+ ${todolist}
11
+ }
12
+
13
+ bindinglist = {
14
+ ${bindinglist}
15
+ }
16
+
17
+ if bindinglist:
18
+ from bronx.system.cpus import set_affinity
19
+ set_affinity(bindinglist[int(rank)])
20
+ # Also bind threads
21
+ os.environ['OMP_PROC_BIND'] = 'true'
22
+
23
+ me = todolist[int(rank)]
24
+ if me[2]:
25
+ os.environ['OMP_NUM_THREADS'] = str(me[2])
26
+
27
+ os.execl(me[0], me[0], *me[1])
@@ -0,0 +1,29 @@
1
+ #!${python}
2
+
3
+ import os
4
+ import sys
5
+
6
+ sys.path.append('${sitepath}')
7
+
8
+ actual_mpirankvariable = os.environ['${mpirankvariable}']
9
+ rank = os.environ[actual_mpirankvariable]
10
+
11
+ todolist = {
12
+ ${todolist}
13
+ }
14
+
15
+ bindinglist = {
16
+ ${bindinglist}
17
+ }
18
+
19
+ if bindinglist:
20
+ from bronx.system.cpus import set_affinity
21
+ set_affinity(bindinglist[int(rank)])
22
+ # Also bind threads
23
+ os.environ['OMP_PROC_BIND'] = 'true'
24
+
25
+ me = todolist[int(rank)]
26
+ if me[2]:
27
+ os.environ['OMP_NUM_THREADS'] = str(me[2])
28
+
29
+ os.execl(me[0], me[0], *me[1])
@@ -0,0 +1,18 @@
1
+ #!${python}
2
+
3
+ import os
4
+ import sys
5
+
6
+ rank = os.environ['${mpirankvariable}']
7
+
8
+ # Redirect stdout and stderr in a very very crude manner
9
+ if int(rank) > 0:
10
+ stdout_fno = sys.stdout.fileno()
11
+ stderr_fno = sys.stderr.fileno()
12
+ red_outputs = os.open('vwrap_stdeo.{:06d}'.format(int(rank)),
13
+ os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o644)
14
+ os.dup2(red_outputs, stdout_fno)
15
+ os.dup2(red_outputs, stderr_fno)
16
+ os.close(red_outputs)
17
+
18
+ os.execl(sys.argv[1], *sys.argv[1:])
@@ -0,0 +1,170 @@
1
+ """
2
+ Utility classes to interact with long running binaries.
3
+ """
4
+
5
+ import socket
6
+ import sys
7
+
8
+ import footprints
9
+ from bronx.fancies import loggers
10
+ from vortex import sessions
11
+ from vortex.util import config
12
+
13
+ # : No automatic export
14
+ __all__ = []
15
+
16
+ logger = loggers.getLogger(__name__)
17
+
18
+
19
+ class ServerSyncTool(footprints.FootprintBase):
20
+ """
21
+ :class:`ServerSyncTool` classes are in charge of interactions between the
22
+ main process and the server.
23
+ """
24
+
25
+ _abstract = True
26
+ _collector = ('serversynctool',)
27
+ _footprint = dict(
28
+ info='Abstract Server Synchronisation Tool',
29
+ attr=dict(
30
+ method=dict(
31
+ ),
32
+ medium=dict(
33
+ optional=True,
34
+ ),
35
+ raiseonexit=dict(
36
+ type=bool,
37
+ optional=True,
38
+ default=True
39
+ ),
40
+ checkinterval=dict(
41
+ type=int,
42
+ optional=True,
43
+ default=10,
44
+ ),
45
+ )
46
+ )
47
+
48
+ def __init__(self, *args, **kw):
49
+ logger.debug('Server Synchronisation Tool init %s', self.__class__)
50
+ self._check_callback = lambda: True
51
+ super().__init__(*args, **kw)
52
+
53
+ def set_servercheck_callback(self, cb):
54
+ """Set a callback method that will be called to check the server state."""
55
+ self._check_callback = cb
56
+
57
+ def trigger_wait(self):
58
+ """Ask the SyncTool to wait for a request."""
59
+ raise NotImplementedError
60
+
61
+ def trigger_run(self):
62
+ """Indicate that the main process is ready for the server to run the next step.
63
+
64
+ It then wait for the server to complete this step.
65
+ """
66
+ raise NotImplementedError
67
+
68
+ def trigger_stop(self):
69
+ """Ask the server to stop (gently)."""
70
+ raise NotImplementedError
71
+
72
+
73
+ class ServerSyncSimpleSocket(ServerSyncTool):
74
+ """Practical implementation of a ServerSyncTool that relies on sockets.
75
+
76
+ A script is created (its name is defined by the *medium* attribute): it
77
+ will be called by the server process before starting any computations. This
78
+ script and the main process communicate using standard UNIX sockets (through
79
+ the socket package).
80
+ """
81
+
82
+ _footprint = dict(
83
+ info='Server Synchronisation Tool that uses a Socket',
84
+ attr=dict(
85
+ method=dict(
86
+ values=['simple_socket'],
87
+ ),
88
+ medium=dict(
89
+ optional=False,
90
+ ),
91
+ tplname=dict(
92
+ optional=True,
93
+ default='@servsync-simplesocket.tpl',
94
+ ),
95
+ )
96
+ )
97
+
98
+ def __init__(self, *args, **kw):
99
+ super().__init__(*args, **kw)
100
+ # Create the socket
101
+ self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
102
+ try:
103
+ self._socket.bind((socket.getfqdn(), 0))
104
+ except OSError:
105
+ self._socket.bind(('localhost', 0))
106
+ self._socket.settimeout(self.checkinterval)
107
+ self._socket.listen(1)
108
+ # Current connection
109
+ self._socket_conn = None
110
+ # Create the script that will be called by the server
111
+ t = sessions.current()
112
+ tpl = config.load_template(t, self.tplname)
113
+ with open(self.medium, 'w') as fd:
114
+ fd.write(tpl.substitute(
115
+ python=sys.executable,
116
+ address=self._socket.getsockname(),
117
+ ))
118
+ t.sh.chmod(self.medium, 0o555)
119
+
120
+ def __del__(self):
121
+ self._socket.close()
122
+ if self._socket_conn is not None:
123
+ logger.warning("The socket is still up... that's odd.")
124
+ t = sessions.current()
125
+ if t.sh.path.exists(self.medium):
126
+ t.sh.remove(self.medium)
127
+
128
+ def _command(self, mess):
129
+ """Send a command (a string) to the server and wait for a response."""
130
+ if self._socket_conn is not None:
131
+ logger.info('Sending "%s" to the server.', mess)
132
+ # NB: For send/recv, the settimeout also applies...
133
+ self._socket_conn.send(mess.encode(encoding='utf-8'))
134
+ repl = self._socket_conn.recv(255).decode(encoding='utf-8')
135
+ logger.info('Server replied "%s" to %s.', repl, mess)
136
+ self._socket_conn.close()
137
+ self._socket_conn = None
138
+ if repl != 'OK':
139
+ raise ValueError(mess + ' failed')
140
+ return True
141
+ else:
142
+ # This should not happen ! If we are sitting here, it's most likely
143
+ # that the main process received a signal like SIGTERM...
144
+ return False
145
+
146
+ def trigger_wait(self):
147
+ logger.info('Waiting for the server to complete')
148
+ while self._socket_conn is None and self._check_callback():
149
+ try:
150
+ self._socket_conn, addr = self._socket.accept() # @UnusedVariable
151
+ except socket.timeout:
152
+ logger.debug('Socket accept timed-out: checking for the server...')
153
+ self._socket_conn = None
154
+ if self._socket_conn is None:
155
+ if self.raiseonexit:
156
+ raise OSError('Apparently the server died.')
157
+ else:
158
+ logger.info('The server stopped.')
159
+ else:
160
+ self._socket_conn.settimeout(self.checkinterval)
161
+ logger.info('The server is now waiting')
162
+
163
+ def trigger_run(self):
164
+ # Tell the server that everything is ready
165
+ self._command('STEP')
166
+ # Wait for the server to complete its work
167
+ self.trigger_wait()
168
+
169
+ def trigger_stop(self):
170
+ return self._command('STOP')
vortex/config.py ADDED
@@ -0,0 +1,115 @@
1
+ """This module provides getter and setter functions to set and get
2
+ the value of configuration options, respectively.
3
+
4
+ """
5
+ import tomli
6
+
7
+ from bronx.fancies import loggers
8
+
9
+ __all__ = [
10
+ "load_config",
11
+ "print_config",
12
+ "from_config",
13
+ "set_config",
14
+ "is_defined",
15
+ ]
16
+
17
+ VORTEX_CONFIG = {}
18
+
19
+ logger = loggers.getLogger(__name__)
20
+
21
+
22
+ def load_config(configpath="vortex.toml"):
23
+ """Load configuration from a TOML configuration file
24
+
25
+ Existing configuration values are overriden. The configuration
26
+ is expected to have valid TOML syntax, e.g.
27
+
28
+ .. code:: toml
29
+
30
+ [data-tree]
31
+ op_rootdir = "/chaine/mxpt001"
32
+
33
+ [storage]
34
+ address = "hendrix.meteo.fr"
35
+ protocol = "ftp"
36
+ # ...
37
+ """
38
+ global VORTEX_CONFIG
39
+ try:
40
+ with open(configpath, "rb") as f:
41
+ VORTEX_CONFIG = tomli.load(f)
42
+ print(f"Successfully read configuration file {configpath}")
43
+ except FileNotFoundError:
44
+ print(
45
+ f"Could not read configuration file {configpath}"
46
+ " (not found)."
47
+ )
48
+ print(
49
+ "Use load_config(/path/to/config) to update the configuration"
50
+ )
51
+
52
+
53
+ def print_config():
54
+ """Print configuration (key, value) pairs
55
+ """
56
+ if VORTEX_CONFIG:
57
+ for k, v in VORTEX_CONFIG:
58
+ print(k.upper(), v)
59
+
60
+
61
+ def from_config(section, key=None):
62
+ """Retrieve a configuration key value for a given section.
63
+
64
+ If key is ``None``, the whole section is returned as a dictionary.
65
+
66
+ """
67
+ try:
68
+ subconfig = VORTEX_CONFIG[section]
69
+ except KeyError as e:
70
+ print(f"Could not find section {section} in configuration")
71
+ raise(e)
72
+
73
+ if not key:
74
+ return subconfig
75
+
76
+ try:
77
+ value = subconfig[key]
78
+ except KeyError as e :
79
+ print(f"Could not find key {key} in section {section} of configuration")
80
+ raise(e)
81
+ return value
82
+
83
+
84
+ def set_config(section, key, value):
85
+ """Set a configuration key to a value"""
86
+ global VORTEX_CONFIG
87
+ if section not in VORTEX_CONFIG.keys():
88
+ VORTEX_CONFIG[section] = {}
89
+ if key in VORTEX_CONFIG[section]:
90
+ logger.warning(
91
+ f"Updating existing configuration {section}:{key}"
92
+ )
93
+ VORTEX_CONFIG[section][key] = value
94
+
95
+
96
+ def is_defined(section, key=None):
97
+ """Return whether or not the key is defined for the section.
98
+
99
+ If ``key`` is ``None``, return whether or not the section exists
100
+ in the current configuration.
101
+
102
+ """
103
+ if section not in VORTEX_CONFIG.keys():
104
+ return False
105
+ if key:
106
+ return key in VORTEX_CONFIG[section].keys()
107
+ return True
108
+
109
+
110
+ def get_from_config_w_default(section, key, default):
111
+ logger.info(f"Reading config value {section}.{key}")
112
+ try:
113
+ return from_config(section, key)
114
+ except KeyError:
115
+ return default
@@ -0,0 +1,13 @@
1
+ """
2
+ Abstract classes involved in data management within VORTEX.
3
+
4
+ Actual resources and custom providers should be defined in dedicated packages.
5
+ """
6
+
7
+ from . import handlers, resources, containers, contents, providers, \
8
+ executables, stores, geometries
9
+
10
+ #: No automatic export
11
+ __all__ = []
12
+
13
+ __tocinfoline__ = 'Abstract classes involved in data management within VORTEX'