sierra-research 1.3.6__py3-none-any.whl → 1.5.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 (254) hide show
  1. sierra/__init__.py +3 -3
  2. sierra/core/__init__.py +3 -3
  3. sierra/core/batchroot.py +223 -0
  4. sierra/core/cmdline.py +681 -1057
  5. sierra/core/compare.py +11 -0
  6. sierra/core/config.py +96 -88
  7. sierra/core/engine.py +306 -0
  8. sierra/core/execenv.py +380 -0
  9. sierra/core/expdef.py +11 -0
  10. sierra/core/experiment/__init__.py +1 -0
  11. sierra/core/experiment/bindings.py +150 -101
  12. sierra/core/experiment/definition.py +414 -245
  13. sierra/core/experiment/spec.py +83 -85
  14. sierra/core/exproot.py +44 -0
  15. sierra/core/generators/__init__.py +10 -0
  16. sierra/core/generators/experiment.py +528 -0
  17. sierra/core/generators/generator_factory.py +138 -137
  18. sierra/core/graphs/__init__.py +23 -0
  19. sierra/core/graphs/bcbridge.py +94 -0
  20. sierra/core/graphs/heatmap.py +245 -324
  21. sierra/core/graphs/pathset.py +27 -0
  22. sierra/core/graphs/schema.py +77 -0
  23. sierra/core/graphs/stacked_line.py +341 -0
  24. sierra/core/graphs/summary_line.py +506 -0
  25. sierra/core/logging.py +3 -2
  26. sierra/core/models/__init__.py +3 -1
  27. sierra/core/models/info.py +19 -0
  28. sierra/core/models/interface.py +52 -122
  29. sierra/core/pipeline/__init__.py +2 -5
  30. sierra/core/pipeline/pipeline.py +228 -126
  31. sierra/core/pipeline/stage1/__init__.py +10 -0
  32. sierra/core/pipeline/stage1/pipeline_stage1.py +45 -31
  33. sierra/core/pipeline/stage2/__init__.py +10 -0
  34. sierra/core/pipeline/stage2/pipeline_stage2.py +8 -11
  35. sierra/core/pipeline/stage2/runner.py +401 -0
  36. sierra/core/pipeline/stage3/__init__.py +12 -0
  37. sierra/core/pipeline/stage3/gather.py +321 -0
  38. sierra/core/pipeline/stage3/pipeline_stage3.py +37 -84
  39. sierra/core/pipeline/stage4/__init__.py +12 -2
  40. sierra/core/pipeline/stage4/pipeline_stage4.py +36 -354
  41. sierra/core/pipeline/stage5/__init__.py +12 -0
  42. sierra/core/pipeline/stage5/pipeline_stage5.py +33 -208
  43. sierra/core/pipeline/yaml.py +48 -0
  44. sierra/core/plugin.py +529 -62
  45. sierra/core/proc.py +11 -0
  46. sierra/core/prod.py +11 -0
  47. sierra/core/ros1/__init__.py +5 -1
  48. sierra/core/ros1/callbacks.py +22 -21
  49. sierra/core/ros1/cmdline.py +59 -88
  50. sierra/core/ros1/generators.py +159 -175
  51. sierra/core/ros1/variables/__init__.py +3 -0
  52. sierra/core/ros1/variables/exp_setup.py +122 -116
  53. sierra/core/startup.py +106 -76
  54. sierra/core/stat_kernels.py +4 -5
  55. sierra/core/storage.py +13 -32
  56. sierra/core/trampoline.py +30 -0
  57. sierra/core/types.py +116 -71
  58. sierra/core/utils.py +103 -106
  59. sierra/core/variables/__init__.py +1 -1
  60. sierra/core/variables/base_variable.py +12 -17
  61. sierra/core/variables/batch_criteria.py +387 -481
  62. sierra/core/variables/builtin.py +135 -0
  63. sierra/core/variables/exp_setup.py +19 -39
  64. sierra/core/variables/population_size.py +72 -76
  65. sierra/core/variables/variable_density.py +44 -68
  66. sierra/core/vector.py +1 -1
  67. sierra/main.py +256 -88
  68. sierra/plugins/__init__.py +119 -0
  69. sierra/plugins/compare/__init__.py +14 -0
  70. sierra/plugins/compare/graphs/__init__.py +19 -0
  71. sierra/plugins/compare/graphs/cmdline.py +120 -0
  72. sierra/plugins/compare/graphs/comparator.py +291 -0
  73. sierra/plugins/compare/graphs/inter_controller.py +531 -0
  74. sierra/plugins/compare/graphs/inter_scenario.py +297 -0
  75. sierra/plugins/compare/graphs/namecalc.py +53 -0
  76. sierra/plugins/compare/graphs/outputroot.py +73 -0
  77. sierra/plugins/compare/graphs/plugin.py +147 -0
  78. sierra/plugins/compare/graphs/preprocess.py +172 -0
  79. sierra/plugins/compare/graphs/schema.py +37 -0
  80. sierra/plugins/engine/__init__.py +14 -0
  81. sierra/plugins/engine/argos/__init__.py +18 -0
  82. sierra/plugins/{platform → engine}/argos/cmdline.py +144 -151
  83. sierra/plugins/{platform/argos/variables → engine/argos/generators}/__init__.py +5 -0
  84. sierra/plugins/engine/argos/generators/engine.py +394 -0
  85. sierra/plugins/engine/argos/plugin.py +393 -0
  86. sierra/plugins/{platform/argos/generators → engine/argos/variables}/__init__.py +5 -0
  87. sierra/plugins/engine/argos/variables/arena_shape.py +183 -0
  88. sierra/plugins/engine/argos/variables/cameras.py +240 -0
  89. sierra/plugins/engine/argos/variables/constant_density.py +112 -0
  90. sierra/plugins/engine/argos/variables/exp_setup.py +82 -0
  91. sierra/plugins/{platform → engine}/argos/variables/physics_engines.py +83 -87
  92. sierra/plugins/engine/argos/variables/population_constant_density.py +178 -0
  93. sierra/plugins/engine/argos/variables/population_size.py +115 -0
  94. sierra/plugins/engine/argos/variables/population_variable_density.py +123 -0
  95. sierra/plugins/engine/argos/variables/rendering.py +108 -0
  96. sierra/plugins/engine/ros1gazebo/__init__.py +18 -0
  97. sierra/plugins/engine/ros1gazebo/cmdline.py +175 -0
  98. sierra/plugins/{platform/ros1robot → engine/ros1gazebo}/generators/__init__.py +5 -0
  99. sierra/plugins/engine/ros1gazebo/generators/engine.py +125 -0
  100. sierra/plugins/engine/ros1gazebo/plugin.py +404 -0
  101. sierra/plugins/engine/ros1gazebo/variables/__init__.py +15 -0
  102. sierra/plugins/engine/ros1gazebo/variables/population_size.py +214 -0
  103. sierra/plugins/engine/ros1robot/__init__.py +18 -0
  104. sierra/plugins/engine/ros1robot/cmdline.py +159 -0
  105. sierra/plugins/{platform/ros1gazebo → engine/ros1robot}/generators/__init__.py +4 -0
  106. sierra/plugins/engine/ros1robot/generators/engine.py +95 -0
  107. sierra/plugins/engine/ros1robot/plugin.py +410 -0
  108. sierra/plugins/{hpc/local → engine/ros1robot/variables}/__init__.py +5 -0
  109. sierra/plugins/engine/ros1robot/variables/population_size.py +146 -0
  110. sierra/plugins/execenv/__init__.py +11 -0
  111. sierra/plugins/execenv/hpc/__init__.py +18 -0
  112. sierra/plugins/execenv/hpc/adhoc/__init__.py +18 -0
  113. sierra/plugins/execenv/hpc/adhoc/cmdline.py +30 -0
  114. sierra/plugins/execenv/hpc/adhoc/plugin.py +131 -0
  115. sierra/plugins/execenv/hpc/cmdline.py +137 -0
  116. sierra/plugins/execenv/hpc/local/__init__.py +18 -0
  117. sierra/plugins/execenv/hpc/local/cmdline.py +31 -0
  118. sierra/plugins/execenv/hpc/local/plugin.py +145 -0
  119. sierra/plugins/execenv/hpc/pbs/__init__.py +18 -0
  120. sierra/plugins/execenv/hpc/pbs/cmdline.py +30 -0
  121. sierra/plugins/execenv/hpc/pbs/plugin.py +121 -0
  122. sierra/plugins/execenv/hpc/slurm/__init__.py +18 -0
  123. sierra/plugins/execenv/hpc/slurm/cmdline.py +30 -0
  124. sierra/plugins/execenv/hpc/slurm/plugin.py +133 -0
  125. sierra/plugins/execenv/prefectserver/__init__.py +18 -0
  126. sierra/plugins/execenv/prefectserver/cmdline.py +66 -0
  127. sierra/plugins/execenv/prefectserver/dockerremote/__init__.py +18 -0
  128. sierra/plugins/execenv/prefectserver/dockerremote/cmdline.py +66 -0
  129. sierra/plugins/execenv/prefectserver/dockerremote/plugin.py +132 -0
  130. sierra/plugins/execenv/prefectserver/flow.py +66 -0
  131. sierra/plugins/execenv/prefectserver/local/__init__.py +18 -0
  132. sierra/plugins/execenv/prefectserver/local/cmdline.py +29 -0
  133. sierra/plugins/execenv/prefectserver/local/plugin.py +133 -0
  134. sierra/plugins/{hpc/adhoc → execenv/robot}/__init__.py +1 -0
  135. sierra/plugins/execenv/robot/turtlebot3/__init__.py +18 -0
  136. sierra/plugins/execenv/robot/turtlebot3/plugin.py +204 -0
  137. sierra/plugins/expdef/__init__.py +14 -0
  138. sierra/plugins/expdef/json/__init__.py +14 -0
  139. sierra/plugins/expdef/json/plugin.py +504 -0
  140. sierra/plugins/expdef/xml/__init__.py +14 -0
  141. sierra/plugins/expdef/xml/plugin.py +386 -0
  142. sierra/{core/hpc → plugins/proc}/__init__.py +1 -1
  143. sierra/plugins/proc/collate/__init__.py +15 -0
  144. sierra/plugins/proc/collate/cmdline.py +47 -0
  145. sierra/plugins/proc/collate/plugin.py +271 -0
  146. sierra/plugins/proc/compress/__init__.py +18 -0
  147. sierra/plugins/proc/compress/cmdline.py +47 -0
  148. sierra/plugins/proc/compress/plugin.py +123 -0
  149. sierra/plugins/proc/decompress/__init__.py +18 -0
  150. sierra/plugins/proc/decompress/plugin.py +96 -0
  151. sierra/plugins/proc/imagize/__init__.py +15 -0
  152. sierra/plugins/proc/imagize/cmdline.py +49 -0
  153. sierra/plugins/proc/imagize/plugin.py +270 -0
  154. sierra/plugins/proc/modelrunner/__init__.py +16 -0
  155. sierra/plugins/proc/modelrunner/plugin.py +250 -0
  156. sierra/plugins/proc/statistics/__init__.py +15 -0
  157. sierra/plugins/proc/statistics/cmdline.py +64 -0
  158. sierra/plugins/proc/statistics/plugin.py +390 -0
  159. sierra/plugins/{hpc → prod}/__init__.py +1 -0
  160. sierra/plugins/prod/graphs/__init__.py +18 -0
  161. sierra/plugins/prod/graphs/cmdline.py +269 -0
  162. sierra/plugins/prod/graphs/collate.py +279 -0
  163. sierra/plugins/prod/graphs/inter/__init__.py +13 -0
  164. sierra/plugins/prod/graphs/inter/generate.py +83 -0
  165. sierra/plugins/prod/graphs/inter/heatmap.py +86 -0
  166. sierra/plugins/prod/graphs/inter/line.py +134 -0
  167. sierra/plugins/prod/graphs/intra/__init__.py +15 -0
  168. sierra/plugins/prod/graphs/intra/generate.py +202 -0
  169. sierra/plugins/prod/graphs/intra/heatmap.py +74 -0
  170. sierra/plugins/prod/graphs/intra/line.py +114 -0
  171. sierra/plugins/prod/graphs/plugin.py +103 -0
  172. sierra/plugins/prod/graphs/targets.py +63 -0
  173. sierra/plugins/prod/render/__init__.py +18 -0
  174. sierra/plugins/prod/render/cmdline.py +72 -0
  175. sierra/plugins/prod/render/plugin.py +282 -0
  176. sierra/plugins/storage/__init__.py +5 -0
  177. sierra/plugins/storage/arrow/__init__.py +18 -0
  178. sierra/plugins/storage/arrow/plugin.py +38 -0
  179. sierra/plugins/storage/csv/__init__.py +9 -0
  180. sierra/plugins/storage/csv/plugin.py +12 -5
  181. sierra/version.py +3 -2
  182. sierra_research-1.5.0.dist-info/METADATA +238 -0
  183. sierra_research-1.5.0.dist-info/RECORD +186 -0
  184. {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info}/WHEEL +1 -2
  185. sierra/core/experiment/xml.py +0 -454
  186. sierra/core/generators/controller_generator_parser.py +0 -34
  187. sierra/core/generators/exp_creator.py +0 -351
  188. sierra/core/generators/exp_generators.py +0 -142
  189. sierra/core/graphs/scatterplot2D.py +0 -109
  190. sierra/core/graphs/stacked_line_graph.py +0 -249
  191. sierra/core/graphs/stacked_surface_graph.py +0 -220
  192. sierra/core/graphs/summary_line_graph.py +0 -369
  193. sierra/core/hpc/cmdline.py +0 -142
  194. sierra/core/models/graphs.py +0 -87
  195. sierra/core/pipeline/stage2/exp_runner.py +0 -286
  196. sierra/core/pipeline/stage3/imagizer.py +0 -149
  197. sierra/core/pipeline/stage3/run_collator.py +0 -317
  198. sierra/core/pipeline/stage3/statistics_calculator.py +0 -478
  199. sierra/core/pipeline/stage4/graph_collator.py +0 -319
  200. sierra/core/pipeline/stage4/inter_exp_graph_generator.py +0 -240
  201. sierra/core/pipeline/stage4/intra_exp_graph_generator.py +0 -317
  202. sierra/core/pipeline/stage4/model_runner.py +0 -168
  203. sierra/core/pipeline/stage4/rendering.py +0 -283
  204. sierra/core/pipeline/stage4/yaml_config_loader.py +0 -103
  205. sierra/core/pipeline/stage5/inter_scenario_comparator.py +0 -328
  206. sierra/core/pipeline/stage5/intra_scenario_comparator.py +0 -989
  207. sierra/core/platform.py +0 -493
  208. sierra/core/plugin_manager.py +0 -369
  209. sierra/core/root_dirpath_generator.py +0 -241
  210. sierra/plugins/hpc/adhoc/plugin.py +0 -125
  211. sierra/plugins/hpc/local/plugin.py +0 -81
  212. sierra/plugins/hpc/pbs/__init__.py +0 -9
  213. sierra/plugins/hpc/pbs/plugin.py +0 -126
  214. sierra/plugins/hpc/slurm/__init__.py +0 -9
  215. sierra/plugins/hpc/slurm/plugin.py +0 -130
  216. sierra/plugins/platform/__init__.py +0 -9
  217. sierra/plugins/platform/argos/__init__.py +0 -9
  218. sierra/plugins/platform/argos/generators/platform_generators.py +0 -383
  219. sierra/plugins/platform/argos/plugin.py +0 -337
  220. sierra/plugins/platform/argos/variables/arena_shape.py +0 -145
  221. sierra/plugins/platform/argos/variables/cameras.py +0 -243
  222. sierra/plugins/platform/argos/variables/constant_density.py +0 -136
  223. sierra/plugins/platform/argos/variables/exp_setup.py +0 -113
  224. sierra/plugins/platform/argos/variables/population_constant_density.py +0 -175
  225. sierra/plugins/platform/argos/variables/population_size.py +0 -102
  226. sierra/plugins/platform/argos/variables/population_variable_density.py +0 -132
  227. sierra/plugins/platform/argos/variables/rendering.py +0 -104
  228. sierra/plugins/platform/ros1gazebo/__init__.py +0 -9
  229. sierra/plugins/platform/ros1gazebo/cmdline.py +0 -213
  230. sierra/plugins/platform/ros1gazebo/generators/platform_generators.py +0 -137
  231. sierra/plugins/platform/ros1gazebo/plugin.py +0 -335
  232. sierra/plugins/platform/ros1gazebo/variables/__init__.py +0 -10
  233. sierra/plugins/platform/ros1gazebo/variables/population_size.py +0 -204
  234. sierra/plugins/platform/ros1robot/__init__.py +0 -9
  235. sierra/plugins/platform/ros1robot/cmdline.py +0 -175
  236. sierra/plugins/platform/ros1robot/generators/platform_generators.py +0 -112
  237. sierra/plugins/platform/ros1robot/plugin.py +0 -373
  238. sierra/plugins/platform/ros1robot/variables/__init__.py +0 -10
  239. sierra/plugins/platform/ros1robot/variables/population_size.py +0 -146
  240. sierra/plugins/robot/__init__.py +0 -9
  241. sierra/plugins/robot/turtlebot3/__init__.py +0 -9
  242. sierra/plugins/robot/turtlebot3/plugin.py +0 -194
  243. sierra_research-1.3.6.data/data/share/man/man1/sierra-cli.1 +0 -2349
  244. sierra_research-1.3.6.data/data/share/man/man7/sierra-examples.7 +0 -488
  245. sierra_research-1.3.6.data/data/share/man/man7/sierra-exec-envs.7 +0 -331
  246. sierra_research-1.3.6.data/data/share/man/man7/sierra-glossary.7 +0 -285
  247. sierra_research-1.3.6.data/data/share/man/man7/sierra-platforms.7 +0 -358
  248. sierra_research-1.3.6.data/data/share/man/man7/sierra-usage.7 +0 -725
  249. sierra_research-1.3.6.data/data/share/man/man7/sierra.7 +0 -78
  250. sierra_research-1.3.6.dist-info/METADATA +0 -500
  251. sierra_research-1.3.6.dist-info/RECORD +0 -133
  252. sierra_research-1.3.6.dist-info/top_level.txt +0 -1
  253. {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info}/entry_points.txt +0 -0
  254. {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info/licenses}/LICENSE +0 -0
