Skip to content

Commit

Permalink
Merge pull request #364 from lsst/tickets/DM-39842
Browse files Browse the repository at this point in the history
DM-39842: Convert MeasureApCorr to new exceptions
  • Loading branch information
parejkoj authored Mar 22, 2024
2 parents 4427e4e + 7fa028a commit 1098895
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 23 deletions.
57 changes: 44 additions & 13 deletions python/lsst/meas/algorithms/measureApCorr.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,50 @@
import lsst.pex.config
from lsst.afw.image import ApCorrMap
from lsst.afw.math import ChebyshevBoundedField, ChebyshevBoundedFieldConfig
from lsst.pipe.base import Task, Struct
from lsst.pipe.base import Task, Struct, AlgorithmError
from lsst.meas.base.apCorrRegistry import getApCorrNameSet

from .sourceSelector import sourceSelectorRegistry


class MeasureApCorrError(RuntimeError):
pass
class MeasureApCorrError(AlgorithmError):
"""Raised if Aperture Correction fails in a non-recoverable way.
Parameters
----------
name : `str`
Name of the kind of aperture correction that failed; typically an
instFlux catalog field.
nSources : `int`
Number of sources available to the fitter at the point of failure.
ndof : `int`
Number of degrees of freedom required at the point of failure.
iteration : `int`, optional
Which fit iteration the failure occurred in.
"""
def __init__(self, *, name, nSources, ndof, iteration=None):
msg = f"Unable to measure aperture correction for '{name}'"
if iteration is not None:
msg += f" after {iteration} steps:"
else:
msg += ":"
msg += f" only {nSources} sources, but require at least {ndof}."
super().__init__(msg)
self.name = name
self.nSources = nSources
self.ndof = ndof
self.iteration = iteration

@property
def metadata(self):
metadata = {"name": self.name,
"nSources": self.nSources,
"ndof": self.ndof,
}
# NOTE: have to do this because task metadata doesn't allow None.
if self.iteration is not None:
metadata["iteration"] = self.iteration
return metadata


class _FluxNames:
Expand Down Expand Up @@ -232,11 +268,8 @@ def run(self, exposure, catalog):
name, isGood.sum(), self.config.minDegreesOfFreedom + 1)
continue
else:
msg = ("Unable to measure aperture correction for required algorithm '%s': "
"only %d sources, but require at least %d." %
(name, isGood.sum(), self.config.minDegreesOfFreedom + 1))
self.log.warning(msg)
raise MeasureApCorrError("Aperture correction failed on required algorithm.")
raise MeasureApCorrError(name=name, nSources=isGood.sum(),
ndof=self.config.minDegreesOfFreedom + 1)

goodCat = goodRefCat[isGood].copy()

Expand Down Expand Up @@ -286,11 +319,9 @@ def run(self, exposure, catalog):
(name, keep.sum(), self.config.minDegreesOfFreedom + 1))
break
else:
msg = ("Unable to measure aperture correction for required algorithm "
"'%s': only %d sources remain, but require at least %d." %
(name, keep.sum(), self.config.minDegreesOfFreedom + 1))
self.log.warning(msg)
raise MeasureApCorrError("Aperture correction failed on required algorithm.")
raise MeasureApCorrError(name=name, nSources=keep.sum(),
ndof=self.config.minDegreesOfFreedom + 1,
iteration=iteration+1)

apCorrField = ChebyshevBoundedField.fit(bbox, x, y, z, ctrl)
fitValues = apCorrField.evaluate(x, y)
Expand Down
21 changes: 11 additions & 10 deletions tests/test_measureApCorr.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,18 @@ def testTooFewSources(self):
""" If there are too few sources, check that an exception is raised."""
# Create an empty catalog with no sources to process.
catalog = afwTable.SourceCatalog(self.schema)
with self.assertLogs(level=logging.WARNING) as cm:
with self.assertRaisesRegex(measureApCorr.MeasureApCorrError, "failed on required algorithm"):
self.meas_apCorr_task.run(catalog=catalog, exposure=self.exposure)
self.assertIn("Unable to measure aperture correction for required algorithm", cm.output[0])
with self.assertRaisesRegex(measureApCorr.MeasureApCorrError,
"Unable to measure aperture correction for 'test1Ap'"):
self.meas_apCorr_task.run(catalog=catalog, exposure=self.exposure)

# We now try again after declaring that the aperture correction is
# allowed to fail. This should run cleanly without raising an exception.
# allowed to fail. This should run without raising an exception, but
# will log a warning.
for name in self.names:
self.meas_apCorr_task.config.allowFailure.append(name + self.apNameStr)
self.meas_apCorr_task.run(catalog=catalog, exposure=self.exposure)
with self.assertLogs(level=logging.WARNING) as cm:
self.meas_apCorr_task.run(catalog=catalog, exposure=self.exposure)
self.assertIn("Unable to measure aperture correction for 'test1Ap'", cm.output[0])

def testSourceNotUsed(self):
""" Check that a source outside the bounding box is flagged as not used (False)."""
Expand Down Expand Up @@ -247,10 +249,9 @@ def testTooFewSourcesAfterFiltering(self):
nameAp = name + self.apNameStr
sourceCat[nameAp + "_instFlux"][0] = 100.0

with self.assertLogs(level=logging.WARNING) as cm:
with self.assertRaisesRegex(measureApCorr.MeasureApCorrError, "Aperture correction failed"):
self.meas_apCorr_task.run(catalog=sourceCat, exposure=self.exposure)
self.assertIn("only 4 sources remain", cm.output[0])
with self.assertRaisesRegex(measureApCorr.MeasureApCorrError,
f"Unable to measure aperture correction for '{nameAp}'"):
self.meas_apCorr_task.run(catalog=sourceCat, exposure=self.exposure)

# We now try again after declaring that the aperture correction is
# allowed to fail. This should run cleanly without raising an exception.
Expand Down

0 comments on commit 1098895

Please sign in to comment.