LSSTApplications  17.0+124,17.0+14,17.0+73,18.0.0+37,18.0.0+80,18.0.0-4-g68ffd23+4,18.1.0-1-g0001055+12,18.1.0-1-g03d53ef+5,18.1.0-1-g1349e88+55,18.1.0-1-g2505f39+44,18.1.0-1-g5315e5e+4,18.1.0-1-g5e4b7ea+14,18.1.0-1-g7e8fceb+4,18.1.0-1-g85f8cd4+48,18.1.0-1-g8ff0b9f+4,18.1.0-1-ga2c679d+1,18.1.0-1-gd55f500+35,18.1.0-10-gb58edde+2,18.1.0-11-g0997b02+4,18.1.0-13-gfe4edf0b+12,18.1.0-14-g259bd21+21,18.1.0-19-gdb69f3f+2,18.1.0-2-g5f9922c+24,18.1.0-2-gd3b74e5+11,18.1.0-2-gfbf3545+32,18.1.0-26-g728bddb4+5,18.1.0-27-g6ff7ca9+2,18.1.0-3-g52aa583+25,18.1.0-3-g8ea57af+9,18.1.0-3-gb69f684+42,18.1.0-3-gfcaddf3+6,18.1.0-32-gd8786685a,18.1.0-4-gf3f9b77+6,18.1.0-5-g1dd662b+2,18.1.0-5-g6dbcb01+41,18.1.0-6-gae77429+3,18.1.0-7-g9d75d83+9,18.1.0-7-gae09a6d+30,18.1.0-9-gc381ef5+4,w.2019.45
LSSTDataManagementBasePackage
characterizeImage.py
Go to the documentation of this file.
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 #
22 import numpy as np
23 
24 from lsstDebug import getDebugFrame
25 import lsst.afw.table as afwTable
26 import lsst.pex.config as pexConfig
27 import lsst.pipe.base as pipeBase
28 import lsst.daf.base as dafBase
30 from lsst.afw.math import BackgroundList
31 from lsst.afw.table import SourceTable, SourceCatalog, IdFactory
32 from lsst.meas.algorithms import SubtractBackgroundTask, SourceDetectionTask, MeasureApCorrTask
33 from lsst.meas.algorithms.installGaussianPsf import InstallGaussianPsfTask
34 from lsst.meas.astrom import RefMatchTask, displayAstrometry
35 from lsst.meas.algorithms import LoadIndexedReferenceObjectsTask
36 from lsst.obs.base import ExposureIdInfo
37 from lsst.meas.base import SingleFrameMeasurementTask, ApplyApCorrTask, CatalogCalculationTask
38 from lsst.meas.deblender import SourceDeblendTask
39 from .measurePsf import MeasurePsfTask
40 from .repair import RepairTask
41 
42 __all__ = ["CharacterizeImageConfig", "CharacterizeImageTask"]
43 
44 
45 class CharacterizeImageConnections(pipeBase.PipelineTaskConnections,
46  dimensions=("instrument", "visit", "detector")):
47  exposure = cT.Input(
48  doc="Input exposure data",
49  name="postISRCCD",
50  storageClass="ExposureF",
51  dimensions=["instrument", "visit", "detector"],
52  )
53  characterized = cT.Output(
54  doc="Output characterized data.",
55  name="icExp",
56  storageClass="ExposureF",
57  dimensions=["instrument", "visit", "detector"],
58  )
59  sourceCat = cT.Output(
60  doc="Output source catalog.",
61  name="icSrc",
62  storageClass="SourceCatalog",
63  dimensions=["instrument", "visit", "detector"],
64  )
65  backgroundModel = cT.Output(
66  doc="Output background model.",
67  name="icExpBackground",
68  storageClass="Background",
69  dimensions=["instrument", "visit", "detector"],
70  )
71  outputSchema = cT.InitOutput(
72  doc="Schema of the catalog produced by CharacterizeImage",
73  name="icSrc_schema",
74  storageClass="SourceCatalog",
75  )
76 
77 
78 class CharacterizeImageConfig(pipeBase.PipelineTaskConfig,
79  pipelineConnections=CharacterizeImageConnections):
80 
81  """!Config for CharacterizeImageTask"""
82  doMeasurePsf = pexConfig.Field(
83  dtype=bool,
84  default=True,
85  doc="Measure PSF? If False then for all subsequent operations use either existing PSF "
86  "model when present, or install simple PSF model when not (see installSimplePsf "
87  "config options)"
88  )
89  doWrite = pexConfig.Field(
90  dtype=bool,
91  default=True,
92  doc="Persist results?",
93  )
94  doWriteExposure = pexConfig.Field(
95  dtype=bool,
96  default=True,
97  doc="Write icExp and icExpBackground in addition to icSrc? Ignored if doWrite False.",
98  )
99  psfIterations = pexConfig.RangeField(
100  dtype=int,
101  default=2,
102  min=1,
103  doc="Number of iterations of detect sources, measure sources, "
104  "estimate PSF. If useSimplePsf is True then 2 should be plenty; "
105  "otherwise more may be wanted.",
106  )
107  background = pexConfig.ConfigurableField(
108  target=SubtractBackgroundTask,
109  doc="Configuration for initial background estimation",
110  )
111  detection = pexConfig.ConfigurableField(
112  target=SourceDetectionTask,
113  doc="Detect sources"
114  )
115  doDeblend = pexConfig.Field(
116  dtype=bool,
117  default=True,
118  doc="Run deblender input exposure"
119  )
120  deblend = pexConfig.ConfigurableField(
121  target=SourceDeblendTask,
122  doc="Split blended source into their components"
123  )
124  measurement = pexConfig.ConfigurableField(
125  target=SingleFrameMeasurementTask,
126  doc="Measure sources"
127  )
128  doApCorr = pexConfig.Field(
129  dtype=bool,
130  default=True,
131  doc="Run subtasks to measure and apply aperture corrections"
132  )
133  measureApCorr = pexConfig.ConfigurableField(
134  target=MeasureApCorrTask,
135  doc="Subtask to measure aperture corrections"
136  )
137  applyApCorr = pexConfig.ConfigurableField(
138  target=ApplyApCorrTask,
139  doc="Subtask to apply aperture corrections"
140  )
141  # If doApCorr is False, and the exposure does not have apcorrections already applied, the
142  # active plugins in catalogCalculation almost certainly should not contain the characterization plugin
143  catalogCalculation = pexConfig.ConfigurableField(
144  target=CatalogCalculationTask,
145  doc="Subtask to run catalogCalculation plugins on catalog"
146  )
147  useSimplePsf = pexConfig.Field(
148  dtype=bool,
149  default=True,
150  doc="Replace the existing PSF model with a simplified version that has the same sigma "
151  "at the start of each PSF determination iteration? Doing so makes PSF determination "
152  "converge more robustly and quickly.",
153  )
154  installSimplePsf = pexConfig.ConfigurableField(
155  target=InstallGaussianPsfTask,
156  doc="Install a simple PSF model",
157  )
158  refObjLoader = pexConfig.ConfigurableField(
159  target=LoadIndexedReferenceObjectsTask,
160  doc="reference object loader",
161  )
162  ref_match = pexConfig.ConfigurableField(
163  target=RefMatchTask,
164  doc="Task to load and match reference objects. Only used if measurePsf can use matches. "
165  "Warning: matching will only work well if the initial WCS is accurate enough "
166  "to give good matches (roughly: good to 3 arcsec across the CCD).",
167  )
168  measurePsf = pexConfig.ConfigurableField(
169  target=MeasurePsfTask,
170  doc="Measure PSF",
171  )
172  repair = pexConfig.ConfigurableField(
173  target=RepairTask,
174  doc="Remove cosmic rays",
175  )
176  checkUnitsParseStrict = pexConfig.Field(
177  doc="Strictness of Astropy unit compatibility check, can be 'raise', 'warn' or 'silent'",
178  dtype=str,
179  default="raise",
180  )
181 
182  def setDefaults(self):
183  super().setDefaults()
184  # just detect bright stars; includeThresholdMultipler=10 seems large,
185  # but these are the values we have been using
186  self.detection.thresholdValue = 5.0
187  self.detection.includeThresholdMultiplier = 10.0
188  # do not deblend, as it makes a mess
189  self.doDeblend = False
190  # measure and apply aperture correction; note: measuring and applying aperture
191  # correction are disabled until the final measurement, after PSF is measured
192  self.doApCorr = True
193  # minimal set of measurements needed to determine PSF
194  self.measurement.plugins.names = [
195  "base_PixelFlags",
196  "base_SdssCentroid",
197  "base_SdssShape",
198  "base_GaussianFlux",
199  "base_PsfFlux",
200  "base_CircularApertureFlux",
201  ]
202 
203  def validate(self):
204  if self.doApCorr and not self.measurePsf:
205  raise RuntimeError("Must measure PSF to measure aperture correction, "
206  "because flags determined by PSF measurement are used to identify "
207  "sources used to measure aperture correction")
208 
209 
215 
216 
217 class CharacterizeImageTask(pipeBase.PipelineTask, pipeBase.CmdLineTask):
218  r"""!Measure bright sources and use this to estimate background and PSF of an exposure
219 
220  @anchor CharacterizeImageTask_
221 
222  @section pipe_tasks_characterizeImage_Contents Contents
223 
224  - @ref pipe_tasks_characterizeImage_Purpose
225  - @ref pipe_tasks_characterizeImage_Initialize
226  - @ref pipe_tasks_characterizeImage_IO
227  - @ref pipe_tasks_characterizeImage_Config
228  - @ref pipe_tasks_characterizeImage_Debug
229 
230 
231  @section pipe_tasks_characterizeImage_Purpose Description
232 
233  Given an exposure with defects repaired (masked and interpolated over, e.g. as output by IsrTask):
234  - detect and measure bright sources
235  - repair cosmic rays
236  - measure and subtract background
237  - measure PSF
238 
239  @section pipe_tasks_characterizeImage_Initialize Task initialisation
240 
241  @copydoc \_\_init\_\_
242 
243  @section pipe_tasks_characterizeImage_IO Invoking the Task
244 
245  If you want this task to unpersist inputs or persist outputs, then call
246  the `runDataRef` method (a thin wrapper around the `run` method).
247 
248  If you already have the inputs unpersisted and do not want to persist the output
249  then it is more direct to call the `run` method:
250 
251  @section pipe_tasks_characterizeImage_Config Configuration parameters
252 
253  See @ref CharacterizeImageConfig
254 
255  @section pipe_tasks_characterizeImage_Debug Debug variables
256 
257  The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag
258  `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`.
259 
260  CharacterizeImageTask has a debug dictionary with the following keys:
261  <dl>
262  <dt>frame
263  <dd>int: if specified, the frame of first debug image displayed (defaults to 1)
264  <dt>repair_iter
265  <dd>bool; if True display image after each repair in the measure PSF loop
266  <dt>background_iter
267  <dd>bool; if True display image after each background subtraction in the measure PSF loop
268  <dt>measure_iter
269  <dd>bool; if True display image and sources at the end of each iteration of the measure PSF loop
270  See @ref lsst.meas.astrom.displayAstrometry for the meaning of the various symbols.
271  <dt>psf
272  <dd>bool; if True display image and sources after PSF is measured;
273  this will be identical to the final image displayed by measure_iter if measure_iter is true
274  <dt>repair
275  <dd>bool; if True display image and sources after final repair
276  <dt>measure
277  <dd>bool; if True display image and sources after final measurement
278  </dl>
279 
280  For example, put something like:
281  @code{.py}
282  import lsstDebug
283  def DebugInfo(name):
284  di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
285  if name == "lsst.pipe.tasks.characterizeImage":
286  di.display = dict(
287  repair = True,
288  )
289 
290  return di
291 
292  lsstDebug.Info = DebugInfo
293  @endcode
294  into your `debug.py` file and run `calibrateTask.py` with the `--debug` flag.
295 
296  Some subtasks may have their own debug variables; see individual Task documentation.
297  """
298 
299  # Example description used to live here, removed 2-20-2017 by MSSG
300 
301  ConfigClass = CharacterizeImageConfig
302  _DefaultName = "characterizeImage"
303  RunnerClass = pipeBase.ButlerInitializedTaskRunner
304 
305  def runQuantum(self, butlerQC, inputRefs, outputRefs):
306  inputs = butlerQC.get(inputRefs)
307  if 'exposureIdInfo' not in inputs.keys():
308  exposureIdInfo = ExposureIdInfo()
309  exposureIdInfo.expId, exposureIdInfo.expBits = butlerQC.quantum.dataId.pack("visit_detector",
310  returnMaxBits=True)
311  inputs['exposureIdInfo'] = exposureIdInfo
312  outputs = self.run(**inputs)
313  butlerQC.put(outputs, outputRefs)
314 
315  def __init__(self, butler=None, refObjLoader=None, schema=None, **kwargs):
316  """!Construct a CharacterizeImageTask
317 
318  @param[in] butler A butler object is passed to the refObjLoader constructor in case
319  it is needed to load catalogs. May be None if a catalog-based star selector is
320  not used, if the reference object loader constructor does not require a butler,
321  or if a reference object loader is passed directly via the refObjLoader argument.
322  @param[in] refObjLoader An instance of LoadReferenceObjectsTasks that supplies an
323  external reference catalog to a catalog-based star selector. May be None if a
324  catalog star selector is not used or the loader can be constructed from the
325  butler argument.
326  @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None
327  @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask
328  """
329  super().__init__(**kwargs)
330 
331  if schema is None:
332  schema = SourceTable.makeMinimalSchema()
333  self.schema = schema
334  self.makeSubtask("background")
335  self.makeSubtask("installSimplePsf")
336  self.makeSubtask("repair")
337  self.makeSubtask("measurePsf", schema=self.schema)
338  if self.config.doMeasurePsf and self.measurePsf.usesMatches:
339  if not refObjLoader:
340  self.makeSubtask('refObjLoader', butler=butler)
341  refObjLoader = self.refObjLoader
342  self.makeSubtask("ref_match", refObjLoader=refObjLoader)
344  self.makeSubtask('detection', schema=self.schema)
345  if self.config.doDeblend:
346  self.makeSubtask("deblend", schema=self.schema)
347  self.makeSubtask('measurement', schema=self.schema, algMetadata=self.algMetadata)
348  if self.config.doApCorr:
349  self.makeSubtask('measureApCorr', schema=self.schema)
350  self.makeSubtask('applyApCorr', schema=self.schema)
351  self.makeSubtask('catalogCalculation', schema=self.schema)
352  self._initialFrame = getDebugFrame(self._display, "frame") or 1
353  self._frame = self._initialFrame
354  self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
356 
358  outputCatSchema = afwTable.SourceCatalog(self.schema)
359  outputCatSchema.getTable().setMetadata(self.algMetadata)
360  return {'outputSchema': outputCatSchema}
361 
362  @pipeBase.timeMethod
363  def runDataRef(self, dataRef, exposure=None, background=None, doUnpersist=True):
364  """!Characterize a science image and, if wanted, persist the results
365 
366  This simply unpacks the exposure and passes it to the characterize method to do the work.
367 
368  @param[in] dataRef: butler data reference for science exposure
369  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
370  If None then unpersist from "postISRCCD".
371  The following changes are made, depending on the config:
372  - set psf to the measured PSF
373  - set apCorrMap to the measured aperture correction
374  - subtract background
375  - interpolate over cosmic rays
376  - update detection and cosmic ray mask planes
377  @param[in,out] background initial model of background already subtracted from exposure
378  (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
379  which is typical for image characterization.
380  A refined background model is output.
381  @param[in] doUnpersist if True the exposure is read from the repository
382  and the exposure and background arguments must be None;
383  if False the exposure must be provided.
384  True is intended for running as a command-line task, False for running as a subtask
385 
386  @return same data as the characterize method
387  """
388  self._frame = self._initialFrame # reset debug display frame
389  self.log.info("Processing %s" % (dataRef.dataId))
390 
391  if doUnpersist:
392  if exposure is not None or background is not None:
393  raise RuntimeError("doUnpersist true; exposure and background must be None")
394  exposure = dataRef.get("postISRCCD", immediate=True)
395  elif exposure is None:
396  raise RuntimeError("doUnpersist false; exposure must be provided")
397 
398  exposureIdInfo = dataRef.get("expIdInfo")
399 
400  charRes = self.run(
401  exposure=exposure,
402  exposureIdInfo=exposureIdInfo,
403  background=background,
404  )
405 
406  if self.config.doWrite:
407  dataRef.put(charRes.sourceCat, "icSrc")
408  if self.config.doWriteExposure:
409  dataRef.put(charRes.exposure, "icExp")
410  dataRef.put(charRes.background, "icExpBackground")
411 
412  return charRes
413 
414  @pipeBase.timeMethod
415  def run(self, exposure, exposureIdInfo=None, background=None):
416  """!Characterize a science image
417 
418  Peforms the following operations:
419  - Iterate the following config.psfIterations times, or once if config.doMeasurePsf false:
420  - detect and measure sources and estimate PSF (see detectMeasureAndEstimatePsf for details)
421  - interpolate over cosmic rays
422  - perform final measurement
423 
424  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
425  The following changes are made:
426  - update or set psf
427  - set apCorrMap
428  - update detection and cosmic ray mask planes
429  - subtract background and interpolate over cosmic rays
430  @param[in] exposureIdInfo ID info for exposure (an lsst.obs.base.ExposureIdInfo).
431  If not provided, returned SourceCatalog IDs will not be globally unique.
432  @param[in,out] background initial model of background already subtracted from exposure
433  (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
434  which is typical for image characterization.
435 
436  @return pipe_base Struct containing these fields, all from the final iteration
437  of detectMeasureAndEstimatePsf:
438  - exposure: characterized exposure; image is repaired by interpolating over cosmic rays,
439  mask is updated accordingly, and the PSF model is set
440  - sourceCat: detected sources (an lsst.afw.table.SourceCatalog)
441  - background: model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
442  - psfCellSet: spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
443  """
444  self._frame = self._initialFrame # reset debug display frame
445 
446  if not self.config.doMeasurePsf and not exposure.hasPsf():
447  self.log.warn("Source catalog detected and measured with placeholder or default PSF")
448  self.installSimplePsf.run(exposure=exposure)
449 
450  if exposureIdInfo is None:
451  exposureIdInfo = ExposureIdInfo()
452 
453  # subtract an initial estimate of background level
454  background = self.background.run(exposure).background
455 
456  psfIterations = self.config.psfIterations if self.config.doMeasurePsf else 1
457  for i in range(psfIterations):
458  dmeRes = self.detectMeasureAndEstimatePsf(
459  exposure=exposure,
460  exposureIdInfo=exposureIdInfo,
461  background=background,
462  )
463 
464  psf = dmeRes.exposure.getPsf()
465  psfSigma = psf.computeShape().getDeterminantRadius()
466  psfDimensions = psf.computeImage().getDimensions()
467  medBackground = np.median(dmeRes.background.getImage().getArray())
468  self.log.info("iter %s; PSF sigma=%0.2f, dimensions=%s; median background=%0.2f" %
469  (i + 1, psfSigma, psfDimensions, medBackground))
470 
471  self.display("psf", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
472 
473  # perform final repair with final PSF
474  self.repair.run(exposure=dmeRes.exposure)
475  self.display("repair", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
476 
477  # perform final measurement with final PSF, including measuring and applying aperture correction,
478  # if wanted
479  self.measurement.run(measCat=dmeRes.sourceCat, exposure=dmeRes.exposure,
480  exposureId=exposureIdInfo.expId)
481  if self.config.doApCorr:
482  apCorrMap = self.measureApCorr.run(exposure=dmeRes.exposure, catalog=dmeRes.sourceCat).apCorrMap
483  dmeRes.exposure.getInfo().setApCorrMap(apCorrMap)
484  self.applyApCorr.run(catalog=dmeRes.sourceCat, apCorrMap=exposure.getInfo().getApCorrMap())
485  self.catalogCalculation.run(dmeRes.sourceCat)
486 
487  self.display("measure", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
488 
489  return pipeBase.Struct(
490  exposure=dmeRes.exposure,
491  sourceCat=dmeRes.sourceCat,
492  background=dmeRes.background,
493  psfCellSet=dmeRes.psfCellSet,
494 
495  characterized=dmeRes.exposure,
496  backgroundModel=dmeRes.background
497  )
498 
499  @pipeBase.timeMethod
500  def detectMeasureAndEstimatePsf(self, exposure, exposureIdInfo, background):
501  """!Perform one iteration of detect, measure and estimate PSF
502 
503  Performs the following operations:
504  - if config.doMeasurePsf or not exposure.hasPsf():
505  - install a simple PSF model (replacing the existing one, if need be)
506  - interpolate over cosmic rays with keepCRs=True
507  - estimate background and subtract it from the exposure
508  - detect, deblend and measure sources, and subtract a refined background model;
509  - if config.doMeasurePsf:
510  - measure PSF
511 
512  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar)
513  The following changes are made:
514  - update or set psf
515  - update detection and cosmic ray mask planes
516  - subtract background
517  @param[in] exposureIdInfo ID info for exposure (an lsst.obs_base.ExposureIdInfo)
518  @param[in,out] background initial model of background already subtracted from exposure
519  (an lsst.afw.math.BackgroundList).
520 
521  @return pipe_base Struct containing these fields, all from the final iteration
522  of detect sources, measure sources and estimate PSF:
523  - exposure characterized exposure; image is repaired by interpolating over cosmic rays,
524  mask is updated accordingly, and the PSF model is set
525  - sourceCat detected sources (an lsst.afw.table.SourceCatalog)
526  - background model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
527  - psfCellSet spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
528  """
529  # install a simple PSF model, if needed or wanted
530  if not exposure.hasPsf() or (self.config.doMeasurePsf and self.config.useSimplePsf):
531  self.log.warn("Source catalog detected and measured with placeholder or default PSF")
532  self.installSimplePsf.run(exposure=exposure)
533 
534  # run repair, but do not interpolate over cosmic rays (do that elsewhere, with the final PSF model)
535  self.repair.run(exposure=exposure, keepCRs=True)
536  self.display("repair_iter", exposure=exposure)
537 
538  if background is None:
539  background = BackgroundList()
540 
541  sourceIdFactory = IdFactory.makeSource(exposureIdInfo.expId, exposureIdInfo.unusedBits)
542  table = SourceTable.make(self.schema, sourceIdFactory)
543  table.setMetadata(self.algMetadata)
544 
545  detRes = self.detection.run(table=table, exposure=exposure, doSmooth=True)
546  sourceCat = detRes.sources
547  if detRes.fpSets.background:
548  for bg in detRes.fpSets.background:
549  background.append(bg)
550 
551  if self.config.doDeblend:
552  self.deblend.run(exposure=exposure, sources=sourceCat)
553 
554  self.measurement.run(measCat=sourceCat, exposure=exposure, exposureId=exposureIdInfo.expId)
555 
556  measPsfRes = pipeBase.Struct(cellSet=None)
557  if self.config.doMeasurePsf:
558  if self.measurePsf.usesMatches:
559  matches = self.ref_match.loadAndMatch(exposure=exposure, sourceCat=sourceCat).matches
560  else:
561  matches = None
562  measPsfRes = self.measurePsf.run(exposure=exposure, sources=sourceCat, matches=matches,
563  expId=exposureIdInfo.expId)
564  self.display("measure_iter", exposure=exposure, sourceCat=sourceCat)
565 
566  return pipeBase.Struct(
567  exposure=exposure,
568  sourceCat=sourceCat,
569  background=background,
570  psfCellSet=measPsfRes.cellSet,
571  )
572 
573  def getSchemaCatalogs(self):
574  """Return a dict of empty catalogs for each catalog dataset produced by this task.
575  """
576  sourceCat = SourceCatalog(self.schema)
577  sourceCat.getTable().setMetadata(self.algMetadata)
578  return {"icSrc": sourceCat}
579 
580  def display(self, itemName, exposure, sourceCat=None):
581  """Display exposure and sources on next frame, if display of itemName has been requested
582 
583  @param[in] itemName name of item in debugInfo
584  @param[in] exposure exposure to display
585  @param[in] sourceCat source catalog to display
586  """
587  val = getDebugFrame(self._display, itemName)
588  if not val:
589  return
590 
591  displayAstrometry(exposure=exposure, sourceCat=sourceCat, frame=self._frame, pause=False)
592  self._frame += 1
def display(self, itemName, exposure, sourceCat=None)
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
def run(self, exposure, exposureIdInfo=None, background=None)
Characterize a science image.
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
Measure bright sources and use this to estimate background and PSF of an exposure.
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)
Definition: display.py:34
def runQuantum(self, butlerQC, inputRefs, outputRefs)
def getDebugFrame(debugDisplay, name)
Definition: lsstDebug.py:90
def runDataRef(self, dataRef, exposure=None, background=None, doUnpersist=True)
Characterize a science image and, if wanted, persist the results.
def __init__(self, butler=None, refObjLoader=None, schema=None, kwargs)
Construct a CharacterizeImageTask.
def detectMeasureAndEstimatePsf(self, exposure, exposureIdInfo, background)
Perform one iteration of detect, measure and estimate PSF.