From 2304396c0e07991213e510aea3ad9a29e2e026a2 Mon Sep 17 00:00:00 2001 From: Eric Bellm Date: Thu, 12 Jun 2025 14:13:07 -0700 Subject: [PATCH] perform forced photometry on template --- python/lsst/ip/diffim/detectAndMeasure.py | 57 +++++++++++++++++------ tests/test_detectAndMeasure.py | 6 ++- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/python/lsst/ip/diffim/detectAndMeasure.py b/python/lsst/ip/diffim/detectAndMeasure.py index bcba5a2c7..1727aab1a 100644 --- a/python/lsst/ip/diffim/detectAndMeasure.py +++ b/python/lsst/ip/diffim/detectAndMeasure.py @@ -420,6 +420,28 @@ def __init__(self, **kwargs): self.schema.addField( "ip_diffim_forced_PsfFlux_flag_edge", "Flag", "Forced PSF flux object was too close to the edge of the image to use the full PSF model.") + self.schema.addField( + "ip_diffim_forced_template_PsfFlux_instFlux", "D", + "Forced PSF flux measured on the template image.", + units="count") + self.schema.addField( + "ip_diffim_forced_template_PsfFlux_instFluxErr", "D", + "Forced PSF flux error measured on the template image.", + units="count") + self.schema.addField( + "ip_diffim_forced_template_PsfFlux_area", "F", + "Forced template PSF flux effective area of PSF.", + units="pixel") + self.schema.addField( + "ip_diffim_forced_template_PsfFlux_flag", "Flag", + "Forced template PSF flux general failure flag.") + self.schema.addField( + "ip_diffim_forced_template_PsfFlux_flag_noGoodPixels", "Flag", + "Forced template PSF flux not enough non-rejected pixels in data to attempt the fit.") + self.schema.addField( + "ip_diffim_forced_template_PsfFlux_flag_edge", "Flag", + """Forced template PSF flux object was too close to the edge of the image """ + """to use the full PSF model.""") self.makeSubtask("forcedMeasurement", refSchema=self.schema) self.schema.addField("refMatchId", "L", "unique id of reference catalog match") @@ -694,6 +716,8 @@ def processResults(self, science, matchedTemplate, difference, sources, idFactor if self.config.doForcedMeasurement: self.measureForcedSources(diaSources, science, difference.getWcs()) + self.measureForcedSources(diaSources, matchedTemplate, difference.getWcs(), + template=True) measurementResults.subtractedMeasuredExposure = difference @@ -857,35 +881,42 @@ def measureDiaSources(self, diaSources, science, difference, matchedTemplate): apCorrMap=apCorrMap, ) - def measureForcedSources(self, diaSources, science, wcs): - """Perform forced measurement of the diaSources on the science image. + def measureForcedSources(self, diaSources, image, wcs, template=False): + """Perform forced measurement of the diaSources on a direct image. Parameters ---------- diaSources : `lsst.afw.table.SourceCatalog` The catalog of detected sources. - science : `lsst.afw.image.ExposureF` - Science exposure that the template was subtracted from. + image: `lsst.afw.image.ExposureF` + Exposure that the forced measurement is being performed on wcs : `lsst.afw.geom.SkyWcs` Coordinate system definition (wcs) for the exposure. + template : `bool` + Is the forced measurement being performed on the template? """ - # Run forced psf photometry on the PVI at the diaSource locations. + # Run forced psf photometry on the image at the diaSource locations. # Copy the measured flux and error into the diaSource. - forcedSources = self.forcedMeasurement.generateMeasCat(science, diaSources, wcs) - self.forcedMeasurement.run(forcedSources, science, diaSources, wcs) + forcedSources = self.forcedMeasurement.generateMeasCat(image, diaSources, wcs) + self.forcedMeasurement.run(forcedSources, image, diaSources, wcs) + + if template: + base_key = 'ip_diffim_forced_template_PsfFlux' + else: + base_key = 'ip_diffim_forced_PsfFlux' mapper = afwTable.SchemaMapper(forcedSources.schema, diaSources.schema) mapper.addMapping(forcedSources.schema.find("base_PsfFlux_instFlux")[0], - "ip_diffim_forced_PsfFlux_instFlux", True) + f"{base_key}_instFlux", True) mapper.addMapping(forcedSources.schema.find("base_PsfFlux_instFluxErr")[0], - "ip_diffim_forced_PsfFlux_instFluxErr", True) + f"{base_key}_instFluxErr", True) mapper.addMapping(forcedSources.schema.find("base_PsfFlux_area")[0], - "ip_diffim_forced_PsfFlux_area", True) + f"{base_key}_area", True) mapper.addMapping(forcedSources.schema.find("base_PsfFlux_flag")[0], - "ip_diffim_forced_PsfFlux_flag", True) + f"{base_key}_flag", True) mapper.addMapping(forcedSources.schema.find("base_PsfFlux_flag_noGoodPixels")[0], - "ip_diffim_forced_PsfFlux_flag_noGoodPixels", True) + f"{base_key}_flag_noGoodPixels", True) mapper.addMapping(forcedSources.schema.find("base_PsfFlux_flag_edge")[0], - "ip_diffim_forced_PsfFlux_flag_edge", True) + f"{base_key}_flag_edge", True) for diaSource, forcedSource in zip(diaSources, forcedSources): diaSource.assign(forcedSource, mapper) diff --git a/tests/test_detectAndMeasure.py b/tests/test_detectAndMeasure.py index 43af77ff1..fa01c76ea 100644 --- a/tests/test_detectAndMeasure.py +++ b/tests/test_detectAndMeasure.py @@ -211,7 +211,8 @@ def test_raise_bad_psf(self): def test_measurements_finite(self): """Measured fluxes and centroids should always be finite. """ - columnNames = ["coord_ra", "coord_dec", "ip_diffim_forced_PsfFlux_instFlux"] + columnNames = ["coord_ra", "coord_dec", "ip_diffim_forced_PsfFlux_instFlux", + "ip_diffim_forced_template_PsfFlux_instFlux"] # Set up the simulated images noiseLevel = 1. @@ -755,7 +756,8 @@ def test_detection_xy0(self): def test_measurements_finite(self): """Measured fluxes and centroids should always be finite. """ - columnNames = ["coord_ra", "coord_dec", "ip_diffim_forced_PsfFlux_instFlux"] + columnNames = ["coord_ra", "coord_dec", "ip_diffim_forced_PsfFlux_instFlux", + "ip_diffim_forced_template_PsfFlux_instFlux"] # Set up the simulated images noiseLevel = 1.