@@ -180,6 +180,11 @@ class BrightStarCutoutConfig(
180180 },
181181 )
182182
183+ scalePsfModel = Field [bool ](
184+ doc = "If True, uses a scale factor to bring the PSF model data to the same level of the star data." ,
185+ default = True ,
186+ )
187+
183188 # PSF Fitting
184189 useExtendedPsf = Field [bool ](
185190 doc = "Use the extended PSF model to normalize bright star cutouts." ,
@@ -348,10 +353,18 @@ def run(
348353 # Fit a scaled PSF and a pedestal to each bright star cutout
349354 psf = WarpedPsf (inputExposure .getPsf (), pixToPolar , warpingControl )
350355 constantPsf = KernelPsf (FixedKernel (psf .computeKernelImage (Point2D (0 , 0 ))))
356+ # TODO: discuss with Lee whether we should warp the psf here as well?
351357 if self .config .useExtendedPsf :
352358 psfImage = extendedPsf # Assumed to be warped, center at [0,0]
353359 else :
354360 psfImage = constantPsf .computeKernelImage (constantPsf .getAveragePosition ())
361+ if self .config .scalePsfModel :
362+ psfNeg = psfImage .array < 0
363+ self .modelScale = np .nanmean (stampMI .image .array ) / np .nanmean (psfImage .array [~ psfNeg ])
364+ psfImage .array *= self .modelScale ######## model scale correction ########
365+ else :
366+ self .modelScale = 1
367+
355368 fitPsfResults = {}
356369 if self .config .doFitPsf :
357370 fitPsfResults = self ._fitPsf (stampMI , psfImage )
@@ -586,7 +599,8 @@ def _fitPsf(self, stampMI: MaskedImageF, psfImage: ImageD | ImageF) -> dict[str,
586599 psfMaskedPixels .array [:, :] = (stampMI .mask [psfImage .getBBox ()].array & badMaskBitMask ).astype (bool )
587600 # TODO: This is np.float64, else FITS metadata serialization fails
588601 # Amir: the following tries to find the fraction of the psf flux in the masked area of the psf image.
589- psfMaskedFluxFrac = np .dot (psfImage .array .flat , psfMaskedPixels .array .flat ).astype (np .float64 )
602+ psfMaskedFluxFrac = np .dot (psfImage .array .flat , psfMaskedPixels .array .flat ).astype (np .float64 ) / psfImage .array .sum ()
603+ # psfMaskedFluxFrac = np.dot(psfImage.array.astype(bool).flat, psfMaskedPixels.array.flat).astype(np.float64) / psfImage.array.astype(bool).sum()
590604 if psfMaskedFluxFrac > self .config .psfMaskedFluxFracThreshold :
591605 return {} # Handle cases where the PSF image is mostly masked
592606
@@ -622,13 +636,14 @@ def _fitPsf(self, stampMI: MaskedImageF, psfImage: ImageD | ImageF) -> dict[str,
622636 return {} # Handle singular matrix errors
623637 if sumSquaredResiduals .size == 0 :
624638 return {} # Handle cases where sum of the squared residuals are empty
625- scale = solutions [0 ]
639+ # scale = solutions[0]
640+ scale = solutions [0 ] * self .modelScale ######## model scale correction ########
626641 if scale <= 0 :
627642 return {} # Handle cases where the PSF scale fit has failed
628- scaleErr = np .sqrt (covarianceMatrix [0 , 0 ])
643+ scaleErr = np .sqrt (covarianceMatrix [0 , 0 ]) * self . modelScale ######## model scale correction ########
629644 pedestal = solutions [1 ]
630645 pedestalErr = np .sqrt (covarianceMatrix [1 , 1 ])
631- scalePedestalCov = covarianceMatrix [0 , 1 ]
646+ scalePedestalCov = covarianceMatrix [0 , 1 ] * self . modelScale ######## model scale correction ########
632647 xGradient = solutions [3 ]
633648 yGradient = solutions [2 ]
634649
@@ -641,6 +656,7 @@ def _fitPsf(self, stampMI: MaskedImageF, psfImage: ImageD | ImageF) -> dict[str,
641656 psfBBoxGoodSpans = goodSpans .clippedTo (psfImage .getBBox ())
642657 psfBBoxGoodSpansX , psfBBoxGoodSpansY = psfBBoxGoodSpans .indices ()
643658 psfBBoxData = psfBBoxGoodSpans .flatten (stampMI .image .array , stampMI .getXY0 ())
659+ paddedPsfImage .array /= self .modelScale ######## model scale correction ########
644660 psfBBoxModel = (
645661 psfBBoxGoodSpans .flatten (paddedPsfImage .array , stampMI .getXY0 ()) * scale
646662 + pedestal
@@ -652,7 +668,6 @@ def _fitPsf(self, stampMI: MaskedImageF, psfImage: ImageD | ImageF) -> dict[str,
652668 psfBBoxChiSquared = np .sum (psfBBoxResiduals )
653669 psfBBoxDegreesOfFreedom = len (psfBBoxData ) - 4
654670 psfBBoxReducedChiSquared = psfBBoxChiSquared / psfBBoxDegreesOfFreedom
655-
656671 return dict (
657672 scale = scale ,
658673 scaleErr = scaleErr ,
0 commit comments