sierra-research 1.3.11__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.11.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 -251
  191. sierra/core/graphs/stacked_surface_graph.py +0 -220
  192. sierra/core/graphs/summary_line_graph.py +0 -371
  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 -320
  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.11.data/data/share/man/man1/sierra-cli.1 +0 -2349
  244. sierra_research-1.3.11.data/data/share/man/man7/sierra-examples.7 +0 -508
  245. sierra_research-1.3.11.data/data/share/man/man7/sierra-exec-envs.7 +0 -331
  246. sierra_research-1.3.11.data/data/share/man/man7/sierra-glossary.7 +0 -285
  247. sierra_research-1.3.11.data/data/share/man/man7/sierra-platforms.7 +0 -358
  248. sierra_research-1.3.11.data/data/share/man/man7/sierra-usage.7 +0 -729
  249. sierra_research-1.3.11.data/data/share/man/man7/sierra.7 +0 -78
  250. sierra_research-1.3.11.dist-info/METADATA +0 -492
  251. sierra_research-1.3.11.dist-info/RECORD +0 -133
  252. sierra_research-1.3.11.dist-info/top_level.txt +0 -1
  253. {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info}/entry_points.txt +0 -0
  254. {sierra_research-1.3.11.dist-info → sierra_research-1.5.0.dist-info/licenses}/LICENSE +0 -0
