Skip to content

Commit 71eeae9

Browse files
committed
Retry warped PSF evaluation if transform fails
for initial rough PSF size estimate
1 parent ab54d7e commit 71eeae9

File tree

1 file changed

+55
-9
lines changed

1 file changed

+55
-9
lines changed

python/lsst/ip/diffim/modelPsfMatch.py

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,55 @@
4545
sigma2fwhm = 2.*np.sqrt(2.*np.log(2.))
4646

4747

48+
def _safeEstimateRoughShape(psf, position, jitter=2.0, maxTries=5, log=None):
49+
50+
"""
51+
Try to compute the shape of `psf` at `position`.
52+
53+
If it fails, perturb the position until success or maxTries.
54+
55+
Parameters
56+
----------
57+
psf : `lsst.afw.detection.Psf`
58+
The PSF object.
59+
position : `lsst.geom.Point2D`
60+
The nominal position at which to evaluate the PSF shape.
61+
jitter : `float`
62+
Size of random offset in pixels to try when retrying.
63+
maxTries : `int`
64+
Maximum number of attempts (including the original).
65+
log : `lsst.utils.logging.LsstLogAdapter` optional
66+
logger to use for logging retries.
67+
68+
Returns
69+
-------
70+
shape : lsst.afw.geom.ellipses.Quadrupole
71+
The shape of the PSF at the (possibly perturbed) position.
72+
"""
73+
try:
74+
return psf.computeShape(position)
75+
except pexExceptions.Exception as err:
76+
if log:
77+
log.info(f"safeEstimateRoughShape: initial evaluation of PSF failed with message: {str(err)}."
78+
" Retrying nearby")
79+
firstErr = err
80+
81+
# random offsets must be deterministic
82+
offsets = np.random.default_rng(seed=40).uniform(-jitter, jitter, size=(maxTries - 1, 2))
83+
candidates = [position + geom.Extent2D(dx, dy) for dx, dy in offsets]
84+
for i, candidate in enumerate(candidates):
85+
try:
86+
shape = psf.computeShape(candidate)
87+
if log:
88+
log.info(f"safeEstimateRoughShape succeeded on try {i + 2} at position {candidate}")
89+
return shape
90+
except pexExceptions.Exception:
91+
continue
92+
93+
# If nothing worked, raise AlgorithmError from original position
94+
raise PsfComputeShapeError(position) from firstErr
95+
96+
4897
def nextOddInteger(x):
4998
nextInt = int(np.ceil(x))
5099
return nextInt + 1 if nextInt%2 == 0 else nextInt
@@ -175,15 +224,12 @@ def run(self, exposure, referencePsfModel, kernelSum=1.0):
175224
# exposure's bounding box in DM-32756.
176225
sciAvgPos = exposure.getPsf().getAveragePosition()
177226
modelAvgPos = referencePsfModel.getAveragePosition()
178-
try:
179-
fwhmScience = exposure.getPsf().computeShape(sciAvgPos).getDeterminantRadius()*sigma2fwhm
180-
except pexExceptions.RangeError as err:
181-
raise WarpedPsfTransformTooBigError(
182-
f"Unable to compute the FWHM of the science Psf at {sciAvgPos}"
183-
"due to an unexpectedly large transform."
184-
) from err
185-
except pexExceptions.Exception as err:
186-
raise PsfComputeShapeError(sciAvgPos) from err
227+
228+
# TODO If DM-52537 eliminates the need for _safeEstimateRoughShape,
229+
# the remove it, and replace next line with a direct call to
230+
# computeShape in a try/except block.
231+
fwhmScience = _safeEstimateRoughShape(exposure.getPsf(), sciAvgPos,
232+
log=self.log).getDeterminantRadius()*sigma2fwhm
187233
fwhmModel = referencePsfModel.computeShape(modelAvgPos).getDeterminantRadius()*sigma2fwhm
188234

189235
basisList = makeKernelBasisList(self.kConfig, fwhmScience, fwhmModel, metadata=self.metadata)

0 commit comments

Comments
 (0)