sierra/core/execenv.py ADDED
@@ -0,0 +1,380 @@
1
+ #
2
+ # Copyright 2024 John Harwell, All rights reserved.
3
+ #
4
+ # SPDX-License Identifier: MIT
5
+ #
6
+ """Common functionality for ``--execenv`` plugins to use."""
7
+
8
+ # Core packages
9
+ import typing as tp
10
+ import re
11
+ import pwd
12
+ import os
13
+ import subprocess
14
+ import shutil
15
+ import logging
16
+ import argparse
17
+
18
+ # 3rd party packages
19
+ import implements
20
+
21
+ # Project packages
22
+ from sierra.core import utils, types, config
23
+ from sierra.core.trampoline import cmdline_parser # noqa: F401
24
+ from sierra.core.experiment import bindings
25
+ import sierra.core.plugin as pm
26
+
27
+ _logger = logging.getLogger(__name__)
28
+
29
+
30
+ @implements.implements(bindings.IExpShellCmdsGenerator)
31
+ class ExpShellCmdsGenerator:
32
+ """Dispatcher for shell cmd generation for an :term:`Experiment`.
33
+
34
+ Dispatches generation to the selected execution environment. Called during
35
+ stage 2 to run shell commands immediately before running a given
36
+ :term:`Experiment`, to run shell commands to actually run the experiment,
37
+ and to run shell commands immediately after the experiment finishes.
38
+ """
39
+
40
+ def __init__(self, cmdopts: types.Cmdopts, exp_num: int) -> None:
41
+ self.cmdopts = cmdopts
42
+
43
+ module = pm.pipeline.get_plugin_module(self.cmdopts["execenv"])
44
+ if hasattr(module, "ExpShellCmdsGenerator"):
45
+ self.env = module.ExpShellCmdsGenerator(self.cmdopts, exp_num)
46
+ else:
47
+ _logger.debug(
48
+ (
49
+ "Skipping generating experiment shell commands "
50
+ "for --execenv=%s: does not define ExpShellCmdsGenerator"
51
+ ),
52
+ self.cmdopts["execenv"],
53
+ )
54
+
55
+ self.env = None
56
+
57
+ def pre_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
58
+ cmds = []
59
+
60
+ if self.env:
61
+ cmds.extend(self.env.pre_exp_cmds())
62
+
63
+ return cmds
64
+
65
+ def exec_exp_cmds(self, exec_opts: types.StrDict) -> tp.List[types.ShellCmdSpec]:
66
+ cmds = []
67
+
68
+ if self.env:
69
+ cmds.extend(self.env.exec_exp_cmds(exec_opts))
70
+
71
+ return cmds
72
+
73
+ def post_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
74
+ cmds = []
75
+
76
+ if self.env:
77
+ cmds.extend(self.env.post_exp_cmds())
78
+
79
+ return cmds
80
+
81
+
82
+ @implements.implements(bindings.IBatchShellCmdsGenerator)
83
+ class BatchShellCmdsGenerator:
84
+ """Dispatcher for shell cmd generation for a :term:`Batch Experiment`.
85
+
86
+ Dispatches generation to the selected execution environment. Called during
87
+ stage 2 to run shell commands immediately before running a given
88
+ :term:`Batch Experiment`, to run shell commands to actually run the
89
+ experiment, and to run shell commands immediately after the whole experiment
90
+ finishes.
91
+ """
92
+
93
+ def __init__(self, cmdopts: types.Cmdopts) -> None:
94
+ self.cmdopts = cmdopts
95
+
96
+ module = pm.pipeline.get_plugin_module(self.cmdopts["execenv"])
97
+ if hasattr(module, "BatchShellCmdsGenerator"):
98
+ self.env = module.BatchShellCmdsGenerator(self.cmdopts)
99
+ else:
100
+ _logger.debug(
101
+ (
102
+ "Skipping generating batch experiment shell commands "
103
+ "for --execenv=%s: does not define BatchShellCmdsGenerator"
104
+ ),
105
+ self.cmdopts["execenv"],
106
+ )
107
+
108
+ self.env = None
109
+
110
+ def pre_batch_cmds(self) -> tp.List[types.ShellCmdSpec]:
111
+ cmds = []
112
+
113
+ if self.env:
114
+ cmds.extend(self.env.pre_batch_cmds())
115
+
116
+ return cmds
117
+
118
+ def exec_batch_cmds(self, exec_opts: types.StrDict) -> tp.List[types.ShellCmdSpec]:
119
+ cmds = []
120
+
121
+ if self.env:
122
+ cmds.extend(self.env.exec_batch_cmds(exec_opts))
123
+
124
+ return cmds
125
+
126
+ def post_batch_cmds(self) -> tp.List[types.ShellCmdSpec]:
127
+ cmds = []
128
+
129
+ if self.env:
130
+ cmds.extend(self.env.post_batch_cmds())
131
+
132
+ return cmds
133
+
134
+
135
+ def cmdline_postparse_configure(
136
+ execenv: str, args: argparse.Namespace
137
+ ) -> argparse.Namespace:
138
+ """Dispatcher for configuring the cmdopts dictionary.
139
+
140
+ Dispatches configuring to the selected ``--execenv``. Called before the
141
+ pipeline starts to add modify existing cmdline arguments after initial
142
+ parsing.
143
+
144
+ ``execenv`` is needed as an arguments as it is not present in ``args``; it
145
+ is a "bootstrap" cmdline arg needed to be parsed first to build the parser
146
+ for the set of cmdline arguments accepted.
147
+ """
148
+ logger = logging.getLogger(__name__)
149
+
150
+ # Configure for selected execution enivornment first, to check for
151
+ # low-level details.
152
+ module = pm.pipeline.get_plugin_module(execenv)
153
+
154
+ if hasattr(module, "cmdline_postparse_configure"):
155
+ args = module.cmdline_postparse_configure(args)
156
+ else:
157
+ logger.debug(
158
+ (
159
+ "Skipping configuring cmdline from --execenv=%s: "
160
+ "does not define cmdline_postparse_configure()"
161
+ ),
162
+ execenv,
163
+ )
164
+
165
+ return args
166
+
167
+
168
+ def execenv_check(cmdopts: types.Cmdopts) -> None:
169
+ """Dispatcher for verifying execution environments in stage 2.
170
+
171
+ This is required because what is needed to create experiments in stage 1 for
172
+ an execution environment is not necessarily the same as what is needed (in
173
+ terms of envvars, daemons, etc.) when running them.
174
+ """
175
+ module = pm.pipeline.get_plugin_module(cmdopts["execenv"])
176
+ if hasattr(module, "execenv_check"):
177
+ module.execenv_check(cmdopts)
178
+ else:
179
+ _logger.debug(
180
+ (
181
+ "Skipping execution environment check for "
182
+ "--execenv=%s: does not define execenv_check()"
183
+ ),
184
+ cmdopts["execenv"],
185
+ )
186
+
187
+
188
+ def parse_nodefile(nodefile: str) -> tp.List[types.ParsedNodefileSpec]:
189
+ """
190
+ Parse a text file containing a list of computational resources to use.
191
+
192
+ Assumed to be GNU-parallel style.
193
+ """
194
+ ret = []
195
+
196
+ with utils.utf8open(nodefile, "r") as f:
197
+ lines = f.readlines()
198
+
199
+ for line in lines:
200
+ if parsed := _parse_nodefile_line(line):
201
+ ret.append(parsed)
202
+
203
+ return ret
204
+
205
+
206
+ def _parse_nodefile_line(line: str) -> tp.Optional[types.ParsedNodefileSpec]:
207
+ # Line starts with a comment--no parsing needed
208
+ comment_re = r"^#"
209
+ if res := re.search(comment_re, line):
210
+ return None
211
+
212
+ cores_re = r"^[0-9]+/"
213
+ if res := re.search(cores_re, line):
214
+ cores = int(line.split("/")[0])
215
+ ssh = line.split("/")[1]
216
+ else:
217
+ cores = 1
218
+ ssh = line
219
+
220
+ identifier_re = r"[a-zA-Z0-9_.:]+"
221
+ port_re = r"ssh -p\s*([0-9]+)"
222
+ username_at_host_re = f"({identifier_re})+@({identifier_re})"
223
+ port_and_username_at_host_re = port_re + r"\*s" + username_at_host_re
224
+ port_and_hostname_re = port_re + rf"\s+({identifier_re})"
225
+
226
+ if res := re.search(port_and_username_at_host_re, ssh):
227
+ # They specified the port AND 'username@host'
228
+ port = int(res.group(1))
229
+ login = res.group(2)
230
+ hostname = res.group(3)
231
+ elif res := re.search(port_and_hostname_re, ssh):
232
+ # They only specified the port and hostname
233
+ port = int(res.group(1))
234
+ hostname = res.group(2)
235
+ login = pwd.getpwuid(os.getuid())[0]
236
+ elif res := re.search(username_at_host_re, ssh):
237
+ # They only specified 'username@host'
238
+ port = 22
239
+ login = res.group(1)
240
+ hostname = res.group(2)
241
+ elif res := re.search(identifier_re, ssh):
242
+ # They only specified the hostname
243
+ port = 22
244
+ login = pwd.getpwuid(os.getuid())[0]
245
+ hostname = res.group(0)
246
+ else:
247
+ raise ValueError(f"Bad ssh/hostname spec {ssh}")
248
+
249
+ return types.ParsedNodefileSpec(
250
+ hostname=hostname, n_cores=cores, login=login, port=port
251
+ )
252
+
253
+
254
+ def check_connectivity(
255
+ cmdopts: types.Cmdopts, login: str, hostname: str, port: int, host_type: str
256
+ ) -> None:
257
+ """
258
+ Check if passwordless connection to the specified host+login works.
259
+ """
260
+ hostname = hostname.split(":")[0]
261
+ _logger.info("Checking connectivity to %s", hostname)
262
+ ssh_diag = f"{host_type},port={port} via {login}@{hostname}"
263
+ nc_diag = f"{host_type},port={port} via {hostname}"
264
+
265
+ res = None
266
+ if cmdopts["online_check_method"] == "ping+ssh":
267
+ try:
268
+ _logger.debug("Attempt to ping %s, type=%s", hostname, host_type)
269
+ timeout = config.kEngine["ping_timeout"]
270
+ res = subprocess.run(
271
+ f"ping -c 3 -W {timeout} {hostname}",
272
+ shell=True,
273
+ check=True,
274
+ stdout=subprocess.PIPE,
275
+ stderr=subprocess.PIPE,
276
+ )
277
+ except subprocess.CalledProcessError:
278
+ _logger.fatal("Unable to ping %s, type=%s", hostname, host_type)
279
+ _logger.fatal(
280
+ "stdout=%s, stderr=%s",
281
+ res.stdout.decode("utf-8") if res else None,
282
+ res.stderr.decode("utf-8") if res else None,
283
+ )
284
+ raise
285
+ _logger.debug("%s is alive, type=%s", hostname, host_type)
286
+ elif cmdopts["online_check_method"] == "nc+ssh":
287
+ try:
288
+ _logger.debug("Check for ssh tunnel to %s", nc_diag)
289
+ timeout = config.kEngine["ping_timeout"]
290
+ res = subprocess.run(
291
+ f"nc -z {hostname} {port}",
292
+ shell=True,
293
+ check=True,
294
+ stdout=subprocess.PIPE,
295
+ stderr=subprocess.PIPE,
296
+ )
297
+ except subprocess.CalledProcessError:
298
+ _logger.fatal("No ssh tunnel to %s", nc_diag)
299
+ _logger.fatal(
300
+ "stdout=%s, stderr=%s",
301
+ res.stdout.decode("utf-8") if res else None,
302
+ res.stderr.decode("utf-8") if res else None,
303
+ )
304
+ raise
305
+ _logger.debug("ssh tunnel to %s alive", nc_diag)
306
+
307
+ try:
308
+
309
+ _logger.debug("Verify ssh to %s", ssh_diag)
310
+ res2 = subprocess.run(
311
+ (
312
+ f"ssh -p{port} "
313
+ "-o PasswordAuthentication=no "
314
+ "-o StrictHostKeyChecking=no "
315
+ "-o BatchMode=yes "
316
+ f"{login}@{hostname} exit"
317
+ ),
318
+ shell=True,
319
+ check=True,
320
+ stdout=subprocess.PIPE,
321
+ stderr=subprocess.PIPE,
322
+ )
323
+ except subprocess.CalledProcessError:
324
+ _logger.fatal("Unable to connect to %s", ssh_diag)
325
+ _logger.fatal(
326
+ "stdout=%s, stderr=%s",
327
+ res2.stdout.decode("utf-8") if res2 else None,
328
+ res2.stderr.decode("utf-8") if res2 else None,
329
+ )
330
+ raise
331
+ _logger.info("%s@%s online", host_type, hostname)
332
+
333
+
334
+ def check_for_simulator(
335
+ engine: str, execenv: str, name: str
336
+ ) -> subprocess.CompletedProcess[bytes]:
337
+ """
338
+ Check if the specified executable name exists/is findable.
339
+
340
+ Returns the version string for the executable. Requires the executable
341
+ respect/accept ``-v``.
342
+
343
+ """
344
+ shellname = get_executable_arch_aware(name)
345
+
346
+ version_cmd = f"{shellname} -v"
347
+ _logger.debug("Check version for '%s' via '%s'", shellname, version_cmd)
348
+
349
+ if shutil.which(shellname):
350
+ res = subprocess.run(
351
+ version_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
352
+ )
353
+ return res
354
+ else:
355
+ raise RuntimeError(
356
+ f"Bad --execenv '{execenv}' for engine '{engine}': cannot find '{name}'"
357
+ )
358
+
359
+
360
+ def get_executable_arch_aware(base: str) -> str:
361
+ """
362
+ Get the executable name in an :envvar:`SIERRA_ARCH`-aware way.
363
+
364
+ Returns <base>-<arch> if the envvar is set, and <base> otherwise.
365
+ """
366
+ if "SIERRA_ARCH" in os.environ:
367
+ arch = os.environ["SIERRA_ARCH"]
368
+ return f"{base}-{arch}"
369
+ else:
370
+ return base
371
+
372
+
373
+ __all__ = [
374
+ "ExpShellCmdsGenerator",
375
+ "cmdline_postparse_configure",
376
+ "parse_nodefile",
377
+ "check_connectivity",
378
+ "check_for_simulator",
379
+ "get_executable_arch_aware",
380
+ ]
sierra/core/expdef.py ADDED
@@ -0,0 +1,11 @@
1
+ # Copyright 2024 John Harwell, All rights reserved.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """Trampoline bindings for the various ``--expdef`` plugins that come with SIERRA."""
5
+
6
+ # Core packages
7
+
8
+ # 3rd party packages
9
+
10
+ # Project packages
11
+ from sierra.core.trampoline import cmdline_parser # noqa: F401
@@ -1,6 +1,7 @@
1
1
  # Copyright 2021 John Harwell, All rights reserved.
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
+ """Container module for things related to experiments."""
4
5
 
5
6
  # Core packages
6
7