22"""Retrieve extended PSF model and subtract bright stars at visit level."""
24__all__ = [
"SubtractBrightStarsConnections",
"SubtractBrightStarsConfig",
"SubtractBrightStarsTask"]
27from functools
import reduce
28from operator
import ior
38 stringToStatisticsProperty,
41from lsst.geom import Box2I, Point2D, Point2I
45from lsst.pipe.base import PipelineTask, PipelineTaskConfig, PipelineTaskConnections, Struct
46from lsst.pipe.base.connectionTypes
import Input, Output, PrerequisiteInput
49logger = logging.getLogger(__name__)
53 PipelineTaskConnections,
54 dimensions=(
"instrument",
"visit",
"detector"),
56 "outputExposureName":
"brightStar_subtracted",
57 "outputBackgroundName":
"brightStars",
58 "badStampsName":
"brightStars",
61 inputExposure = Input(
62 doc=
"Input exposure from which to subtract bright star stamps.",
64 storageClass=
"ExposureF",
70 inputBrightStarStamps = Input(
71 doc=
"Set of preprocessed postage stamps, each centered on a single bright star.",
72 name=
"brightStarStamps",
73 storageClass=
"BrightStarStamps",
79 inputExtendedPsf = Input(
80 doc=
"Extended PSF model.",
82 storageClass=
"ExtendedPsf",
86 doc=
"Input Sky Correction to be subtracted from the calexp if ``doApplySkyCorr``=True.",
88 storageClass=
"Background",
95 refCat = PrerequisiteInput(
96 doc=
"Reference catalog that contains bright star positions",
97 name=
"gaia_dr2_20200414",
98 storageClass=
"SimpleCatalog",
99 dimensions=(
"skypix",),
103 outputExposure = Output(
104 doc=
"Exposure with bright stars subtracted.",
105 name=
"{outputExposureName}_calexp",
106 storageClass=
"ExposureF",
112 outputBackgroundExposure = Output(
113 doc=
"Exposure containing only the modelled bright stars.",
114 name=
"{outputBackgroundName}_calexp_background",
115 storageClass=
"ExposureF",
121 outputBadStamps = Output(
122 doc=
"The stamps that are not normalized and consequently not subtracted from the exposure.",
123 name=
"{badStampsName}_unsubtracted_stamps",
124 storageClass=
"BrightStarStamps",
131 def __init__(self, *, config=None):
132 super().__init__(config=config)
133 if not config.doApplySkyCorr:
134 self.inputs.remove(
"skyCorr")
137class SubtractBrightStarsConfig(PipelineTaskConfig, pipelineConnections=SubtractBrightStarsConnections):
138 """Configuration parameters for SubtractBrightStarsTask"""
140 doWriteSubtractor = Field[bool](
141 doc=
"Should an exposure containing all bright star models be written to disk?",
144 doWriteSubtractedExposure = Field[bool](
145 doc=
"Should an exposure with bright stars subtracted be written to disk?",
148 magLimit = Field[float](
149 doc=
"Magnitude limit, in Gaia G; all stars brighter than this value will be subtracted",
152 minValidAnnulusFraction = Field[float](
153 doc=
"Minimum number of valid pixels that must fall within the annulus for the bright star to be "
154 "saved for subsequent generation of a PSF.",
157 numSigmaClip = Field[float](
158 doc=
"Sigma for outlier rejection; ignored if annularFluxStatistic != 'MEANCLIP'.",
161 numIter = Field[int](
162 doc=
"Number of iterations of outlier rejection; ignored if annularFluxStatistic != 'MEANCLIP'.",
165 warpingKernelName = ChoiceField[str](
166 doc=
"Warping kernel",
169 "bilinear":
"bilinear interpolation",
170 "lanczos3":
"Lanczos kernel of order 3",
171 "lanczos4":
"Lanczos kernel of order 4",
172 "lanczos5":
"Lanczos kernel of order 5",
173 "lanczos6":
"Lanczos kernel of order 6",
174 "lanczos7":
"Lanczos kernel of order 7",
177 scalingType = ChoiceField[str](
178 doc=
"How the model should be scaled to each bright star; implemented options are "
179 "`annularFlux` to reuse the annular flux of each stamp, or `leastSquare` to perform "
180 "least square fitting on each pixel with no bad mask plane set.",
181 default=
"leastSquare",
183 "annularFlux":
"reuse BrightStarStamp annular flux measurement",
184 "leastSquare":
"find least square scaling factor",
187 annularFluxStatistic = ChoiceField[str](
188 doc=
"Type of statistic to use to compute annular flux.",
193 "MEANCLIP":
"clipped mean",
196 badMaskPlanes = ListField[str](
197 doc=
"Mask planes that, if set, lead to associated pixels not being included in the computation of "
198 "the scaling factor (`BAD` should always be included). Ignored if scalingType is `annularFlux`, "
199 "as the stamps are expected to already be normalized.",
203 default=(
"BAD",
"CR",
"CROSSTALK",
"EDGE",
"NO_DATA",
"SAT",
"SUSPECT",
"UNMASKEDNAN"),
205 subtractionBox = ListField[int](
206 doc=
"Size of the stamps to be extracted, in pixels.",
209 subtractionBoxBuffer = Field[float](
211 "'Buffer' (multiplicative) factor to be applied to determine the size of the stamp the "
212 "processed stars will be saved in. This is also the size of the extended PSF model. The buffer "
213 "region is masked and contain no data and subtractionBox determines the region where contains "
218 doApplySkyCorr = Field[bool](
219 doc=
"Apply full focal plane sky correction before extracting stars?",
222 refObjLoader = ConfigField[LoadReferenceObjectsConfig](
223 doc=
"Reference object loader for astrometric calibration.",
227class SubtractBrightStarsTask(PipelineTask):
228 """Use an extended PSF model to subtract bright stars from a calibrated
229 exposure (i.e. at single-visit level).
231 This task uses both a set of bright star stamps produced by
232 `~lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask`
233 and an extended PSF model produced by
234 `~lsst.pipe.tasks.extended_psf.MeasureExtendedPsfTask`.
237 ConfigClass = SubtractBrightStarsConfig
238 _DefaultName =
"subtractBrightStars"
240 def __init__(self, *args, **kwargs):
241 super().__init__(*args, **kwargs)
243 self.statsControl, self.statsFlag =
None,
None
247 def runQuantum(self, butlerQC, inputRefs, outputRefs):
249 inputs = butlerQC.get(inputRefs)
250 if inputs[
"inputExtendedPsf"].default_extended_psf
is None:
251 if not self._detectorInRegions(inputs[
"inputExposure"], inputs[
"inputExtendedPsf"]):
253 "Extended PSF model is not available for detector %i. Skipping withouth processing this "
255 inputs[
"inputExposure"].detector.getId(),
258 dataId = butlerQC.quantum.dataId
260 dataIds=[ref.datasetRef.dataId
for ref
in inputRefs.refCat],
261 refCats=inputs.pop(
"refCat"),
262 name=self.config.connections.refCat,
263 config=self.config.refObjLoader,
265 subtractor, _, badStamps = self.run(**inputs, dataId=dataId, refObjLoader=refObjLoader)
266 if self.config.doWriteSubtractedExposure:
267 outputExposure = inputs[
"inputExposure"].clone()
268 outputExposure.image -= subtractor.image
270 outputExposure =
None
271 outputBackgroundExposure = subtractor
if self.config.doWriteSubtractor
else None
277 outputExposure=outputExposure,
278 outputBackgroundExposure=outputBackgroundExposure,
279 outputBadStamps=badStamps,
281 butlerQC.put(output, outputRefs)
284 self, inputExposure, inputBrightStarStamps, inputExtendedPsf, dataId, skyCorr=None, refObjLoader=None
286 """Iterate over all bright stars in an exposure to scale the extended
287 PSF model before subtracting bright stars.
291 inputExposure : `~lsst.afw.image.ExposureF`
292 The image from which bright stars should be subtracted.
293 inputBrightStarStamps :
294 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`
295 Set of stamps centered on each bright star to be subtracted,
297 `~lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask`.
298 inputExtendedPsf : `~lsst.pipe.tasks.extended_psf.ExtendedPsf`
299 Extended PSF model, produced by
300 `~lsst.pipe.tasks.extended_psf.MeasureExtendedPsfTask`.
301 dataId : `dict` or `~lsst.daf.butler.DataCoordinate`
302 The dataId of the exposure (and detector) bright stars should be
304 skyCorr : `~lsst.afw.math.backgroundList.BackgroundList`, optional
305 Full focal plane sky correction, obtained by running
306 `~lsst.pipe.tasks.skyCorrection.SkyCorrectionTask`. If
307 `doApplySkyCorr` is set to `True`, `skyCorr` cannot be `None`.
308 refObjLoader : `~lsst.meas.algorithms.ReferenceObjectLoader`, optional
309 Loader to find objects within a reference catalog.
313 subtractorExp : `~lsst.afw.image.ExposureF`
314 An Exposure containing a scaled bright star model fit to every
315 bright star profile; its image can then be subtracted from the
317 invImages : `list` [`~lsst.afw.image.MaskedImageF`]
318 A list of small images ("stamps") containing the model, each scaled
319 to its corresponding input bright star.
321 self.inputExpBBox = inputExposure.getBBox()
322 if self.config.doApplySkyCorr
and (skyCorr
is not None):
324 "Applying sky correction to exposure %s (exposure will be modified in-place).", dataId
326 self.applySkyCorr(inputExposure, skyCorr)
330 subtractorExp = ExposureF(bbox=inputExposure.getBBox())
331 subtractor = subtractorExp.maskedImage
335 self.modelStampSize = self.model.getDimensions()
337 self.inv90Rots = 4 - inputBrightStarStamps.nb90Rots % 4
338 self.model = rotateImageBy90(self.model, self.inv90Rots)
340 brightStarList = self.makeBrightStarList(inputBrightStarStamps, inputExposure, refObjLoader)
342 subtractor, invImages = self.buildSubtractor(
343 inputBrightStarStamps, subtractor, invImages, multipleAnnuli=
False
346 self.setMissedStarsStatsControl()
349 innerRadius = inputBrightStarStamps._innerRadius
350 outerRadius = inputBrightStarStamps._outerRadius
351 brightStarStamps, badStamps = BrightStarStamps.initAndNormalize(
353 innerRadius=innerRadius,
354 outerRadius=outerRadius,
355 nb90Rots=self.warpOutputs.nb90Rots,
356 imCenter=self.warper.modelCenter,
358 statsControl=self.missedStatsControl,
359 statsFlag=self.missedStatsFlag,
360 badMaskPlanes=self.warper.config.badMaskPlanes,
361 discardNanFluxObjects=
False,
365 self.psf_annular_fluxes = self.findPsfAnnularFluxes(brightStarStamps)
366 subtractor, invImages = self.buildSubtractor(
367 brightStarStamps, subtractor, invImages, multipleAnnuli=
True
373 return subtractorExp, invImages, badStamps
375 def _detectorInRegions(self, inputExposure, inputExtendedPsf):
376 """Determine whether the input exposure's detector is in the region(s)
377 where the extended PSF model(s) is(are) available.
381 inputExposure : `lsst.afw.image.ExposureF`
382 The image from which bright stars should be subtracted. The ID of
383 the detector will be used to determine whether the detector is in
384 the region(s) where the extended PSF model(s) is(are) available.
385 inputExtendedPsf: `~lsst.pipe.tasks.extended_psf.ExtendedPsf`
386 Extended PSF model(s), produced by
387 `~lsst.pipe.tasks.extended_psf.MeasureExtendedPsfTask`. The ID's of
388 the detectors in the region(s) where the extended PSF model(s)
389 is(are) available will be used to cross match with the ID of the
390 input exposure's detector.
395 True if the detector is in the region(s) where the extended PSF
396 model(s) is(are) available, False otherwise.
398 availableDetectors = [
400 for detectorList
in inputExtendedPsf.detectors_focal_plane_regions.values()
401 for detector
in detectorList.detectors
403 if inputExposure.detector.getId()
in availableDetectors:
408 def _setUpStatistics(self, exampleMask):
409 """Configure statistics control and flag, for use if ``scalingType`` is
412 if self.config.scalingType ==
"leastSquare":
416 (exampleMask.getPlaneBitMask(bm)
for bm
in self.config.badMaskPlanes),
421 self.statsFlag = stringToStatisticsProperty(
"SUM")
423 def applySkyCorr(self, calexp, skyCorr):
424 """Apply correction to the sky background level.
425 Sky corrections can be generated via the SkyCorrectionTask within the
426 pipe_tools module. Because the sky model used by that code extends over
427 the entire focal plane, this can produce better sky subtraction.
428 The calexp is updated in-place.
432 calexp : `~lsst.afw.image.Exposure` or `~lsst.afw.image.MaskedImage`
434 skyCorr : `~lsst.afw.math.backgroundList.BackgroundList`
435 Full focal plane sky correction, obtained by running
436 `~lsst.pipe.tasks.skyCorrection.SkyCorrectionTask`.
438 if isinstance(calexp, Exposure):
439 calexp = calexp.getMaskedImage()
440 calexp -= skyCorr.getImage()
442 def scaleModel(self, model, star, inPlace=True, nb90Rots=0, psf_annular_flux=1.0):
443 """Compute scaling factor to be applied to the extended PSF so that its
444 amplitude matches that of an individual star.
448 model : `~lsst.afw.image.MaskedImageF`
449 The extended PSF model, shifted (and potentially warped) to match
450 the bright star position.
451 star : `~lsst.meas.algorithms.brightStarStamps.BrightStarStamp`
452 A stamp centered on the bright star to be subtracted.
454 Whether the model should be scaled in place. Default is `True`.
456 The number of 90-degrees rotations to apply to the star stamp.
457 psf_annular_flux: `float`, optional
458 The annular flux of the PSF model at the radius where the flux of
459 the given star is determined. This is 1 for stars present in
460 inputBrightStarStamps, but can be different for stars that are
461 missing from inputBrightStarStamps.
465 scalingFactor : `float`
466 The factor by which the model image should be multiplied for it
467 to be scaled to the input bright star.
469 if self.config.scalingType ==
"annularFlux":
470 scalingFactor = star.annularFlux * psf_annular_flux
471 elif self.config.scalingType ==
"leastSquare":
472 if self.statsControl
is None:
473 self._setUpStatistics(star.stamp_im.mask)
474 starIm = star.stamp_im.clone()
476 starIm = rotateImageBy90(starIm, nb90Rots)
478 starIm *= star.annularFlux
482 xy.image.array *= model.image.array
484 xx.image.array = model.image.array**2
486 xySum = makeStatistics(xy, self.statsFlag, self.statsControl).getValue()
487 xxSum = makeStatistics(xx, self.statsFlag, self.statsControl).getValue()
488 scalingFactor = xySum / xxSum
if xxSum
else 1
490 model.image *= scalingFactor
493 def _overrideWarperConfig(self):
494 """Override the warper config with the config of this task.
496 This override is necessary for stars that are missing from the
497 inputBrightStarStamps object but still need to be subtracted.
500 self.warper.config.minValidAnnulusFraction = self.config.minValidAnnulusFraction
501 self.warper.config.numSigmaClip = self.config.numSigmaClip
502 self.warper.config.numIter = self.config.numIter
503 self.warper.config.annularFluxStatistic = self.config.annularFluxStatistic
504 self.warper.config.badMaskPlanes = self.config.badMaskPlanes
505 self.warper.config.stampSize = self.config.subtractionBox
506 self.warper.modelStampBuffer = self.config.subtractionBoxBuffer
507 self.warper.config.magLimit = self.config.magLimit
508 self.warper.setModelStamp()
510 def setMissedStarsStatsControl(self):
511 """Configure statistics control for processing missing stars from
512 inputBrightStarStamps.
515 numSigmaClip=self.warper.config.numSigmaClip,
516 numIter=self.warper.config.numIter,
518 self.missedStatsFlag = stringToStatisticsProperty(self.warper.config.annularFluxStatistic)
520 def setWarpTask(self):
521 """Create an instance of ProcessBrightStarsTask that will be used to
522 produce stamps of stars to be subtracted.
525 self._overrideWarperConfig()
526 self.warper.modelCenter = self.modelStampSize[0] // 2, self.modelStampSize[1] // 2
528 def makeBrightStarList(self, inputBrightStarStamps, inputExposure, refObjLoader):
529 """Make a list of bright stars that are missing from
530 inputBrightStarStamps to be subtracted.
534 inputBrightStarStamps :
535 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`
536 Set of stamps centered on each bright star to be subtracted,
538 `~lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask`.
539 inputExposure : `~lsst.afw.image.ExposureF`
540 The image from which bright stars should be subtracted.
541 refObjLoader : `~lsst.meas.algorithms.ReferenceObjectLoader`, optional
542 Loader to find objects within a reference catalog.
548 `lsst.meas.algorithms.brightStarStamps.BrightStarStamp` of stars to
552 missedStars = self.warper.extractStamps(
553 inputExposure, refObjLoader=refObjLoader, inputBrightStarStamps=inputBrightStarStamps
555 if missedStars.starStamps:
556 self.warpOutputs = self.warper.warpStamps(missedStars.starStamps, missedStars.pixCenters)
560 archive_element=transform,
561 position=self.warpOutputs.xy0s[j],
562 gaiaGMag=missedStars.gMags[j],
563 gaiaId=missedStars.gaiaIds[j],
564 minValidAnnulusFraction=self.warper.config.minValidAnnulusFraction,
566 for j, (warp, transform)
in enumerate(
567 zip(self.warpOutputs.warpedStars, self.warpOutputs.warpTransforms)
572 return brightStarList
574 def initAnnulusImage(self):
575 """Initialize an annulus image of the given star.
579 annulusImage : `~lsst.afw.image.MaskedImageF`
580 The initialized annulus image.
582 maskPlaneDict = self.model.mask.getMaskPlaneDict()
583 annulusImage = MaskedImageF(self.modelStampSize, planeDict=maskPlaneDict)
584 annulusImage.mask.array[:] = 2 ** maskPlaneDict[
"NO_DATA"]
587 def createAnnulus(self, brightStarStamp):
588 """Create a circular annulus around the given star.
590 The circular annulus is set based on the inner and outer optimal radii.
591 These radii describe the annulus where the flux of the star is found.
592 The aim is to create the same annulus for the PSF model, eventually
593 measuring the model flux around that annulus.
594 An optimal radius usually differs from the radius where the PSF model
600 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamp`
601 A stamp of a bright star to be subtracted.
605 annulus : `~lsst.afw.image.MaskedImageF`
606 An annulus of the given star.
609 outerCircle = SpanSet.fromShape(
610 brightStarStamp.optimalOuterRadius, Stencil.CIRCLE, offset=self.warper.modelCenter
612 innerCircle = SpanSet.fromShape(
613 brightStarStamp.optimalInnerRadius, Stencil.CIRCLE, offset=self.warper.modelCenter
615 annulus = outerCircle.intersectNot(innerCircle)
618 def applyStatsControl(self, annulusImage):
619 """Apply statistics control to the PSF annulus image.
623 annulusImage : `~lsst.afw.image.MaskedImageF`
624 An image containing an annulus of the given model.
629 The annular flux of the PSF model at the radius where the flux of
630 the given star is determined.
633 ior, (annulusImage.mask.getPlaneBitMask(bm)
for bm
in self.warper.config.badMaskPlanes)
635 self.missedStatsControl.setAndMask(andMask)
636 annulusStat = makeStatistics(annulusImage, self.missedStatsFlag, self.missedStatsControl)
637 return annulusStat.getValue()
639 def findPsfAnnularFlux(self, brightStarStamp, maskedModel):
640 """Find the annular flux of the PSF model within a specified annulus.
642 This flux will be used for re-scaling the PSF to the level of stars
643 with bad stamps. Stars with bad stamps are those without a flux within
644 the normalization annulus.
649 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamp`
650 A stamp of a bright star to be subtracted.
651 maskedModel : `~lsst.afw.image.MaskedImageF`
652 A masked image of the PSF model.
656 annularFlux: float (between 0 and 1)
657 The annular flux of the PSF model at the radius where the flux of
658 the given star is determined.
660 annulusImage = self.initAnnulusImage()
661 annulus = self.createAnnulus(brightStarStamp)
662 annulus.copyMaskedImage(maskedModel, annulusImage)
663 annularFlux = self.applyStatsControl(annulusImage)
666 def findPsfAnnularFluxes(self, brightStarStamps):
667 """Find the annular fluxes of the given PSF model.
672 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`
673 The stamps of stars that will be subtracted from the exposure.
677 PsfAnnularFluxes: numpy.array
678 A two column numpy.array containing annular fluxes of the PSF at
679 radii where the flux for stars exist (could be found).
683 While the PSF model is normalized at a certain radius, the annular flux
684 of a star around that radius might be impossible to find. Therefore, we
685 have to scale the PSF model considering a radius where the star has an
686 identified flux. To do that, the flux of the model should be found and
687 used to adjust the scaling step.
691 maskedModel = MaskedImageF(self.model.image)
693 maskedModel.setXY0(0, 0)
694 for star
in brightStarStamps:
695 if star.optimalOuterRadius
not in outerRadii:
696 annularFlux = self.findPsfAnnularFlux(star, maskedModel)
697 outerRadii.append(star.optimalOuterRadius)
698 annularFluxes.append(annularFlux)
699 return np.array([outerRadii, annularFluxes]).T
701 def preparePlaneModelStamp(self, brightStarStamp):
702 """Prepare the PSF plane model stamp.
704 It is called PlaneModel because, while it is a PSF model stamp that is
705 warped and rotated to the same orientation of a chosen star, it is not
706 yet scaled to the brightness level of the star.
711 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamp`
712 The stamp of the star to which the PSF model will be scaled.
716 bbox: `~lsst.geom.Box2I`
717 Contains the corner coordination and the dimensions of the model
720 invImage: `~lsst.afw.image.MaskedImageF`
721 The extended PSF model, shifted (and potentially warped and
722 rotated) to match the bright star position.
727 Raised if warping of the model failed.
731 Since detectors have different orientations, the PSF model should be
732 rotated to match the orientation of the detectors in some cases. To do
733 that, the code uses the inverse of the transform that is applied to the
734 bright star stamp to match the orientation of the detector.
737 self.model.setXY0(brightStarStamp.position)
739 invTransform = brightStarStamp.archive_element.inverted()
740 invOrigin = Point2I(invTransform.applyForward(Point2D(brightStarStamp.position)))
741 bbox =
Box2I(corner=invOrigin, dimensions=self.modelStampSize)
742 invImage = MaskedImageF(bbox)
744 goodPix = warpImage(invImage, self.model, invTransform, self.warpControl)
750 f
"Warping of a model failed for star {brightStarStamp.gaiaId}: no good pixel in output."
752 return bbox, invImage
754 def addScaledModel(self, subtractor, brightStarStamp, multipleAnnuli=False):
755 """Add the scaled model of the given star to the subtractor plane.
759 subtractor : `~lsst.afw.image.MaskedImageF`
760 The full image containing the scaled model of bright stars to be
761 subtracted from the input exposure.
763 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamp`
764 The stamp of the star of which the PSF model will be scaled and
765 added to the subtractor.
766 multipleAnnuli : bool, optional
767 If true, the model should be scaled based on a flux at a radius
768 other than its normalization radius.
772 subtractor : `~lsst.afw.image.MaskedImageF`
773 The input subtractor full image with the added scaled model at the
774 given star's location in the exposure.
775 invImage: `~lsst.afw.image.MaskedImageF`
776 The extended PSF model, shifted (and potentially warped) to match
777 the bright star position.
779 bbox, invImage = self.preparePlaneModelStamp(brightStarStamp)
780 bbox.clip(self.inputExpBBox)
781 if bbox.getArea() > 0:
783 cond = self.psf_annular_fluxes[:, 0] == brightStarStamp.optimalOuterRadius
784 psf_annular_flux = self.psf_annular_fluxes[cond, 1][0]
789 nb90Rots=self.inv90Rots,
790 psf_annular_flux=psf_annular_flux,
793 self.scaleModel(invImage, brightStarStamp, inPlace=
True, nb90Rots=self.inv90Rots)
795 invImage.image.array[np.isnan(invImage.image.array)] = 0
796 subtractor[bbox] += invImage[bbox]
797 return subtractor, invImage
799 def buildSubtractor(self, brightStarStamps, subtractor, invImages, multipleAnnuli=False):
800 """Build an image containing potentially multiple scaled PSF models,
801 each at the location of a given bright star.
806 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`
807 Set of stamps centered on each bright star to be subtracted,
809 `~lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask`.
810 subtractor : `~lsst.afw.image.MaskedImageF`
811 The Exposure that will contain the scaled model of bright stars to
812 be subtracted from the exposure.
814 A list containing extended PSF models, shifted (and potentially
815 warped) to match the bright stars positions.
816 multipleAnnuli : bool, optional
817 This will be passed to addScaledModel method, by default False.
821 subtractor : `~lsst.afw.image.MaskedImageF`
822 An Exposure containing a scaled bright star model fit to every
823 bright star profile; its image can then be subtracted from the
826 A list containing the extended PSF models, shifted (and potentially
827 warped) to match bright stars' positions.
829 for star
in brightStarStamps:
830 if star.gaiaGMag < self.config.magLimit:
833 subtractor, invImage = self.addScaledModel(subtractor, star, multipleAnnuli)
834 invImages.append(invImage)
835 except RuntimeError
as err:
837 return subtractor, invImages
Pass parameters to a Statistics object.
Parameters to control convolution.
An integer coordinate rectangle.