Coverage for python/lsst/pipe/tasks/deblendCoaddSourcesPipeline.py: 54%
88 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-17 08:55 +0000
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-17 08:55 +0000
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/>.
22import numpy as np
24from lsst.pipe.base import (Struct, PipelineTask, PipelineTaskConfig, PipelineTaskConnections)
25import lsst.pipe.base.connectionTypes as cT
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
32import lsst.afw.image as afwImage
33import lsst.afw.table as afwTable
35__all__ = ("DeblendCoaddSourcesSingleConfig", "DeblendCoaddSourcesSingleTask",
36 "DeblendCoaddSourcesMultiConfig", "DeblendCoaddSourcesMultiTask")
39deblendBaseTemplates = {"inputCoaddName": "deep", "outputCoaddName": "deep"}
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 )
79 def setDefaults(self):
80 super().setDefaults()
81 self.singleBandDeblend.propagateAllPeaks = True
84class DeblendCoaddSourcesSingleConfig(PipelineTaskConfig,
85 pipelineConnections=DeblendCoaddSourceSingleConnections):
86 singleBandDeblend = ConfigurableField(
87 target=SourceDeblendTask,
88 doc="Task to deblend an image in one band"
89 )
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 )
132class DeblendCoaddSourcesMultiConfig(PipelineTaskConfig,
133 pipelineConnections=DeblendCoaddSourcesMultiConnections):
134 multibandDeblend = ConfigurableField(
135 target=ScarletDeblendTask,
136 doc="Task to deblend an images in multiple bands"
137 )
140class DeblendCoaddSourcesBaseTask(PipelineTask):
141 def __init__(self, initInputs, **kwargs):
142 super().__init__(initInputs=initInputs, **kwargs)
143 schema = initInputs["inputSchema"].schema
144 self.peakSchema = initInputs["peakSchema"].schema
145 self.schemaMapper = afwTable.SchemaMapper(schema)
146 self.schemaMapper.addMinimalSchema(schema)
147 self.schema = self.schemaMapper.getOutputSchema()
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)
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.schema, idFactory)
165 sources = afwTable.SourceCatalog(table)
166 sources.extend(mergedDetections, self.schemaMapper)
167 return sources
170class DeblendCoaddSourcesSingleTask(DeblendCoaddSourcesBaseTask):
171 ConfigClass = DeblendCoaddSourcesSingleConfig
172 _DefaultName = "deblendCoaddSourcesSingle"
174 def __init__(self, initInputs, **kwargs):
175 super().__init__(initInputs=initInputs, **kwargs)
176 self.makeSubtask("singleBandDeblend", schema=self.schema, peakSchema=self.peakSchema)
177 self.outputSchema = afwTable.SourceCatalog(self.schema)
179 def run(self, coadd, mergedDetections, idFactory):
180 sources = self._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)
187class DeblendCoaddSourcesMultiTask(DeblendCoaddSourcesBaseTask):
188 ConfigClass = DeblendCoaddSourcesMultiConfig
189 _DefaultName = "deblendCoaddSourcesMulti"
191 def __init__(self, initInputs, **kwargs):
192 super().__init__(initInputs=initInputs, **kwargs)
193 self.makeSubtask("multibandDeblend", schema=self.schema, peakSchema=self.peakSchema)
194 self.outputSchema = afwTable.SourceCatalog(self.schema)
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.run(**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)
207 def run(self, coadds, filters, mergedDetections, idFactory):
208 sources = self._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