134 def run(self, exposure, sources, expId=0, matches=None):
135 """Measure the PSF.
136
137 Parameters
138 ----------
139 exposure : `lsst.afw.image.Exposure`
140 Exposure to process; measured PSF will be added.
141 sources : `Unknown`
142 Measured sources on exposure; flag fields will be set marking
143 stars chosen by the star selector and the PSF determiner if a schema
144 was passed to the task constructor.
145 expId : `int`, optional
146 Exposure id used for generating random seed.
147 matches : `list`, optional
148 A list of ``lsst.afw.table.ReferenceMatch`` objects
149 (i.e. of ``lsst.afw.table.Match`` with @c first being
150 of type ``lsst.afw.table.SimpleRecord`` and @c second
151 type lsst.afw.table.SourceRecord --- the reference object and detected
152 object respectively) as returned by @em e.g. the AstrometryTask.
153 Used by star selectors that choose to refer to an external catalog.
154
155 Returns
156 -------
157 measurement : `lsst.pipe.base.Struct`
158 PSF measurement as a struct with attributes:
159
160 ``psf``
161 The measured PSF (also set in the input exposure).
162 ``cellSet``
163 An `lsst.afw.math.SpatialCellSet` containing the PSF candidates
164 as returned by the psf determiner.
165 """
166 self.log.info("Measuring PSF")
167
168 import lsstDebug
172 displayPsfCandidates =
lsstDebug.Info(__name__).displayPsfCandidates
176
177
178
179
180 stars = self.starSelector.run(sourceCat=sources, matches=matches, exposure=exposure)
181 selectionResult = self.makePsfCandidates.run(stars.sourceCat, exposure=exposure)
182 self.log.info("PSF star selector found %d candidates", len(selectionResult.psfCandidates))
183 reserveResult = self.reserve.run(selectionResult.goodStarCat, expId=expId)
184
185 psfDeterminerList = [cand for cand, use
186 in zip(selectionResult.psfCandidates, reserveResult.use) if use]
187
188 if selectionResult.psfCandidates and self.candidateKey is not None:
189 for cand in selectionResult.psfCandidates:
190 source = cand.getSource()
191 source.set(self.candidateKey, True)
192
193 self.log.info("Sending %d candidates to PSF determiner", len(psfDeterminerList))
194
195 if display:
196 frame = 1
197 if displayExposure:
198 disp = afwDisplay.Display(frame=frame)
199 disp.mtv(exposure, title="psf determination")
200 frame += 1
201
202
203
204 psf, cellSet = self.psfDeterminer.determinePsf(exposure, psfDeterminerList, self.metadata,
205 flagKey=self.usedKey)
206 self.log.info("PSF determination using %d/%d stars.",
207 self.metadata.getScalar("numGoodStars"), self.metadata.getScalar("numAvailStars"))
208
209 exposure.setPsf(psf)
210
211 if display:
212 frame = display
213 if displayExposure:
214 disp = afwDisplay.Display(frame=frame)
215 showPsfSpatialCells(exposure, cellSet, showBadCandidates, frame=frame)
216 frame += 1
217
218 if displayPsfCandidates:
219 plotPsfCandidates(cellSet, showBadCandidates=showBadCandidates, frame=frame)
220 frame += 1
221
222 if displayResiduals:
223 frame = plotResiduals(exposure, cellSet,
224 showBadCandidates=showBadCandidates,
225 normalizeResiduals=normalizeResiduals,
226 frame=frame)
227 if displayPsfMosaic:
228 disp = afwDisplay.Display(frame=frame)
229 maUtils.showPsfMosaic(exposure, psf, display=disp, showFwhm=True)
230 disp.scale("linear", 0, 1)
231 frame += 1
232
233 return pipeBase.Struct(
234 psf=psf,
235 cellSet=cellSet,
236 )
237