LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
processBrightStars.py
Go to the documentation of this file.
1 # This file is part of pipe_tasks.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 #
22 """Extract small cutouts around bright stars, normalize and warp them to the
23 same arbitrary pixel grid.
24 """
25 
26 __all__ = ["ProcessBrightStarsTask"]
27 
28 import numpy as np
29 import astropy.units as u
30 
31 from lsst import geom
32 from lsst.afw import math as afwMath
33 from lsst.afw import image as afwImage
34 from lsst.afw import detection as afwDetect
35 from lsst.afw import cameraGeom as cg
36 from lsst.afw.geom import transformFactory as tFactory
37 import lsst.pex.config as pexConfig
38 from lsst.pipe import base as pipeBase
39 from lsst.pipe.base import connectionTypes as cT
40 from lsst.pex.exceptions import InvalidParameterError
41 from lsst.meas.algorithms.loadIndexedReferenceObjects import LoadIndexedReferenceObjectsTask
42 from lsst.meas.algorithms import ReferenceObjectLoader
43 from lsst.meas.algorithms import brightStarStamps as bSS
44 from lsst.utils.timer import timeMethod
45 
46 
47 class ProcessBrightStarsConnections(pipeBase.PipelineTaskConnections,
48  dimensions=("instrument", "visit", "detector")):
49  inputExposure = cT.Input(
50  doc="Input exposure from which to extract bright star stamps",
51  name="calexp",
52  storageClass="ExposureF",
53  dimensions=("visit", "detector")
54  )
55  skyCorr = cT.Input(
56  doc="Input Sky Correction to be subtracted from the calexp if doApplySkyCorr=True",
57  name="skyCorr",
58  storageClass="Background",
59  dimensions=("instrument", "visit", "detector")
60  )
61  refCat = cT.PrerequisiteInput(
62  doc="Reference catalog that contains bright star positions",
63  name="gaia_dr2_20200414",
64  storageClass="SimpleCatalog",
65  dimensions=("skypix",),
66  multiple=True,
67  deferLoad=True
68  )
69  brightStarStamps = cT.Output(
70  doc="Set of preprocessed postage stamps, each centered on a single bright star.",
71  name="brightStarStamps",
72  storageClass="BrightStarStamps",
73  dimensions=("visit", "detector")
74  )
75 
76  def __init__(self, *, config=None):
77  super().__init__(config=config)
78  if not config.doApplySkyCorr:
79  self.inputs.remove("skyCorr")
80 
81 
82 class ProcessBrightStarsConfig(pipeBase.PipelineTaskConfig,
83  pipelineConnections=ProcessBrightStarsConnections):
84  """Configuration parameters for ProcessBrightStarsTask
85  """
86  magLimit = pexConfig.Field(
87  dtype=float,
88  doc="Magnitude limit, in Gaia G; all stars brighter than this value will be processed",
89  default=18
90  )
91  stampSize = pexConfig.ListField(
92  dtype=int,
93  doc="Size of the stamps to be extracted, in pixels",
94  default=(250, 250)
95  )
96  modelStampBuffer = pexConfig.Field(
97  dtype=float,
98  doc="'Buffer' factor to be applied to determine the size of the stamp the processed stars will "
99  "be saved in. This will also be the size of the extended PSF model.",
100  default=1.1
101  )
102  doRemoveDetected = pexConfig.Field(
103  dtype=bool,
104  doc="Whether DETECTION footprints, other than that for the central object, should be changed to "
105  "BAD",
106  default=True
107  )
108  doApplyTransform = pexConfig.Field(
109  dtype=bool,
110  doc="Apply transform to bright star stamps to correct for optical distortions?",
111  default=True
112  )
113  warpingKernelName = pexConfig.ChoiceField(
114  dtype=str,
115  doc="Warping kernel",
116  default="lanczos5",
117  allowed={
118  "bilinear": "bilinear interpolation",
119  "lanczos3": "Lanczos kernel of order 3",
120  "lanczos4": "Lanczos kernel of order 4",
121  "lanczos5": "Lanczos kernel of order 5",
122  }
123  )
124  annularFluxRadii = pexConfig.ListField(
125  dtype=int,
126  doc="Inner and outer radii of the annulus used to compute the AnnularFlux for normalization, "
127  "in pixels.",
128  default=(40, 50)
129  )
130  annularFluxStatistic = pexConfig.ChoiceField(
131  dtype=str,
132  doc="Type of statistic to use to compute annular flux.",
133  default="MEANCLIP",
134  allowed={
135  "MEAN": "mean",
136  "MEDIAN": "median",
137  "MEANCLIP": "clipped mean",
138  }
139  )
140  numSigmaClip = pexConfig.Field(
141  dtype=float,
142  doc="Sigma for outlier rejection; ignored if annularFluxStatistic != 'MEANCLIP'.",
143  default=4
144  )
145  numIter = pexConfig.Field(
146  dtype=int,
147  doc="Number of iterations of outlier rejection; ignored if annularFluxStatistic != 'MEANCLIP'.",
148  default=3
149  )
150  badMaskPlanes = pexConfig.ListField(
151  dtype=str,
152  doc="Mask planes that, if set, lead to associated pixels not being included in the computation of the"
153  " annular flux.",
154  default=('BAD', 'CR', 'CROSSTALK', 'EDGE', 'NO_DATA', 'SAT', 'SUSPECT', 'UNMASKEDNAN')
155  )
156  minPixelsWithinFrame = pexConfig.Field(
157  dtype=int,
158  doc="Minimum number of pixels that must fall within the stamp boundary for the bright star to be"
159  " saved when its center is beyond the exposure boundary.",
160  default=50
161  )
162  doApplySkyCorr = pexConfig.Field(
163  dtype=bool,
164  doc="Apply full focal plane sky correction before extracting stars?",
165  default=True
166  )
167  discardNanFluxStars = pexConfig.Field(
168  dtype=bool,
169  doc="Should stars with NaN annular flux be discarded?",
170  default=False
171  )
172  refObjLoader = pexConfig.ConfigurableField(
173  target=LoadIndexedReferenceObjectsTask,
174  doc="Reference object loader for astrometric calibration.",
175  )
176 
177  def setDefaults(self):
178  self.refObjLoaderrefObjLoader.ref_dataset_name = "gaia_dr2_20200414"
179 
180 
181 class ProcessBrightStarsTask(pipeBase.PipelineTask, pipeBase.CmdLineTask):
182  """The description of the parameters for this Task are detailed in
183  :lsst-task:`~lsst.pipe.base.PipelineTask`.
184 
185  Notes
186  -----
187  `ProcessBrightStarsTask` is used to extract, process, and store small
188  image cut-outs (or "postage stamps") around bright stars. It relies on
189  three methods, called in succession:
190 
191  `extractStamps`
192  Find bright stars within the exposure using a reference catalog and
193  extract a stamp centered on each.
194  `warpStamps`
195  Shift and warp each stamp to remove optical distortions and sample all
196  stars on the same pixel grid.
197  `measureAndNormalize`
198  Compute the flux of an object in an annulus and normalize it. This is
199  required to normalize each bright star stamp as their central pixels
200  are likely saturated and/or contain ghosts, and cannot be used.
201  """
202  ConfigClass = ProcessBrightStarsConfig
203  _DefaultName = "processBrightStars"
204  RunnerClass = pipeBase.ButlerInitializedTaskRunner
205 
206  def __init__(self, butler=None, initInputs=None, *args, **kwargs):
207  super().__init__(*args, **kwargs)
208  # Compute (model) stamp size depending on provided "buffer" value
209  self.modelStampSizemodelStampSize = [int(self.config.stampSize[0]*self.config.modelStampBuffer),
210  int(self.config.stampSize[1]*self.config.modelStampBuffer)]
211  # force it to be odd-sized so we have a central pixel
212  if not self.modelStampSizemodelStampSize[0] % 2:
213  self.modelStampSizemodelStampSize[0] += 1
214  if not self.modelStampSizemodelStampSize[1] % 2:
215  self.modelStampSizemodelStampSize[1] += 1
216  # central pixel
217  self.modelCentermodelCenter = self.modelStampSizemodelStampSize[0]//2, self.modelStampSizemodelStampSize[1]//2
218  # configure Gaia refcat
219  if butler is not None:
220  self.makeSubtask('refObjLoader', butler=butler)
221 
222  def applySkyCorr(self, calexp, skyCorr):
223  """Apply correction to the sky background level.
224 
225  Sky corrections can be generated with the 'skyCorrection.py'
226  executable in pipe_drivers. Because the sky model used by that
227  code extends over the entire focal plane, this can produce
228  better sky subtraction.
229  The calexp is updated in-place.
230 
231  Parameters
232  ----------
233  calexp : `lsst.afw.image.Exposure` or `lsst.afw.image.MaskedImage`
234  Calibrated exposure.
235  skyCorr : `lsst.afw.math.backgroundList.BackgroundList` or None,
236  optional
237  Full focal plane sky correction, obtained by running
238  `lsst.pipe.drivers.skyCorrection.SkyCorrectionTask`.
239  """
240  if isinstance(calexp, afwImage.Exposure):
241  calexp = calexp.getMaskedImage()
242  calexp -= skyCorr.getImage()
243 
244  def extractStamps(self, inputExposure, refObjLoader=None):
245  """ Read position of bright stars within `inputExposure` from refCat
246  and extract them.
247 
248  Parameters
249  ----------
250  inputExposure : `afwImage.exposure.exposure.ExposureF`
251  The image from which bright star stamps should be extracted.
252  refObjLoader : `LoadIndexedReferenceObjectsTask`, optional
253  Loader to find objects within a reference catalog.
254 
255  Returns
256  -------
257  result : `lsst.pipe.base.Struct`
258  Result struct with components:
259 
260  - ``starIms``: `list` of stamps
261  - ``pixCenters``: `list` of corresponding coordinates to each
262  star's center, in pixels.
263  - ``GMags``: `list` of corresponding (Gaia) G magnitudes.
264  - ``gaiaIds``: `np.ndarray` of corresponding unique Gaia
265  identifiers.
266  """
267  if refObjLoader is None:
268  refObjLoader = self.refObjLoader
269  starIms = []
270  pixCenters = []
271  GMags = []
272  ids = []
273  wcs = inputExposure.getWcs()
274  # select stars within, or close enough to input exposure from refcat
275  inputIm = inputExposure.maskedImage
276  inputExpBBox = inputExposure.getBBox()
277  dilatationExtent = geom.Extent2I(np.array(self.config.stampSize) - self.config.minPixelsWithinFrame)
278  # TODO (DM-25894): handle catalog with stars missing from Gaia
279  withinCalexp = refObjLoader.loadPixelBox(inputExpBBox.dilatedBy(dilatationExtent), wcs,
280  filterName="phot_g_mean")
281  refCat = withinCalexp.refCat
282  # keep bright objects
283  fluxLimit = ((self.config.magLimit*u.ABmag).to(u.nJy)).to_value()
284  GFluxes = np.array(refCat['phot_g_mean_flux'])
285  bright = GFluxes > fluxLimit
286  # convert to AB magnitudes
287  allGMags = [((gFlux*u.nJy).to(u.ABmag)).to_value() for gFlux in GFluxes[bright]]
288  allIds = refCat.columns.extract("id", where=bright)["id"]
289  selectedColumns = refCat.columns.extract('coord_ra', 'coord_dec', where=bright)
290  for j, (ra, dec) in enumerate(zip(selectedColumns["coord_ra"], selectedColumns["coord_dec"])):
291  sp = geom.SpherePoint(ra, dec, geom.radians)
292  cpix = wcs.skyToPixel(sp)
293  try:
294  starIm = inputExposure.getCutout(sp, geom.Extent2I(self.config.stampSize))
295  except InvalidParameterError:
296  # star is beyond boundary
297  bboxCorner = np.array(cpix) - np.array(self.config.stampSize)/2
298  # compute bbox as it would be otherwise
299  idealBBox = geom.Box2I(geom.Point2I(bboxCorner), geom.Extent2I(self.config.stampSize))
300  clippedStarBBox = geom.Box2I(idealBBox)
301  clippedStarBBox.clip(inputExpBBox)
302  if clippedStarBBox.getArea() > 0:
303  # create full-sized stamp with all pixels
304  # flagged as NO_DATA
305  starIm = afwImage.ExposureF(bbox=idealBBox)
306  starIm.image[:] = np.nan
307  starIm.mask.set(inputExposure.mask.getPlaneBitMask("NO_DATA"))
308  # recover pixels from intersection with the exposure
309  clippedIm = inputIm.Factory(inputIm, clippedStarBBox)
310  starIm.maskedImage[clippedStarBBox] = clippedIm
311  # set detector and wcs, used in warpStars
312  starIm.setDetector(inputExposure.getDetector())
313  starIm.setWcs(inputExposure.getWcs())
314  else:
315  continue
316  if self.config.doRemoveDetected:
317  # give detection footprint of other objects the BAD flag
318  detThreshold = afwDetect.Threshold(starIm.mask.getPlaneBitMask("DETECTED"),
319  afwDetect.Threshold.BITMASK)
320  omask = afwDetect.FootprintSet(starIm.mask, detThreshold)
321  allFootprints = omask.getFootprints()
322  otherFootprints = []
323  for fs in allFootprints:
324  if not fs.contains(geom.Point2I(cpix)):
325  otherFootprints.append(fs)
326  nbMatchingFootprints = len(allFootprints) - len(otherFootprints)
327  if not nbMatchingFootprints == 1:
328  self.log.warning("Failed to uniquely identify central DETECTION footprint for star "
329  "%s; found %d footprints instead.",
330  allIds[j], nbMatchingFootprints)
331  omask.setFootprints(otherFootprints)
332  omask.setMask(starIm.mask, "BAD")
333  starIms.append(starIm)
334  pixCenters.append(cpix)
335  GMags.append(allGMags[j])
336  ids.append(allIds[j])
337  return pipeBase.Struct(starIms=starIms,
338  pixCenters=pixCenters,
339  GMags=GMags,
340  gaiaIds=ids)
341 
342  def warpStamps(self, stamps, pixCenters):
343  """Warps and shifts all given stamps so they are sampled on the same
344  pixel grid and centered on the central pixel. This includes rotating
345  the stamp depending on detector orientation.
346 
347  Parameters
348  ----------
349  stamps : `collections.abc.Sequence`
350  [`afwImage.exposure.exposure.ExposureF`]
351  Image cutouts centered on a single object.
352  pixCenters : `collections.abc.Sequence` [`geom.Point2D`]
353  Positions of each object's center (as obtained from the refCat),
354  in pixels.
355 
356  Returns
357  -------
358  result : `lsst.pipe.base.Struct`
359  Result struct with components:
360 
361  - ``warpedStars``:
362  `list` [`afwImage.maskedImage.maskedImage.MaskedImage`] of
363  stamps of warped stars
364  - ``warpTransforms``:
365  `list` [`afwGeom.TransformPoint2ToPoint2`] of
366  the corresponding Transform from the initial star stamp to
367  the common model grid
368  - ``xy0s``:
369  `list` [`geom.Point2I`] of coordinates of the bottom-left
370  pixels of each stamp, before rotation
371  - ``nb90Rots``: `int`, the number of 90 degrees rotations required
372  to compensate for detector orientation
373  """
374  # warping control; only contains shiftingALg provided in config
375  warpCont = afwMath.WarpingControl(self.config.warpingKernelName)
376  # Compare model to star stamp sizes
377  bufferPix = (self.modelStampSizemodelStampSize[0] - self.config.stampSize[0],
378  self.modelStampSizemodelStampSize[1] - self.config.stampSize[1])
379  # Initialize detector instance (note all stars were extracted from an
380  # exposure from the same detector)
381  det = stamps[0].getDetector()
382  # Define correction for optical distortions
383  if self.config.doApplyTransform:
384  pixToTan = det.getTransform(cg.PIXELS, cg.TAN_PIXELS)
385  else:
386  pixToTan = tFactory.makeIdentityTransform()
387  # Array of all possible rotations for detector orientation:
388  possibleRots = np.array([k*np.pi/2 for k in range(4)])
389  # determine how many, if any, rotations are required
390  yaw = det.getOrientation().getYaw()
391  nb90Rots = np.argmin(np.abs(possibleRots - float(yaw)))
392 
393  # apply transformation to each star
394  warpedStars, warpTransforms, xy0s = [], [], []
395  for star, cent in zip(stamps, pixCenters):
396  # (re)create empty destination image
397  destImage = afwImage.MaskedImageF(*self.modelStampSizemodelStampSize)
398  bottomLeft = geom.Point2D(star.image.getXY0())
399  newBottomLeft = pixToTan.applyForward(bottomLeft)
400  newBottomLeft.setX(newBottomLeft.getX() - bufferPix[0]/2)
401  newBottomLeft.setY(newBottomLeft.getY() - bufferPix[1]/2)
402  # Convert to int
403  newBottomLeft = geom.Point2I(newBottomLeft)
404  # Set origin and save it
405  destImage.setXY0(newBottomLeft)
406  xy0s.append(newBottomLeft)
407 
408  # Define linear shifting to recenter stamps
409  newCenter = pixToTan.applyForward(cent) # center of warped star
410  shift = self.modelCentermodelCenter[0] + newBottomLeft[0] - newCenter[0],\
411  self.modelCentermodelCenter[1] + newBottomLeft[1] - newCenter[1]
412  affineShift = geom.AffineTransform(shift)
413  shiftTransform = tFactory.makeTransform(affineShift)
414 
415  # Define full transform (warp and shift)
416  starWarper = pixToTan.then(shiftTransform)
417 
418  # Apply it
419  goodPix = afwMath.warpImage(destImage, star.getMaskedImage(),
420  starWarper, warpCont)
421  if not goodPix:
422  self.log.debug("Warping of a star failed: no good pixel in output")
423 
424  # Arbitrarily set origin of shifted star to 0
425  destImage.setXY0(0, 0)
426 
427  # Apply rotation if appropriate
428  if nb90Rots:
429  destImage = afwMath.rotateImageBy90(destImage, nb90Rots)
430  warpedStars.append(destImage.clone())
431  warpTransforms.append(starWarper)
432  return pipeBase.Struct(warpedStars=warpedStars, warpTransforms=warpTransforms, xy0s=xy0s,
433  nb90Rots=nb90Rots)
434 
435  @timeMethod
436  def run(self, inputExposure, refObjLoader=None, dataId=None, skyCorr=None):
437  """Identify bright stars within an exposure using a reference catalog,
438  extract stamps around each, then preprocess them. The preprocessing
439  steps are: shifting, warping and potentially rotating them to the same
440  pixel grid; computing their annular flux and normalizing them.
441 
442  Parameters
443  ----------
444  inputExposure : `afwImage.exposure.exposure.ExposureF`
445  The image from which bright star stamps should be extracted.
446  refObjLoader : `LoadIndexedReferenceObjectsTask`, optional
447  Loader to find objects within a reference catalog.
448  dataId : `dict` or `lsst.daf.butler.DataCoordinate`
449  The dataId of the exposure (and detector) bright stars should be
450  extracted from.
451  skyCorr : `lsst.afw.math.backgroundList.BackgroundList` or ``None``,
452  optional
453  Full focal plane sky correction, obtained by running
454  `lsst.pipe.drivers.skyCorrection.SkyCorrectionTask`.
455 
456  Returns
457  -------
458  result : `lsst.pipe.base.Struct`
459  Result struct with component:
460 
461  - ``brightStarStamps``: ``bSS.BrightStarStamps``
462  """
463  if self.config.doApplySkyCorr:
464  self.log.info("Applying sky correction to exposure %s (exposure will be modified in-place).",
465  dataId)
466  self.applySkyCorrapplySkyCorr(inputExposure, skyCorr)
467  self.log.info("Extracting bright stars from exposure %s", dataId)
468  # Extract stamps around bright stars
469  extractedStamps = self.extractStampsextractStamps(inputExposure, refObjLoader=refObjLoader)
470  if not extractedStamps.starIms:
471  self.log.info("No suitable bright star found.")
472  return None
473  # Warp (and shift, and potentially rotate) them
474  self.log.info("Applying warp and/or shift to %i star stamps from exposure %s",
475  len(extractedStamps.starIms), dataId)
476  warpOutputs = self.warpStampswarpStamps(extractedStamps.starIms, extractedStamps.pixCenters)
477  warpedStars = warpOutputs.warpedStars
478  xy0s = warpOutputs.xy0s
479  brightStarList = [bSS.BrightStarStamp(stamp_im=warp,
480  archive_element=transform,
481  position=xy0s[j],
482  gaiaGMag=extractedStamps.GMags[j],
483  gaiaId=extractedStamps.gaiaIds[j])
484  for j, (warp, transform) in
485  enumerate(zip(warpedStars, warpOutputs.warpTransforms))]
486  # Compute annularFlux and normalize
487  self.log.info("Computing annular flux and normalizing %i bright stars from exposure %s",
488  len(warpedStars), dataId)
489  # annularFlux statistic set-up, excluding mask planes
490  statsControl = afwMath.StatisticsControl()
491  statsControl.setNumSigmaClip(self.config.numSigmaClip)
492  statsControl.setNumIter(self.config.numIter)
493  innerRadius, outerRadius = self.config.annularFluxRadii
494  statsFlag = afwMath.stringToStatisticsProperty(self.config.annularFluxStatistic)
495  brightStarStamps = bSS.BrightStarStamps.initAndNormalize(brightStarList,
496  innerRadius=innerRadius,
497  outerRadius=outerRadius,
498  nb90Rots=warpOutputs.nb90Rots,
499  imCenter=self.modelCentermodelCenter,
500  use_archive=True,
501  statsControl=statsControl,
502  statsFlag=statsFlag,
503  badMaskPlanes=self.config.badMaskPlanes,
504  discardNanFluxObjects=(
505  self.config.discardNanFluxStars))
506  return pipeBase.Struct(brightStarStamps=brightStarStamps)
507 
508  def runDataRef(self, dataRef):
509  """Read in required calexp, extract and process stamps around bright
510  stars and write them to disk.
511 
512  Parameters
513  ----------
514  dataRef : `lsst.daf.persistence.butlerSubset.ButlerDataRef`
515  Data reference to the calexp to extract bright stars from.
516  """
517  calexp = dataRef.get("calexp")
518  skyCorr = dataRef.get("skyCorr") if self.config.doApplySkyCorr else None
519  output = self.runrun(calexp, dataId=dataRef.dataId, skyCorr=skyCorr)
520  # Save processed bright star stamps
521  dataRef.put(output.brightStarStamps, "brightStarStamps")
522  return pipeBase.Struct(brightStarStamps=output.brightStarStamps)
523 
524  def runQuantum(self, butlerQC, inputRefs, outputRefs):
525  inputs = butlerQC.get(inputRefs)
526  inputs['dataId'] = str(butlerQC.quantum.dataId)
527  refObjLoader = ReferenceObjectLoader(dataIds=[ref.datasetRef.dataId
528  for ref in inputRefs.refCat],
529  refCats=inputs.pop("refCat"),
530  config=self.config.refObjLoader)
531  output = self.runrun(**inputs, refObjLoader=refObjLoader)
532  if output:
533  butlerQC.put(output, outputRefs)
table::Key< int > to
A set of Footprints, associated with a MaskedImage.
Definition: FootprintSet.h:53
A Threshold is used to pass a threshold value to detection algorithms.
Definition: Threshold.h:43
A class to contain the data, WCS, and other information needed to describe an image of the sky.
Definition: Exposure.h:72
Pass parameters to a Statistics object.
Definition: Statistics.h:92
Parameters to control convolution.
Definition: warpExposure.h:276
An affine coordinate transformation consisting of a linear transformation and an offset.
An integer coordinate rectangle.
Definition: Box.h:55
Point in an unspecified spherical coordinate system.
Definition: SpherePoint.h:57
def runQuantum(self, butlerQC, inputRefs, outputRefs)
def run(self, inputExposure, refObjLoader=None, dataId=None, skyCorr=None)
def extractStamps(self, inputExposure, refObjLoader=None)
def __init__(self, butler=None, initInputs=None, *args, **kwargs)
Property stringToStatisticsProperty(std::string const property)
Conversion function to switch a string to a Property (see Statistics.h)
Definition: Statistics.cc:738
std::shared_ptr< ImageT > rotateImageBy90(ImageT const &image, int nQuarter)
Rotate an image by an integral number of quarter turns.
Definition: rotateImage.cc:39
int warpImage(DestImageT &destImage, geom::SkyWcs const &destWcs, SrcImageT const &srcImage, geom::SkyWcs const &srcWcs, WarpingControl const &control, typename DestImageT::SinglePixel padValue=lsst::afw::math::edgePixel< DestImageT >(typename lsst::afw::image::detail::image_traits< DestImageT >::image_category()))
Warp an Image or MaskedImage to a new Wcs.
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.