LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
coaddInputRecorder.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__ = ["CoaddInputRecorderTask"]
23
24import numpy
25
26import lsst.pex.config as pexConfig
27import lsst.afw.table as afwTable
28import lsst.afw.image as afwImage
29import lsst.pipe.base as pipeBase
30from lsst.meas.algorithms import CoaddPsf, makeCoaddApCorrMap
31
32
33class CoaddInputRecorderConfig(pexConfig.Config):
34 saveEmptyCcds = pexConfig.Field(
35 dtype=bool, default=False, optional=False,
36 doc=("Add records for CCDs we iterated over but did not add a coaddTempExp"
37 " due to a lack of unmasked pixels in the coadd footprint.")
38 )
39 saveErrorCcds = pexConfig.Field(
40 dtype=bool, default=False, optional=False,
41 doc=("Add records for CCDs we iterated over but did not add a coaddTempExp"
42 " due to an exception (often due to the calexp not being found on disk).")
43 )
44 saveVisitGoodPix = pexConfig.Field(
45 dtype=bool, default=True, optional=False,
46 doc=("Save the total number of good pixels in each coaddTempExp (redundant with a sum of"
47 " good pixels in associated CCDs)")
48 )
49 saveCcdWeights = pexConfig.Field(
50 dtype=bool, default=True, optional=False,
51 doc=("Save weights in the CCDs table as well as the visits table?"
52 " (This is necessary for easy construction of CoaddPsf, but otherwise duplicate information.)")
53 )
54
55
57 """A helper class for CoaddInputRecorderTask, managing the CoaddInputs object for that single
58 CoaddTempExp. This will contain a single 'visit' record for the CoaddTempExp and a number of 'ccd'
59 records.
60
61 Should generally be created by calling CoaddInputRecorderTask.makeCoaddTempExp().
62
63 Parameters
64 ----------
65 task : `lsst.pipe.tasks.coaddInputRecorder.CoaddInputRecorderTask`
66 The CoaddInputRecorderTask that is utilising us.
67 visitId : `int`
68 Identifier (integer) for the visit.
69 num : `int`
70 Number of CCDs for this visit that overlap this patch (for reserving memory).
71 """
72
73 def __init__(self, task, visitId, num=0):
74 self.task = task
75 self.coaddInputs = self.task.makeCoaddInputs()
76 self.coaddInputs.visits.reserve(1)
77 if num > 0:
78 self.coaddInputs.ccds.reserve(num)
79 self.visitRecord = self.coaddInputs.visits.addNew()
80 self.visitRecord.setId(visitId)
81
82 def addCalExp(self, calExp, ccdId, nGoodPix):
83 """Add a 'ccd' record for a calexp just added to the CoaddTempExp.
84
85 Parameters
86 ----------
87 calExp : `lsst.afw.image.Exposure`
88 Calibrated exposure just added to the CoaddTempExp, or None in case of
89 failures that should nonetheless be tracked. Should be the original
90 calexp, in that it should contain the original Psf and Wcs, not the
91 warped and/or matched ones.
92 ccdId : `int`
93 A unique numeric ID for the Exposure.
94 nGoodPix : `int`
95 Number of good pixels this image will contribute to the CoaddTempExp.
96 If saveEmptyCcds is not set and this value is zero, no record will be
97 added.
98 """
99 if nGoodPix == 0 and not self.task.config.saveEmptyCcds:
100 return
101 record = self.coaddInputs.ccds.addNew()
102 record.setId(ccdId)
103 record.setL(self.task.ccdVisitKey, self.visitRecord.getId())
104 try:
105 record.setI(self.task.ccdCcdKey, calExp.getDetector().getId())
106 except Exception as e:
107 self.task.log.warning("Error getting detector serial number in visit %d; using -1; error=%s",
108 self.visitRecord.getId(), e)
109 record.setI(self.task.ccdCcdKey, -1)
110 record.setI(self.task.ccdGoodPixKey, nGoodPix)
111 if calExp is not None:
112 self._setExposureInfoInRecord(exposure=calExp, record=record)
113 if self.task.config.saveCcdWeights:
114 record.setD(self.task.ccdWeightKey, 1.0) # No weighting or overlap when warping
115 record.set(self.task.ccdFilterKey, calExp.getFilter().physicalLabel)
116
117 def finish(self, coaddTempExp, nGoodPix=None):
118 """Finish creating the CoaddInputs for a CoaddTempExp.
119
120 Parameters
121 ----------
122 coaddTempExp : `lsst.afw.image.Exposure`
123 Exposure object from which to obtain the PSF, WCS, and bounding
124 box for the entry in the 'visits' table. On return, the completed
125 CoaddInputs object will be attached to it.
126 nGoodPix : `int`
127 Total number of good pixels in the CoaddTempExp; ignored unless
128 saveVisitGoodPix is true.
129 """
130 self._setExposureInfoInRecord(exposure=coaddTempExp, record=self.visitRecord)
131 if self.task.config.saveVisitGoodPix:
132 self.visitRecord.setI(self.task.visitGoodPixKey, nGoodPix)
133 coaddTempExp.getInfo().setCoaddInputs(self.coaddInputs)
134 wcs = coaddTempExp.getWcs()
135 if False:
136 # This causes a test failure, pending fix in issue HSC-802
137 coaddTempExp.setPsf(CoaddPsf(self.coaddInputs.ccds, wcs))
138 apCorrMap = makeCoaddApCorrMap(self.coaddInputs.ccds, coaddTempExp.getBBox(afwImage.PARENT), wcs)
139 coaddTempExp.getInfo().setApCorrMap(apCorrMap)
140
141 def _setExposureInfoInRecord(self, exposure, record):
142 """Set exposure info and bbox in an ExposureTable record.
143
144 Parameters
145 ----------
146 exposure : `lsst.afw.image.ExposureF`
147 Exposure whose info is to be recorded.
148 record : `Unknown`
149 Record of an ExposureTable to set.
150 """
151 info = exposure.getInfo()
152 record.setPsf(info.getPsf())
153 record.setWcs(info.getWcs())
154 record.setPhotoCalib(info.getPhotoCalib())
155 record.setApCorrMap(info.getApCorrMap())
156 record.setValidPolygon(info.getValidPolygon())
157 record.setVisitInfo(info.getVisitInfo())
158 record.setBBox(exposure.getBBox())
159 record.setTransmissionCurve(info.getTransmissionCurve())
160
161
162class CoaddInputRecorderTask(pipeBase.Task):
163 """Subtask that handles filling a CoaddInputs object for a coadd exposure, tracking the CCDs and
164 visits that went into a coadd.
165
166 The interface here is a little messy, but I think this is at least partly a product of a bit of
167 messiness in the coadd code it's plugged into. I hope #2590 might result in a better design.
168 """
169
170 ConfigClass = CoaddInputRecorderConfig
171
172 def __init__(self, *args, **kwargs):
173 pipeBase.Task.__init__(self, *args, **kwargs)
174 self.visitSchema = afwTable.ExposureTable.makeMinimalSchema()
175 if self.config.saveVisitGoodPix:
176 self.visitGoodPixKey = self.visitSchema.addField("goodpix", type=numpy.int32,
177 doc="Number of good pixels in the coaddTempExp")
178 self.visitWeightKey = self.visitSchema.addField("weight", type=float,
179 doc="Weight for this visit in the coadd")
180 self.ccdSchema = afwTable.ExposureTable.makeMinimalSchema()
181 self.ccdCcdKey = self.ccdSchema.addField("ccd", type=numpy.int32, doc="cameraGeom CCD serial number")
182 self.ccdVisitKey = self.ccdSchema.addField("visit", type=numpy.int64,
183 doc="Foreign key for the visits (coaddTempExp) catalog")
184 self.ccdGoodPixKey = self.ccdSchema.addField("goodpix", type=numpy.int32,
185 doc="Number of good pixels in this CCD")
186 if self.config.saveCcdWeights:
187 self.ccdWeightKey = self.ccdSchema.addField("weight", type=float,
188 doc="Weight for this visit in the coadd")
189 self.visitFilterKey = self.visitSchema.addField("filter", type=str, size=32,
190 doc="Physical filter associated with this visit.")
191 self.ccdFilterKey = self.ccdSchema.addField("filter", type=str, size=32,
192 doc="Physical filter associated with this visit.")
193
194 def makeCoaddTempExpRecorder(self, visitId, num=0):
195 """Return a CoaddTempExpInputRecorder instance to help with saving a CoaddTempExp's inputs.
196
197 Parameters
198 ----------
199 visitId : `Unknown`
200 num : `int`, optional
201 Number of CCDs for this visit that overlap this patch (for reserving memory).
202
203 Notes
204 -----
205 The visitId may be any number that is unique for each :that goes into a coadd,
206 but ideally should be something more meaningful that can be used to reconstruct a data ID.
207 """
208 return CoaddTempExpInputRecorder(self, visitId, num=num)
209
211 """Create a CoaddInputs object with schemas defined by the task configuration."""
213
214 def addVisitToCoadd(self, coaddInputs, coaddTempExp, weight):
215 """Called by AssembleCoaddTask when adding (a subset of) a coaddTempExp to a coadd. The
216 base class impementation extracts the CoaddInputs from the coaddTempExp and appends
217 them to the given coaddInputs, filling in the weight column(s).
218
219 Parameters
220 ----------
221 coaddInputs : `lsst.afw.Image.CoaddInputs`
222 A record of the observations that are included in the coadd.
223 coaddTempExp : `lsst.afw.image.Exposure`
224 Exposure object from which to obtain the PSF, WCS, and bounding
225 box for the entry in the 'visits' table. On return, the completed
226 CoaddInputs object will be attached to it.
227 weight : `Unknown`
228
229 Returns
230 -------
231 inputVisitRecord : `Unknown`
232 The record for the visit to allow subclasses to fill in additional fields or
233 None if the inputRecorder catalogs for the coaddTempExp are not usable.
234
235 Notes
236 -----
237 Note that the passed coaddTempExp may be a subimage, but that this method will only be
238 called for the first subimage.
239 """
240 tempExpInputs = coaddTempExp.getInfo().getCoaddInputs()
241 if len(tempExpInputs.visits) != 1:
242 self.log.warning("CoaddInputs for coaddTempExp should have exactly one record in visits table "
243 "(found %d). CoaddInputs for this visit will not be saved.",
244 len(tempExpInputs.visits))
245 return None
246 inputVisitRecord = tempExpInputs.visits[0]
247 outputVisitRecord = coaddInputs.visits.addNew()
248 outputVisitRecord.assign(inputVisitRecord)
249 outputVisitRecord.setD(self.visitWeightKey, weight)
250 outputVisitRecord.set(self.visitFilterKey, coaddTempExp.getFilter().physicalLabel)
251 for inputCcdRecord in tempExpInputs.ccds:
252 if inputCcdRecord.getL(self.ccdVisitKey) != inputVisitRecord.getId():
253 self.log.warning("CoaddInputs for coaddTempExp with id %d contains CCDs with visit=%d. "
254 "CoaddInputs may be unreliable.",
255 inputVisitRecord.getId(), inputCcdRecord.getL(self.ccdVisitKey))
256 outputCcdRecord = coaddInputs.ccds.addNew()
257 outputCcdRecord.assign(inputCcdRecord)
258 if self.config.saveCcdWeights:
259 outputCcdRecord.setD(self.ccdWeightKey, weight)
260 outputCcdRecord.set(self.ccdFilterKey, coaddTempExp.getFilter().physicalLabel)
261 return inputVisitRecord
A simple Persistable struct containing ExposureCatalogs that record the inputs to a coadd.
Definition CoaddInputs.h:49
CoaddPsf is the Psf derived to be used for non-PSF-matched Coadd images.
Definition CoaddPsf.h:58
addVisitToCoadd(self, coaddInputs, coaddTempExp, weight)