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.
- sierra/__init__.py +3 -3
- sierra/core/__init__.py +3 -3
- sierra/core/batchroot.py +223 -0
- sierra/core/cmdline.py +681 -1057
- sierra/core/compare.py +11 -0
- sierra/core/config.py +96 -88
- sierra/core/engine.py +306 -0
- sierra/core/execenv.py +380 -0
- sierra/core/expdef.py +11 -0
- sierra/core/experiment/__init__.py +1 -0
- sierra/core/experiment/bindings.py +150 -101
- sierra/core/experiment/definition.py +414 -245
- sierra/core/experiment/spec.py +83 -85
- sierra/core/exproot.py +44 -0
- sierra/core/generators/__init__.py +10 -0
- sierra/core/generators/experiment.py +528 -0
- sierra/core/generators/generator_factory.py +138 -137
- sierra/core/graphs/__init__.py +23 -0
- sierra/core/graphs/bcbridge.py +94 -0
- sierra/core/graphs/heatmap.py +245 -324
- sierra/core/graphs/pathset.py +27 -0
- sierra/core/graphs/schema.py +77 -0
- sierra/core/graphs/stacked_line.py +341 -0
- sierra/core/graphs/summary_line.py +506 -0
- sierra/core/logging.py +3 -2
- sierra/core/models/__init__.py +3 -1
- sierra/core/models/info.py +19 -0
- sierra/core/models/interface.py +52 -122
- sierra/core/pipeline/__init__.py +2 -5
- sierra/core/pipeline/pipeline.py +228 -126
- sierra/core/pipeline/stage1/__init__.py +10 -0
- sierra/core/pipeline/stage1/pipeline_stage1.py +45 -31
- sierra/core/pipeline/stage2/__init__.py +10 -0
- sierra/core/pipeline/stage2/pipeline_stage2.py +8 -11
- sierra/core/pipeline/stage2/runner.py +401 -0
- sierra/core/pipeline/stage3/__init__.py +12 -0
- sierra/core/pipeline/stage3/gather.py +321 -0
- sierra/core/pipeline/stage3/pipeline_stage3.py +37 -84
- sierra/core/pipeline/stage4/__init__.py +12 -2
- sierra/core/pipeline/stage4/pipeline_stage4.py +36 -354
- sierra/core/pipeline/stage5/__init__.py +12 -0
- sierra/core/pipeline/stage5/pipeline_stage5.py +33 -208
- sierra/core/pipeline/yaml.py +48 -0
- sierra/core/plugin.py +529 -62
- sierra/core/proc.py +11 -0
- sierra/core/prod.py +11 -0
- sierra/core/ros1/__init__.py +5 -1
- sierra/core/ros1/callbacks.py +22 -21
- sierra/core/ros1/cmdline.py +59 -88
- sierra/core/ros1/generators.py +159 -175
- sierra/core/ros1/variables/__init__.py +3 -0
- sierra/core/ros1/variables/exp_setup.py +122 -116
- sierra/core/startup.py +106 -76
- sierra/core/stat_kernels.py +4 -5
- sierra/core/storage.py +13 -32
- sierra/core/trampoline.py +30 -0
- sierra/core/types.py +116 -71
- sierra/core/utils.py +103 -106
- sierra/core/variables/__init__.py +1 -1
- sierra/core/variables/base_variable.py +12 -17
- sierra/core/variables/batch_criteria.py +387 -481
- sierra/core/variables/builtin.py +135 -0
- sierra/core/variables/exp_setup.py +19 -39
- sierra/core/variables/population_size.py +72 -76
- sierra/core/variables/variable_density.py +44 -68
- sierra/core/vector.py +1 -1
- sierra/main.py +256 -88
- sierra/plugins/__init__.py +119 -0
- sierra/plugins/compare/__init__.py +14 -0
- sierra/plugins/compare/graphs/__init__.py +19 -0
- sierra/plugins/compare/graphs/cmdline.py +120 -0
- sierra/plugins/compare/graphs/comparator.py +291 -0
- sierra/plugins/compare/graphs/inter_controller.py +531 -0
- sierra/plugins/compare/graphs/inter_scenario.py +297 -0
- sierra/plugins/compare/graphs/namecalc.py +53 -0
- sierra/plugins/compare/graphs/outputroot.py +73 -0
- sierra/plugins/compare/graphs/plugin.py +147 -0
- sierra/plugins/compare/graphs/preprocess.py +172 -0
- sierra/plugins/compare/graphs/schema.py +37 -0
- sierra/plugins/engine/__init__.py +14 -0
- sierra/plugins/engine/argos/__init__.py +18 -0
- sierra/plugins/{platform → engine}/argos/cmdline.py +144 -151
- sierra/plugins/{platform/argos/variables → engine/argos/generators}/__init__.py +5 -0
- sierra/plugins/engine/argos/generators/engine.py +394 -0
- sierra/plugins/engine/argos/plugin.py +393 -0
- sierra/plugins/{platform/argos/generators → engine/argos/variables}/__init__.py +5 -0
- sierra/plugins/engine/argos/variables/arena_shape.py +183 -0
- sierra/plugins/engine/argos/variables/cameras.py +240 -0
- sierra/plugins/engine/argos/variables/constant_density.py +112 -0
- sierra/plugins/engine/argos/variables/exp_setup.py +82 -0
- sierra/plugins/{platform → engine}/argos/variables/physics_engines.py +83 -87
- sierra/plugins/engine/argos/variables/population_constant_density.py +178 -0
- sierra/plugins/engine/argos/variables/population_size.py +115 -0
- sierra/plugins/engine/argos/variables/population_variable_density.py +123 -0
- sierra/plugins/engine/argos/variables/rendering.py +108 -0
- sierra/plugins/engine/ros1gazebo/__init__.py +18 -0
- sierra/plugins/engine/ros1gazebo/cmdline.py +175 -0
- sierra/plugins/{platform/ros1robot → engine/ros1gazebo}/generators/__init__.py +5 -0
- sierra/plugins/engine/ros1gazebo/generators/engine.py +125 -0
- sierra/plugins/engine/ros1gazebo/plugin.py +404 -0
- sierra/plugins/engine/ros1gazebo/variables/__init__.py +15 -0
- sierra/plugins/engine/ros1gazebo/variables/population_size.py +214 -0
- sierra/plugins/engine/ros1robot/__init__.py +18 -0
- sierra/plugins/engine/ros1robot/cmdline.py +159 -0
- sierra/plugins/{platform/ros1gazebo → engine/ros1robot}/generators/__init__.py +4 -0
- sierra/plugins/engine/ros1robot/generators/engine.py +95 -0
- sierra/plugins/engine/ros1robot/plugin.py +410 -0
- sierra/plugins/{hpc/local → engine/ros1robot/variables}/__init__.py +5 -0
- sierra/plugins/engine/ros1robot/variables/population_size.py +146 -0
- sierra/plugins/execenv/__init__.py +11 -0
- sierra/plugins/execenv/hpc/__init__.py +18 -0
- sierra/plugins/execenv/hpc/adhoc/__init__.py +18 -0
- sierra/plugins/execenv/hpc/adhoc/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/adhoc/plugin.py +131 -0
- sierra/plugins/execenv/hpc/cmdline.py +137 -0
- sierra/plugins/execenv/hpc/local/__init__.py +18 -0
- sierra/plugins/execenv/hpc/local/cmdline.py +31 -0
- sierra/plugins/execenv/hpc/local/plugin.py +145 -0
- sierra/plugins/execenv/hpc/pbs/__init__.py +18 -0
- sierra/plugins/execenv/hpc/pbs/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/pbs/plugin.py +121 -0
- sierra/plugins/execenv/hpc/slurm/__init__.py +18 -0
- sierra/plugins/execenv/hpc/slurm/cmdline.py +30 -0
- sierra/plugins/execenv/hpc/slurm/plugin.py +133 -0
- sierra/plugins/execenv/prefectserver/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/cmdline.py +66 -0
- sierra/plugins/execenv/prefectserver/dockerremote/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/dockerremote/cmdline.py +66 -0
- sierra/plugins/execenv/prefectserver/dockerremote/plugin.py +132 -0
- sierra/plugins/execenv/prefectserver/flow.py +66 -0
- sierra/plugins/execenv/prefectserver/local/__init__.py +18 -0
- sierra/plugins/execenv/prefectserver/local/cmdline.py +29 -0
- sierra/plugins/execenv/prefectserver/local/plugin.py +133 -0
- sierra/plugins/{hpc/adhoc → execenv/robot}/__init__.py +1 -0
- sierra/plugins/execenv/robot/turtlebot3/__init__.py +18 -0
- sierra/plugins/execenv/robot/turtlebot3/plugin.py +204 -0
- sierra/plugins/expdef/__init__.py +14 -0
- sierra/plugins/expdef/json/__init__.py +14 -0
- sierra/plugins/expdef/json/plugin.py +504 -0
- sierra/plugins/expdef/xml/__init__.py +14 -0
- sierra/plugins/expdef/xml/plugin.py +386 -0
- sierra/{core/hpc → plugins/proc}/__init__.py +1 -1
- sierra/plugins/proc/collate/__init__.py +15 -0
- sierra/plugins/proc/collate/cmdline.py +47 -0
- sierra/plugins/proc/collate/plugin.py +271 -0
- sierra/plugins/proc/compress/__init__.py +18 -0
- sierra/plugins/proc/compress/cmdline.py +47 -0
- sierra/plugins/proc/compress/plugin.py +123 -0
- sierra/plugins/proc/decompress/__init__.py +18 -0
- sierra/plugins/proc/decompress/plugin.py +96 -0
- sierra/plugins/proc/imagize/__init__.py +15 -0
- sierra/plugins/proc/imagize/cmdline.py +49 -0
- sierra/plugins/proc/imagize/plugin.py +270 -0
- sierra/plugins/proc/modelrunner/__init__.py +16 -0
- sierra/plugins/proc/modelrunner/plugin.py +250 -0
- sierra/plugins/proc/statistics/__init__.py +15 -0
- sierra/plugins/proc/statistics/cmdline.py +64 -0
- sierra/plugins/proc/statistics/plugin.py +390 -0
- sierra/plugins/{hpc → prod}/__init__.py +1 -0
- sierra/plugins/prod/graphs/__init__.py +18 -0
- sierra/plugins/prod/graphs/cmdline.py +269 -0
- sierra/plugins/prod/graphs/collate.py +279 -0
- sierra/plugins/prod/graphs/inter/__init__.py +13 -0
- sierra/plugins/prod/graphs/inter/generate.py +83 -0
- sierra/plugins/prod/graphs/inter/heatmap.py +86 -0
- sierra/plugins/prod/graphs/inter/line.py +134 -0
- sierra/plugins/prod/graphs/intra/__init__.py +15 -0
- sierra/plugins/prod/graphs/intra/generate.py +202 -0
- sierra/plugins/prod/graphs/intra/heatmap.py +74 -0
- sierra/plugins/prod/graphs/intra/line.py +114 -0
- sierra/plugins/prod/graphs/plugin.py +103 -0
- sierra/plugins/prod/graphs/targets.py +63 -0
- sierra/plugins/prod/render/__init__.py +18 -0
- sierra/plugins/prod/render/cmdline.py +72 -0
- sierra/plugins/prod/render/plugin.py +282 -0
- sierra/plugins/storage/__init__.py +5 -0
- sierra/plugins/storage/arrow/__init__.py +18 -0
- sierra/plugins/storage/arrow/plugin.py +38 -0
- sierra/plugins/storage/csv/__init__.py +9 -0
- sierra/plugins/storage/csv/plugin.py +12 -5
- sierra/version.py +3 -2
- sierra_research-1.5.0.dist-info/METADATA +238 -0
- sierra_research-1.5.0.dist-info/RECORD +186 -0
- {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info}/WHEEL +1 -2
- sierra/core/experiment/xml.py +0 -454
- sierra/core/generators/controller_generator_parser.py +0 -34
- sierra/core/generators/exp_creator.py +0 -351
- sierra/core/generators/exp_generators.py +0 -142
- sierra/core/graphs/scatterplot2D.py +0 -109
- sierra/core/graphs/stacked_line_graph.py +0 -249
- sierra/core/graphs/stacked_surface_graph.py +0 -220
- sierra/core/graphs/summary_line_graph.py +0 -369
- sierra/core/hpc/cmdline.py +0 -142
- sierra/core/models/graphs.py +0 -87
- sierra/core/pipeline/stage2/exp_runner.py +0 -286
- sierra/core/pipeline/stage3/imagizer.py +0 -149
- sierra/core/pipeline/stage3/run_collator.py +0 -317
- sierra/core/pipeline/stage3/statistics_calculator.py +0 -478
- sierra/core/pipeline/stage4/graph_collator.py +0 -319
- sierra/core/pipeline/stage4/inter_exp_graph_generator.py +0 -240
- sierra/core/pipeline/stage4/intra_exp_graph_generator.py +0 -317
- sierra/core/pipeline/stage4/model_runner.py +0 -168
- sierra/core/pipeline/stage4/rendering.py +0 -283
- sierra/core/pipeline/stage4/yaml_config_loader.py +0 -103
- sierra/core/pipeline/stage5/inter_scenario_comparator.py +0 -328
- sierra/core/pipeline/stage5/intra_scenario_comparator.py +0 -989
- sierra/core/platform.py +0 -493
- sierra/core/plugin_manager.py +0 -369
- sierra/core/root_dirpath_generator.py +0 -241
- sierra/plugins/hpc/adhoc/plugin.py +0 -125
- sierra/plugins/hpc/local/plugin.py +0 -81
- sierra/plugins/hpc/pbs/__init__.py +0 -9
- sierra/plugins/hpc/pbs/plugin.py +0 -126
- sierra/plugins/hpc/slurm/__init__.py +0 -9
- sierra/plugins/hpc/slurm/plugin.py +0 -130
- sierra/plugins/platform/__init__.py +0 -9
- sierra/plugins/platform/argos/__init__.py +0 -9
- sierra/plugins/platform/argos/generators/platform_generators.py +0 -383
- sierra/plugins/platform/argos/plugin.py +0 -337
- sierra/plugins/platform/argos/variables/arena_shape.py +0 -145
- sierra/plugins/platform/argos/variables/cameras.py +0 -243
- sierra/plugins/platform/argos/variables/constant_density.py +0 -136
- sierra/plugins/platform/argos/variables/exp_setup.py +0 -113
- sierra/plugins/platform/argos/variables/population_constant_density.py +0 -175
- sierra/plugins/platform/argos/variables/population_size.py +0 -102
- sierra/plugins/platform/argos/variables/population_variable_density.py +0 -132
- sierra/plugins/platform/argos/variables/rendering.py +0 -104
- sierra/plugins/platform/ros1gazebo/__init__.py +0 -9
- sierra/plugins/platform/ros1gazebo/cmdline.py +0 -213
- sierra/plugins/platform/ros1gazebo/generators/platform_generators.py +0 -137
- sierra/plugins/platform/ros1gazebo/plugin.py +0 -335
- sierra/plugins/platform/ros1gazebo/variables/__init__.py +0 -10
- sierra/plugins/platform/ros1gazebo/variables/population_size.py +0 -204
- sierra/plugins/platform/ros1robot/__init__.py +0 -9
- sierra/plugins/platform/ros1robot/cmdline.py +0 -175
- sierra/plugins/platform/ros1robot/generators/platform_generators.py +0 -112
- sierra/plugins/platform/ros1robot/plugin.py +0 -373
- sierra/plugins/platform/ros1robot/variables/__init__.py +0 -10
- sierra/plugins/platform/ros1robot/variables/population_size.py +0 -146
- sierra/plugins/robot/__init__.py +0 -9
- sierra/plugins/robot/turtlebot3/__init__.py +0 -9
- sierra/plugins/robot/turtlebot3/plugin.py +0 -194
- sierra_research-1.3.6.data/data/share/man/man1/sierra-cli.1 +0 -2349
- sierra_research-1.3.6.data/data/share/man/man7/sierra-examples.7 +0 -488
- sierra_research-1.3.6.data/data/share/man/man7/sierra-exec-envs.7 +0 -331
- sierra_research-1.3.6.data/data/share/man/man7/sierra-glossary.7 +0 -285
- sierra_research-1.3.6.data/data/share/man/man7/sierra-platforms.7 +0 -358
- sierra_research-1.3.6.data/data/share/man/man7/sierra-usage.7 +0 -725
- sierra_research-1.3.6.data/data/share/man/man7/sierra.7 +0 -78
- sierra_research-1.3.6.dist-info/METADATA +0 -500
- sierra_research-1.3.6.dist-info/RECORD +0 -133
- sierra_research-1.3.6.dist-info/top_level.txt +0 -1
- {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info}/entry_points.txt +0 -0
- {sierra_research-1.3.6.dist-info → sierra_research-1.5.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,404 @@
|
|
1
|
+
# Copyright 2021 John Harwell, All rights reserved.
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
"""
|
5
|
+
Provides engine-specific callbacks for the :term:`ROS1+Gazebo` engine.
|
6
|
+
"""
|
7
|
+
# Core packages
|
8
|
+
import argparse
|
9
|
+
import logging
|
10
|
+
import os
|
11
|
+
import re
|
12
|
+
import typing as tp
|
13
|
+
import sys
|
14
|
+
import pathlib
|
15
|
+
import psutil
|
16
|
+
|
17
|
+
# 3rd party packages
|
18
|
+
import packaging.version
|
19
|
+
import implements
|
20
|
+
|
21
|
+
# Project packages
|
22
|
+
from sierra.core import config, ros1, types, batchroot, execenv
|
23
|
+
from sierra.core.experiment import bindings, definition
|
24
|
+
import sierra.core.variables.batch_criteria as bc
|
25
|
+
|
26
|
+
_logger = logging.getLogger("ros1gazebo.plugin")
|
27
|
+
|
28
|
+
|
29
|
+
@implements.implements(bindings.IExpRunShellCmdsGenerator)
|
30
|
+
class ExpRunShellCmdsGenerator:
|
31
|
+
def __init__(
|
32
|
+
self,
|
33
|
+
cmdopts: types.Cmdopts,
|
34
|
+
criteria: bc.XVarBatchCriteria,
|
35
|
+
n_agents: int,
|
36
|
+
exp_num: int,
|
37
|
+
) -> None:
|
38
|
+
self.cmdopts = cmdopts
|
39
|
+
self.gazebo_port = -1
|
40
|
+
self.roscore_port = -1
|
41
|
+
|
42
|
+
def pre_run_cmds(
|
43
|
+
self, host: str, input_fpath: pathlib.Path, run_num: int
|
44
|
+
) -> tp.List[types.ShellCmdSpec]:
|
45
|
+
if host == "master":
|
46
|
+
return []
|
47
|
+
|
48
|
+
# First, the cmd to start roscore. We need to be on a unique port so
|
49
|
+
# that multiple ROS instances corresponding to multiple Gazebo
|
50
|
+
# instances with the same topic names are considered distinct/not
|
51
|
+
# accessible between instances of Gazebo.
|
52
|
+
self.roscore_port = config.kROS["port_base"] + run_num * 2
|
53
|
+
|
54
|
+
# roscore will run on each slave node used during stage 2, so we have to
|
55
|
+
# use 'localhost' for binding.
|
56
|
+
roscore_uri = types.ShellCmdSpec(
|
57
|
+
cmd=f"export ROS_MASTER_URI=http://localhost:{self.roscore_port};",
|
58
|
+
shell=True,
|
59
|
+
wait=True,
|
60
|
+
env=True,
|
61
|
+
)
|
62
|
+
# ROS/Gazebo don't provide options to not print stuff, so we have to use
|
63
|
+
# the nuclear option.
|
64
|
+
roscore_cmd = f"roscore -p {self.roscore_port} "
|
65
|
+
if self.cmdopts["exec_devnull"]:
|
66
|
+
roscore_cmd += "> /dev/null 2>&1 "
|
67
|
+
|
68
|
+
roscore_cmd += "& "
|
69
|
+
|
70
|
+
# Each experiment gets their own roscore. Because each roscore has a
|
71
|
+
# different port, this prevents any robots from pre-emptively starting
|
72
|
+
# the next experiment before the rest of the robots have finished the
|
73
|
+
# current one.
|
74
|
+
roscore_process = types.ShellCmdSpec(
|
75
|
+
cmd=roscore_cmd,
|
76
|
+
shell=True,
|
77
|
+
wait=False,
|
78
|
+
)
|
79
|
+
|
80
|
+
# Second, the command to give Gazebo a unique port on the host during
|
81
|
+
# stage 2. We need to be on a unique port so that multiple Gazebo
|
82
|
+
# instances can be run in parallel.
|
83
|
+
self.gazebo_port = config.kROS["port_base"] + run_num * 2 + 1
|
84
|
+
|
85
|
+
# 2021/12/13: You can't use HTTPS for some reason or gazebo won't
|
86
|
+
# start...
|
87
|
+
gazebo_uri = types.ShellCmdSpec(
|
88
|
+
cmd=f"export GAZEBO_MASTER_URI=http://localhost:{self.gazebo_port};",
|
89
|
+
shell=True,
|
90
|
+
env=True,
|
91
|
+
wait=True,
|
92
|
+
)
|
93
|
+
|
94
|
+
return [roscore_uri, roscore_process, gazebo_uri]
|
95
|
+
|
96
|
+
def exec_run_cmds(
|
97
|
+
self, host: str, input_fpath: pathlib.Path, run_num: int
|
98
|
+
) -> tp.List[types.ShellCmdSpec]:
|
99
|
+
if host == "master":
|
100
|
+
return []
|
101
|
+
|
102
|
+
# For ROS+gazebo, we have two files per experimental run:
|
103
|
+
#
|
104
|
+
# - One for the stuff that is run on the ROS master (can be
|
105
|
+
# nothing/empty file).
|
106
|
+
#
|
107
|
+
# - One for the stuff that describes what to run on each robot/how many
|
108
|
+
# robots to spawn.
|
109
|
+
#
|
110
|
+
# We COULD do it all in a single file, but in order to share base code
|
111
|
+
# with the ROS+robot engine, we need to do it this way.
|
112
|
+
#
|
113
|
+
# 2022/02/28: I don't use the -u argument here to set ROS_MASTER_URI,
|
114
|
+
# because ROS works well enough when only running on the localhost, in
|
115
|
+
# terms of respecting whatever the envvar is set to.
|
116
|
+
master = str(input_fpath) + "_master" + config.kROS["launch_file_ext"]
|
117
|
+
robots = str(input_fpath) + "_robots" + config.kROS["launch_file_ext"]
|
118
|
+
|
119
|
+
cmd = "{0} --wait {1} {2} ".format(config.kROS["launch_cmd"], master, robots)
|
120
|
+
|
121
|
+
# ROS/Gazebo don't provide options to not print stuff, so we have to use
|
122
|
+
# the nuclear option.
|
123
|
+
if self.cmdopts["exec_devnull"]:
|
124
|
+
cmd += "> /dev/null 2>&1"
|
125
|
+
|
126
|
+
cmd += ";"
|
127
|
+
return [types.ShellCmdSpec(cmd=cmd, shell=True, wait=True)]
|
128
|
+
|
129
|
+
def post_run_cmds(
|
130
|
+
self, host: str, run_output_root: pathlib.Path
|
131
|
+
) -> tp.List[types.ShellCmdSpec]:
|
132
|
+
return []
|
133
|
+
|
134
|
+
|
135
|
+
@implements.implements(bindings.IExpShellCmdsGenerator)
|
136
|
+
class ExpShellCmdsGenerator:
|
137
|
+
def __init__(self, cmdopts: types.Cmdopts, exp_num: int) -> None:
|
138
|
+
self.cmdopts = cmdopts
|
139
|
+
self.exp_num = exp_num
|
140
|
+
|
141
|
+
def pre_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
|
142
|
+
# 2025-09-11 [JRH]: This was a NASTY bug which got triggered when
|
143
|
+
# running SIERRA in a venv. ROS is installed system-wide, but mixing
|
144
|
+
# venv+system packages via a --system venv caused all sorts of problems
|
145
|
+
# because the venv versions were often mixing newer with older packages
|
146
|
+
# at load time. So, we have to allow the venv interpreter to find the
|
147
|
+
# system-wide packages AFTER everything is loaded by modifying the
|
148
|
+
# PYTHONPATH for the sub-shell that SIERRA runs everything in.
|
149
|
+
#
|
150
|
+
# Hopefully this is better in ROS2.
|
151
|
+
|
152
|
+
return [
|
153
|
+
types.ShellCmdSpec(
|
154
|
+
cmd="export PYTHONPATH=$PYTHONPATH:/usr/lib/python3/dist-packages/",
|
155
|
+
shell=True,
|
156
|
+
wait=True,
|
157
|
+
env=True,
|
158
|
+
),
|
159
|
+
]
|
160
|
+
|
161
|
+
def exec_exp_cmds(self, exec_opts: types.StrDict) -> tp.List[types.ShellCmdSpec]:
|
162
|
+
return []
|
163
|
+
|
164
|
+
def post_exp_cmds(self) -> tp.List[types.ShellCmdSpec]:
|
165
|
+
# Cleanup roscore and gazebo processes which are still active because
|
166
|
+
# they don't know how to clean up after themselves.
|
167
|
+
#
|
168
|
+
# This is OK to do even when we have multiple Gazebo+ROS instances on
|
169
|
+
# the same machine, because we only run these commands after an
|
170
|
+
# experiment finishes, so there isn't anything currently running we
|
171
|
+
# might accidentally kill.
|
172
|
+
#
|
173
|
+
# Can't use killall, because that returns non-zero if things
|
174
|
+
# are cleaned up nicely.
|
175
|
+
return [
|
176
|
+
types.ShellCmdSpec(
|
177
|
+
cmd="if pgrep gzserver; then pkill gzserver; fi;", shell=True, wait=True
|
178
|
+
),
|
179
|
+
types.ShellCmdSpec(
|
180
|
+
cmd="if pgrep rosmaster; then pkill rosmaster; fi;",
|
181
|
+
shell=True,
|
182
|
+
wait=True,
|
183
|
+
),
|
184
|
+
types.ShellCmdSpec(
|
185
|
+
cmd="if pgrep roscore; then pkill roscore; fi;", shell=True, wait=True
|
186
|
+
),
|
187
|
+
types.ShellCmdSpec(
|
188
|
+
cmd="if pgrep rosout; then pkill rosout; fi;", shell=True, wait=True
|
189
|
+
),
|
190
|
+
]
|
191
|
+
|
192
|
+
|
193
|
+
@implements.implements(bindings.IExpConfigurer)
|
194
|
+
class ExpConfigurer:
|
195
|
+
def __init__(self, cmdopts: types.Cmdopts) -> None:
|
196
|
+
self.cmdopts = cmdopts
|
197
|
+
|
198
|
+
def for_exp_run(
|
199
|
+
self, exp_input_root: pathlib.Path, run_output_root: pathlib.Path
|
200
|
+
) -> None:
|
201
|
+
pass
|
202
|
+
|
203
|
+
def for_exp(self, exp_input_root: pathlib.Path) -> None:
|
204
|
+
pass
|
205
|
+
|
206
|
+
def parallelism_paradigm(self) -> str:
|
207
|
+
return "per-exp"
|
208
|
+
|
209
|
+
|
210
|
+
def cmdline_postparse_configure(
|
211
|
+
env: str, args: argparse.Namespace
|
212
|
+
) -> argparse.Namespace:
|
213
|
+
"""
|
214
|
+
Configure cmdline args after parsing for the :term:`ROS1+Gazebo` engine.
|
215
|
+
|
216
|
+
This sets arguments appropriately depending on what HPC environment is
|
217
|
+
selected with ``--execenv``:
|
218
|
+
|
219
|
+
- hpc.local
|
220
|
+
|
221
|
+
- hpc.adhoc
|
222
|
+
|
223
|
+
- hpc.slurm
|
224
|
+
|
225
|
+
- hpc.pbs
|
226
|
+
"""
|
227
|
+
# No configuration needed for stages 3-5
|
228
|
+
if not any(stage in args.pipeline for stage in [1, 2]):
|
229
|
+
return args
|
230
|
+
|
231
|
+
if env == "hpc.local":
|
232
|
+
return _configure_hpc_local(args)
|
233
|
+
elif env == "hpc.adhoc":
|
234
|
+
return _configure_hpc_adhoc(args)
|
235
|
+
elif env == "hpc.slurm":
|
236
|
+
return _configure_hpc_slurm(args)
|
237
|
+
elif env == "hpc.pbs":
|
238
|
+
return _configure_hpc_pbs(args)
|
239
|
+
|
240
|
+
raise RuntimeError(f"'{env}' unsupported on ROS1+Gazebo")
|
241
|
+
|
242
|
+
|
243
|
+
def _configure_hpc_pbs(args: argparse.Namespace) -> argparse.Namespace:
|
244
|
+
# For now, nothing to do. If more stuff with physics engine
|
245
|
+
# configuration is implemented, this may change.
|
246
|
+
_logger.debug(
|
247
|
+
"Allocated %s physics threads/run, %s parallel runs/node",
|
248
|
+
args.physics_n_threads,
|
249
|
+
args.exec_jobs_per_node,
|
250
|
+
)
|
251
|
+
return args
|
252
|
+
|
253
|
+
|
254
|
+
def _configure_hpc_slurm(args: argparse.Namespace) -> argparse.Namespace:
|
255
|
+
# We rely on the user to request their job intelligently so that
|
256
|
+
# SLURM_TASKS_PER_NODE is appropriate.
|
257
|
+
if args.exec_jobs_per_node is None:
|
258
|
+
res = re.search(r"^[^\(]+", os.environ["SLURM_TASKS_PER_NODE"])
|
259
|
+
assert (
|
260
|
+
res is not None
|
261
|
+
), "Unexpected format in SLURM_TASKS_PER_NODE: '{0}'".format(
|
262
|
+
os.environ["SLURM_TASKS_PER_NODE"]
|
263
|
+
)
|
264
|
+
args.exec_jobs_per_node = int(res.group(0))
|
265
|
+
|
266
|
+
_logger.debug(
|
267
|
+
"Allocated %s physics threads/run, %s parallel runs/node",
|
268
|
+
args.physics_n_threads,
|
269
|
+
args.exec_jobs_per_node,
|
270
|
+
)
|
271
|
+
return args
|
272
|
+
|
273
|
+
|
274
|
+
def _configure_hpc_adhoc(args: argparse.Namespace) -> argparse.Namespace:
|
275
|
+
nodes = execenv.parse_nodefile(args.nodefile)
|
276
|
+
ppn = sys.maxsize
|
277
|
+
for node in nodes:
|
278
|
+
ppn = min(ppn, node.n_cores)
|
279
|
+
|
280
|
+
if args.exec_jobs_per_node is None:
|
281
|
+
args.exec_jobs_per_node = int(float(args.n_runs) / len(nodes))
|
282
|
+
|
283
|
+
_logger.debug(
|
284
|
+
"Allocated %s physics threads/run, %s parallel runs/node",
|
285
|
+
args.physics_n_threads,
|
286
|
+
args.exec_jobs_per_node,
|
287
|
+
)
|
288
|
+
|
289
|
+
return args
|
290
|
+
|
291
|
+
|
292
|
+
def _configure_hpc_local(args: argparse.Namespace) -> argparse.Namespace:
|
293
|
+
# For now. If more physics engine configuration is added, this will
|
294
|
+
# change.
|
295
|
+
ppn_per_run_req = 1
|
296
|
+
|
297
|
+
if args.exec_jobs_per_node is None:
|
298
|
+
parallel_jobs = int(psutil.cpu_count() / float(ppn_per_run_req))
|
299
|
+
|
300
|
+
if parallel_jobs == 0:
|
301
|
+
_logger.warning(
|
302
|
+
(
|
303
|
+
"Local machine has %s logical cores, but "
|
304
|
+
"%s threads/run requested; "
|
305
|
+
"allocating anyway"
|
306
|
+
),
|
307
|
+
psutil.cpu_count(),
|
308
|
+
ppn_per_run_req,
|
309
|
+
)
|
310
|
+
parallel_jobs = 1
|
311
|
+
|
312
|
+
# Make sure we don't oversubscribe cores--each simulation needs at
|
313
|
+
# least 1 core.
|
314
|
+
args.exec_jobs_per_node = min(args.n_runs, parallel_jobs)
|
315
|
+
|
316
|
+
_logger.debug(
|
317
|
+
"Allocated %s physics threads/run, %s parallel runs/node",
|
318
|
+
args.physics_n_threads,
|
319
|
+
args.exec_jobs_per_node,
|
320
|
+
)
|
321
|
+
return args
|
322
|
+
|
323
|
+
|
324
|
+
def execenv_check(cmdopts: types.Cmdopts) -> None:
|
325
|
+
"""
|
326
|
+
Verify execution environment in stage 2 for :term:`ROS1+Gazebo`.
|
327
|
+
|
328
|
+
Check for:
|
329
|
+
|
330
|
+
- :envvar:`ROS_VERSION` is ROS1.
|
331
|
+
|
332
|
+
- :envvar:`ROS_DISTRO` is {kinetic/noetic}.
|
333
|
+
|
334
|
+
- :program:`gazebo` can be found and the version is supported.
|
335
|
+
"""
|
336
|
+
keys = ["ROS_DISTRO", "ROS_VERSION"]
|
337
|
+
|
338
|
+
for k in keys:
|
339
|
+
assert k in os.environ, f"Non-ROS+Gazebo environment detected: '{k}' not found"
|
340
|
+
|
341
|
+
# Check ROS distro
|
342
|
+
assert os.environ["ROS_DISTRO"] in [
|
343
|
+
"kinetic",
|
344
|
+
"noetic",
|
345
|
+
], "SIERRA only supports ROS1 kinetic,noetic"
|
346
|
+
|
347
|
+
# Check ROS version
|
348
|
+
assert (
|
349
|
+
os.environ["ROS_VERSION"] == "1"
|
350
|
+
), "Wrong ROS version: this plugin is for ROS1"
|
351
|
+
|
352
|
+
# Check we can find Gazebo
|
353
|
+
version = execenv.check_for_simulator(
|
354
|
+
cmdopts["engine"], cmdopts["execenv"], config.kGazebo["launch_cmd"]
|
355
|
+
)
|
356
|
+
|
357
|
+
# Check Gazebo version
|
358
|
+
stdout = version.stdout.decode("utf-8")
|
359
|
+
stderr = version.stderr.decode("utf-8")
|
360
|
+
res = re.search(r"[0-9]+.[0-9]+.[0-9]+", stdout)
|
361
|
+
assert (
|
362
|
+
res is not None
|
363
|
+
), f"Gazebo version not in std: have stdout='{stdout}',stderr='{stderr}'"
|
364
|
+
|
365
|
+
version = packaging.version.parse(res.group(0))
|
366
|
+
min_version = packaging.version.parse(config.kGazebo["min_version"])
|
367
|
+
|
368
|
+
assert (
|
369
|
+
version >= min_version
|
370
|
+
), f"Gazebo version {version} < min required {min_version}"
|
371
|
+
|
372
|
+
|
373
|
+
def population_size_from_pickle(
|
374
|
+
adds_def: tp.Union[definition.AttrChangeSet, definition.ElementAddList],
|
375
|
+
main_config: types.YAMLDict,
|
376
|
+
cmdopts: types.Cmdopts,
|
377
|
+
) -> int:
|
378
|
+
return ros1.callbacks.population_size_from_pickle(adds_def, main_config, cmdopts)
|
379
|
+
|
380
|
+
|
381
|
+
def population_size_from_def(
|
382
|
+
exp_def: definition.BaseExpDef, main_config: types.YAMLDict, cmdopts: types.Cmdopts
|
383
|
+
) -> int:
|
384
|
+
return ros1.callbacks.population_size_from_def(exp_def, main_config, cmdopts)
|
385
|
+
|
386
|
+
|
387
|
+
def agent_prefix_extract(main_config: types.YAMLDict, cmdopts: types.Cmdopts) -> str:
|
388
|
+
return ros1.callbacks.robot_prefix_extract(main_config, cmdopts)
|
389
|
+
|
390
|
+
|
391
|
+
def pre_exp_diagnostics(
|
392
|
+
cmdopts: types.Cmdopts, pathset: batchroot.PathSet, logger: logging.Logger
|
393
|
+
) -> None:
|
394
|
+
s = "batch_exp_root='%s',runs/exp=%s,threads/job=%s,n_jobs=%s"
|
395
|
+
logger.info(
|
396
|
+
s,
|
397
|
+
pathset.root,
|
398
|
+
cmdopts["n_runs"],
|
399
|
+
cmdopts["physics_n_threads"],
|
400
|
+
cmdopts["exec_jobs_per_node"],
|
401
|
+
)
|
402
|
+
|
403
|
+
|
404
|
+
__all__ = ["cmdline_postparse_configure", "execenv_check"]
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright 2021 John Harwell, All rights reserved.
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
"""
|
5
|
+
Variables module for the :term:`ROS1+Gazebo` engine.
|
6
|
+
|
7
|
+
See :ref:`plugins/engine/ros1gazebo`.
|
8
|
+
"""
|
9
|
+
|
10
|
+
# Core packages
|
11
|
+
|
12
|
+
# 3rd party packages
|
13
|
+
|
14
|
+
# Project packages
|
15
|
+
from sierra.core.ros1.variables import exp_setup as exp_setup
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# Copyright 2020 John Harwell, All rights reserved.
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
"""Classes for the population size batch criteria.
|
5
|
+
|
6
|
+
See :ref:`plugins/engine/ros1gazebo/bc/population-size` for usage
|
7
|
+
documentation.
|
8
|
+
|
9
|
+
"""
|
10
|
+
|
11
|
+
# Core packages
|
12
|
+
import typing as tp
|
13
|
+
import random
|
14
|
+
import logging
|
15
|
+
import pathlib
|
16
|
+
|
17
|
+
# 3rd party packages
|
18
|
+
import implements
|
19
|
+
|
20
|
+
# Project packages
|
21
|
+
from sierra.core.variables import batch_criteria as bc
|
22
|
+
from sierra.core.experiment import definition
|
23
|
+
from sierra.core import types, utils
|
24
|
+
from sierra.core.vector import Vector3D
|
25
|
+
from sierra.core.variables import population_size
|
26
|
+
from sierra.core.graphs import bcbridge
|
27
|
+
|
28
|
+
|
29
|
+
@implements.implements(bcbridge.IGraphable)
|
30
|
+
@implements.implements(bc.IQueryableBatchCriteria)
|
31
|
+
class PopulationSize(population_size.PopulationSize):
|
32
|
+
"""A univariate range of system sizes used to define batch experiments.
|
33
|
+
|
34
|
+
This class is a base class which should (almost) never be used on its
|
35
|
+
own. Instead, the ``factory()`` function should be used to dynamically
|
36
|
+
create derived classes expressing the user's desired size distribution.
|
37
|
+
|
38
|
+
Note: Usage of this class assumes homogeneous systems.
|
39
|
+
|
40
|
+
Attributes:
|
41
|
+
size_list: List of integer system sizes defining the range of the
|
42
|
+
variable for the batch experiment.
|
43
|
+
|
44
|
+
"""
|
45
|
+
|
46
|
+
def __init__(
|
47
|
+
self,
|
48
|
+
cli_arg: str,
|
49
|
+
main_config: types.YAMLDict,
|
50
|
+
batch_input_root: pathlib.Path,
|
51
|
+
robot: str,
|
52
|
+
sizes: tp.List[int],
|
53
|
+
positions: tp.List[Vector3D],
|
54
|
+
) -> None:
|
55
|
+
population_size.PopulationSize.__init__(
|
56
|
+
self, cli_arg, main_config, batch_input_root
|
57
|
+
)
|
58
|
+
self.sizes = sizes
|
59
|
+
self.robot = robot
|
60
|
+
self.positions = positions
|
61
|
+
self.logger = logging.getLogger(__name__)
|
62
|
+
if len(positions) < self.sizes[-1]:
|
63
|
+
self.logger.warning(
|
64
|
+
"# possible positions < # robots: %s < %s",
|
65
|
+
len(positions),
|
66
|
+
self.sizes[-1],
|
67
|
+
)
|
68
|
+
self.element_adds = [] # type: tp.List[definition.ElementAddList]
|
69
|
+
|
70
|
+
def gen_element_addlist(self) -> tp.List[definition.ElementAddList]:
|
71
|
+
"""Generate XML modifications to set system sizes."""
|
72
|
+
if not self.element_adds:
|
73
|
+
robot_config = self.main_config["ros"]["robots"][self.robot]
|
74
|
+
prefix = robot_config["prefix"]
|
75
|
+
model_base = robot_config["model"]
|
76
|
+
model_variant = robot_config.get("model_variant", "")
|
77
|
+
|
78
|
+
if model_variant != "":
|
79
|
+
model = f"{model_base}_{model_variant}"
|
80
|
+
else:
|
81
|
+
model = model_base
|
82
|
+
|
83
|
+
desc_cmd = f"$(find xacro)/xacro $(find {model_base}_description)/urdf/{model}.urdf.xacro"
|
84
|
+
for s in self.sizes:
|
85
|
+
exp_adds = definition.ElementAddList()
|
86
|
+
pos_i = random.randint(0, len(self.positions) - 1)
|
87
|
+
|
88
|
+
exp_adds.append(definition.ElementAdd(".", "master", {}, True))
|
89
|
+
exp_adds.append(
|
90
|
+
definition.ElementAdd("./master", "group", {"ns": "sierra"}, False)
|
91
|
+
)
|
92
|
+
exp_adds.append(
|
93
|
+
definition.ElementAdd(
|
94
|
+
"./master/group/[@ns='sierra']",
|
95
|
+
"param",
|
96
|
+
{"name": "experiment/n_agents", "value": str(s)},
|
97
|
+
False,
|
98
|
+
)
|
99
|
+
)
|
100
|
+
|
101
|
+
for i in range(0, s):
|
102
|
+
|
103
|
+
ns = f"{prefix}{i}"
|
104
|
+
pos = self.positions[pos_i]
|
105
|
+
pos_i = (pos_i + 1) % len(self.positions)
|
106
|
+
spawn_cmd_args = f"-urdf -model {model}_{ns} -x {pos.x} -y {pos.y} -z {pos.z} -param robot_description"
|
107
|
+
|
108
|
+
exp_adds.append(
|
109
|
+
definition.ElementAdd("./robot", "group", {"ns": ns}, True)
|
110
|
+
)
|
111
|
+
|
112
|
+
exp_adds.append(
|
113
|
+
definition.ElementAdd(
|
114
|
+
f"./robot/group/[@ns='{ns}']",
|
115
|
+
"param",
|
116
|
+
{"name": "tf_prefix", "value": ns},
|
117
|
+
True,
|
118
|
+
)
|
119
|
+
)
|
120
|
+
|
121
|
+
# These two tag adds are OK to use because:
|
122
|
+
#
|
123
|
+
# - All robots in Gazebo are created using spawn_model
|
124
|
+
# initially.
|
125
|
+
#
|
126
|
+
# - All robots in Gazebo will provide a robot description
|
127
|
+
# .urdf.xacro per ROS naming conventions
|
128
|
+
exp_adds.append(
|
129
|
+
definition.ElementAdd(
|
130
|
+
f"./robot/group/[@ns='{ns}']",
|
131
|
+
"param",
|
132
|
+
{"name": "robot_description", "command": desc_cmd},
|
133
|
+
True,
|
134
|
+
)
|
135
|
+
)
|
136
|
+
|
137
|
+
exp_adds.append(
|
138
|
+
definition.ElementAdd(
|
139
|
+
f"./robot/group/[@ns='{ns}']",
|
140
|
+
"node",
|
141
|
+
{
|
142
|
+
"name": "spawn_urdf",
|
143
|
+
"pkg": "gazebo_ros",
|
144
|
+
"type": "spawn_model",
|
145
|
+
"args": spawn_cmd_args,
|
146
|
+
},
|
147
|
+
True,
|
148
|
+
)
|
149
|
+
)
|
150
|
+
|
151
|
+
self.element_adds.append(exp_adds)
|
152
|
+
|
153
|
+
return self.element_adds
|
154
|
+
|
155
|
+
def graph_info(
|
156
|
+
self,
|
157
|
+
cmdopts: types.Cmdopts,
|
158
|
+
batch_output_root: tp.Optional[pathlib.Path] = None,
|
159
|
+
exp_names: tp.Optional[tp.List[str]] = None,
|
160
|
+
) -> bcbridge.GraphInfo:
|
161
|
+
info = bcbridge.GraphInfo(
|
162
|
+
cmdopts,
|
163
|
+
batch_output_root,
|
164
|
+
exp_names if exp_names else self.gen_exp_names(),
|
165
|
+
)
|
166
|
+
|
167
|
+
info.xlabel = super().graph_xlabel(info.cmdopts)
|
168
|
+
info.xticklabels = super().graph_xticklabels(
|
169
|
+
info.cmdopts, info.batch_output_root, info.exp_names
|
170
|
+
)
|
171
|
+
info.xticks = super().graph_xticks(
|
172
|
+
info.cmdopts, info.batch_output_root, info.exp_names
|
173
|
+
)
|
174
|
+
return info
|
175
|
+
|
176
|
+
def n_agents(self, exp_num: int) -> int:
|
177
|
+
return int(len(self.element_adds[exp_num]) / len(self.element_adds[0]))
|
178
|
+
|
179
|
+
|
180
|
+
def factory(
|
181
|
+
cli_arg: str,
|
182
|
+
main_config: types.YAMLDict,
|
183
|
+
cmdopts: types.Cmdopts,
|
184
|
+
batch_input_root: pathlib.Path,
|
185
|
+
**kwargs,
|
186
|
+
) -> PopulationSize:
|
187
|
+
"""Create a :class:`PopulationSize` derived class from the cmdline definition."""
|
188
|
+
max_sizes = population_size.parse(cli_arg)
|
189
|
+
|
190
|
+
if cmdopts["robot_positions"]:
|
191
|
+
positions = [
|
192
|
+
Vector3D.from_str(s, astype=float) for s in cmdopts["robot_positions"]
|
193
|
+
]
|
194
|
+
else:
|
195
|
+
# Get the dimensions of the effective arena from the scenario so we can
|
196
|
+
# place robots randomly within it.
|
197
|
+
kw = utils.gen_scenario_spec(cmdopts, **kwargs)
|
198
|
+
|
199
|
+
xs = random.choices(range(0, kw["arena_x"]), k=max_sizes[-1]) # type: ignore
|
200
|
+
ys = random.choices(range(0, kw["arena_y"]), k=max_sizes[-1]) # type: ignore
|
201
|
+
zs = random.choices(range(0, kw["arena_z"]), k=max_sizes[-1]) # type: ignore
|
202
|
+
positions = [Vector3D(x, y, z) for x, y, z in zip(xs, ys, zs)]
|
203
|
+
|
204
|
+
return PopulationSize(
|
205
|
+
cli_arg,
|
206
|
+
main_config,
|
207
|
+
batch_input_root,
|
208
|
+
cmdopts["robot"],
|
209
|
+
max_sizes,
|
210
|
+
positions,
|
211
|
+
)
|
212
|
+
|
213
|
+
|
214
|
+
__all__ = ["PopulationSize"]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright 2021 John Harwell, All rights reserved.
|
2
|
+
#
|
3
|
+
# SPDX-License-Identifier: MIT
|
4
|
+
"""
|
5
|
+
Container module for the :term:`ROS1+Robot` engine.
|
6
|
+
|
7
|
+
See :ref:`plugins/engine/ros1robot`.
|
8
|
+
"""
|
9
|
+
|
10
|
+
# Core packages
|
11
|
+
|
12
|
+
# 3rd party packages
|
13
|
+
|
14
|
+
# Project packages
|
15
|
+
|
16
|
+
|
17
|
+
def sierra_plugin_type() -> str:
|
18
|
+
return "pipeline"
|