From f78e4ec2b66c4219a4b3116d66099baf55e35667 Mon Sep 17 00:00:00 2001 From: jrmullaney Date: Wed, 12 Jun 2024 03:45:14 -0700 Subject: [PATCH] Add summary metric creation to calibrateImage.py --- python/lsst/pipe/tasks/calibrateImage.py | 44 +++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/python/lsst/pipe/tasks/calibrateImage.py b/python/lsst/pipe/tasks/calibrateImage.py index 8b4839d01..149a78aa9 100644 --- a/python/lsst/pipe/tasks/calibrateImage.py +++ b/python/lsst/pipe/tasks/calibrateImage.py @@ -41,6 +41,23 @@ from . import measurePsf, repair, photoCal, computeExposureSummaryStats, snapCombine +class _EmptyTargetTask(pipeBase.PipelineTask): + """ + This is a placeholder target for CreateSummaryMetrics and must be retargeted at runtime. + CreateSummaryMetrics should target an analysis tool task, but that would, at the time + of writing, result in a circular import. + + As a result, this class should not be used for anything else. + """ + ConfigClass = pipeBase.PipelineTaskConfig + + def __init__(self, **kwargs) -> None: + raise NotImplementedError( + "doCreateSummaryMetrics is set to True, in which case " + "createSummaryMetrics must be retargeted." + ) + + class CalibrateImageConnections(pipeBase.PipelineTaskConnections, dimensions=("instrument", "visit", "detector")): @@ -136,6 +153,11 @@ class CalibrateImageConnections(pipeBase.PipelineTaskConnections, storageClass="Catalog", dimensions=("instrument", "visit", "detector"), ) + summary_metrics = connectionTypes.Output( + name="initial_summary_metrics", + storageClass="MetricMeasurementBundle", + dimensions=("instrument", "visit", "detector"), + ) def __init__(self, *, config=None): super().__init__(config=config) @@ -144,6 +166,8 @@ def __init__(self, *, config=None): del self.psf_stars_footprints del self.astrometry_matches del self.photometry_matches + if config.do_create_summary_metrics is False: + del self.summary_metrics class CalibrateImageConfig(pipeBase.PipelineTaskConfig, pipelineConnections=CalibrateImageConnections): @@ -255,6 +279,16 @@ class CalibrateImageConfig(pipeBase.PipelineTaskConfig, pipelineConnections=Cali target=computeExposureSummaryStats.ComputeExposureSummaryStatsTask, doc="Task to to compute summary statistics on the calibrated exposure." ) + do_create_summary_metrics = pexConfig.Field( + dtype=bool, + default=False, + doc="Run the subtask to create summary metrics, and then write those metrics." + ) + create_summary_metrics = pexConfig.ConfigurableField( + target=_EmptyTargetTask, + doc="Subtask to create metrics from the summary stats. This must be retargeted, likely to an" + "analysis_tools task such as CalexpSummaryMetrics." + ) def setDefaults(self): super().setDefaults() @@ -406,6 +440,7 @@ def __init__(self, initial_stars_schema=None, **kwargs): self.makeSubtask("photometry", schema=initial_stars_schema) self.makeSubtask("compute_summary_stats") + self.makeSubtask("create_summary_metrics") # For the butler to persist it. self.initial_stars_schema = afwTable.SourceCatalog(initial_stars_schema) @@ -539,7 +574,9 @@ def run(self, *, exposures, id_generator=None, result=None): result.photometry_matches = lsst.meas.astrom.denormalizeMatches(photometry_matches, photometry_meta) - self._summarize(result.exposure, result.stars_footprints, result.background) + result.summary_metrics = self._summarize(result.exposure, + result.stars_footprints, + result.background) return result @@ -849,3 +886,8 @@ def _summarize(self, exposure, stars, background): # applied calibration). This needs to be checked. summary = self.compute_summary_stats.run(exposure, stars, background) exposure.info.setSummaryStats(summary) + + summaryMetrics = None + if self.config.do_create_summary_metrics: + summaryMetrics = self.create_summary_metrics.run(data=summary.__dict__).metrics + return summaryMetrics