LSST Applications g042eb84c57+730a74494b,g04e9c324dd+8c5ae1fdc5,g134cb467dc+1f1e3e7524,g199a45376c+0ba108daf9,g1fd858c14a+fa7d31856b,g210f2d0738+f66ac109ec,g262e1987ae+83a3acc0e5,g29ae962dfc+d856a2cb1f,g2cef7863aa+aef1011c0b,g35bb328faa+8c5ae1fdc5,g3fd5ace14f+a1e0c9f713,g47891489e3+0d594cb711,g4d44eb3520+c57ec8f3ed,g4d7b6aa1c5+f66ac109ec,g53246c7159+8c5ae1fdc5,g56a1a4eaf3+fd7ad03fde,g64539dfbff+f66ac109ec,g67b6fd64d1+0d594cb711,g67fd3c3899+f66ac109ec,g6985122a63+0d594cb711,g74acd417e5+3098891321,g786e29fd12+668abc6043,g81db2e9a8d+98e2ab9f28,g87389fa792+8856018cbb,g89139ef638+0d594cb711,g8d7436a09f+80fda9ce03,g8ea07a8fe4+760ca7c3fc,g90f42f885a+033b1d468d,g97be763408+a8a29bda4b,g99822b682c+e3ec3c61f9,g9d5c6a246b+0d5dac0c3d,ga41d0fce20+9243b26dd2,gbf99507273+8c5ae1fdc5,gd7ef33dd92+0d594cb711,gdab6d2f7ff+3098891321,ge410e46f29+0d594cb711,geaed405ab2+c4bbc419c6,gf9a733ac38+8c5ae1fdc5,w.2025.38
LSST Data Management Base Package
Loading...
Searching...
No Matches
deblendCoaddSourcesPipeline.py
Go to the documentation of this file.
1# This file is part of pipe_tasks.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22__all__ = ["DeblendCoaddSourcesMultiConfig", "DeblendCoaddSourcesMultiTask"]
23
24import numpy as np
25
26from lsst.pipe.base import PipelineTask, PipelineTaskConfig, PipelineTaskConnections
27import lsst.pipe.base.connectionTypes as cT
28
29from lsst.pex.config import ConfigurableField, Field
30from lsst.meas.base import SkyMapIdGeneratorConfig
31from lsst.meas.extensions.scarlet import ScarletDeblendTask
32
33import lsst.afw.image as afwImage
34import lsst.afw.table as afwTable
35
36from .coaddBase import reorderRefs
37
38
39deblendBaseTemplates = {"inputCoaddName": "deep", "outputCoaddName": "deep"}
40
41
42class DeblendCoaddSourcesMultiConnections(PipelineTaskConnections,
43 dimensions=("tract", "patch", "skymap"),
44 defaultTemplates=deblendBaseTemplates):
45 inputSchema = cT.InitInput(
46 doc="Input schema to use in the deblend catalog",
47 name="{inputCoaddName}Coadd_mergeDet_schema",
48 storageClass="SourceCatalog"
49 )
50 peakSchema = cT.InitInput(
51 doc="Schema of the footprint peak catalogs",
52 name="{inputCoaddName}Coadd_peak_schema",
53 storageClass="PeakCatalog"
54 )
55 mergedDetections = cT.Input(
56 doc="Detection catalog merged across bands",
57 name="{inputCoaddName}Coadd_mergeDet",
58 storageClass="SourceCatalog",
59 dimensions=("tract", "patch", "skymap")
60 )
61 coadds = cT.Input(
62 doc="Exposure on which to run deblending",
63 name="{inputCoaddName}Coadd_calexp",
64 storageClass="ExposureF",
65 multiple=True,
66 dimensions=("tract", "patch", "band", "skymap")
67 )
68 coadds_cell = cT.Input(
69 doc="Exposure on which to run deblending",
70 name="{inputCoaddName}CoaddCell",
71 storageClass="MultipleCellCoadd",
72 multiple=True,
73 dimensions=("tract", "patch", "band", "skymap")
74 )
75 backgrounds = cT.Input(
76 doc="Background model to subtract from the cell-based coadd",
77 name="{inputCoaddName}Coadd_calexp_background",
78 storageClass="Background",
79 multiple=True,
80 dimensions=("tract", "patch", "band", "skymap")
81 )
82 deconvolvedCoadds = cT.Input(
83 doc="Deconvolved coadds",
84 name="deconvolved_{inputCoaddName}_coadd",
85 storageClass="ExposureF",
86 multiple=True,
87 dimensions=("tract", "patch", "band", "skymap")
88 )
89 outputSchema = cT.InitOutput(
90 doc="Output of the schema used in deblending task",
91 name="{outputCoaddName}Coadd_deblendedFlux_schema",
92 storageClass="SourceCatalog"
93 )
94 # TODO[DM-47405]: remove this deprecated connection.
95 fluxCatalogs = cT.Output(
96 doc="Flux weighted catalogs produced by multiband deblending",
97 name="{outputCoaddName}Coadd_deblendedFlux",
98 storageClass="SourceCatalog",
99 dimensions=("tract", "patch", "band", "skymap"),
100 multiple=True,
101 deprecated="Deprecated and unused; will be removed after v29."
102 )
103 # TODO[DM-47405]: remove this deprecated connection.
104 templateCatalogs = cT.Output(
105 doc="Template catalogs produced by multiband deblending",
106 name="{outputCoaddName}Coadd_deblendedModel",
107 storageClass="SourceCatalog",
108 dimensions=("tract", "patch", "band", "skymap"),
109 multiple=True,
110 deprecated="Deprecated and unused; will be removed after v29."
111 )
112 deblendedCatalog = cT.Output(
113 doc="Catalogs produced by multiband deblending",
114 name="{outputCoaddName}Coadd_deblendedCatalog",
115 storageClass="SourceCatalog",
116 dimensions=("tract", "patch", "skymap"),
117 )
118 scarletModelData = cT.Output(
119 doc="Multiband scarlet models produced by the deblender",
120 name="{outputCoaddName}Coadd_scarletModelData",
121 storageClass="ScarletModelData",
122 dimensions=("tract", "patch", "skymap"),
123 )
124 objectParents = cT.Output(
125 doc="Parents of the deblended objects",
126 name="object_parents",
127 storageClass="SourceCatalog",
128 dimensions=("tract", "patch", "skymap"),
129 )
130
131 def __init__(self, *, config=None):
132 super().__init__(config=config)
133 del self.fluxCatalogs
134 del self.templateCatalogs
135
136 if config:
137 if config.useCellCoadds:
138 del self.coadds
139 else:
140 del self.coadds_cell
141 del self.backgrounds
142
143
144class DeblendCoaddSourcesMultiConfig(PipelineTaskConfig,
145 pipelineConnections=DeblendCoaddSourcesMultiConnections):
146 useCellCoadds = Field[bool](
147 doc="Use cell-based coadds instead of regular coadds?",
148 default=False,
149 )
150 multibandDeblend = ConfigurableField(
151 target=ScarletDeblendTask,
152 doc="Task to deblend an images in multiple bands"
153 )
154 idGenerator = SkyMapIdGeneratorConfig.make_field()
155
156
158 ConfigClass = DeblendCoaddSourcesMultiConfig
159 _DefaultName = "deblendCoaddSourcesMulti"
160
161 def __init__(self, initInputs, **kwargs):
162 super().__init__(initInputs=initInputs, **kwargs)
163 schema = initInputs["inputSchema"].schema
164 self.peakSchema = initInputs["peakSchema"].schema
166 self.schemaMapper.addMinimalSchema(schema)
167 self.schema = self.schemaMapper.getOutputSchema()
168 self.makeSubtask("multibandDeblend", schema=self.schema, peakSchema=self.peakSchema)
170
171 def runQuantum(self, butlerQC, inputRefs, outputRefs):
172 # Obtain the list of bands, sort them (alphabetically), then reorder
173 # all input lists to match this band order.
174 # Note: sometimes deconvolution fails. If this happens then
175 # the dataIds missing from deconvolvedRefs will be removed
176 # during the process.
177 deconvolvedRefs = inputRefs.deconvolvedCoadds
178 bandOrder = [dRef.dataId["band"] for dRef in deconvolvedRefs]
179 bandOrder.sort()
180 inputRefs = reorderRefs(inputRefs, bandOrder, dataIdKey="band")
181 inputs = butlerQC.get(inputRefs)
182 bands = [dRef.dataId["band"] for dRef in deconvolvedRefs]
183 mergedDetections = inputs.pop("mergedDetections")
184 if self.config.useCellCoadds:
185 exposures = [mcc.stitch().asExposure() for mcc in inputs.pop("coadds_cell")]
186 backgrounds = inputs.pop("backgrounds")
187 for exposure, background in zip(exposures, backgrounds):
188 exposure.image -= background.getImage()
189 coadds = exposures
190 else:
191 coadds = inputs.pop("coadds")
192
193 # Ensure that the coadd bands and deconvolved coadd bands match
194 coaddRefs = inputRefs.coadds_cell if self.config.useCellCoadds else inputRefs.coadds
195 coaddBands = [dRef.dataId["band"] for dRef in coaddRefs]
196 if bands != coaddBands:
197 self.log.error("Coadd bands %s != deconvolved coadd bands %s", bands, coaddBands)
198 raise RuntimeError(
199 "Number of coadd bands and deconvolved coadd bands do not match. "
200 "This should never happen and indicates a bug in reorderRefs."
201 )
202
203 deconvolvedCoadds = inputs.pop("deconvolvedCoadds")
204
205 # Check that all inputs have been extracted correctly.
206 assert not inputs, "runQuantum got extra inputs"
207
208 outputs = self.run(
209 coadds=coadds,
210 bands=bands,
211 mergedDetections=mergedDetections,
212 idFactory=self.config.idGenerator.apply(butlerQC.quantum.dataId).make_table_id_factory(),
213 deconvolvedCoadds=deconvolvedCoadds,
214 )
215 butlerQC.put(outputs, outputRefs)
216
217 def run(self, coadds, bands, mergedDetections, deconvolvedCoadds, idFactory):
218 sources = self._makeSourceCatalog(mergedDetections, idFactory)
219 multiExposure = afwImage.MultibandExposure.fromExposures(bands, coadds)
220 mDeconvolved = afwImage.MultibandExposure.fromExposures(bands, deconvolvedCoadds)
221 result = self.multibandDeblend.run(multiExposure, mDeconvolved, sources)
222 return result
223
224 def _makeSourceCatalog(self, mergedDetections, idFactory):
225 # There may be gaps in the mergeDet catalog, which will cause the
226 # source ids to be inconsistent. So we update the id factory
227 # with the largest id already in the catalog.
228 maxId = np.max(mergedDetections["id"])
229 idFactory.notify(maxId)
230 table = afwTable.SourceTable.make(self.schema, idFactory)
231 sources = afwTable.SourceCatalog(table)
232 sources.extend(mergedDetections, self.schemaMapper)
233 return sources
A mapping between the keys of two Schemas, used to copy data between them.
run(self, coadds, bands, mergedDetections, deconvolvedCoadds, idFactory)