lsst.pipe.tasks  18.1.0-13-gaf553342
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 from lsst.pipe.base import (Struct, PipelineTask, PipelineTaskConfig, PipelineTaskConnections)
24 
25 from lsst.pex.config import ConfigurableField
26 from lsst.meas.deblender import SourceDeblendTask, MultibandDeblendTask
27 
28 import lsst.afw.image as afwImage
29 import lsst.afw.table as afwTable
30 
31 __all__ = ("DeblendCoaddSourcesSingleConfig", "DeblendCoaddSourcesSingleTask",
32  "DeblendCoaddSourcesMultiConfig", "DeblendCoaddSourcesMultiTask")
33 
34 
35 deblendBaseTemplates = {"inputCoaddName": "deep", "outputCoaddName": "deep"}
36 
37 
38 class DeblendCoaddSourceSingleConnections(PipelineTaskConnections,
39  dimensions=("tract", "patch", "abstract_filter", "skymap"),
40  defaultTemplates=deblendBaseTemplates):
41  inputSchema = cT.InitInput(
42  doc="Input schema to use in the deblend catalog",
43  name="{inputCoaddName}Coadd_mergeDet_schema",
44  storageClass="SourceCatalog"
45  )
46  peakSchema = cT.InitInput(
47  doc="Schema of the footprint peak catalogs",
48  name="{inputCoaddName}Coadd_peak_schema",
49  storageClass="PeakCatalog"
50  )
51  mergedDetections = cT.Input(
52  doc="Detection catalog merged across bands",
53  name="{inputCoaddName}Coadd_mergeDet",
54  storageClass="SourceCatalog",
55  dimensions=("tract", "patch", "skymap")
56  )
57  coadd = cT.Input(
58  doc="Exposure on which to run deblending",
59  name="{inputCoaddName}Coadd_calexp",
60  storageClass="ExposureF",
61  dimensions=("tract", "patch", "abstract_filter", "skymap")
62  )
63  measureCatalog = cT.Output(
64  doc="The output measurement catalog of deblended sources",
65  name="{outputCoaddName}Coadd_deblendedFlux",
66  storageClass="SourceCatalog",
67  dimensions=("tract", "patch", "abstract_filter", "skymap")
68  )
69  outputSchema = cT.InitOutput(
70  doc="Output of the schema used in deblending task",
71  name="{outputCoaddName}Coadd_deblendedFlux_schema",
72  storageClass="SourceCatalog"
73  )
74 
75  def setDefaults(self):
76  super().setDefaults()
77  self.singleBandDeblend.propagateAllPeaks = True
78 
79 
80 class DeblendCoaddSourcesSingleConfig(PipelineTaskConfig,
81  pipelineConnections=DeblendCoaddSourceSingleConnections):
82  singleBandDeblend = ConfigurableField(
83  target=SourceDeblendTask,
84  doc="Task to deblend an image in one band"
85  )
86 
87 
88 class DeblendCoaddSourcesMultiConnections(PipelineTaskConnections,
89  dimensions=("tract", "patch", "skymap"),
90  defaultTemplates=deblendBaseTemplates):
91  inputSchema = cT.InitInput(
92  doc="Input schema to use in the deblend catalog",
93  name="{inputCoaddName}Coadd_mergeDet_schema",
94  storageClass="SourceCatalog"
95  )
96  peakSchema = cT.InitInput(
97  doc="Schema of the footprint peak catalogs",
98  name="{inputCoaddName}Coadd_peak_schema",
99  storageClass="PeakCatalog"
100  )
101  mergedDetections = cT.Input(
102  doc="Detection catalog merged across bands",
103  name="{inputCoaddName}Coadd_mergeDet",
104  storageClass="SourceCatalog",
105  dimensions=("tract", "patch", "skymap")
106  )
107  coadds = cT.Input(
108  doc="Exposure on which to run deblending",
109  name="{inputCoaddName}Coadd_calexp",
110  storageClass="ExposureF",
111  multiple=True,
112  dimensions=("tract", "patch", "abstract_filter", "skymap")
113  )
114  outputSchema = cT.InitOutput(
115  doc="Output of the schema used in deblending task",
116  name="{outputCoaddName}Coadd_deblendedModel_schema",
117  storageClass="SourceCatalog"
118  )
119  fluxCatalogs = cT.Output(
120  doc="Flux catalogs produced by multiband deblending, not written "
121  "if conserve flux is turned off",
122  name="{outputCoaddName}Coadd_deblendedFlux",
123  storageClass="SourceCatalog",
124  dimensions=("tract", "patch", "abstract_filter", "skymap")
125  )
126  templateCatalogs = cT.Output(
127  doc="Template catalogs produced by multiband deblending",
128  name="{outputCoaddName}Coadd_deblendedModel",
129  storageClass="SourceCatalog",
130  dimensions=("tract", "patch", "abstract_filter", "skymap")
131  )
132 
133  def __init__(self, *, config=None):
134  super().__init__(config=config)
135  if not config.multibandDeblend.conserveFlux:
136  self.outputs -= set(("fluxCatalogs",))
137 
138 
139 class DeblendCoaddSourcesMultiConfig(PipelineTaskConfig,
140  pipelineConnections=DeblendCoaddSourcesMultiConnections):
141  multibandDeblend = ConfigurableField(
142  target=MultibandDeblendTask,
143  doc="Task to deblend an images in multiple bands"
144  )
145 
146 
147 class DeblendCoaddSourcesBaseTask(PipelineTask):
148  def __init__(self, initInputs, **kwargs):
149  super().__init__(initInputs=initInputs, **kwargs)
150  schema = initInputs["inputSchema"].schema
151  self.peakSchema = initInputs["peakSchema"].schema
152  self.schemaMapper = afwTable.SchemaMapper(schema)
153  self.schemaMapper.addMinimalSchema(schema)
154  self.schema = self.schemaMapper.getOutputSchema()
155 
156  def runQuantum(self, butlerQC, inputRefs, outputRefs):
157  inputs = butlerQC.get(inputRefs)
158  packedId, maxBits = butlerQC.registry.packDataId("tract_patch", inputRefs.mergedDetections.dataId,
159  returnMaxBits=True)
160  inputs["idFactory"] = afwTable.IdFactory.makeSource(packedId, 64 - maxBits)
161  outputs = self.run(**inputs)
162  butlerQC.put(outputs, outputRefs)
163 
164  def _makeSourceCatalog(self, mergedDetections, idFactory):
165  table = afwTable.SourceTable.make(self.schema, idFactory)
166  sources = afwTable.SourceCatalog(table)
167  sources.extend(mergedDetections, self.schemaMapper)
168  return sources
169 
170 
172  ConfigClass = DeblendCoaddSourcesSingleConfig
173  _DefaultName = "deblendCoaddSourcesSingle"
174 
175  def __init__(self, initInputs, **kwargs):
176  super().__init__(initInputs=initInputs, **kwargs)
177  self.makeSubtask("singleBandDeblend", schema=self.schema, peakSchema=self.peakSchema)
178  self.outputSchema = afwTable.SourceCatalog(self.schema)
179 
180  def run(self, coadd, mergedDetections, idFactory):
181  sources = self._makeSourceCatalog(mergedDetections, idFactory)
182  self.singleBandDeblend.run(coadd, sources)
183  if not sources.isContiguous():
184  sources = sources.copy(deep=True)
185  return Struct(measureCatalog=sources)
186 
187 
189  ConfigClass = DeblendCoaddSourcesMultiConfig
190  _DefaultName = "deblendCoaddSourcesMulti"
191 
192  def __init__(self, initInputs, **kwargs):
193  super().__init__(initInputs=initInputs, **kwargs)
194  self.makeSubtask("multibandDeblend", schema=self.schema, peakSchema=self.peakSchema)
195  self.outputSchema = afwTable.SourceCatalog(self.schema)
196 
197  def runQuantum(self, butlerQC, inputRefs, outputRefs):
198  inputs = butlerQC.get(inputRefs)
199  packedId, maxBits = butlerQC.registry.packDataId("tract_patch", inputRefs.mergedDetections.dataId,
200  returnMaxBits=True)
201  inputs["idFactory"] = afwTable.IdFactory.makeSource(packedId, 64 - maxBits)
202  inputs["filters"] = [dRef.dataId["abstract_filter"] for dRef in inputRefs.coadds]
203  outputs = self.run(**inputs)
204  butlerQC.put(outputs, outputRefs)
205 
206  def run(self, coadds, filters, mergedDetections, idFactory):
207  sources = self._makeSourceCatalog(mergedDetections, idFactory)
208  multiExposure = afwImage.MultibandExposure.fromExposures(filters, coadds)
209  fluxCatalogs, templateCatalogs = self.multibandDeblend.run(multiExposure, sources)
210  retStruct = Struct(templateCatalogs)
211  if self.config.multibandDeblend.conserveFlux:
212  retStruct.fluxCatalogs = fluxCatalogs
213  return retStruct