Skip to content

Commit

Permalink
Add image-based diffim metric, with test
Browse files Browse the repository at this point in the history
  • Loading branch information
parejkoj committed Jan 16, 2025
1 parent 3c79e8c commit 4c7ac34
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
50 changes: 49 additions & 1 deletion python/lsst/ip/diffim/subtractImages.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@ def run(self, template, science, sources, visitSummary=None):
Raised if fraction of good pixels, defined as not having NO_DATA
set, is less then the configured requiredTemplateFraction
"""

# Save this mask for use in metrics calculations, before we clear it.
science_mask = science.mask.clone()
self._prepareInputs(template, science, visitSummary=visitSummary)

# In the event that getPsfFwhm fails, evaluate the PSF on a grid.
Expand Down Expand Up @@ -465,8 +466,55 @@ def run(self, template, science, sources, visitSummary=None):
# checkTemplateIsSufficient did not raise NoWorkFound, so raise original exception
raise e

self._compute_image_metrics(science, science_mask, subtractResults.difference, sources)

return subtractResults

def _compute_image_metrics(self, science, science_mask, difference, stars):
"""Compute quality metrics (saved to the task metadata) on the
difference image, at the locations of detected stars on the science
image. This restricts the metric to locations that should be
well-subtracted.
Parameters
----------
science : `lsst.afw.image.ExposureF`
Science exposure that was subtracted.
science_mask : `lsst.afw.image.Mask`
Original, unmodified science mask.
difference : `lsst.afw.image.ExposureF`
Result of subtracting template and science.
stars : `lsst.afw.table.SourceCatalog`
Good calibration sources detected on science image; these
footprints are what the metrics are computed on.
"""
def footprint_mean(sources, sky=0):
"""Compute ratio of the absolute value of the diffim to the science
image, within each source footprint, subtracting the sky from the
diffim values if provided.
"""
n = len(sources)
science_footprints = np.zeros(n)
difference_footprints = np.zeros(n)
ratio = np.zeros(n)
for i, record in enumerate(sources):
footprint = record.getFootprint()
heavy = lsst.afw.detection.makeHeavyFootprint(footprint, science.maskedImage)
heavy_diff = lsst.afw.detection.makeHeavyFootprint(footprint, difference.maskedImage)
science_footprints[i] = heavy.getImageArray().sum()
difference_footprints[i] = abs(heavy_diff.getImageArray()).sum()
ratio[i] = (difference_footprints[i] - sky) / science_footprints[i]
return science_footprints, difference_footprints, ratio

sky = stars["sky_source"]
sky_science, sky_difference, sky_ratio = footprint_mean(stars[sky])
science_footprints, difference_footprints, ratio = footprint_mean(stars[~sky], sky_difference.mean())

self.metadata["differenceFootprintRatioMean"] = ratio.mean()
self.metadata["differenceFootprintRatioStdev"] = ratio.std()
self.metadata["differenceFootprintSkyRatioMean"] = sky_ratio.mean()
self.metadata["differenceFootprintSkyRatioStdev"] = sky_ratio.std()

def runConvolveTemplate(self, template, science, selectSources):
"""Convolve the template image with a PSF-matching kernel and subtract
from the science image.
Expand Down
16 changes: 16 additions & 0 deletions tests/test_subtractTask.py
Original file line number Diff line number Diff line change
Expand Up @@ -895,6 +895,18 @@ def test_metadata_metrics(self):
template_good, _ = makeTestImage(psfSize=2.4, doApplyCalibration=True)
template_bad, _ = makeTestImage(psfSize=9.5, doApplyCalibration=True)

# Add a few sky objects; sky footprints are needed for some metrics.
config = measAlg.SkyObjectsTask.ConfigClass()
config.nSources = 3
skyTask = measAlg.SkyObjectsTask(config=config, name="skySources")
skyTask.skySourceKey = sources.schema["sky_source"].asKey()
skyTask.run(science.mask, 10, catalog=sources)
sources = sources.copy(deep=True)
# Add centroids, since these sources were added post-measurement.
for record in sources[sources["sky_source"]]:
record["truth_x"] = record.getFootprint().getPeaks()[0].getFx()
record["truth_y"] = record.getFootprint().getPeaks()[0].getFy()

# The metadata fields are attached to the subtractTask, so we do
# need to run that; run it for both "good" and "bad" seeing templates

Expand Down Expand Up @@ -955,6 +967,10 @@ def test_metadata_metrics(self):
self.assertIn('scienceLimitingMagnitude', subtractTask_good.metadata)
self.assertIn('templateLimitingMagnitude', subtractTask_good.metadata)

# The mean ratio metric should be much worse on the "bad" subtraction.
self.assertLess(subtractTask_good.metadata['differenceFootprintRatioMean'], 0.2)
self.assertGreater(subtractTask_bad.metadata['differenceFootprintRatioMean'], 1.0)


class AlardLuptonPreconvolveSubtractTest(AlardLuptonSubtractTestBase, lsst.utils.tests.TestCase):
subtractTask = subtractImages.AlardLuptonPreconvolveSubtractTask
Expand Down

0 comments on commit 4c7ac34

Please sign in to comment.