LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
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  self.detection.doTempLocalBackground = False
189  # do not deblend, as it makes a mess
190  self.doDeblend = False
191  # measure and apply aperture correction; note: measuring and applying aperture
192  # correction are disabled until the final measurement, after PSF is measured
193  self.doApCorr = True
194  # minimal set of measurements needed to determine PSF
195  self.measurement.plugins.names = [
196  "base_PixelFlags",
197  "base_SdssCentroid",
198  "base_SdssShape",
199  "base_GaussianFlux",
200  "base_PsfFlux",
201  "base_CircularApertureFlux",
202  ]
203 
204  def validate(self):
205  if self.doApCorr and not self.measurePsf:
206  raise RuntimeError("Must measure PSF to measure aperture correction, "
207  "because flags determined by PSF measurement are used to identify "
208  "sources used to measure aperture correction")
209 
210 
216 
217 
218 class CharacterizeImageTask(pipeBase.PipelineTask, pipeBase.CmdLineTask):
219  r"""!Measure bright sources and use this to estimate background and PSF of an exposure
220 
221  @anchor CharacterizeImageTask_
222 
223  @section pipe_tasks_characterizeImage_Contents Contents
224 
225  - @ref pipe_tasks_characterizeImage_Purpose
226  - @ref pipe_tasks_characterizeImage_Initialize
227  - @ref pipe_tasks_characterizeImage_IO
228  - @ref pipe_tasks_characterizeImage_Config
229  - @ref pipe_tasks_characterizeImage_Debug
230 
231 
232  @section pipe_tasks_characterizeImage_Purpose Description
233 
234  Given an exposure with defects repaired (masked and interpolated over, e.g. as output by IsrTask):
235  - detect and measure bright sources
236  - repair cosmic rays
237  - measure and subtract background
238  - measure PSF
239 
240  @section pipe_tasks_characterizeImage_Initialize Task initialisation
241 
242  @copydoc \_\_init\_\_
243 
244  @section pipe_tasks_characterizeImage_IO Invoking the Task
245 
246  If you want this task to unpersist inputs or persist outputs, then call
247  the `runDataRef` method (a thin wrapper around the `run` method).
248 
249  If you already have the inputs unpersisted and do not want to persist the output
250  then it is more direct to call the `run` method:
251 
252  @section pipe_tasks_characterizeImage_Config Configuration parameters
253 
254  See @ref CharacterizeImageConfig
255 
256  @section pipe_tasks_characterizeImage_Debug Debug variables
257 
258  The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a flag
259  `--debug` to import `debug.py` from your `$PYTHONPATH`; see @ref baseDebug for more about `debug.py`.
260 
261  CharacterizeImageTask has a debug dictionary with the following keys:
262  <dl>
263  <dt>frame
264  <dd>int: if specified, the frame of first debug image displayed (defaults to 1)
265  <dt>repair_iter
266  <dd>bool; if True display image after each repair in the measure PSF loop
267  <dt>background_iter
268  <dd>bool; if True display image after each background subtraction in the measure PSF loop
269  <dt>measure_iter
270  <dd>bool; if True display image and sources at the end of each iteration of the measure PSF loop
271  See @ref lsst.meas.astrom.displayAstrometry for the meaning of the various symbols.
272  <dt>psf
273  <dd>bool; if True display image and sources after PSF is measured;
274  this will be identical to the final image displayed by measure_iter if measure_iter is true
275  <dt>repair
276  <dd>bool; if True display image and sources after final repair
277  <dt>measure
278  <dd>bool; if True display image and sources after final measurement
279  </dl>
280 
281  For example, put something like:
282  @code{.py}
283  import lsstDebug
284  def DebugInfo(name):
285  di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
286  if name == "lsst.pipe.tasks.characterizeImage":
287  di.display = dict(
288  repair = True,
289  )
290 
291  return di
292 
293  lsstDebug.Info = DebugInfo
294  @endcode
295  into your `debug.py` file and run `calibrateTask.py` with the `--debug` flag.
296 
297  Some subtasks may have their own debug variables; see individual Task documentation.
298  """
299 
300  # Example description used to live here, removed 2-20-2017 by MSSG
301 
302  ConfigClass = CharacterizeImageConfig
303  _DefaultName = "characterizeImage"
304  RunnerClass = pipeBase.ButlerInitializedTaskRunner
305 
306  def runQuantum(self, butlerQC, inputRefs, outputRefs):
307  inputs = butlerQC.get(inputRefs)
308  if 'exposureIdInfo' not in inputs.keys():
309  exposureIdInfo = ExposureIdInfo()
310  exposureIdInfo.expId, exposureIdInfo.expBits = butlerQC.quantum.dataId.pack("visit_detector",
311  returnMaxBits=True)
312  inputs['exposureIdInfo'] = exposureIdInfo
313  outputs = self.run(**inputs)
314  butlerQC.put(outputs, outputRefs)
315 
316  def __init__(self, butler=None, refObjLoader=None, schema=None, **kwargs):
317  """!Construct a CharacterizeImageTask
318 
319  @param[in] butler A butler object is passed to the refObjLoader constructor in case
320  it is needed to load catalogs. May be None if a catalog-based star selector is
321  not used, if the reference object loader constructor does not require a butler,
322  or if a reference object loader is passed directly via the refObjLoader argument.
323  @param[in] refObjLoader An instance of LoadReferenceObjectsTasks that supplies an
324  external reference catalog to a catalog-based star selector. May be None if a
325  catalog star selector is not used or the loader can be constructed from the
326  butler argument.
327  @param[in,out] schema initial schema (an lsst.afw.table.SourceTable), or None
328  @param[in,out] kwargs other keyword arguments for lsst.pipe.base.CmdLineTask
329  """
330  super().__init__(**kwargs)
331 
332  if schema is None:
333  schema = SourceTable.makeMinimalSchema()
334  self.schema = schema
335  self.makeSubtask("background")
336  self.makeSubtask("installSimplePsf")
337  self.makeSubtask("repair")
338  self.makeSubtask("measurePsf", schema=self.schema)
339  if self.config.doMeasurePsf and self.measurePsf.usesMatches:
340  if not refObjLoader:
341  self.makeSubtask('refObjLoader', butler=butler)
342  refObjLoader = self.refObjLoader
343  self.makeSubtask("ref_match", refObjLoader=refObjLoader)
345  self.makeSubtask('detection', schema=self.schema)
346  if self.config.doDeblend:
347  self.makeSubtask("deblend", schema=self.schema)
348  self.makeSubtask('measurement', schema=self.schema, algMetadata=self.algMetadata)
349  if self.config.doApCorr:
350  self.makeSubtask('measureApCorr', schema=self.schema)
351  self.makeSubtask('applyApCorr', schema=self.schema)
352  self.makeSubtask('catalogCalculation', schema=self.schema)
353  self._initialFrame = getDebugFrame(self._display, "frame") or 1
354  self._frame = self._initialFrame
355  self.schema.checkUnits(parse_strict=self.config.checkUnitsParseStrict)
357 
359  outputCatSchema = afwTable.SourceCatalog(self.schema)
360  outputCatSchema.getTable().setMetadata(self.algMetadata)
361  return {'outputSchema': outputCatSchema}
362 
363  @pipeBase.timeMethod
364  def runDataRef(self, dataRef, exposure=None, background=None, doUnpersist=True):
365  """!Characterize a science image and, if wanted, persist the results
366 
367  This simply unpacks the exposure and passes it to the characterize method to do the work.
368 
369  @param[in] dataRef: butler data reference for science exposure
370  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
371  If None then unpersist from "postISRCCD".
372  The following changes are made, depending on the config:
373  - set psf to the measured PSF
374  - set apCorrMap to the measured aperture correction
375  - subtract background
376  - interpolate over cosmic rays
377  - update detection and cosmic ray mask planes
378  @param[in,out] background initial model of background already subtracted from exposure
379  (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
380  which is typical for image characterization.
381  A refined background model is output.
382  @param[in] doUnpersist if True the exposure is read from the repository
383  and the exposure and background arguments must be None;
384  if False the exposure must be provided.
385  True is intended for running as a command-line task, False for running as a subtask
386 
387  @return same data as the characterize method
388  """
389  self._frame = self._initialFrame # reset debug display frame
390  self.log.info("Processing %s" % (dataRef.dataId))
391 
392  if doUnpersist:
393  if exposure is not None or background is not None:
394  raise RuntimeError("doUnpersist true; exposure and background must be None")
395  exposure = dataRef.get("postISRCCD", immediate=True)
396  elif exposure is None:
397  raise RuntimeError("doUnpersist false; exposure must be provided")
398 
399  exposureIdInfo = dataRef.get("expIdInfo")
400 
401  charRes = self.run(
402  exposure=exposure,
403  exposureIdInfo=exposureIdInfo,
404  background=background,
405  )
406 
407  if self.config.doWrite:
408  dataRef.put(charRes.sourceCat, "icSrc")
409  if self.config.doWriteExposure:
410  dataRef.put(charRes.exposure, "icExp")
411  dataRef.put(charRes.background, "icExpBackground")
412 
413  return charRes
414 
415  @pipeBase.timeMethod
416  def run(self, exposure, exposureIdInfo=None, background=None):
417  """!Characterize a science image
418 
419  Peforms the following operations:
420  - Iterate the following config.psfIterations times, or once if config.doMeasurePsf false:
421  - detect and measure sources and estimate PSF (see detectMeasureAndEstimatePsf for details)
422  - interpolate over cosmic rays
423  - perform final measurement
424 
425  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar).
426  The following changes are made:
427  - update or set psf
428  - set apCorrMap
429  - update detection and cosmic ray mask planes
430  - subtract background and interpolate over cosmic rays
431  @param[in] exposureIdInfo ID info for exposure (an lsst.obs.base.ExposureIdInfo).
432  If not provided, returned SourceCatalog IDs will not be globally unique.
433  @param[in,out] background initial model of background already subtracted from exposure
434  (an lsst.afw.math.BackgroundList). May be None if no background has been subtracted,
435  which is typical for image characterization.
436 
437  @return pipe_base Struct containing these fields, all from the final iteration
438  of detectMeasureAndEstimatePsf:
439  - exposure: characterized exposure; image is repaired by interpolating over cosmic rays,
440  mask is updated accordingly, and the PSF model is set
441  - sourceCat: detected sources (an lsst.afw.table.SourceCatalog)
442  - background: model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
443  - psfCellSet: spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
444  """
445  self._frame = self._initialFrame # reset debug display frame
446 
447  if not self.config.doMeasurePsf and not exposure.hasPsf():
448  self.log.warn("Source catalog detected and measured with placeholder or default PSF")
449  self.installSimplePsf.run(exposure=exposure)
450 
451  if exposureIdInfo is None:
452  exposureIdInfo = ExposureIdInfo()
453 
454  # subtract an initial estimate of background level
455  background = self.background.run(exposure).background
456 
457  psfIterations = self.config.psfIterations if self.config.doMeasurePsf else 1
458  for i in range(psfIterations):
459  dmeRes = self.detectMeasureAndEstimatePsf(
460  exposure=exposure,
461  exposureIdInfo=exposureIdInfo,
462  background=background,
463  )
464 
465  psf = dmeRes.exposure.getPsf()
466  psfSigma = psf.computeShape().getDeterminantRadius()
467  psfDimensions = psf.computeImage().getDimensions()
468  medBackground = np.median(dmeRes.background.getImage().getArray())
469  self.log.info("iter %s; PSF sigma=%0.2f, dimensions=%s; median background=%0.2f" %
470  (i + 1, psfSigma, psfDimensions, medBackground))
471 
472  self.display("psf", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
473 
474  # perform final repair with final PSF
475  self.repair.run(exposure=dmeRes.exposure)
476  self.display("repair", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
477 
478  # perform final measurement with final PSF, including measuring and applying aperture correction,
479  # if wanted
480  self.measurement.run(measCat=dmeRes.sourceCat, exposure=dmeRes.exposure,
481  exposureId=exposureIdInfo.expId)
482  if self.config.doApCorr:
483  apCorrMap = self.measureApCorr.run(exposure=dmeRes.exposure, catalog=dmeRes.sourceCat).apCorrMap
484  dmeRes.exposure.getInfo().setApCorrMap(apCorrMap)
485  self.applyApCorr.run(catalog=dmeRes.sourceCat, apCorrMap=exposure.getInfo().getApCorrMap())
486  self.catalogCalculation.run(dmeRes.sourceCat)
487 
488  self.display("measure", exposure=dmeRes.exposure, sourceCat=dmeRes.sourceCat)
489 
490  return pipeBase.Struct(
491  exposure=dmeRes.exposure,
492  sourceCat=dmeRes.sourceCat,
493  background=dmeRes.background,
494  psfCellSet=dmeRes.psfCellSet,
495 
496  characterized=dmeRes.exposure,
497  backgroundModel=dmeRes.background
498  )
499 
500  @pipeBase.timeMethod
501  def detectMeasureAndEstimatePsf(self, exposure, exposureIdInfo, background):
502  """!Perform one iteration of detect, measure and estimate PSF
503 
504  Performs the following operations:
505  - if config.doMeasurePsf or not exposure.hasPsf():
506  - install a simple PSF model (replacing the existing one, if need be)
507  - interpolate over cosmic rays with keepCRs=True
508  - estimate background and subtract it from the exposure
509  - detect, deblend and measure sources, and subtract a refined background model;
510  - if config.doMeasurePsf:
511  - measure PSF
512 
513  @param[in,out] exposure exposure to characterize (an lsst.afw.image.ExposureF or similar)
514  The following changes are made:
515  - update or set psf
516  - update detection and cosmic ray mask planes
517  - subtract background
518  @param[in] exposureIdInfo ID info for exposure (an lsst.obs_base.ExposureIdInfo)
519  @param[in,out] background initial model of background already subtracted from exposure
520  (an lsst.afw.math.BackgroundList).
521 
522  @return pipe_base Struct containing these fields, all from the final iteration
523  of detect sources, measure sources and estimate PSF:
524  - exposure characterized exposure; image is repaired by interpolating over cosmic rays,
525  mask is updated accordingly, and the PSF model is set
526  - sourceCat detected sources (an lsst.afw.table.SourceCatalog)
527  - background model of background subtracted from exposure (an lsst.afw.math.BackgroundList)
528  - psfCellSet spatial cells of PSF candidates (an lsst.afw.math.SpatialCellSet)
529  """
530  # install a simple PSF model, if needed or wanted
531  if not exposure.hasPsf() or (self.config.doMeasurePsf and self.config.useSimplePsf):
532  self.log.warn("Source catalog detected and measured with placeholder or default PSF")
533  self.installSimplePsf.run(exposure=exposure)
534 
535  # run repair, but do not interpolate over cosmic rays (do that elsewhere, with the final PSF model)
536  self.repair.run(exposure=exposure, keepCRs=True)
537  self.display("repair_iter", exposure=exposure)
538 
539  if background is None:
540  background = BackgroundList()
541 
542  sourceIdFactory = IdFactory.makeSource(exposureIdInfo.expId, exposureIdInfo.unusedBits)
543  table = SourceTable.make(self.schema, sourceIdFactory)
544  table.setMetadata(self.algMetadata)
545 
546  detRes = self.detection.run(table=table, exposure=exposure, doSmooth=True)
547  sourceCat = detRes.sources
548  if detRes.fpSets.background:
549  for bg in detRes.fpSets.background:
550  background.append(bg)
551 
552  if self.config.doDeblend:
553  self.deblend.run(exposure=exposure, sources=sourceCat)
554 
555  self.measurement.run(measCat=sourceCat, exposure=exposure, exposureId=exposureIdInfo.expId)
556 
557  measPsfRes = pipeBase.Struct(cellSet=None)
558  if self.config.doMeasurePsf:
559  if self.measurePsf.usesMatches:
560  matches = self.ref_match.loadAndMatch(exposure=exposure, sourceCat=sourceCat).matches
561  else:
562  matches = None
563  measPsfRes = self.measurePsf.run(exposure=exposure, sources=sourceCat, matches=matches,
564  expId=exposureIdInfo.expId)
565  self.display("measure_iter", exposure=exposure, sourceCat=sourceCat)
566 
567  return pipeBase.Struct(
568  exposure=exposure,
569  sourceCat=sourceCat,
570  background=background,
571  psfCellSet=measPsfRes.cellSet,
572  )
573 
574  def getSchemaCatalogs(self):
575  """Return a dict of empty catalogs for each catalog dataset produced by this task.
576  """
577  sourceCat = SourceCatalog(self.schema)
578  sourceCat.getTable().setMetadata(self.algMetadata)
579  return {"icSrc": sourceCat}
580 
581  def display(self, itemName, exposure, sourceCat=None):
582  """Display exposure and sources on next frame, if display of itemName has been requested
583 
584  @param[in] itemName name of item in debugInfo
585  @param[in] exposure exposure to display
586  @param[in] sourceCat source catalog to display
587  """
588  val = getDebugFrame(self._display, itemName)
589  if not val:
590  return
591 
592  displayAstrometry(exposure=exposure, sourceCat=sourceCat, frame=self._frame, pause=False)
593  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.