31 starSelector = measAlg.starSelectorRegistry.makeField(
"Star selection algorithm", default=
"secondMoment")
32 psfDeterminer = measAlg.psfDeterminerRegistry.makeField(
"PSF Determination algorithm", default=
"pca")
43 \anchor MeasurePsfTask_
45 \brief Measure the PSF
47 \section pipe_tasks_measurePsf_Contents Contents
49 - \ref pipe_tasks_measurePsf_Purpose
50 - \ref pipe_tasks_measurePsf_Initialize
51 - \ref pipe_tasks_measurePsf_IO
52 - \ref pipe_tasks_measurePsf_Config
53 - \ref pipe_tasks_measurePsf_Debug
54 - \ref pipe_tasks_measurePsf_Example
56 \section pipe_tasks_measurePsf_Purpose Description
58 A task that wraps two algorithms set via a pair of registries specified in the task's
59 \ref pipe_tasks_measurePsf_Config.
60 Both algorithms are classes with a constructor taking a pex.config.Config object (\em e.g.
61 lsst.meas.algorithms.objectSizeStarSelector.ObjectSizeStarSelector.__init__).
64 - a star selector with API:
66 selectStars(self, exposure, catalog, matches=None)
68 which returns a list of lsst.meas.algorithms.PsfCandidate (\em e.g.
69 lsst.meas.algorithms.objectSizeStarSelector.ObjectSizeStarSelector.selectStars)
71 - a psf estimator with API:
73 determinePsf(exposure, psfCandidateList, metadata=None, flagKey=None)
75 which returns an lsst.afw.detection.Psf and lsst.afw.math.SpatialCellSet (\em e.g.
76 lsst.meas.algorithms.pcaPsfDeterminer.PcaPsfDeterminer.determinePsf).
77 MeasurePsfTask calls determinePsf with \c flagKey set to
78 "calib.psf.used" if a schema is passed to its constructor (see \ref pipe_tasks_measurePsf_Initialize).
80 See also lsst.meas.algorithms.starSelectorRegistry.starSelectorRegistry and
81 lsst.meas.algorithms.psfDeterminerRegistry.psfDeterminerRegistry.
84 There is no establised set of configuration parameters for these algorithms, so once you start modifying
85 parameters (as we do in \ref pipe_tasks_measurePsf_Example) your code is no longer portable.
87 \section pipe_tasks_measurePsf_Initialize Task initialisation
91 \section pipe_tasks_measurePsf_IO Invoking the Task
95 \section pipe_tasks_measurePsf_Config Configuration parameters
97 See \ref MeasurePsfConfig.
100 The star selector and psf determiner registries should be modified to return a class
101 which has a ConfigClass attribute and can be instantiated with a config. Until then, there's no
102 obvious way to get a registry algorithm's Config from another Config.
104 \section pipe_tasks_measurePsf_Debug Debug variables
106 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
107 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files.
111 <DD> If True, display debugging plots
113 <DD> display the Exposure + spatialCells
114 <DT> displayPsfCandidates
115 <DD> show mosaic of candidates
116 <DT> showBadCandidates
117 <DD> Include bad candidates
118 <DT> displayPsfMosaic
119 <DD> show mosaic of reconstructed PSF(xy)
120 <DT> displayResiduals
122 <DT> normalizeResiduals
123 <DD> Normalise residuals by object amplitude
126 Additionally you can enable any debug outputs that your chosen star selector and psf determiner support.
128 \section pipe_tasks_measurePsf_Example A complete example of using MeasurePsfTask
130 This code is in \link measurePsfTask.py\endlink in the examples directory, and can be run as \em e.g.
132 examples/measurePsfTask.py --ds9
134 \dontinclude measurePsfTask.py
136 The example also runs SourceDetectionTask and SourceMeasurementTask; see \ref meas_algorithms_measurement_Example for more explanation.
138 Import the tasks (there are some other standard imports; read the file to see them all):
140 \skip SourceDetectionTask
141 \until MeasurePsfTask
143 We need to create the tasks before processing any data as the task constructor
144 can add an extra column to the schema, but first we need an almost-empty
147 \skipline makeMinimalSchema
149 We can now call the constructors for the tasks we need to find and characterize candidate
152 \skip SourceDetectionTask.ConfigClass
155 Note that we've chosen a minimal set of measurement plugins: we need the
156 outputs of \c base_SdssCentroid, \c base_SdssShape and \c base_CircularApertureFlux as
157 inputs to the PSF measurement algorithm, while \c base_PixelFlags identifies
158 and flags bad sources (e.g. with pixels too close to the edge) so they can be
161 Now we can create and configure the task that we're interested in:
164 \until measurePsfTask
166 We're now ready to process the data (we could loop over multiple exposures/catalogues using the same
167 task objects). First create the output table:
171 And process the image:
176 We can then unpack and use the results:
181 If you specified \c --ds9 you can see the PSF candidates:
188 To investigate the \ref pipe_tasks_measurePsf_Debug, put something like
192 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
194 if name == "lsst.pipe.tasks.measurePsf" :
196 di.displayExposure = False # display the Exposure + spatialCells
197 di.displayPsfCandidates = True # show mosaic of candidates
198 di.displayPsfMosaic = True # show mosaic of reconstructed PSF(xy)
199 di.displayResiduals = True # show residuals
200 di.showBadCandidates = True # Include bad candidates
201 di.normalizeResiduals = False # Normalise residuals by object amplitude
205 lsstDebug.Info = DebugInfo
207 into your debug.py file and run measurePsfTask.py with the \c --debug flag.
209 ConfigClass = MeasurePsfConfig
210 _DefaultName =
"measurePsf"
213 """!Create the detection task. Most arguments are simply passed onto pipe.base.Task.
215 \param schema An lsst::afw::table::Schema used to create the output lsst.afw.table.SourceCatalog
216 \param **kwargs Keyword arguments passed to lsst.pipe.base.task.Task.__init__.
218 If schema is not None, 'calib.psf.candidate' and 'calib.psf.used' fields will be added to
219 identify which stars were employed in the PSF estimation.
221 \note This task can add fields to the schema, so any code calling this task must ensure that
222 these fields are indeed present in the input table.
225 pipeBase.Task.__init__(self, **kwargs)
226 if schema
is not None:
228 "calib_psfCandidate", type=
"Flag",
229 doc=(
"Flag set if the source was a candidate for PSF determination, "
230 "as determined by the '%s' star selector.") % self.config.starSelector.name
233 "calib_psfUsed", type=
"Flag",
234 doc=(
"Flag set if the source was actually used for PSF determination, "
235 "as determined by the '%s' PSF determiner.") % self.config.psfDeterminer.name
244 def run(self, exposure, sources, matches=None):
247 \param[in,out] exposure Exposure to process; measured PSF will be added.
248 \param[in,out] sources Measured sources on exposure; flag fields will be set marking
249 stars chosen by the star selector and the PSF determiner if a schema
250 was passed to the task constructor.
252 \param[in] matches a list of lsst.afw.table.ReferenceMatch objects (\em i.e. of lsst.afw.table.Match
253 with \c first being of type lsst.afw.table.SimpleRecord and \c second
254 type lsst.afw.table.SourceRecord --- the reference object and detected
255 object respectively) as returned by \em e.g. the AstrometryTask.
256 Used by star selectors that choose to refer to an external catalog.
258 \return a pipe.base.Struct with fields:
259 - psf: The measured PSF (also set in the input exposure)
260 - cellSet: an lsst.afw.math.SpatialCellSet containing the PSF candidates as returned by the psf determiner.
262 self.log.info(
"Measuring PSF")
268 displayPsfCandidates =
lsstDebug.Info(__name__).displayPsfCandidates
277 psfCandidateList = self.starSelector.selectStars(exposure, sources, matches=matches)
279 for cand
in psfCandidateList:
280 source = cand.getSource()
283 self.log.info(
"PSF star selector found %d candidates" % len(psfCandidateList))
288 ds9.mtv(exposure, frame=frame, title=
"psf determination")
294 psf, cellSet = self.psfDeterminer.determinePsf(exposure, psfCandidateList, self.metadata,
296 self.log.info(
"PSF determination using %d/%d stars." %
297 (self.metadata.get(
"numGoodStars"), self.metadata.get(
"numAvailStars")))
307 if displayPsfCandidates:
313 showBadCandidates=showBadCandidates,
314 normalizeResiduals=normalizeResiduals,
317 maUtils.showPsfMosaic(exposure, psf, frame=frame, showFwhm=
True)
318 ds9.scale(0, 1,
"linear", frame=frame)
321 return pipeBase.Struct(
331 maUtils.showPsfSpatialCells(exposure, cellSet,
332 symb=
"o", ctype=ds9.CYAN, ctypeUnused=ds9.YELLOW,
334 for cell
in cellSet.getCellList():
335 for cand
in cell.begin(
not showBadCandidates):
336 cand = measAlg.cast_PsfCandidateF(cand)
337 status = cand.getStatus()
338 ds9.dot(
'+', *cand.getSource().getCentroid(), frame=frame,
339 ctype=ds9.GREEN
if status == afwMath.SpatialCellCandidate.GOOD
else
340 ds9.YELLOW
if status == afwMath.SpatialCellCandidate.UNKNOWN
else ds9.RED)
346 for cell
in cellSet.getCellList():
347 for cand
in cell.begin(
not showBadCandidates):
348 cand = measAlg.cast_PsfCandidateF(cand)
351 im = cand.getMaskedImage()
353 chi2 = cand.getChi2()
359 stamps.append((im,
"%d%s" %
360 (maUtils.splitId(cand.getSource().getId(),
True)[
"objId"], chi2),
365 mos = displayUtils.Mosaic()
366 for im, label, status
in stamps:
367 im = type(im)(im,
True)
370 except NotImplementedError:
373 mos.append(im, label,
374 ds9.GREEN
if status == afwMath.SpatialCellCandidate.GOOD
else
375 ds9.YELLOW
if status == afwMath.SpatialCellCandidate.UNKNOWN
else ds9.RED)
378 mos.makeMosaic(frame=frame, title=
"Psf Candidates")
380 def plotResiduals(exposure, cellSet, showBadCandidates=False, normalizeResiduals=True, frame=2):
381 psf = exposure.getPsf()
384 maUtils.showPsfCandidates(exposure, cellSet, psf=psf, frame=frame,
385 normalize=normalizeResiduals,
386 showBadCandidates=showBadCandidates)
388 maUtils.showPsfCandidates(exposure, cellSet, psf=psf, frame=frame,
389 normalize=normalizeResiduals,
390 showBadCandidates=showBadCandidates,
393 except Exception
as e:
394 if not showBadCandidates:
395 showBadCandidates =
True
def __init__
Create the detection task.
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.