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
@@ -0,0 +1,393 @@
1
+ # Copyright 2021 John Harwell, All rights reserved.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """
5
+ The plugin for the :term:`ARGoS` :term:`Engine`.
6
+ """
7
+ # Core packages
8
+ import argparse
9
+ import os
10
+ import random
11
+ import typing as tp
12
+ import re
13
+ import shutil
14
+ import logging
15
+ import sys
16
+ import pathlib
17
+ import psutil
18
+
19
+ # 3rd party packages
20
+ import implements
21
+ import packaging.version
22
+
23
+ # Project packages
24
+ from sierra.core import config, types, utils, batchroot, execenv
25
+ from sierra.core.experiment import bindings, definition
26
+ import sierra.core.variables.batch_criteria as bc
27
+
28
+ _logger = logging.getLogger("engine.argos")
29
+
30
+
31
+ @implements.implements(bindings.IExpRunShellCmdsGenerator)
32
+ class ExpRunShellCmdsGenerator:
33
+ def __init__(
34
+ self,
35
+ cmdopts: types.Cmdopts,
36
+ criteria: bc.XVarBatchCriteria,
37
+ n_agents: int,
38
+ exp_num: int,
39
+ ) -> None:
40
+ self.cmdopts = cmdopts
41
+ self.display_port = -1
42
+
43
+ def pre_run_cmds(
44
+ self, host: str, input_fpath: pathlib.Path, run_num: int
45
+ ) -> tp.List[types.ShellCmdSpec]:
46
+ # When running ARGoS under Xvfb in order to headlessly render frames, we
47
+ # need to start a per-instance Xvfb server that we tell ARGoS to use via
48
+ # the DISPLAY environment variable, which will then be killed when the
49
+ # shell GNU parallel spawns to run each line in the commands file exits.
50
+
51
+ if host == "slave":
52
+ if self.cmdopts["engine_vc"]:
53
+ self.display_port = random.randint(0, 1000000)
54
+ cmd1 = f"Xvfb :{self.display_port} -screen 0, 1600x1200x24 &"
55
+ cmd2 = f"export DISPLAY=:{self.display_port};"
56
+ spec1 = types.ShellCmdSpec(cmd=cmd1, shell=True, wait=True)
57
+ spec2 = types.ShellCmdSpec(cmd=cmd2, shell=True, wait=True, env=True)
58
+ return [spec1, spec2]
59
+
60
+ return []
61
+
62
+ def exec_run_cmds(
63
+ self, host: str, input_fpath: pathlib.Path, run_num: int
64
+ ) -> tp.List[types.ShellCmdSpec]:
65
+ shellname = execenv.get_executable_arch_aware(config.kARGoS["launch_cmd"])
66
+ cmd = "{0} -c {1}{2}".format(
67
+ shellname, str(input_fpath), config.kARGoS["launch_file_ext"]
68
+ )
69
+
70
+ # ARGoS is pretty good about not printing stuff if we pass these
71
+ # arguments. We don't want to pass > /dev/null so that we get the
72
+ # text of any exceptions that cause ARGoS to crash.
73
+ if self.cmdopts["exec_devnull"]:
74
+ cmd += " --log-file /dev/null --logerr-file /dev/null"
75
+
76
+ cmd += ";"
77
+
78
+ return [types.ShellCmdSpec(cmd=cmd, shell=True, wait=True)]
79
+
80
+ def post_run_cmds(
81
+ self, host: str, run_output_root: pathlib.Path
82
+ ) -> tp.List[types.ShellCmdSpec]:
83
+ return []
84
+
85
+
86
+ @implements.implements(bindings.IExpShellCmdsGenerator)
87
+ class ExpShellCmdsGenerator:
88
+ def __init__(self, cmdopts: types.Cmdopts, exp_num: int) -> None:
89
+ self.cmdopts = cmdopts
90
+
91
+ def pre_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
92
+ return []
93
+
94
+ def exec_exp_cmds(self, exec_opts: types.StrDict) -> tp.List[types.ShellCmdSpec]:
95
+ return []
96
+
97
+ def post_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
98
+ # Cleanup Xvfb processes which were started in the background. If SIERRA
99
+ # was run with --exec-resume, then there may be no Xvfb processes to
100
+ # kill, so we can't (in general) check the return code.
101
+ if self.cmdopts["engine_vc"]:
102
+ return [types.ShellCmdSpec(cmd="killall Xvfb", shell=True, wait=True)]
103
+
104
+ return []
105
+
106
+
107
+ @implements.implements(bindings.IExpConfigurer)
108
+ class ExpConfigurer:
109
+ def __init__(self, cmdopts: types.Cmdopts) -> None:
110
+ self.cmdopts = cmdopts
111
+
112
+ def for_exp_run(
113
+ self, exp_input_root: pathlib.Path, run_output_root: pathlib.Path
114
+ ) -> None:
115
+ if self.cmdopts["engine_vc"]:
116
+ argos = config.kRendering["argos"]
117
+ frames_fpath = run_output_root / argos["frames_leaf"]
118
+ utils.dir_create_checked(frames_fpath, exist_ok=True)
119
+
120
+ def for_exp(self, exp_input_root: pathlib.Path) -> None:
121
+ pass
122
+
123
+ def parallelism_paradigm(self) -> str:
124
+ return "per-exp"
125
+
126
+
127
+ def execenv_check(cmdopts: types.Cmdopts) -> None:
128
+ """
129
+ Perform stage2 execution environment checks for the :term:`ARgoS` engine.
130
+
131
+ Checks:
132
+
133
+ - ARGoS can be found
134
+
135
+ - ARGoS version supported
136
+
137
+ - :envvar:`ARGOS_PLUGIN_PATH` is set
138
+
139
+ - for :program:`Xvfb` if ``--engine-vc`` was passed.
140
+ """
141
+ keys = ["ARGOS_PLUGIN_PATH"]
142
+
143
+ for k in keys:
144
+ assert k in os.environ, f"Non-ARGoS environment detected: '{k}' not found"
145
+
146
+ # Check we can find ARGoS
147
+ proc = execenv.check_for_simulator(
148
+ cmdopts["engine"], cmdopts["execenv"], config.kARGoS["launch_cmd"]
149
+ )
150
+
151
+ # Check ARGoS version
152
+ stdout = proc.stdout.decode("utf-8")
153
+ stderr = proc.stderr.decode("utf-8")
154
+ res = re.search(r"[0-9]+.[0-9]+.[0-9]+-beta[0-9]+", stdout)
155
+ assert (
156
+ res is not None
157
+ ), f"ARGOS_VERSION not in stdout: stdout='{stdout}',stderr='{stderr}'"
158
+
159
+ _logger.trace("Parsed ARGOS_VERSION: %s", res.group(0)) # type: ignore
160
+
161
+ version = packaging.version.parse(res.group(0))
162
+ min_version = config.kARGoS["min_version"]
163
+
164
+ assert (
165
+ version >= min_version
166
+ ), f"ARGoS version {version} < min required {min_version}"
167
+
168
+ if cmdopts["engine_vc"]:
169
+ assert shutil.which("Xvfb") is not None, "Xvfb not found"
170
+
171
+
172
+ def cmdline_postparse_configure(
173
+ env: str, args: argparse.Namespace
174
+ ) -> argparse.Namespace:
175
+ """
176
+ Configure cmdline args after parsing for the :term:`ARGoS` engine.
177
+
178
+ This sets arguments appropriately depending on what HPC environment is
179
+ selected with ``--execenv``.
180
+
181
+ - hpc.local
182
+
183
+ - hpc.adhoc
184
+
185
+ - hpc.slurm
186
+
187
+ - hpc.pbs
188
+
189
+ """
190
+
191
+ # No configuration needed for stages 3-5
192
+ if not any(stage in args.pipeline for stage in [1, 2]):
193
+ return args
194
+
195
+ if env == "hpc.local":
196
+ return _configure_hpc_local(args)
197
+ elif env == "hpc.adhoc":
198
+ return _configure_hpc_adhoc(args)
199
+ elif env == "hpc.slurm":
200
+ return _configure_hpc_slurm(args)
201
+ elif env == "hpc.pbs":
202
+ return _configure_hpc_pbs(args)
203
+ else:
204
+ _logger.warning("Execution environment %s untested", env)
205
+ return args
206
+
207
+
208
+ def _configure_hpc_pbs(args: argparse.Namespace) -> argparse.Namespace:
209
+ _logger.debug("Configuring ARGoS for PBS execution")
210
+ # For HPC, we want to use the the maximum # of simultaneous jobs per
211
+ # node such that there is no thread oversubscription. We also always
212
+ # want to allocate each physics engine its own thread for maximum
213
+ # performance, per the original ARGoS paper.
214
+ #
215
+ # However, PBS does not have an environment variable for # jobs/node, so
216
+ # we have to rely on the user to set this appropriately.
217
+ args.physics_n_engines = int(
218
+ float(os.environ["PBS_NUM_PPN"]) / args.exec_jobs_per_node
219
+ )
220
+
221
+ _logger.debug(
222
+ "Allocated %s physics engines/run, %s parallel runs/node",
223
+ args.physics_n_engines,
224
+ args.exec_jobs_per_node,
225
+ )
226
+
227
+ return args
228
+
229
+
230
+ def _configure_hpc_slurm(args: argparse.Namespace) -> argparse.Namespace:
231
+ _logger.debug("Configuring ARGoS for SLURM execution")
232
+ # For HPC, we want to use the the maximum # of simultaneous jobs per
233
+ # node such that there is no thread oversubscription. We also always
234
+ # want to allocate each physics engine its own thread for maximum
235
+ # performance, per the original ARGoS paper.
236
+ #
237
+ # We rely on the user to request their job intelligently so that
238
+ # SLURM_TASKS_PER_NODE is appropriate.
239
+ if args.exec_jobs_per_node is None:
240
+ res = re.search(r"^[^\(]+", os.environ["SLURM_TASKS_PER_NODE"])
241
+ assert (
242
+ res is not None
243
+ ), "Unexpected format in SLURM_TASKS_PER_NODE: '{0}'".format(
244
+ os.environ["SLURM_TASKS_PER_NODE"]
245
+ )
246
+ args.exec_jobs_per_node = int(res.group(0))
247
+
248
+ args.physics_n_engines = int(os.environ["SLURM_CPUS_PER_TASK"])
249
+
250
+ _logger.debug(
251
+ "Allocated %s physics engines/run, %s parallel runs/node",
252
+ args.physics_n_engines,
253
+ args.exec_jobs_per_node,
254
+ )
255
+
256
+ return args
257
+
258
+
259
+ def _configure_hpc_local(args: argparse.Namespace) -> argparse.Namespace:
260
+ _logger.debug("Configuring ARGoS for LOCAL execution")
261
+ if any(stage in args.pipeline for stage in [1, 2]):
262
+ assert (
263
+ args.physics_n_engines is not None
264
+ ), "--physics-n-engines is required for --execenv=hpc.local when running stage{1,2}"
265
+
266
+ ppn_per_run_req = args.physics_n_engines
267
+
268
+ if args.exec_jobs_per_node is None:
269
+ # Every physics engine gets at least 1 core
270
+ parallel_jobs = int(psutil.cpu_count() / float(ppn_per_run_req))
271
+ if parallel_jobs == 0:
272
+ _logger.warning(
273
+ (
274
+ "Local machine has %s logical cores, but "
275
+ "%s physics engines/run requested; "
276
+ "allocating anyway"
277
+ ),
278
+ psutil.cpu_count(),
279
+ ppn_per_run_req,
280
+ )
281
+ parallel_jobs = 1
282
+
283
+ # Make sure we don't oversubscribe cores--each simulation needs at
284
+ # least 1 core.
285
+ args.exec_jobs_per_node = min(args.n_runs, parallel_jobs)
286
+
287
+ _logger.debug(
288
+ "Allocated %s physics engines/run, %s parallel runs/node",
289
+ args.physics_n_engines,
290
+ args.exec_jobs_per_node,
291
+ )
292
+
293
+ return args
294
+
295
+
296
+ def _configure_hpc_adhoc(args: argparse.Namespace) -> argparse.Namespace:
297
+ _logger.debug("Configuring ARGoS for ADHOC execution")
298
+
299
+ nodes = execenv.parse_nodefile(args.nodefile)
300
+ ppn = sys.maxsize
301
+ for node in nodes:
302
+ ppn = min(ppn, node.n_cores)
303
+
304
+ # For HPC, we want to use the the maximum # of simultaneous jobs per
305
+ # node such that there is no thread oversubscription. We also always
306
+ # want to allocate each physics engine its own thread for maximum
307
+ # performance, per the original ARGoS paper.
308
+ if args.exec_jobs_per_node is None:
309
+ args.exec_jobs_per_node = int(float(args.n_runs) / len(nodes))
310
+
311
+ args.physics_n_engines = int(ppn / args.exec_jobs_per_node)
312
+
313
+ _logger.debug(
314
+ "Allocated %s physics engines/run, %s parallel runs/node",
315
+ args.physics_n_engines,
316
+ args.exec_jobs_per_node,
317
+ )
318
+ return args
319
+
320
+
321
+ def population_size_from_pickle(
322
+ chgs: tp.Union[definition.AttrChangeSet, definition.ElementAddList],
323
+ main_config: types.YAMLDict,
324
+ cmdopts: types.Cmdopts,
325
+ ) -> int:
326
+ for path, attr, value in chgs:
327
+ if path == ".//arena/distribute/entity" and attr == "quantity":
328
+ return int(value)
329
+
330
+ return -1
331
+
332
+
333
+ def arena_dims_from_criteria(
334
+ criteria: bc.XVarBatchCriteria,
335
+ ) -> tp.List[utils.ArenaExtent]:
336
+ dims = []
337
+ for exp in criteria.gen_attr_changelist():
338
+ for c in exp:
339
+ if c.path == ".//arena" and c.attr == "size":
340
+ d = utils.Vector3D.from_str(c.value)
341
+ dims.append(utils.ArenaExtent(d))
342
+
343
+ assert len(dims) > 0, "Scenario dimensions not contained in batch criteria"
344
+
345
+ return dims
346
+
347
+
348
+ def robot_type_from_def(exp_def: definition.BaseExpDef) -> tp.Optional[str]:
349
+ """
350
+ Get the entity type of the robots managed by ARGoS.
351
+
352
+ .. NOTE:: Assumes homgeneous systems.
353
+ """
354
+ for robot in config.kARGoS["spatial_hash2D"]:
355
+ if exp_def.has_element(f".//arena/distribute/entity/{robot}"):
356
+ return robot
357
+
358
+ return None
359
+
360
+
361
+ def population_size_from_def(
362
+ exp_def: definition.BaseExpDef, main_config: types.YAMLDict, cmdopts: types.Cmdopts
363
+ ) -> int:
364
+ return population_size_from_pickle(exp_def.attr_chgs, main_config, cmdopts)
365
+
366
+
367
+ def pre_exp_diagnostics(
368
+ cmdopts: types.Cmdopts, pathset: batchroot.PathSet, logger: logging.Logger
369
+ ) -> None:
370
+ s = "batch_exp_root='%s',runs/exp=%s,threads/job=%s,n_jobs=%s"
371
+ logger.info(
372
+ s,
373
+ pathset.root,
374
+ cmdopts["n_runs"],
375
+ cmdopts["physics_n_threads"],
376
+ cmdopts["exec_jobs_per_node"],
377
+ )
378
+
379
+
380
+ def expsetup_from_def(exp_def: definition.BaseExpDef) -> types.SimpleDict:
381
+ ret = {} # type: types.SimpleDict
382
+
383
+ for path, attr, value in exp_def:
384
+ if "experiment" in path:
385
+ if "length" in attr:
386
+ ret["duration"] = int(value)
387
+ if "ticks_per_second" in attr:
388
+ ret["n_ticks_per_sec"] = int(value)
389
+
390
+ if any(k not in ret for k in ["duration", "n_ticks_per_sec"]):
391
+ raise RuntimeError("Malformed experiment definition")
392
+
393
+ return ret
@@ -1,6 +1,11 @@
1
1
  # Copyright 2022 John Harwell, All rights reserved.
2
2
  #
3
3
  # SPDX-License-Identifier: MIT
4
+ """
5
+ Variables module for the :term:`ARGoS` engine.
6
+
7
+ See :ref:`plugins/engine/argos`.
8
+ """
4
9
 
5
10
  # Core packages
6
11
 
@@ -0,0 +1,183 @@
1
+ # Copyright 2018 John Harwell, All rights reserved.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+ """Functionality for modifying/setting the size of the arena in ARGoS."""
5
+
6
+ # Core packages
7
+ import typing as tp
8
+
9
+ # 3rd party packages
10
+ import implements
11
+
12
+ # Project packages
13
+ from sierra.core.variables.base_variable import IBaseVariable
14
+ from sierra.core.utils import ArenaExtent
15
+ from sierra.core.experiment import definition
16
+
17
+ kWALL_WIDTH = 0.4
18
+
19
+
20
+ @implements.implements(IBaseVariable)
21
+ class ArenaShape:
22
+ """Maps a list of desired arena dimensions sets of XML changes.
23
+
24
+ This class is a base class which should (almost) never be used on its
25
+ own. Instead, derived classes defined in this file should be used instead.
26
+
27
+ Attributes:
28
+ extents: List of arena extents.
29
+
30
+ """
31
+
32
+ def __init__(self, extents: tp.List[ArenaExtent]) -> None:
33
+ self.extents = extents
34
+ self.attr_changes = [] # type: tp.List[definition.AttrChangeSet]
35
+
36
+ def gen_attr_changelist(self) -> tp.List[definition.AttrChangeSet]:
37
+ """Generate changes necessary setup ARGoS with the specified arena sizes."""
38
+ if not self.attr_changes:
39
+ for extent in self.extents:
40
+ self.attr_changes.append(self._gen_chgs_for_extent(extent))
41
+
42
+ return self.attr_changes
43
+
44
+ def _gen_chgs_for_extent(self, extent: ArenaExtent) -> definition.AttrChangeSet:
45
+
46
+ xsize = extent.xsize()
47
+ ysize = extent.ysize()
48
+ zsize = extent.zsize()
49
+
50
+ chgs = definition.AttrChangeSet(
51
+ definition.AttrChange(".//arena", "size", f"{xsize},{ysize},{zsize}"),
52
+ definition.AttrChange(
53
+ ".//arena",
54
+ "center",
55
+ "{0:.9f},{1:.9f},{2}".format(xsize / 2.0, ysize / 2.0, zsize / 2.0),
56
+ ),
57
+ )
58
+
59
+ # We restrict the places robots can spawn within the arena as follows:
60
+ #
61
+ # - Subtract width of the walls so that robots do not spawn inside walls
62
+ # (which ARGoS seems to allow?).
63
+ #
64
+ # - Subtract a little bit more so robots don't get into weird states by
65
+ # being near arena boundaries on the first timestep.
66
+ #
67
+ # - All robots start on the ground with Z=0.
68
+ chgs.add(
69
+ definition.AttrChange(
70
+ ".//arena/distribute/position",
71
+ "max",
72
+ "{0:.9f}, {1:.9f}, 0".format(
73
+ xsize - 2.0 * kWALL_WIDTH * 1.1, ysize - 2.0 * kWALL_WIDTH * 1.1
74
+ ),
75
+ )
76
+ )
77
+ chgs.add(
78
+ definition.AttrChange(
79
+ ".//arena/distribute/position",
80
+ "min",
81
+ "{0:.9f}, {1:.9f}, 0".format(
82
+ 2.0 * kWALL_WIDTH * 1.1, 2.0 * kWALL_WIDTH * 1.1
83
+ ),
84
+ )
85
+ )
86
+
87
+ chgs.add(
88
+ definition.AttrChange(
89
+ ".//arena/*[@id='wall_north']",
90
+ "size",
91
+ "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH),
92
+ )
93
+ )
94
+
95
+ chgs.add(
96
+ definition.AttrChange(
97
+ ".//arena/*[@id='wall_north']/body",
98
+ "position",
99
+ "{0:.9f}, {1:.9f}, 0".format(xsize / 2.0, ysize),
100
+ )
101
+ )
102
+ chgs.add(
103
+ definition.AttrChange(
104
+ ".//arena/*[@id='wall_south']",
105
+ "size",
106
+ "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH),
107
+ )
108
+ )
109
+
110
+ chgs.add(
111
+ definition.AttrChange(
112
+ ".//arena/*[@id='wall_north']/body",
113
+ "position",
114
+ "{0:.9f}, {1:.9f}, 0".format(xsize / 2.0, ysize),
115
+ )
116
+ )
117
+ chgs.add(
118
+ definition.AttrChange(
119
+ ".//arena/*[@id='wall_south']",
120
+ "size",
121
+ "{0:.9f}, {1:.9f}, 0.5".format(xsize, kWALL_WIDTH),
122
+ )
123
+ )
124
+ chgs.add(
125
+ definition.AttrChange(
126
+ ".//arena/*[@id='wall_south']/body",
127
+ "position",
128
+ "{0:.9f}, 0, 0 ".format(xsize / 2.0),
129
+ )
130
+ )
131
+
132
+ # East wall needs to have its X coordinate offset by the width of the
133
+ # wall / 2 in order to be centered on the boundary for the arena. This
134
+ # is necessary to ensure that the maximum X coordinate that robots can
135
+ # access is LESS than the upper boundary of physics engines incident
136
+ # along the east wall.
137
+ #
138
+ # I think this is a bug in ARGoS.
139
+ chgs.add(
140
+ definition.AttrChange(
141
+ ".//arena/*[@id='wall_east']",
142
+ "size",
143
+ "{0:.9f}, {1:.9f}, 0.5".format(kWALL_WIDTH, ysize + kWALL_WIDTH),
144
+ )
145
+ )
146
+ chgs.add(
147
+ definition.AttrChange(
148
+ ".//arena/*[@id='wall_east']/body",
149
+ "position",
150
+ "{0:.9f}, {1:.9f}, 0".format(xsize - kWALL_WIDTH / 2.0, ysize / 2.0),
151
+ )
152
+ )
153
+
154
+ chgs.add(
155
+ definition.AttrChange(
156
+ ".//arena/*[@id='wall_west']",
157
+ "size",
158
+ "{0:.9f}, {1:.9f}, 0.5".format(kWALL_WIDTH, ysize + kWALL_WIDTH),
159
+ )
160
+ )
161
+ chgs.add(
162
+ definition.AttrChange(
163
+ ".//arena/*[@id='wall_west']/body",
164
+ "position",
165
+ "0, {0:.9f}, 0".format(ysize / 2.0),
166
+ )
167
+ )
168
+
169
+ return chgs
170
+
171
+ def gen_tag_rmlist(self) -> tp.List[definition.ElementRmList]:
172
+ return []
173
+
174
+ def gen_element_addlist(self) -> tp.List[definition.ElementAddList]:
175
+ return []
176
+
177
+ def gen_files(self) -> None:
178
+ pass
179
+
180
+
181
+ __all__ = [
182
+ "ArenaShape",
183
+ ]