lsst.pipe.tasks 21.0.0-175-g7497abfa+2a6ce44392
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
22import numpy as np
23
24from lsst.pipe.base import (Struct, PipelineTask, PipelineTaskConfig, PipelineTaskConnections)
25import lsst.pipe.base.connectionTypes as cT
26
27from lsst.pex.config import ConfigurableField
28from lsst.meas.deblender import SourceDeblendTask
29from lsst.meas.extensions.scarlet import ScarletDeblendTask
30from lsst.obs.base import ExposureIdInfo
31
32import lsst.afw.image as afwImage
33import lsst.afw.table as afwTable
34
35__all__ = ("DeblendCoaddSourcesSingleConfig", "DeblendCoaddSourcesSingleTask",
36 "DeblendCoaddSourcesMultiConfig", "DeblendCoaddSourcesMultiTask")
37
38
39deblendBaseTemplates = {"inputCoaddName": "deep", "outputCoaddName": "deep"}
40
41
42class DeblendCoaddSourceSingleConnections(PipelineTaskConnections,
43 dimensions=("tract", "patch", "band", "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 coadd = cT.Input(
62 doc="Exposure on which to run deblending",
63 name="{inputCoaddName}Coadd_calexp",
64 storageClass="ExposureF",
65 dimensions=("tract", "patch", "band", "skymap")
66 )
67 measureCatalog = cT.Output(
68 doc="The output measurement catalog of deblended sources",
69 name="{outputCoaddName}Coadd_deblendedFlux",
70 storageClass="SourceCatalog",
71 dimensions=("tract", "patch", "band", "skymap")
72 )
73 outputSchema = cT.InitOutput(
74 doc="Output of the schema used in deblending task",
75 name="{outputCoaddName}Coadd_deblendedFlux_schema",
76 storageClass="SourceCatalog"
77 )
78
79 def setDefaults(self):
80 super().setDefaults()
81 self.singleBandDeblend.propagateAllPeaks = True
82
83
84class DeblendCoaddSourcesSingleConfig(PipelineTaskConfig,
85 pipelineConnections=DeblendCoaddSourceSingleConnections):
86 singleBandDeblend = ConfigurableField(
87 target=SourceDeblendTask,
88 doc="Task to deblend an image in one band"
89 )
90
91
92class DeblendCoaddSourcesMultiConnections(PipelineTaskConnections,
93 dimensions=("tract", "patch", "skymap"),
94 defaultTemplates=deblendBaseTemplates):
95 inputSchema = cT.InitInput(
96 doc="Input schema to use in the deblend catalog",
97 name="{inputCoaddName}Coadd_mergeDet_schema",
98 storageClass="SourceCatalog"
99 )
100 peakSchema = cT.InitInput(
101 doc="Schema of the footprint peak catalogs",
102 name="{inputCoaddName}Coadd_peak_schema",
103 storageClass="PeakCatalog"
104 )
105 mergedDetections = cT.Input(
106 doc="Detection catalog merged across bands",
107 name="{inputCoaddName}Coadd_mergeDet",
108 storageClass="SourceCatalog",
109 dimensions=("tract", "patch", "skymap")
110 )
111 coadds = cT.Input(
112 doc="Exposure on which to run deblending",
113 name="{inputCoaddName}Coadd_calexp",
114 storageClass="ExposureF",
115 multiple=True,
116 dimensions=("tract", "patch", "band", "skymap")
117 )
118 outputSchema = cT.InitOutput(
119 doc="Output of the schema used in deblending task",
120 name="{outputCoaddName}Coadd_deblendedFlux_schema",
121 storageClass="SourceCatalog"
122 )
123 templateCatalogs = cT.Output(
124 doc="Template catalogs produced by multiband deblending",
125 name="{outputCoaddName}Coadd_deblendedFlux",
126 storageClass="SourceCatalog",
127 dimensions=("tract", "patch", "band", "skymap"),
128 multiple=True
129 )
130
131
132class DeblendCoaddSourcesMultiConfig(PipelineTaskConfig,
133 pipelineConnections=DeblendCoaddSourcesMultiConnections):
134 multibandDeblend = ConfigurableField(
135 target=ScarletDeblendTask,
136 doc="Task to deblend an images in multiple bands"
137 )
138
139
140class DeblendCoaddSourcesBaseTask(PipelineTask):
141 def __init__(self, initInputs, **kwargs):
142 super().__init__(initInputs=initInputs, **kwargs)
143 schema = initInputs["inputSchema"].schema
144 self.peakSchemapeakSchema = initInputs["peakSchema"].schema
145 self.schemaMapperschemaMapper = afwTable.SchemaMapper(schema)
146 self.schemaMapperschemaMapper.addMinimalSchema(schema)
147 self.schemaschema = self.schemaMapperschemaMapper.getOutputSchema()
148
149 def runQuantum(self, butlerQC, inputRefs, outputRefs):
150 inputs = butlerQC.get(inputRefs)
151 inputs["idFactory"] = ExposureIdInfo.fromDataId(
152 butlerQC.quantum.dataId,
153 "tract_patch"
154 ).makeSourceIdFactory()
155 outputs = self.run(**inputs)
156 butlerQC.put(outputs, outputRefs)
157
158 def _makeSourceCatalog(self, mergedDetections, idFactory):
159 # There may be gaps in the mergeDet catalog, which will cause the
160 # source ids to be inconsistent. So we update the id factory
161 # with the largest id already in the catalog.
162 maxId = np.max(mergedDetections["id"])
163 idFactory.notify(maxId)
164 table = afwTable.SourceTable.make(self.schemaschema, idFactory)
165 sources = afwTable.SourceCatalog(table)
166 sources.extend(mergedDetections, self.schemaMapperschemaMapper)
167 return sources
168
169
171 ConfigClass = DeblendCoaddSourcesSingleConfig
172 _DefaultName = "deblendCoaddSourcesSingle"
173
174 def __init__(self, initInputs, **kwargs):
175 super().__init__(initInputs=initInputs, **kwargs)
176 self.makeSubtask("singleBandDeblend", schema=self.schemaschema, peakSchema=self.peakSchemapeakSchema)
177 self.outputSchemaoutputSchema = afwTable.SourceCatalog(self.schemaschema)
178
179 def run(self, coadd, mergedDetections, idFactory):
180 sources = self._makeSourceCatalog_makeSourceCatalog(mergedDetections, idFactory)
181 self.singleBandDeblend.run(coadd, sources)
182 if not sources.isContiguous():
183 sources = sources.copy(deep=True)
184 return Struct(measureCatalog=sources)
185
186
188 ConfigClass = DeblendCoaddSourcesMultiConfig
189 _DefaultName = "deblendCoaddSourcesMulti"
190
191 def __init__(self, initInputs, **kwargs):
192 super().__init__(initInputs=initInputs, **kwargs)
193 self.makeSubtask("multibandDeblend", schema=self.schemaschema, peakSchema=self.peakSchemapeakSchema)
194 self.outputSchemaoutputSchema = afwTable.SourceCatalog(self.schemaschema)
195
196 def runQuantum(self, butlerQC, inputRefs, outputRefs):
197 inputs = butlerQC.get(inputRefs)
198 exposureIdInfo = ExposureIdInfo.fromDataId(butlerQC.quantum.dataId, "tract_patch")
199 inputs["idFactory"] = exposureIdInfo.makeSourceIdFactory()
200 inputs["filters"] = [dRef.dataId["band"] for dRef in inputRefs.coadds]
201 outputs = self.runrun(**inputs)
202 for outRef in outputRefs.templateCatalogs:
203 band = outRef.dataId['band']
204 if (catalog := outputs.templateCatalogs.get(band)) is not None:
205 butlerQC.put(catalog, outRef)
206
207 def run(self, coadds, filters, mergedDetections, idFactory):
208 sources = self._makeSourceCatalog_makeSourceCatalog(mergedDetections, idFactory)
209 multiExposure = afwImage.MultibandExposure.fromExposures(filters, coadds)
210 templateCatalogs = self.multibandDeblend.run(multiExposure, sources)
211 retStruct = Struct(templateCatalogs=templateCatalogs)
212 return retStruct