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