Coverage for python/lsst/pipe/tasks/characterizeImage.py : 27%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#
2# LSST Data Management System
3# Copyright 2008-2015 AURA/LSST.
4#
5# This product includes software developed by the
6# LSST Project (http://www.lsst.org/).
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <https://www.lsstcorp.org/LegalNotices/>.
21#
22import numpy as np
24from lsstDebug import getDebugFrame
25import lsst.afw.table as afwTable
26import lsst.pex.config as pexConfig
27import lsst.pipe.base as pipeBase
28import lsst.daf.base as dafBase
29import lsst.pipe.base.connectionTypes as cT
30from lsst.afw.math import BackgroundList
31from lsst.afw.table import SourceTable, SourceCatalog
32from lsst.meas.algorithms import SubtractBackgroundTask, SourceDetectionTask, MeasureApCorrTask
33from lsst.meas.algorithms.installGaussianPsf import InstallGaussianPsfTask
34from lsst.meas.astrom import RefMatchTask, displayAstrometry
35from lsst.meas.algorithms import LoadIndexedReferenceObjectsTask
36from lsst.obs.base import ExposureIdInfo
37from lsst.meas.base import SingleFrameMeasurementTask, ApplyApCorrTask, CatalogCalculationTask
38from lsst.meas.deblender import SourceDeblendTask
39from .measurePsf import MeasurePsfTask
40from .repair import RepairTask
41from .computeExposureSummaryStats import ComputeExposureSummaryStatsTask
42from lsst.pex.exceptions import LengthError
44__all__ = ["CharacterizeImageConfig", "CharacterizeImageTask"]
47class CharacterizeImageConnections(pipeBase.PipelineTaskConnections,
48 dimensions=("instrument", "visit", "detector")):
49 exposure = cT.Input(
50 doc="Input exposure data",
51 name="postISRCCD",
52 storageClass="Exposure",
53 dimensions=["instrument", "exposure", "detector"],
54 )
55 characterized = cT.Output(
56 doc="Output characterized data.",
57 name="icExp",
58 storageClass="ExposureF",
59 dimensions=["instrument", "visit", "detector"],
60 )
61 sourceCat = cT.Output(
62 doc="Output source catalog.",
63 name="icSrc",
64 storageClass="SourceCatalog",
65 dimensions=["instrument", "visit", "detector"],
66 )
67 backgroundModel = cT.Output(
68 doc="Output background model.",
69 name="icExpBackground",
70 storageClass="Background",
71 dimensions=["instrument", "visit", "detector"],
72 )
73 outputSchema = cT.InitOutput(
74 doc="Schema of the catalog produced by CharacterizeImage",
75 name="icSrc_schema",
76 storageClass="SourceCatalog",
77 )
79 def adjustQuantum(self, inputs, outputs, label, dataId):
80 # Docstring inherited from PipelineTaskConnections
81 try:
82 return super().adjustQuantum(inputs, outputs, label, dataId)
83 except pipeBase.ScalarError as err:
84 raise pipeBase.ScalarError(
85 "CharacterizeImageTask can at present only be run on visits that are associated with "
86 "exactly one exposure. Either this is not a valid exposure for this pipeline, or the "
87 "snap-combination step you probably want hasn't been configured to run between ISR and "
88 "this task (as of this writing, that would be because it hasn't been implemented yet)."
89 ) from err
92class CharacterizeImageConfig(pipeBase.PipelineTaskConfig,
93 pipelineConnections=CharacterizeImageConnections):
95 """!Config for CharacterizeImageTask"""
96 doMeasurePsf = pexConfig.Field(
97 dtype=bool,
98 default=True,
99 doc="Measure PSF? If False then for all subsequent operations use either existing PSF "
100 "model when present, or install simple PSF model when not (see installSimplePsf "
101 "config options)"
102 )
103 doWrite = pexConfig.Field(
104 dtype=bool,
105 default=True,
106 doc="Persist results?",
107 )
108 doWriteExposure = pexConfig.Field(
109 dtype=bool,
110 default=True,
111 doc="Write icExp and icExpBackground in addition to icSrc? Ignored if doWrite False.",
112 )
113 psfIterations = pexConfig.RangeField(
114 dtype=int,
115 default=2,
116 min=1,
117 doc="Number of iterations of detect sources, measure sources, "
118 "estimate PSF. If useSimplePsf is True then 2 should be plenty; "
119 "otherwise more may be wanted.",
120 )
121 background = pexConfig.ConfigurableField(
122 target=SubtractBackgroundTask,
123 doc="Configuration for initial background estimation",
124 )
125 detection = pexConfig.ConfigurableField(
126 target=SourceDetectionTask,
127 doc="Detect sources"
128 )
129 doDeblend = pexConfig.Field(
130 dtype=bool,
131 default=True,
132 doc="Run deblender input exposure"
133 )
134 deblend = pexConfig.ConfigurableField(
135 target=SourceDeblendTask,
136 doc="Split blended source into their components"
137 )
138 measurement = pexConfig.ConfigurableField(
139 target=SingleFrameMeasurementTask,
140 doc="Measure sources"
141 )
142 doApCorr = pexConfig.Field(
143 dtype=bool,
144 default=True,
145 doc="Run subtasks to measure and apply aperture corrections"
146 )
147 measureApCorr = pexConfig.ConfigurableField(
148 target=MeasureApCorrTask,
149 doc="Subtask to measure aperture corrections"
150 )
151 applyApCorr = pexConfig.ConfigurableField(
152 target=ApplyApCorrTask,
153 doc="Subtask to apply aperture corrections"
154 )
155 # If doApCorr is False, and the exposure does not have apcorrections already applied, the
156 # active plugins in catalogCalculation almost certainly should not contain the characterization plugin
157 catalogCalculation = pexConfig.ConfigurableField(
158 target=CatalogCalculationTask,
159 doc="Subtask to run catalogCalculation plugins on catalog"
160 )
161 doComputeSummaryStats = pexConfig.Field(
162 dtype=bool,
163 default=True,
164 doc="Run subtask to measure exposure summary statistics"
165 )
166 computeSummaryStats = pexConfig.ConfigurableField(
167 target=ComputeExposureSummaryStatsTask,
168 doc="Subtask to run computeSummaryStats on exposure"
169 )
170 useSimplePsf = pexConfig.Field(
171 dtype=bool,
172 default=True,
173 doc="Replace the existing PSF model with a simplified version that has the same sigma "
174 "at the start of each PSF determination iteration? Doing so makes PSF determination "
175 "converge more robustly and quickly.",
176 )
177 installSimplePsf = pexConfig.ConfigurableField(
178 target=InstallGaussianPsfTask,
179 doc="Install a simple PSF model",
180 )
181 refObjLoader = pexConfig.ConfigurableField(
182 target=LoadIndexedReferenceObjectsTask,
183 doc="reference object loader",
184 )
185 ref_match = pexConfig.ConfigurableField(
186 target=RefMatchTask,
187 doc="Task to load and match reference objects. Only used if measurePsf can use matches. "
188 "Warning: matching will only work well if the initial WCS is accurate enough "
189 "to give good matches (roughly: good to 3 arcsec across the CCD).",
190 )
191 measurePsf = pexConfig.ConfigurableField(
192 target=MeasurePsfTask,
193 doc="Measure PSF",
194 )
195 repair = pexConfig.ConfigurableField(
196 target=RepairTask,
197 doc="Remove cosmic rays",
198 )
199 requireCrForPsf = pexConfig.Field(
200 dtype=bool,
201 default=True,
202 doc="Require cosmic ray detection and masking to run successfully before measuring the PSF."
203 )
204 checkUnitsParseStrict = pexConfig.Field(
205 doc="Strictness of Astropy unit compatibility check, can be 'raise', 'warn' or 'silent'",
206 dtype=str,
207 default="raise",
208 )
210 def setDefaults(self):
211 super().setDefaults()
212 # just detect bright stars; includeThresholdMultipler=10 seems large,
213 # but these are the values we have been using
214 self.detection.thresholdValue = 5.0
215 self.detection.includeThresholdMultiplier = 10.0
216 self.detection.doTempLocalBackground = False
217 # do not deblend, as it makes a mess
218 self.doDeblend = False
219 # measure and apply aperture correction; note: measuring and applying aperture
220 # correction are disabled until the final measurement, after PSF is measured
221 self.doApCorr = True
222 # minimal set of measurements needed to determine PSF
223 self.measurement.plugins.names = [
224 "base_PixelFlags",
225 "base_SdssCentroid",
226 "base_SdssShape",
227 "base_GaussianFlux",
228 "base_PsfFlux",
229 "base_CircularApertureFlux",
230 ]
232 def validate(self):
233 if self.doApCorr and not self.measurePsf:
234 raise RuntimeError("Must measure PSF to measure aperture correction, "
235 "because flags determined by PSF measurement are used to identify "
236 "sources used to measure aperture correction")
238## \addtogroup LSST_task_documentation
239## \{
240## \page CharacterizeImageTask
241## \ref CharacterizeImageTask_ "CharacterizeImageTask"
242## \copybrief CharacterizeImageTask
243## \}
246class CharacterizeImageTask(pipeBase.PipelineTask, pipeBase.CmdLineTask):
247 r"""!Measure bright sources and use this to estimate background and PSF of an exposure
249 @anchor CharacterizeImageTask_
251 @section pipe_tasks_characterizeImage_Contents Contents
253 - @ref pipe_tasks_characterizeImage_Purpose
254 - @ref pipe_tasks_characterizeImage_Initialize
255 - @ref pipe_tasks_characterizeImage_IO
256 - @ref pipe_tasks_characterizeImage_Config
257 - @ref pipe_tasks_characterizeImage_Debug
260 @section pipe_tasks_characterizeImage_Purpose Description
262 Given an exposure with defects repaired (masked and interpolated over, e.g. as output by IsrTask):
263 - detect and measure bright sources
264 - repair cosmic rays
265 - measure and subtract background
266 - measure PSF
268 @section pipe_tasks_characterizeImage_Initialize Task initialisation
270 @copydoc \_\_init\_\_
272 @section pipe_tasks_characterizeImage_IO Invoking the Task
274 If you want this task to unpersist inputs or persist outputs, then call
275 the `runDataRef` method (a thin wrapper around the `run` method).
277 If you already have the inputs unpersisted and do not want to persist the output
278 then it is more direct to call the `run` method:
280 @section pipe_tasks_characterizeImage_Config Configuration parameters
282 See @ref CharacterizeImageConfig
284 @section pipe_tasks_characterizeImage_Debug Debug variables
286 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag
287 `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`.
289 CharacterizeImageTask has a debug dictionary with the following keys:
290 <dl>
291 <dt>frame
292 <dd>int: if specified, the frame of first debug image displayed (defaults to 1)
293 <dt>repair_iter
294 <dd>bool; if True display image after each repair in the measure PSF loop
295 <dt>background_iter
296 <dd>bool; if True display image after each background subtraction in the measure PSF loop
297 <dt>measure_iter
298 <dd>bool; if True display image and sources at the end of each iteration of the measure PSF loop
299 See @ref lsst.meas.astrom.displayAstrometry for the meaning of the various symbols.
300 <dt>psf
301 <dd>bool; if True display image and sources after PSF is measured;
302 this will be identical to the final image displayed by measure_iter if measure_iter is true
303 <dt>repair
304 <dd>bool; if True display image and sources after final repair
305 <dt>measure
306 <dd>bool; if True display image and sources after final measurement
307 </dl>
309 For example, put something like:
310 @code{.py}
311 import lsstDebug
312 def DebugInfo(name):
313 di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
314 if name == "lsst.pipe.tasks.characterizeImage":
315 di.display = dict(
316 repair = True,
317 )
319 return di
321 lsstDebug.Info = DebugInfo
322 @endcode
323 into your `debug.py` file and run `calibrateTask.py` with the `--debug` flag.
325 Some subtasks may have their own debug variables; see individual Task documentation.
326 """
328 # Example description used to live here, removed 2-20-2017 by MSSG
330 ConfigClass = CharacterizeImageConfig
331 _DefaultName = "characterizeImage"
332 RunnerClass = pipeBase.ButlerInitializedTaskRunner
334 def runQuantum(self, butlerQC, inputRefs, outputRefs):
335 inputs = butlerQC.get(inputRefs)
336 if 'exposureIdInfo' not in inputs.keys():
337 inputs['exposureIdInfo'] = ExposureIdInfo.fromDataId(butlerQC.quantum.dataId, "visit_detector")
338 outputs = self.run(**inputs)
339 butlerQC.put(outputs, outputRefs)
341 def __init__(self, butler=None, refObjLoader=None, schema=None, **kwargs):
342 """!Construct a CharacterizeImageTask
344 @param[in] butler A butler object is passed to the refObjLoader constructor in case
345 it is needed to load catalogs. May be None if a catalog-based star selector is
346 not used, if the reference object loader constructor does not require a butler,
347 or if a reference object loader is passed directly via the refObjLoader argument.
348 @param[in] refObjLoader An instance of LoadReferenceObjectsTasks that supplies an
349 external reference catalog to a catalog-based star selector. May be None if a
350 catalog star selector is not used or the loader can be constructed from the
351 butler argument.
352 @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None
353 @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask
354 """
355 super().__init__(**kwargs)
357 if schema is None:
358 schema = SourceTable.makeMinimalSchema()
359 self.schema = schema
360 self.makeSubtask("background")
361 self.makeSubtask("installSimplePsf")
362 self.makeSubtask("repair")
363 self.makeSubtask("measurePsf", schema=self.schema)
364 if self.config.doMeasurePsf and self.measurePsf.usesMatches:
365 if not refObjLoader:
366 self.makeSubtask('refObjLoader', butler=butler)
367 refObjLoader = self.refObjLoader
368 self.makeSubtask("ref_match", refObjLoader=refObjLoader)
369 self.algMetadata = dafBase.PropertyList()
370 self.makeSubtask('detection', schema=self.schema)
371 if self.config.doDeblend:
372 self.makeSubtask("deblend", schema=self.schema)
373 self.makeSubtask('measurement', schema=self.schema, algMetadata=self.algMetadata)
374 if self.config.doApCorr:
375 self.makeSubtask('measureApCorr', schema=self.schema)
376 self.makeSubtask('applyApCorr', schema=self.schema)
377 self.makeSubtask('catalogCalculation', schema=self.schema)
378 if self.config.doComputeSummaryStats:
379 self.makeSubtask('computeSummaryStats')
380 self._initialFrame = getDebugFrame(self._display, "frame") or 1
381 self._frame = self._initialFrame
382 self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
383 self.outputSchema = afwTable.SourceCatalog(self.schema)
385 def getInitOutputDatasets(self):
386 outputCatSchema = afwTable.SourceCatalog(self.schema)
387 outputCatSchema.getTable().setMetadata(self.algMetadata)
388 return {'outputSchema': outputCatSchema}
390 @pipeBase.timeMethod
391 def runDataRef(self, dataRef, exposure=None, background=None, doUnpersist=True):
392 """!Characterize a science image and, if wanted, persist the results
394 This simply unpacks the exposure and passes it to the characterize method to do the work.
396 @param[in] dataRef: butler data reference for science exposure
397 @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
398 If None then unpersist from "postISRCCD".
399 The following changes are made, depending on the config:
400 - set psf to the measured PSF
401 - set apCorrMap to the measured aperture correction
402 - subtract background
403 - interpolate over cosmic rays
404 - update detection and cosmic ray mask planes
405 @param[in,out] background initial model of background already subtracted from exposure
406 (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
407 which is typical for image characterization.
408 A refined background model is output.
409 @param[in] doUnpersist if True the exposure is read from the repository
410 and the exposure and background arguments must be None;
411 if False the exposure must be provided.
412 True is intended for running as a command-line task, False for running as a subtask
414 @return same data as the characterize method
415 """
416 self._frame = self._initialFrame # reset debug display frame
417 self.log.info("Processing %s" % (dataRef.dataId))
419 if doUnpersist:
420 if exposure is not None or background is not None:
421 raise RuntimeError("doUnpersist true; exposure and background must be None")
422 exposure = dataRef.get("postISRCCD", immediate=True)
423 elif exposure is None:
424 raise RuntimeError("doUnpersist false; exposure must be provided")
426 exposureIdInfo = dataRef.get("expIdInfo")
428 charRes = self.run(
429 exposure=exposure,
430 exposureIdInfo=exposureIdInfo,
431 background=background,
432 )
434 if self.config.doWrite:
435 dataRef.put(charRes.sourceCat, "icSrc")
436 if self.config.doWriteExposure:
437 dataRef.put(charRes.exposure, "icExp")
438 dataRef.put(charRes.background, "icExpBackground")
440 return charRes
442 @pipeBase.timeMethod
443 def run(self, exposure, exposureIdInfo=None, background=None):
444 """!Characterize a science image
446 Peforms the following operations:
447 - Iterate the following config.psfIterations times, or once if config.doMeasurePsf false:
448 - detect and measure sources and estimate PSF (see detectMeasureAndEstimatePsf for details)
449 - interpolate over cosmic rays
450 - perform final measurement
452 @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
453 The following changes are made:
454 - update or set psf
455 - set apCorrMap
456 - update detection and cosmic ray mask planes
457 - subtract background and interpolate over cosmic rays
458 @param[in] exposureIdInfo ID info for exposure (an lsst.obs.base.ExposureIdInfo).
459 If not provided, returned SourceCatalog IDs will not be globally unique.
460 @param[in,out] background initial model of background already subtracted from exposure
461 (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
462 which is typical for image characterization.
464 @return pipe_base Struct containing these fields, all from the final iteration
465 of detectMeasureAndEstimatePsf:
466 - exposure: characterized exposure; image is repaired by interpolating over cosmic rays,
467 mask is updated accordingly, and the PSF model is set
468 - sourceCat: detected sources (an lsst.afw.table.SourceCatalog)
469 - background: model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
470 - psfCellSet: spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
471 """
472 self._frame = self._initialFrame # reset debug display frame
474 if not self.config.doMeasurePsf and not exposure.hasPsf():
475 self.log.warn("Source catalog detected and measured with placeholder or default PSF")
476 self.installSimplePsf.run(exposure=exposure)
478 if exposureIdInfo is None:
479 exposureIdInfo = ExposureIdInfo()
481 # subtract an initial estimate of background level
482 background = self.background.run(exposure).background
484 psfIterations = self.config.psfIterations if self.config.doMeasurePsf else 1
485 for i in range(psfIterations):
486 dmeRes = self.detectMeasureAndEstimatePsf(
487 exposure=exposure,
488 exposureIdInfo=exposureIdInfo,
489 background=background,
490 )
492 psf = dmeRes.exposure.getPsf()
493 psfSigma = psf.computeShape().getDeterminantRadius()
494 psfDimensions = psf.computeImage().getDimensions()
495 medBackground = np.median(dmeRes.background.getImage().getArray())
496 self.log.info("iter %s; PSF sigma=%0.2f, dimensions=%s; median background=%0.2f" %
497 (i + 1, psfSigma, psfDimensions, medBackground))
499 self.display("psf", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
501 # perform final repair with final PSF
502 self.repair.run(exposure=dmeRes.exposure)
503 self.display("repair", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
505 # perform final measurement with final PSF, including measuring and applying aperture correction,
506 # if wanted
507 self.measurement.run(measCat=dmeRes.sourceCat, exposure=dmeRes.exposure,
508 exposureId=exposureIdInfo.expId)
509 if self.config.doApCorr:
510 apCorrMap = self.measureApCorr.run(exposure=dmeRes.exposure, catalog=dmeRes.sourceCat).apCorrMap
511 dmeRes.exposure.getInfo().setApCorrMap(apCorrMap)
512 self.applyApCorr.run(catalog=dmeRes.sourceCat, apCorrMap=exposure.getInfo().getApCorrMap())
513 self.catalogCalculation.run(dmeRes.sourceCat)
514 if self.config.doComputeSummaryStats:
515 summary = self.computeSummaryStats.run(exposure=dmeRes.exposure,
516 sources=dmeRes.sourceCat,
517 background=dmeRes.background)
518 dmeRes.exposure.getInfo().setSummaryStats(summary)
520 self.display("measure", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
522 return pipeBase.Struct(
523 exposure=dmeRes.exposure,
524 sourceCat=dmeRes.sourceCat,
525 background=dmeRes.background,
526 psfCellSet=dmeRes.psfCellSet,
528 characterized=dmeRes.exposure,
529 backgroundModel=dmeRes.background
530 )
532 @pipeBase.timeMethod
533 def detectMeasureAndEstimatePsf(self, exposure, exposureIdInfo, background):
534 """!Perform one iteration of detect, measure and estimate PSF
536 Performs the following operations:
537 - if config.doMeasurePsf or not exposure.hasPsf():
538 - install a simple PSF model (replacing the existing one, if need be)
539 - interpolate over cosmic rays with keepCRs=True
540 - estimate background and subtract it from the exposure
541 - detect, deblend and measure sources, and subtract a refined background model;
542 - if config.doMeasurePsf:
543 - measure PSF
545 @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar)
546 The following changes are made:
547 - update or set psf
548 - update detection and cosmic ray mask planes
549 - subtract background
550 @param[in] exposureIdInfo ID info for exposure (an lsst.obs_base.ExposureIdInfo)
551 @param[in,out] background initial model of background already subtracted from exposure
552 (an lsst.afw.math.BackgroundList).
554 @return pipe_base Struct containing these fields, all from the final iteration
555 of detect sources, measure sources and estimate PSF:
556 - exposure characterized exposure; image is repaired by interpolating over cosmic rays,
557 mask is updated accordingly, and the PSF model is set
558 - sourceCat detected sources (an lsst.afw.table.SourceCatalog)
559 - background model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
560 - psfCellSet spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
561 """
562 # install a simple PSF model, if needed or wanted
563 if not exposure.hasPsf() or (self.config.doMeasurePsf and self.config.useSimplePsf):
564 self.log.warn("Source catalog detected and measured with placeholder or default PSF")
565 self.installSimplePsf.run(exposure=exposure)
567 # run repair, but do not interpolate over cosmic rays (do that elsewhere, with the final PSF model)
568 if self.config.requireCrForPsf:
569 self.repair.run(exposure=exposure, keepCRs=True)
570 else:
571 try:
572 self.repair.run(exposure=exposure, keepCRs=True)
573 except LengthError:
574 self.log.warn("Skipping cosmic ray detection: Too many CR pixels (max %0.f)" %
575 self.config.repair.cosmicray.nCrPixelMax)
577 self.display("repair_iter", exposure=exposure)
579 if background is None:
580 background = BackgroundList()
582 sourceIdFactory = exposureIdInfo.makeSourceIdFactory()
583 table = SourceTable.make(self.schema, sourceIdFactory)
584 table.setMetadata(self.algMetadata)
586 detRes = self.detection.run(table=table, exposure=exposure, doSmooth=True)
587 sourceCat = detRes.sources
588 if detRes.fpSets.background:
589 for bg in detRes.fpSets.background:
590 background.append(bg)
592 if self.config.doDeblend:
593 self.deblend.run(exposure=exposure, sources=sourceCat)
595 self.measurement.run(measCat=sourceCat, exposure=exposure, exposureId=exposureIdInfo.expId)
597 measPsfRes = pipeBase.Struct(cellSet=None)
598 if self.config.doMeasurePsf:
599 if self.measurePsf.usesMatches:
600 matches = self.ref_match.loadAndMatch(exposure=exposure, sourceCat=sourceCat).matches
601 else:
602 matches = None
603 measPsfRes = self.measurePsf.run(exposure=exposure, sources=sourceCat, matches=matches,
604 expId=exposureIdInfo.expId)
605 self.display("measure_iter", exposure=exposure, sourceCat=sourceCat)
607 return pipeBase.Struct(
608 exposure=exposure,
609 sourceCat=sourceCat,
610 background=background,
611 psfCellSet=measPsfRes.cellSet,
612 )
614 def getSchemaCatalogs(self):
615 """Return a dict of empty catalogs for each catalog dataset produced by this task.
616 """
617 sourceCat = SourceCatalog(self.schema)
618 sourceCat.getTable().setMetadata(self.algMetadata)
619 return {"icSrc": sourceCat}
621 def display(self, itemName, exposure, sourceCat=None):
622 """Display exposure and sources on next frame, if display of itemName has been requested
624 @param[in] itemName name of item in debugInfo
625 @param[in] exposure exposure to display
626 @param[in] sourceCat source catalog to display
627 """
628 val = getDebugFrame(self._display, itemName)
629 if not val:
630 return
632 displayAstrometry(exposure=exposure, sourceCat=sourceCat, frame=self._frame, pause=False)
633 self._frame += 1