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