lsst-ctrl-bps 29.2025.3900__tar.gz → 29.2025.4100__tar.gz
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.
- {lsst_ctrl_bps-29.2025.3900/python/lsst_ctrl_bps.egg-info → lsst_ctrl_bps-29.2025.4100}/PKG-INFO +1 -1
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/doc/lsst.ctrl.bps/quickstart.rst +6 -7
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_utils.py +1 -1
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/clustered_quantum_graph.py +48 -61
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/drivers.py +4 -3
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/etc/bps_defaults.yaml +2 -2
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/pre_transform.py +18 -8
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/quantum_clustering_funcs.py +96 -83
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/report.py +14 -1
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/transform.py +6 -18
- lsst_ctrl_bps-29.2025.4100/python/lsst/ctrl/bps/version.py +2 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100/python/lsst_ctrl_bps.egg-info}/PKG-INFO +1 -1
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_clustered_quantum_graph.py +18 -22
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_pre_transform.py +6 -7
- lsst_ctrl_bps-29.2025.3900/python/lsst/ctrl/bps/version.py +0 -2
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/COPYRIGHT +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/LICENSE +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/MANIFEST.in +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/README.md +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/bsd_license.txt +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/doc/lsst.ctrl.bps/CHANGES.rst +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/doc/lsst.ctrl.bps/index.rst +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/gpl-v3.0.txt +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/pyproject.toml +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/__init__.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/__init__.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/__init__.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/_exceptions.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_config.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_draw.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_reports.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cancel.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/__init__.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/bps.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/cmd/__init__.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/cmd/commands.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/__init__.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/arguments.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/option_groups.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/options.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/constants.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/construct.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/generic_workflow.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/initialize.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/ping.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/prepare.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/restart.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/status.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/submit.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/tests/config_test_utils.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/tests/gw_test_utils.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/wms_service.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/SOURCES.txt +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/dependency_links.txt +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/entry_points.txt +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/requires.txt +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/top_level.txt +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/zip-safe +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/setup.cfg +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_bps_reports.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_bps_utils.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_bpsconfig.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_cli_commands.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_construct.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_drivers.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_generic_workflow.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_initialize.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_ping.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_quantum_clustering_funcs.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_report.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_status.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_transform.py +0 -0
- {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_wms_service.py +0 -0
{lsst_ctrl_bps-29.2025.3900/python/lsst_ctrl_bps.egg-info → lsst_ctrl_bps-29.2025.4100}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lsst-ctrl-bps
|
|
3
|
-
Version: 29.2025.
|
|
3
|
+
Version: 29.2025.4100
|
|
4
4
|
Summary: Pluggable execution of workflow graphs from Rubin pipelines.
|
|
5
5
|
Author-email: Rubin Observatory Data Management <dm-admin@lists.lsst.org>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -157,7 +157,7 @@ or a pre-made file containing a serialized QuantumGraph, for example
|
|
|
157
157
|
|
|
158
158
|
.. code-block:: YAML
|
|
159
159
|
|
|
160
|
-
qgraphFile: pipelines_check_w_2020_45.
|
|
160
|
+
qgraphFile: pipelines_check_w_2020_45.qg
|
|
161
161
|
|
|
162
162
|
.. warning::
|
|
163
163
|
|
|
@@ -846,7 +846,7 @@ Supported settings
|
|
|
846
846
|
When to output job QuantumGraph files (default = TRANSFORM).
|
|
847
847
|
|
|
848
848
|
* NEVER = all jobs will use full QuantumGraph file. (Warning: make sure
|
|
849
|
-
runQuantumCommand has ``--qgraph-
|
|
849
|
+
runQuantumCommand has ``--qgraph-node-id {qgraphNodeId}``.)
|
|
850
850
|
* TRANSFORM = Output QuantumGraph files after creating GenericWorkflow.
|
|
851
851
|
* PREPARE = QuantumGraph files are output after creating WMS submission.
|
|
852
852
|
|
|
@@ -904,7 +904,7 @@ Reserved keywords
|
|
|
904
904
|
However, contrary to YAML specification, it is currently not portable.
|
|
905
905
|
|
|
906
906
|
**qgraphId**
|
|
907
|
-
|
|
907
|
+
Ignored; accepted for backwards compatibility.
|
|
908
908
|
|
|
909
909
|
**qgraphNodeId**
|
|
910
910
|
Comma-separated list of internal QuantumGraph node numbers to be
|
|
@@ -1079,13 +1079,12 @@ single full QuantumGraph file plus node numbers for each job. The default is
|
|
|
1079
1079
|
using per-job QuantumGraph files.
|
|
1080
1080
|
|
|
1081
1081
|
To use full QuantumGraph file, the submit YAML must set ``whenSaveJobQgraph`` to
|
|
1082
|
-
"NEVER" and the ``pipetask run`` command must include ``--qgraph-id {
|
|
1083
|
-
--qgraph-node-id {qgraphNodeId}``. For example:
|
|
1082
|
+
"NEVER" and the ``pipetask run`` command must include ``--qgraph-node-id {qgraphNodeId}``. For example:
|
|
1084
1083
|
|
|
1085
1084
|
.. code::
|
|
1086
1085
|
|
|
1087
1086
|
whenSaveJobQgraph: "NEVER"
|
|
1088
|
-
runQuantumCommand: "${CTRL_MPEXEC_DIR}/bin/pipetask --long-log run -b {butlerConfig} --output {output} --output-run {outputRun} --qgraph {qgraphFile} --qgraph-
|
|
1087
|
+
runQuantumCommand: "${CTRL_MPEXEC_DIR}/bin/pipetask --long-log run -b {butlerConfig} --output {output} --output-run {outputRun} --qgraph {qgraphFile} --qgraph-node-id {qgraphNodeId} --skip-init-writes --extend-run --clobber-outputs --skip-existing"
|
|
1089
1088
|
|
|
1090
1089
|
|
|
1091
1090
|
.. warning::
|
|
@@ -1244,7 +1243,7 @@ The major differences to users are:
|
|
|
1244
1243
|
the output run in the provided pre-existing quantum graph.
|
|
1245
1244
|
- ``final_post_finalJob.out``: An internal file for debugging incorrect
|
|
1246
1245
|
reporting of final run status.
|
|
1247
|
-
- ``<qgraph_filename>_orig.
|
|
1246
|
+
- ``<qgraph_filename>_orig.qg``: A backup copy of the original
|
|
1248
1247
|
pre-existing quantum graph file that was used for submitting the run. Note
|
|
1249
1248
|
that this file will *not* be present in the submit directory if the
|
|
1250
1249
|
pipeline YAML specification was used during the submission instead.
|
|
@@ -146,7 +146,7 @@ def create_job_quantum_graph_filename(config, job, out_prefix=None):
|
|
|
146
146
|
found, subdir = config.search("subDirTemplate", opt={"curvals": curvals})
|
|
147
147
|
if not found:
|
|
148
148
|
subdir = "{job.label}"
|
|
149
|
-
full_filename = Path("inputs") / subdir / f"quantum_{job.name}.
|
|
149
|
+
full_filename = Path("inputs") / subdir / f"quantum_{job.name}.qg"
|
|
150
150
|
|
|
151
151
|
if out_prefix is not None:
|
|
152
152
|
full_filename = Path(out_prefix) / full_filename
|
|
@@ -29,18 +29,21 @@
|
|
|
29
29
|
a QuantumGraph.
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
from __future__ import annotations
|
|
33
33
|
|
|
34
|
+
__all__ = ["ClusteredQuantumGraph", "QuantaCluster"]
|
|
34
35
|
|
|
35
36
|
import logging
|
|
36
37
|
import pickle
|
|
37
38
|
import re
|
|
39
|
+
import uuid
|
|
38
40
|
from collections import Counter, defaultdict
|
|
39
41
|
from pathlib import Path
|
|
40
42
|
|
|
41
43
|
from networkx import DiGraph, is_directed_acyclic_graph, is_isomorphic, topological_sort
|
|
42
44
|
|
|
43
|
-
from lsst.pipe.base import
|
|
45
|
+
from lsst.pipe.base.pipeline_graph import TaskImportMode
|
|
46
|
+
from lsst.pipe.base.quantum_graph import PredictedQuantumGraph, QuantumInfo
|
|
44
47
|
from lsst.utils.iteration import ensure_iterable
|
|
45
48
|
|
|
46
49
|
from .bps_draw import draw_networkx_dot
|
|
@@ -79,13 +82,17 @@ class QuantaCluster:
|
|
|
79
82
|
self.tags = {}
|
|
80
83
|
|
|
81
84
|
@classmethod
|
|
82
|
-
def
|
|
83
|
-
|
|
85
|
+
def from_quantum_info(
|
|
86
|
+
cls, quantum_id: uuid.UUID, quantum_info: QuantumInfo, template: str
|
|
87
|
+
) -> QuantaCluster:
|
|
88
|
+
"""Create single quantum cluster from the given quantum information.
|
|
84
89
|
|
|
85
90
|
Parameters
|
|
86
91
|
----------
|
|
87
|
-
|
|
88
|
-
|
|
92
|
+
quantum_id : `uuid.UUID`
|
|
93
|
+
ID of the quantum.
|
|
94
|
+
quantum_info : `lsst.pipe.base.quantum_graph.QuantumInfo`
|
|
95
|
+
Dictionary of additional information about the quantum.
|
|
89
96
|
template : `str`
|
|
90
97
|
Template for creating cluster name.
|
|
91
98
|
|
|
@@ -94,14 +101,13 @@ class QuantaCluster:
|
|
|
94
101
|
cluster : `QuantaCluster`
|
|
95
102
|
Newly created cluster containing the given quantum.
|
|
96
103
|
"""
|
|
97
|
-
label =
|
|
98
|
-
|
|
99
|
-
data_id = quantum_node.quantum.dataId
|
|
104
|
+
label = quantum_info["task_label"]
|
|
105
|
+
data_id = quantum_info["data_id"]
|
|
100
106
|
|
|
101
107
|
# Gather info for name template into a dictionary.
|
|
102
108
|
info = dict(data_id.required)
|
|
103
109
|
info["label"] = label
|
|
104
|
-
info["node_number"] =
|
|
110
|
+
info["node_number"] = quantum_id
|
|
105
111
|
_LOG.debug("template = %s", template)
|
|
106
112
|
_LOG.debug("info for template = %s", info)
|
|
107
113
|
|
|
@@ -116,7 +122,7 @@ class QuantaCluster:
|
|
|
116
122
|
_LOG.debug("template name = %s", name)
|
|
117
123
|
|
|
118
124
|
cluster = QuantaCluster(name, label, info)
|
|
119
|
-
cluster.add_quantum(
|
|
125
|
+
cluster.add_quantum(quantum_id, label)
|
|
120
126
|
return cluster
|
|
121
127
|
|
|
122
128
|
@property
|
|
@@ -130,24 +136,12 @@ class QuantaCluster:
|
|
|
130
136
|
"""Counts of Quanta per taskDef.label in this cluster."""
|
|
131
137
|
return Counter(self._task_label_counts)
|
|
132
138
|
|
|
133
|
-
def add_quantum_node(self, quantum_node):
|
|
134
|
-
"""Add a quantumNode to this cluster.
|
|
135
|
-
|
|
136
|
-
Parameters
|
|
137
|
-
----------
|
|
138
|
-
quantum_node : `lsst.pipe.base.QuantumNode`
|
|
139
|
-
Quantum node to add.
|
|
140
|
-
"""
|
|
141
|
-
_LOG.debug("quantum_node = %s", quantum_node)
|
|
142
|
-
_LOG.debug("quantum_node.nodeId = %s", quantum_node.nodeId)
|
|
143
|
-
self.add_quantum(quantum_node.nodeId, quantum_node.taskDef.label)
|
|
144
|
-
|
|
145
139
|
def add_quantum(self, node_id, task_label):
|
|
146
140
|
"""Add a quantumNode to this cluster.
|
|
147
141
|
|
|
148
142
|
Parameters
|
|
149
143
|
----------
|
|
150
|
-
node_id : `
|
|
144
|
+
node_id : `uuid.UUID`
|
|
151
145
|
ID for quantumNode to be added to cluster.
|
|
152
146
|
task_label : `str`
|
|
153
147
|
Task label for quantumNode to be added to cluster.
|
|
@@ -185,11 +179,10 @@ class ClusteredQuantumGraph:
|
|
|
185
179
|
----------
|
|
186
180
|
name : `str`
|
|
187
181
|
Name to be given to the ClusteredQuantumGraph.
|
|
188
|
-
qgraph : `lsst.pipe.base.
|
|
189
|
-
The
|
|
182
|
+
qgraph : `lsst.pipe.base.quantum_graph.PredictedQuantumGraph`
|
|
183
|
+
The quantum graph to be clustered.
|
|
190
184
|
qgraph_filename : `str`
|
|
191
|
-
Filename for given
|
|
192
|
-
serialized.
|
|
185
|
+
Filename for given quantum graph.
|
|
193
186
|
|
|
194
187
|
Raises
|
|
195
188
|
------
|
|
@@ -203,11 +196,12 @@ class ClusteredQuantumGraph:
|
|
|
203
196
|
use API over totally minimized memory usage.
|
|
204
197
|
"""
|
|
205
198
|
|
|
206
|
-
def __init__(self, name, qgraph, qgraph_filename
|
|
199
|
+
def __init__(self, name: str, qgraph: PredictedQuantumGraph, qgraph_filename: str):
|
|
207
200
|
if "/" in name:
|
|
208
201
|
raise ValueError(f"name cannot have a / ({name})")
|
|
209
202
|
self._name = name
|
|
210
203
|
self._quantum_graph = qgraph
|
|
204
|
+
self._quantum_only_xgraph = qgraph.quantum_only_xgraph
|
|
211
205
|
self._quantum_graph_filename = Path(qgraph_filename).resolve()
|
|
212
206
|
self._cluster_graph = DiGraph()
|
|
213
207
|
|
|
@@ -228,22 +222,27 @@ class ClusteredQuantumGraph:
|
|
|
228
222
|
return False
|
|
229
223
|
if len(self) != len(other):
|
|
230
224
|
return False
|
|
231
|
-
return self.
|
|
225
|
+
return is_isomorphic(self.qxgraph, other.qxgraph) and is_isomorphic(
|
|
232
226
|
self._cluster_graph, other._cluster_graph
|
|
233
227
|
)
|
|
234
228
|
|
|
235
229
|
@property
|
|
236
|
-
def name(self):
|
|
230
|
+
def name(self) -> str:
|
|
237
231
|
"""The name of the ClusteredQuantumGraph."""
|
|
238
232
|
return self._name
|
|
239
233
|
|
|
240
234
|
@property
|
|
241
|
-
def qgraph(self):
|
|
242
|
-
"""The
|
|
235
|
+
def qgraph(self) -> PredictedQuantumGraph:
|
|
236
|
+
"""The quantum graph associated with this Clustered
|
|
243
237
|
QuantumGraph.
|
|
244
238
|
"""
|
|
245
239
|
return self._quantum_graph
|
|
246
240
|
|
|
241
|
+
@property
|
|
242
|
+
def qxgraph(self) -> DiGraph:
|
|
243
|
+
"""A networkx graph of all quanta."""
|
|
244
|
+
return self._quantum_only_xgraph
|
|
245
|
+
|
|
247
246
|
def add_cluster(self, clusters_for_adding):
|
|
248
247
|
"""Add a cluster of quanta as a node in the graph.
|
|
249
248
|
|
|
@@ -286,30 +285,26 @@ class ClusteredQuantumGraph:
|
|
|
286
285
|
raise KeyError(f"{self.name} does not have a cluster named {name}") from ex
|
|
287
286
|
return attr["cluster"]
|
|
288
287
|
|
|
289
|
-
def
|
|
290
|
-
"""Retrieve a
|
|
288
|
+
def get_quantum_info(self, id_: uuid.UUID) -> QuantumInfo:
|
|
289
|
+
"""Retrieve a quantum info dict from the ClusteredQuantumGraph by ID.
|
|
291
290
|
|
|
292
291
|
Parameters
|
|
293
292
|
----------
|
|
294
|
-
id_ : `
|
|
295
|
-
ID of the
|
|
293
|
+
id_ : `uuid.UUID`
|
|
294
|
+
ID of the quantum to retrieve.
|
|
296
295
|
|
|
297
296
|
Returns
|
|
298
297
|
-------
|
|
299
|
-
|
|
300
|
-
|
|
298
|
+
quantum_info : `lsst.pipe.base.quantum_graph.QuantumInfo`
|
|
299
|
+
Quantum info dictionary for the given ID.
|
|
301
300
|
|
|
302
301
|
Raises
|
|
303
302
|
------
|
|
304
303
|
KeyError
|
|
305
304
|
Raised if the ClusteredQuantumGraph does not contain
|
|
306
|
-
a
|
|
305
|
+
a quantum with given ID.
|
|
307
306
|
"""
|
|
308
|
-
|
|
309
|
-
if isinstance(id_, int):
|
|
310
|
-
node_id = NodeId(id, self._quantum_graph.graphID)
|
|
311
|
-
_LOG.debug("get_quantum_node: node_id = %s", node_id)
|
|
312
|
-
return self._quantum_graph.getQuantumNodeByNodeId(node_id)
|
|
307
|
+
return self._quantum_only_xgraph.nodes[id_]
|
|
313
308
|
|
|
314
309
|
def __iter__(self):
|
|
315
310
|
"""Iterate over names of clusters.
|
|
@@ -414,8 +409,8 @@ class ClusteredQuantumGraph:
|
|
|
414
409
|
|
|
415
410
|
def save(self, filename, format_=None):
|
|
416
411
|
"""Save the ClusteredQuantumGraph in a format that is loadable.
|
|
417
|
-
|
|
418
|
-
|
|
412
|
+
|
|
413
|
+
The quantum graph is assumed to have been saved separately.
|
|
419
414
|
|
|
420
415
|
Parameters
|
|
421
416
|
----------
|
|
@@ -433,14 +428,6 @@ class ClusteredQuantumGraph:
|
|
|
433
428
|
if format_ not in {"pickle"}:
|
|
434
429
|
raise RuntimeError(f"Unknown format ({format_})")
|
|
435
430
|
|
|
436
|
-
if not self._quantum_graph_filename:
|
|
437
|
-
# Create filename based on given ClusteredQuantumGraph filename
|
|
438
|
-
self._quantum_graph_filename = path.with_suffix(".qgraph")
|
|
439
|
-
|
|
440
|
-
# If QuantumGraph file doesn't already exist, save it:
|
|
441
|
-
if not Path(self._quantum_graph_filename).exists():
|
|
442
|
-
self._quantum_graph.saveUri(self._quantum_graph_filename)
|
|
443
|
-
|
|
444
431
|
if format_ == "pickle":
|
|
445
432
|
# Don't save QuantumGraph in same file.
|
|
446
433
|
tmp_qgraph = self._quantum_graph
|
|
@@ -503,14 +490,14 @@ class ClusteredQuantumGraph:
|
|
|
503
490
|
cgraph = None
|
|
504
491
|
if format_ == "pickle":
|
|
505
492
|
with open(filename, "rb") as fh:
|
|
506
|
-
cgraph = pickle.load(fh)
|
|
493
|
+
cgraph: ClusteredQuantumGraph = pickle.load(fh)
|
|
507
494
|
|
|
508
495
|
# The QuantumGraph was saved separately
|
|
509
|
-
|
|
510
|
-
cgraph.
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
cgraph._quantum_graph =
|
|
496
|
+
with PredictedQuantumGraph.open(
|
|
497
|
+
cgraph._quantum_graph_filename, import_mode=TaskImportMode.DO_NOT_IMPORT
|
|
498
|
+
) as reader:
|
|
499
|
+
reader.read_thin_graph()
|
|
500
|
+
cgraph._quantum_graph = reader.finish()
|
|
514
501
|
|
|
515
502
|
return cgraph
|
|
516
503
|
|
|
@@ -50,7 +50,7 @@ import logging
|
|
|
50
50
|
import os
|
|
51
51
|
from pathlib import Path
|
|
52
52
|
|
|
53
|
-
from lsst.pipe.base import
|
|
53
|
+
from lsst.pipe.base.quantum_graph import PredictedQuantumGraph
|
|
54
54
|
from lsst.utils.timer import time_this
|
|
55
55
|
from lsst.utils.usage import get_peak_mem_usage
|
|
56
56
|
|
|
@@ -111,7 +111,7 @@ def _init_submission_driver(config_file: str, **kwargs) -> BpsConfig:
|
|
|
111
111
|
return config
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
def acquire_qgraph_driver(config_file: str, **kwargs) -> tuple[BpsConfig,
|
|
114
|
+
def acquire_qgraph_driver(config_file: str, **kwargs) -> tuple[BpsConfig, PredictedQuantumGraph]:
|
|
115
115
|
"""Read a quantum graph from a file or create one from pipeline definition.
|
|
116
116
|
|
|
117
117
|
Parameters
|
|
@@ -125,7 +125,7 @@ def acquire_qgraph_driver(config_file: str, **kwargs) -> tuple[BpsConfig, Quantu
|
|
|
125
125
|
-------
|
|
126
126
|
config : `lsst.ctrl.bps.BpsConfig`
|
|
127
127
|
Updated configuration.
|
|
128
|
-
qgraph : `lsst.pipe.base.
|
|
128
|
+
qgraph : `lsst.pipe.base.quantum_graph.PredictedQuantumGraph`
|
|
129
129
|
A graph representing quanta.
|
|
130
130
|
"""
|
|
131
131
|
config = _init_submission_driver(config_file, **kwargs)
|
|
@@ -451,6 +451,7 @@ def report_driver(wms_service, run_id, user, hist_days, pass_thru, is_global=Fal
|
|
|
451
451
|
hist=hist_days,
|
|
452
452
|
pass_thru=pass_thru,
|
|
453
453
|
is_global=is_global,
|
|
454
|
+
return_exit_codes=return_exit_codes,
|
|
454
455
|
postprocessors=postprocessors,
|
|
455
456
|
)
|
|
456
457
|
|
{lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/etc/bps_defaults.yaml
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#USER pipelineYaml: "${OBS_SUBARU_DIR}/pipelines/DRP.yaml#processCcd"
|
|
2
2
|
# OR
|
|
3
|
-
#USER qgraphFile: "/path/to/existing/file.
|
|
3
|
+
#USER qgraphFile: "/path/to/existing/file.qg"
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
# At minimum, following group used in bps report and can be
|
|
@@ -94,7 +94,7 @@ clusterAlgorithm: lsst.ctrl.bps.quantum_clustering_funcs.single_quantum_clusteri
|
|
|
94
94
|
|
|
95
95
|
# Templates for bps filenames
|
|
96
96
|
submitPath: ${PWD}/submit/{outputRun}
|
|
97
|
-
qgraphFileTemplate: "{uniqProcName}.
|
|
97
|
+
qgraphFileTemplate: "{uniqProcName}.qg"
|
|
98
98
|
subDirTemplate: "{label}/{tract}/{patch}/{band}/{subfilter}/{physical_filter}/{visit}/{exposure}"
|
|
99
99
|
templateDataId: "{tract}_{patch}_{band}_{visit}_{exposure}_{detector}"
|
|
100
100
|
|
{lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/pre_transform.py
RENAMED
|
@@ -38,7 +38,10 @@ import subprocess
|
|
|
38
38
|
from pathlib import Path
|
|
39
39
|
|
|
40
40
|
from lsst.ctrl.bps import BpsConfig, BpsSubprocessError
|
|
41
|
-
from lsst.pipe.base
|
|
41
|
+
from lsst.pipe.base import QuantumGraph
|
|
42
|
+
from lsst.pipe.base.pipeline_graph import TaskImportMode
|
|
43
|
+
from lsst.pipe.base.quantum_graph import PredictedQuantumGraph
|
|
44
|
+
from lsst.resources import ResourcePath
|
|
42
45
|
from lsst.utils import doImport
|
|
43
46
|
from lsst.utils.logging import VERBOSE
|
|
44
47
|
from lsst.utils.timer import time_this, timeMethod
|
|
@@ -47,7 +50,7 @@ _LOG = logging.getLogger(__name__)
|
|
|
47
50
|
|
|
48
51
|
|
|
49
52
|
@timeMethod(logger=_LOG, logLevel=VERBOSE)
|
|
50
|
-
def acquire_quantum_graph(config: BpsConfig, out_prefix: str = "") -> tuple[str,
|
|
53
|
+
def acquire_quantum_graph(config: BpsConfig, out_prefix: str = "") -> tuple[str, PredictedQuantumGraph]:
|
|
51
54
|
"""Read a quantum graph from a file or create one from scratch.
|
|
52
55
|
|
|
53
56
|
Parameters
|
|
@@ -62,8 +65,8 @@ def acquire_quantum_graph(config: BpsConfig, out_prefix: str = "") -> tuple[str,
|
|
|
62
65
|
-------
|
|
63
66
|
qgraph_filename : `str`
|
|
64
67
|
Name of file containing QuantumGraph that was read into qgraph.
|
|
65
|
-
qgraph : `lsst.pipe.base.
|
|
66
|
-
A
|
|
68
|
+
qgraph : `lsst.pipe.base.quantum_graph.PredictedQuantumGraph`
|
|
69
|
+
A quantum graph read in from pre-generated file or one that is the
|
|
67
70
|
result of running code that generates it.
|
|
68
71
|
"""
|
|
69
72
|
# Check to see if user provided pre-generated QuantumGraph.
|
|
@@ -90,8 +93,15 @@ def acquire_quantum_graph(config: BpsConfig, out_prefix: str = "") -> tuple[str,
|
|
|
90
93
|
|
|
91
94
|
_LOG.info("Reading quantum graph from '%s'", qgraph_filename)
|
|
92
95
|
with time_this(log=_LOG, level=logging.INFO, prefix=None, msg="Completed reading quantum graph"):
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
qgraph_path = ResourcePath(qgraph_filename)
|
|
97
|
+
if qgraph_path.getExtension() == ".qg":
|
|
98
|
+
with PredictedQuantumGraph.open(qgraph_path, import_mode=TaskImportMode.DO_NOT_IMPORT) as reader:
|
|
99
|
+
reader.read_thin_graph()
|
|
100
|
+
qgraph = reader.finish()
|
|
101
|
+
elif qgraph_path.getExtension() == ".qgraph":
|
|
102
|
+
qgraph = PredictedQuantumGraph.from_old_quantum_graph(QuantumGraph.loadUri(qgraph_path))
|
|
103
|
+
else:
|
|
104
|
+
raise ValueError(f"Unrecognized extension for quantum graph file: {qgraph_filename}.")
|
|
95
105
|
return qgraph_filename, qgraph
|
|
96
106
|
|
|
97
107
|
|
|
@@ -244,8 +254,8 @@ def cluster_quanta(config, qgraph, name):
|
|
|
244
254
|
----------
|
|
245
255
|
config : `lsst.ctrl.bps.BpsConfig`
|
|
246
256
|
BPS configuration.
|
|
247
|
-
qgraph : `lsst.pipe.base.
|
|
248
|
-
Original full
|
|
257
|
+
qgraph : `lsst.pipe.base.quantum_graph.PredictedQuantumGraph`
|
|
258
|
+
Original full quantum graph for the run.
|
|
249
259
|
name : `str`
|
|
250
260
|
Name for the ClusteredQuantumGraph that will be generated.
|
|
251
261
|
|