@@ -0,0 +1,270 @@
1
+ # Copyright 2019 John Harwell, All rights reserved.
2
+ #
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ """Classes for creating image files from ``.mean`` files for experiments.
6
+
7
+ See :ref:`plugins/proc/imagize` for usage documentation.
8
+
9
+ """
10
+
11
+ # Core packages
12
+ import multiprocessing as mp
13
+ import logging
14
+ import pathlib
15
+ import typing as tp
16
+
17
+ # 3rd party packages
18
+ import yaml
19
+
20
+ # Project packages
21
+ import sierra.core.variables.batch_criteria as bc
22
+ from sierra.core import types, utils, batchroot, graphs, config
23
+ from sierra.core.pipeline.stage3 import gather
24
+ from sierra.plugins.proc.statistics import plugin as statistics
25
+ import sierra.core.plugin as pm
26
+
27
+ _logger = logging.getLogger(__name__)
28
+
29
+
30
+ def proc_batch_exp(
31
+ main_config: types.YAMLDict,
32
+ cmdopts: types.Cmdopts,
33
+ pathset: batchroot.PathSet,
34
+ criteria: bc.XVarBatchCriteria,
35
+ ) -> None:
36
+ """
37
+ Generate images for each :term:`Experiment` in the :term:`Batch Experiment`.
38
+
39
+ Ideally this is done in parallel across experiments, but this can be changed
40
+ to serial if memory on the SIERRA host machine is limited via
41
+ ``--processing-parallelism``.
42
+ """
43
+ config_path = pathlib.Path(cmdopts["project_config_root"]) / pathlib.Path(
44
+ config.kYAML.graphs
45
+ )
46
+ if utils.path_exists(config_path):
47
+ _logger.info("Loading imagizing config for project=%s", cmdopts["project"])
48
+ imagize_config = yaml.load(utils.utf8open(config_path), yaml.FullLoader)[
49
+ "imagize"
50
+ ]
51
+ else:
52
+ _logger.warning("%s does not exist--cannot imagize", config_path)
53
+ return
54
+
55
+ if not cmdopts["imagize_no_stats"]:
56
+ statistics.proc_batch_exp(
57
+ main_config, cmdopts, pathset, criteria, ImagizeInputGatherer
58
+ )
59
+
60
+ exp_to_imagize = utils.exp_range_calc(
61
+ cmdopts["exp_range"], pathset.output_root, criteria.gen_exp_names()
62
+ )
63
+
64
+ parallelism = cmdopts["processing_parallelism"]
65
+
66
+ tasks = []
67
+ for exp in exp_to_imagize:
68
+ exp_stat_root = pathset.stat_root / exp.name
69
+ exp_imagize_root = pathset.imagize_root / exp.name
70
+
71
+ tasks.extend(
72
+ _build_tasklist_for_exp(
73
+ exp_stat_root, exp_imagize_root, imagize_config, cmdopts["storage"]
74
+ )
75
+ )
76
+
77
+ # 2025-06-06 [JRH]: This works around what is apparently a nasty memory leak
78
+ # in hv caused by the hv.save() function for which the usual methods of
79
+ # clearing memory/figures do not work. The maxtasksperchild argument +
80
+ # chunksize kills all the child threads periodically, which fixes the leak
81
+ # problem, for now.
82
+ _logger.debug("Starting %s workers, method=%s", parallelism, mp.get_start_method())
83
+ with mp.Pool(processes=parallelism, maxtasksperchild=1) as pool:
84
+ processed = pool.starmap_async(_worker, tasks, chunksize=10)
85
+
86
+ _logger.debug("Waiting for workers to finish")
87
+ processed.get()
88
+
89
+ _logger.debug("All workers finished")
90
+
91
+
92
+ def _build_tasklist_for_exp(
93
+ exp_stat_root: pathlib.Path,
94
+ exp_imagize_root: pathlib.Path,
95
+ imagize_config: types.YAMLDict,
96
+ storage: str,
97
+ ) -> tp.List[tp.Tuple[dict, types.YAMLDict]]:
98
+ """Add all files from experiment to multiprocessing queue for processing.
99
+
100
+ Enqueueing for processing is done at the file-level rather than
101
+ per-experiment, so that for systems with more CPUs than experiments you
102
+ still get maximum throughput.
103
+ """
104
+ res = []
105
+ # For each graph in each category
106
+ for graph in imagize_config:
107
+ candidate = exp_stat_root / dict(graph)["src_stem"]
108
+
109
+ if not candidate.is_dir():
110
+ _logger.debug(
111
+ "Configured imagize source <batch stat root>/%s does not exist",
112
+ (candidate.relative_to(exp_stat_root)),
113
+ )
114
+ continue
115
+
116
+ imagize_output_root = exp_imagize_root / candidate.relative_to(exp_stat_root)
117
+ utils.dir_create_checked(imagize_output_root, exist_ok=True)
118
+
119
+ for fpath in candidate.iterdir():
120
+ assert (
121
+ fpath.is_file()
122
+ ), f"Imagize directory {candidate} must only contain files!"
123
+
124
+ res.append(
125
+ (
126
+ {
127
+ "input_path": fpath,
128
+ "graph_stem": candidate.relative_to(exp_stat_root),
129
+ "imagize_output_root": imagize_output_root,
130
+ "batch_root": exp_stat_root.parent.parent,
131
+ "storage": storage,
132
+ },
133
+ imagize_config,
134
+ )
135
+ )
136
+
137
+ return res
138
+
139
+
140
+ def _worker(imagize_opts: dict, imagize_config: types.YAMLDict) -> None:
141
+ _proc_single_exp(imagize_config, imagize_opts)
142
+
143
+
144
+ def _proc_single_exp(imagize_config: types.YAMLDict, imagize_opts: dict) -> None:
145
+ """Create images from the averaged ``.mean`` files from a single experiment.
146
+
147
+ If no ``.mean`` files suitable for averaging are found, nothing is done. See
148
+ :ref:`plugins/proc/imagize` for per-engine descriptions of what
149
+ "suitable" means.
150
+
151
+ Arguments:
152
+
153
+ imagize_config: Parsed YAML configuration for heatmaps.
154
+
155
+ imagize_opts: Dictionary of imagizing options.
156
+ """
157
+
158
+ match = None
159
+ for graph in imagize_config:
160
+ if dict(graph)["src_stem"] == str(imagize_opts["graph_stem"]):
161
+ match = graph
162
+
163
+ if match is not None:
164
+ graph_pathset = graphs.PathSet(
165
+ input_root=imagize_opts["input_path"].parent,
166
+ output_root=imagize_opts["imagize_output_root"],
167
+ model_root=None,
168
+ batchroot=imagize_opts["batch_root"],
169
+ )
170
+
171
+ # 2025-06-05 [JRH]: We always write stage {3,4} output data files as
172
+ # .csv because that is currently SIERRA's 'native' format; this may
173
+ # change in the future.
174
+ #
175
+ # Input paths are of the form <dir>/<dir>_<NUMBER>.{extension}
176
+ graphs.heatmap(
177
+ pathset=graph_pathset,
178
+ input_stem=imagize_opts["input_path"].stem,
179
+ output_stem=imagize_opts["input_path"].stem,
180
+ title=dict(match)["title"],
181
+ medium="storage.csv",
182
+ xlabel="X",
183
+ ylabel="Y",
184
+ colnames=(
185
+ match.get("x", "x"),
186
+ match.get("y", "y"),
187
+ match.get("z", "z"),
188
+ ),
189
+ backend="matplotlib",
190
+ )
191
+
192
+ else:
193
+ _logger.warning(
194
+ "No match for graph with src_stem='%s' found in configuration",
195
+ imagize_opts["graph_stem"],
196
+ )
197
+
198
+
199
+ class ImagizeInputGatherer(gather.BaseGatherer):
200
+ """Gather :term:`Raw Output Data` files from all runs for imagizing.
201
+
202
+ The configured output directory for each run is searched recursively for
203
+ directories containing files to gather. To be eligible for gathering and
204
+ later processing, files must:
205
+
206
+ - Be in a directory with the same name as the file, sans extension.
207
+
208
+ - Be non-empty
209
+
210
+ - Have a suffix which supported by the selected ``--storage`` plugin.
211
+
212
+ Recursive nesting of files *within* a directory containing files to imagize
213
+ is not supported--why would you do this anyway?
214
+ """
215
+
216
+ def __init__(
217
+ self,
218
+ main_config: types.YAMLDict,
219
+ gather_opts: types.SimpleDict,
220
+ processq: mp.Queue,
221
+ ) -> None:
222
+ super().__init__(main_config, gather_opts, processq)
223
+ self.logger = logging.getLogger(__name__)
224
+
225
+ self.config_path = (
226
+ pathlib.Path(gather_opts["project_config_root"]) / config.kYAML.graphs
227
+ )
228
+
229
+ self.imagize_config = yaml.load(
230
+ utils.utf8open(self.config_path), yaml.FullLoader
231
+ )["imagize"]
232
+
233
+ def calc_gather_items(
234
+ self, run_output_root: pathlib.Path, exp_name: str
235
+ ) -> tp.List[gather.GatherSpec]:
236
+ to_gather = []
237
+ proj_output_root = run_output_root / str(self.run_metrics_leaf)
238
+ plugin = pm.pipeline.get_plugin_module(self.gather_opts["storage"])
239
+
240
+ for item in proj_output_root.rglob("*"):
241
+ if not item.is_dir():
242
+ continue
243
+
244
+ for imagizable in item.iterdir():
245
+ if (
246
+ not any(s in plugin.suffixes() for s in imagizable.suffixes)
247
+ and imagizable.stat().st_size > 0
248
+ ):
249
+ continue
250
+
251
+ if not any(
252
+ g["src_stem"] in str(imagizable) for g in self.imagize_config
253
+ ):
254
+ continue
255
+
256
+ if item.name in imagizable.name:
257
+ to_gather.append(
258
+ gather.GatherSpec(
259
+ exp_name=exp_name,
260
+ item_stem_path=imagizable.relative_to(proj_output_root),
261
+ collate_col=None,
262
+ )
263
+ )
264
+
265
+ return to_gather
266
+
267
+
268
+ __all__ = [
269
+ "proc_batch_exp",
270
+ ]
@@ -0,0 +1,16 @@
1
+ #
2
+ # Copyright 2025 John Harwell, All rights reserved.
3
+ #
4
+ # SPDX-License Identifier: MIT
5
+ #
6
+ "Plugin for running models during stage 3."
7
+
8
+ # Core packages
9
+
10
+ # 3rd party packages
11
+
12
+ # Project packages
13
+
14
+
15
+ def sierra_plugin_type() -> str:
16
+ return "pipeline"
@@ -0,0 +1,250 @@
1
+ #
2
+ # Copyright 2025 John Harwell, All rights reserved.
3
+ #
4
+ # SPDX-License Identifier: MIT
5
+ #
6
+ """Functionality for runner different types of models.
7
+
8
+ See :ref:`plugins/proc/modelrunner` for usage documentation.
9
+
10
+ """
11
+ # Core packages
12
+ import pathlib
13
+ import time
14
+ import datetime
15
+ import typing as tp
16
+ import logging
17
+
18
+ # 3rd party packages
19
+ import yaml
20
+
21
+ # Project packages
22
+ from sierra.core import config, utils, types, batchroot, storage, exproot
23
+ from sierra.core.variables import batch_criteria as bc
24
+ from sierra.core import plugin as pm
25
+ from sierra.core.models import interface
26
+
27
+ _logger = logging.getLogger(__name__)
28
+
29
+
30
+ def proc_batch_exp(
31
+ main_config: types.YAMLDict,
32
+ cmdopts: types.Cmdopts,
33
+ pathset: batchroot.PathSet,
34
+ criteria: bc.XVarBatchCriteria,
35
+ ) -> None:
36
+ """
37
+ Run all intra- and inter-exp models.
38
+ """
39
+ models = _load_models(main_config, cmdopts, "intra")
40
+
41
+ _logger.info("Running %d intra-experiment models...", len(models))
42
+ start = time.time()
43
+ _run_intra_exp(cmdopts, pathset, models, criteria)
44
+ elapsed = int(time.time() - start)
45
+ sec = datetime.timedelta(seconds=elapsed)
46
+ _logger.info("Intra-experiment models finished in %s", str(sec))
47
+
48
+ models = _load_models(main_config, cmdopts, "inter")
49
+
50
+ _logger.info("Running %d inter-experiment models...", len(models))
51
+ start = time.time()
52
+
53
+ _run_inter_exp(cmdopts, pathset, models, criteria)
54
+
55
+ elapsed = int(time.time() - start)
56
+ sec = datetime.timedelta(seconds=elapsed)
57
+ _logger.info("Inter-experiment models finished in %s", str(sec))
58
+
59
+
60
+ def _load_models(
61
+ main_config: types.YAMLDict, cmdopts: types.Cmdopts, model_type: str
62
+ ) -> tp.Dict[str, tp.Union[tp.Dict[str, tp.Any]]]:
63
+ project_models = pathlib.Path(cmdopts["project_config_root"]) / config.kYAML.models
64
+ loaded = {}
65
+
66
+ _logger.info("Loading %s-exp models for project %s", model_type, cmdopts["project"])
67
+
68
+ models_config = yaml.load(utils.utf8open(project_models), yaml.FullLoader)
69
+
70
+ # This is ALL model plugins found by SIERRA.
71
+ loaded_model_plugins = [
72
+ p
73
+ for p in pm.pipeline.loaded_plugins()
74
+ if pm.pipeline.loaded_plugins()[p]["type"] == "model"
75
+ ]
76
+ _logger.debug(
77
+ "%d loaded model plugins on SIERRA_PLUGIN_PATH", len(loaded_model_plugins)
78
+ )
79
+
80
+ for plugin_name in loaded_model_plugins:
81
+ # This is all available models for a specific plugin
82
+ module = pm.module_load(plugin_name)
83
+ available_models = getattr(module, "sierra_models")(model_type)
84
+ _logger.debug(
85
+ "Loaded model plugin %s has %d %s-exp models: %s",
86
+ plugin_name,
87
+ len(available_models) if available_models else 0,
88
+ model_type,
89
+ available_models,
90
+ )
91
+ if models_config.get(f"{model_type}-exp"):
92
+ for conf in models_config[f"{model_type}-exp"]:
93
+
94
+ # Class name of the model is the last part of the dot-separated
95
+ # path, and plays no part in module lookup in the python
96
+ # interpreter.
97
+ model_name = conf["name"].split(".")[-1]
98
+
99
+ # The part of the model name which is relative to the plugin
100
+ # directory in which it should be found.
101
+ model_module_relpath = ".".join(conf["name"].split(".")[:-1])
102
+ model_path = "{0}.{1}".format(plugin_name, model_module_relpath)
103
+ model_fullpath = f"{model_module_relpath}.{model_name}"
104
+ if pm.module_exists(model_path):
105
+ _logger.debug(
106
+ "Loading %s-exp model %s using path %s: YAML configuration match",
107
+ model_type,
108
+ model_name,
109
+ model_module_relpath,
110
+ )
111
+ model_params = {
112
+ k: v for k, v in conf.items() if k not in ["name", "targets"]
113
+ }
114
+ loaded[model_fullpath] = {
115
+ "targets": conf["targets"],
116
+ "legend": (
117
+ conf["legend"]
118
+ if "legend" in conf
119
+ else ["Model Prediction" for t in conf["targets"]]
120
+ ),
121
+ "model": getattr(pm.module_load(model_path), model_name)(
122
+ model_params
123
+ ),
124
+ }
125
+
126
+ else:
127
+ _logger.debug("All %s-exp models disabled: no configuration", model_type)
128
+
129
+ if len(loaded) > 0:
130
+ _logger.info(
131
+ "Loaded %s-exp %s models for project %s",
132
+ len(loaded),
133
+ model_type,
134
+ cmdopts["project"],
135
+ )
136
+
137
+ return loaded
138
+
139
+
140
+ def _run_intra_exp(
141
+ cmdopts: types.Cmdopts,
142
+ pathset: batchroot.PathSet,
143
+ to_run: tp.Dict[str, tp.Dict[str, tp.Any]],
144
+ criteria: bc.XVarBatchCriteria,
145
+ ) -> None:
146
+ """
147
+ Run all enabled intra-experiment models for all experiments in a batch.
148
+ """
149
+ exp_dirnames = criteria.gen_exp_names()
150
+ exp_to_run = utils.exp_range_calc(
151
+ cmdopts["exp_range"], pathset.output_root, exp_dirnames
152
+ )
153
+
154
+ for exp in exp_to_run:
155
+ exp_index = exp_dirnames.index(exp.name)
156
+ exproots = exproot.PathSet(pathset, exp.name, exp_dirnames[0])
157
+
158
+ utils.dir_create_checked(exproots.model_root, exist_ok=True)
159
+
160
+ for blob in to_run.values():
161
+ _run_intra_single_in_exp(criteria, cmdopts, exproots, exp_index, blob)
162
+
163
+
164
+ def _run_intra_single_in_exp(
165
+ criteria: bc.XVarBatchCriteria,
166
+ cmdopts: types.Cmdopts,
167
+ pathset: exproot.PathSet,
168
+ exp_index: int,
169
+ blob: tp.Dict[str, tp.Union[interface.IIntraExpModel1D, tp.List[str]]],
170
+ ) -> None:
171
+ model = blob["model"]
172
+ targets = blob["targets"]
173
+ if not model.should_run(criteria, cmdopts, exp_index):
174
+ _logger.debug(
175
+ "Skip running intra-experiment model from '%s' for exp%s",
176
+ str(model),
177
+ exp_index,
178
+ )
179
+ return
180
+
181
+ # Run the model
182
+ _logger.debug(
183
+ "Run intra-experiment model %s for %s",
184
+ str(model),
185
+ pathset.input_root.name,
186
+ )
187
+ dfs = model.run(criteria, exp_index, cmdopts, pathset)
188
+ legend = blob["legend"]
189
+
190
+ for df, target in zip(dfs, targets):
191
+ path_stem = pathset.model_root / target
192
+
193
+ # Write model legend file so the generated graph can find it
194
+ idx = dfs.index(df)
195
+ with utils.utf8open(
196
+ path_stem.with_suffix(config.kModelsExt["legend"]), "w"
197
+ ) as f:
198
+ f.write(legend[idx])
199
+
200
+ # Write model .csv file
201
+ storage.df_write(
202
+ df,
203
+ path_stem.with_suffix(config.kModelsExt["model"]),
204
+ "storage.csv",
205
+ index=False,
206
+ )
207
+
208
+
209
+ def _run_inter_exp(
210
+ cmdopts: types.Cmdopts,
211
+ pathset: batchroot.PathSet,
212
+ to_run: tp.Dict[str, tp.Any],
213
+ criteria: bc.XVarBatchCriteria,
214
+ ) -> None:
215
+ utils.dir_create_checked(pathset.model_interexp_root, exist_ok=True)
216
+
217
+ for blob in to_run.values():
218
+ model = blob["model"]
219
+ legend = blob["legend"]
220
+ targets = blob["targets"]
221
+
222
+ if not model.should_run(criteria, cmdopts):
223
+ _logger.debug("Skip running inter-experiment model '%s'", str(model))
224
+ continue
225
+
226
+ # Run the model
227
+ _logger.debug("Run inter-experiment model '%s'", str(model))
228
+
229
+ dfs = model.run(criteria, cmdopts, pathset)
230
+
231
+ for df, csv_stem in zip(dfs, targets):
232
+ path_stem = pathset.model_interexp_root / csv_stem
233
+ utils.dir_create_checked(path_stem.parent, exist_ok=True)
234
+
235
+ # Write model .csv file
236
+ storage.df_write(
237
+ df,
238
+ path_stem.with_suffix(config.kModelsExt["model"]),
239
+ "storage.csv",
240
+ index=True,
241
+ )
242
+
243
+ idx = dfs.index(df)
244
+ with utils.utf8open(
245
+ path_stem.with_suffix(config.kModelsExt["legend"]), "w"
246
+ ) as f:
247
+ f.write(legend[idx])
248
+
249
+
250
+ __all__ = ["proc_batch_exp"]
@@ -0,0 +1,15 @@
1
+ #
2
+ # Copyright 2025 John Harwell, All rights reserved.
3
+ #
4
+ # SPDX-License Identifier: MIT
5
+ #
6
+ """Container module for the statistics generation data processing plugin."""
7
+ # Core packages
8
+
9
+ # 3rd party packages
10
+
11
+ # Project packages
12
+
13
+
14
+ def sierra_plugin_type() -> str:
15
+ return "pipeline"
@@ -0,0 +1,64 @@
1
+ #
2
+ # Copyright 2025 John Harwell, All rights reserved.
3
+ #
4
+ # SPDX-License Identifier: MIT
5
+ #
6
+
7
+ # Core packages
8
+ import typing as tp
9
+ import argparse
10
+
11
+ # 3rd party packages
12
+
13
+ # Project packages
14
+ from sierra.core import types
15
+ from sierra.plugins import PluginCmdline
16
+
17
+
18
+ def build(
19
+ parents: tp.List[argparse.ArgumentParser], stages: tp.List[int]
20
+ ) -> PluginCmdline:
21
+ """
22
+ Get a cmdline supporting the ``proc.statistics`` plugin.
23
+ """
24
+ cmdline = PluginCmdline(parents, stages)
25
+ cmdline.multistage.add_argument(
26
+ "--dist-stats",
27
+ choices=["none", "all", "conf95", "bw"],
28
+ help="""
29
+ Specify what kinds of statistics, if any, should be calculated on
30
+ the distribution of experimental data during stage 3 for inclusion
31
+ on graphs during stage 4:
32
+
33
+ - ``none`` - Only calculate and show raw mean on graphs.
34
+
35
+ - ``conf95`` - Calculate standard deviation of experimental
36
+ distribution and show 95%% confidence interval on relevant
37
+ graphs.
38
+
39
+ - ``bw`` - Calculate statistics necessary to show box and
40
+ whisker plots around each point in the graph (Summary Line
41
+ graphs only).
42
+
43
+ - ``all`` - Generate all possible statistics, and plot all
44
+ possible statistics on graphs.
45
+ """
46
+ + cmdline.graphs_applicable_doc(
47
+ [
48
+ ":py:func:`Summary Line <sierra.core.graphs.summary_line.generate>`",
49
+ ":py:func:`Stacked Line <sierra.core.graphs.stacked_line.generate>`",
50
+ ]
51
+ )
52
+ + cmdline.stage_usage_doc([3, 4, 5]),
53
+ default="none",
54
+ )
55
+
56
+ return cmdline
57
+
58
+
59
+ def to_cmdopts(args: argparse.Namespace) -> types.Cmdopts:
60
+ return {"dist_stats": args.dist_stats}
61
+
62
+
63
+ def sphinx_cmdline_multistage():
64
+ return build([], [3, 4, 5]).parser