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.
Files changed (73) hide show
  1. {lsst_ctrl_bps-29.2025.3900/python/lsst_ctrl_bps.egg-info → lsst_ctrl_bps-29.2025.4100}/PKG-INFO +1 -1
  2. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/doc/lsst.ctrl.bps/quickstart.rst +6 -7
  3. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_utils.py +1 -1
  4. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/clustered_quantum_graph.py +48 -61
  5. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/drivers.py +4 -3
  6. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/etc/bps_defaults.yaml +2 -2
  7. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/pre_transform.py +18 -8
  8. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/quantum_clustering_funcs.py +96 -83
  9. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/report.py +14 -1
  10. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/transform.py +6 -18
  11. lsst_ctrl_bps-29.2025.4100/python/lsst/ctrl/bps/version.py +2 -0
  12. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100/python/lsst_ctrl_bps.egg-info}/PKG-INFO +1 -1
  13. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_clustered_quantum_graph.py +18 -22
  14. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_pre_transform.py +6 -7
  15. lsst_ctrl_bps-29.2025.3900/python/lsst/ctrl/bps/version.py +0 -2
  16. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/COPYRIGHT +0 -0
  17. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/LICENSE +0 -0
  18. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/MANIFEST.in +0 -0
  19. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/README.md +0 -0
  20. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/bsd_license.txt +0 -0
  21. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/doc/lsst.ctrl.bps/CHANGES.rst +0 -0
  22. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/doc/lsst.ctrl.bps/index.rst +0 -0
  23. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/gpl-v3.0.txt +0 -0
  24. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/pyproject.toml +0 -0
  25. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/__init__.py +0 -0
  26. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/__init__.py +0 -0
  27. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/__init__.py +0 -0
  28. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/_exceptions.py +0 -0
  29. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_config.py +0 -0
  30. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_draw.py +0 -0
  31. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/bps_reports.py +0 -0
  32. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cancel.py +0 -0
  33. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/__init__.py +0 -0
  34. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/bps.py +0 -0
  35. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/cmd/__init__.py +0 -0
  36. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/cmd/commands.py +0 -0
  37. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/__init__.py +0 -0
  38. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/arguments.py +0 -0
  39. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/option_groups.py +0 -0
  40. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/cli/opt/options.py +0 -0
  41. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/constants.py +0 -0
  42. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/construct.py +0 -0
  43. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/generic_workflow.py +0 -0
  44. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/initialize.py +0 -0
  45. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/ping.py +0 -0
  46. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/prepare.py +0 -0
  47. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/restart.py +0 -0
  48. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/status.py +0 -0
  49. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/submit.py +0 -0
  50. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/tests/config_test_utils.py +0 -0
  51. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/tests/gw_test_utils.py +0 -0
  52. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst/ctrl/bps/wms_service.py +0 -0
  53. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/SOURCES.txt +0 -0
  54. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/dependency_links.txt +0 -0
  55. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/entry_points.txt +0 -0
  56. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/requires.txt +0 -0
  57. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/top_level.txt +0 -0
  58. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/python/lsst_ctrl_bps.egg-info/zip-safe +0 -0
  59. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/setup.cfg +0 -0
  60. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_bps_reports.py +0 -0
  61. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_bps_utils.py +0 -0
  62. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_bpsconfig.py +0 -0
  63. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_cli_commands.py +0 -0
  64. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_construct.py +0 -0
  65. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_drivers.py +0 -0
  66. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_generic_workflow.py +0 -0
  67. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_initialize.py +0 -0
  68. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_ping.py +0 -0
  69. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_quantum_clustering_funcs.py +0 -0
  70. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_report.py +0 -0
  71. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_status.py +0 -0
  72. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_transform.py +0 -0
  73. {lsst_ctrl_bps-29.2025.3900 → lsst_ctrl_bps-29.2025.4100}/tests/test_wms_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lsst-ctrl-bps
3
- Version: 29.2025.3900
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.qgraph
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-id {qgraphId} --qgraph-node-id {qgraphNodeId}``.)
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
- Internal ID for the full QuantumGraph (passed as ``--qgraph-id`` on pipetask command line).
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 {qgraphId}
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-id {qgraphId} --qgraph-node-id {qgraphNodeId} --skip-init-writes --extend-run --clobber-outputs --skip-existing"
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.qgraph``: A backup copy of the original
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}.qgraph"
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
- __all__ = ["ClusteredQuantumGraph", "QuantaCluster"]
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 NodeId, QuantumGraph
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 from_quantum_node(cls, quantum_node, template):
83
- """Create single quantum cluster from given quantum node.
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
- quantum_node : `lsst.pipe.base.QuantumNode`
88
- QuantumNode for which to make into a single quantum cluster.
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 = quantum_node.taskDef.label
98
- node_id = quantum_node.nodeId
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"] = node_id
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(quantum_node.nodeId, label)
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 : `lsst.pipe.base.NodeId`
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.QuantumGraph`
189
- The QuantumGraph to be clustered.
182
+ qgraph : `lsst.pipe.base.quantum_graph.PredictedQuantumGraph`
183
+ The quantum graph to be clustered.
190
184
  qgraph_filename : `str`
191
- Filename for given QuantumGraph if it has already been
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=None):
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._quantum_graph == other._quantum_graph and is_isomorphic(
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 QuantumGraph associated with this Clustered
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 get_quantum_node(self, id_):
290
- """Retrieve a QuantumNode from the ClusteredQuantumGraph by ID.
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_ : `lsst.pipe.base.NodeId` or int
295
- ID of the QuantumNode to retrieve.
293
+ id_ : `uuid.UUID`
294
+ ID of the quantum to retrieve.
296
295
 
297
296
  Returns
298
297
  -------
299
- quantum_node : `lsst.pipe.base.QuantumNode`
300
- QuantumNode matching given ID.
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 QuantumNode with given ID.
305
+ a quantum with given ID.
307
306
  """
308
- node_id = id_
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
- The QuantumGraph is saved separately if hasn't already been
418
- serialized.
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
- try:
510
- cgraph._quantum_graph = QuantumGraph.loadUri(cgraph._quantum_graph_filename)
511
- except FileNotFoundError: # Try same path as ClusteredQuantumGraph
512
- new_filename = path.parent / Path(cgraph._quantum_graph_filename).name
513
- cgraph._quantum_graph = QuantumGraph.loadUri(new_filename)
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 QuantumGraph
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, QuantumGraph]:
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.graph.QuantumGraph`
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
 
@@ -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.qgraph"
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}.qgraph"
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
 
@@ -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.graph import QuantumGraph
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, QuantumGraph]:
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.graph.QuantumGraph`
66
- A QuantumGraph read in from pre-generated file or one that is the
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
- qgraph = QuantumGraph.loadUri(qgraph_filename)
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.QuantumGraph`
248
- Original full QuantumGraph for the run.
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