|
29 | 29 | import lsst.geom |
30 | 30 | from lsst.ip.diffim.utils import evaluateMaskFraction, computeDifferenceImageMetrics |
31 | 31 | from lsst.meas.algorithms import SkyObjectsTask, SourceDetectionTask, SetPrimaryFlagsTask, MaskStreaksTask |
| 32 | +from lsst.meas.algorithms import FindGlintTrailsTask |
32 | 33 | from lsst.meas.base import ForcedMeasurementTask, ApplyApCorrTask, DetectorVisitIdGeneratorConfig |
33 | 34 | import lsst.meas.deblender |
34 | 35 | import lsst.meas.extensions.trailedSources # noqa: F401 |
@@ -135,13 +136,21 @@ class DetectAndMeasureConnections(pipeBase.PipelineTaskConnections, |
135 | 136 | dimensions=("instrument", "visit", "detector"), |
136 | 137 | name="{fakesType}{coaddName}Diff_streaks", |
137 | 138 | ) |
| 139 | + trailedGlintInfo = pipeBase.connectionTypes.Output( |
| 140 | + doc='Dict of fit parameters for trailed glints in the catalog.', |
| 141 | + storageClass="ArrowNumpyDict", |
| 142 | + dimensions=("instrument", "visit", "detector"), |
| 143 | + name="trailed_glints", |
| 144 | + ) |
138 | 145 |
|
139 | 146 | def __init__(self, *, config): |
140 | 147 | super().__init__(config=config) |
141 | 148 | if not (self.config.writeStreakInfo and self.config.doMaskStreaks): |
142 | 149 | self.outputs.remove("maskedStreaks") |
143 | 150 | if not (self.config.doSubtractBackground and self.config.doWriteBackground): |
144 | 151 | self.outputs.remove("differenceBackground") |
| 152 | + if not (self.config.writeGlintInfo): |
| 153 | + self.outputs.remove("trailedGlintInfo") |
145 | 154 |
|
146 | 155 |
|
147 | 156 | class DetectAndMeasureConfig(pipeBase.PipelineTaskConfig, |
@@ -257,6 +266,15 @@ class DetectAndMeasureConfig(pipeBase.PipelineTaskConfig, |
257 | 266 | doc="Record the parameters of any detected streaks. For LSST, this should be turned off except for " |
258 | 267 | "development work." |
259 | 268 | ) |
| 269 | + findGlints = pexConfig.ConfigurableField( |
| 270 | + target=FindGlintTrailsTask, |
| 271 | + doc="Subtask for finding trailed glints, usually caused by satellites or debris." |
| 272 | + ) |
| 273 | + writeGlintInfo = pexConfig.Field( |
| 274 | + dtype=bool, |
| 275 | + default=True, |
| 276 | + doc="Record the parameters of any detected trailed glints." |
| 277 | + ) |
260 | 278 | setPrimaryFlags = pexConfig.ConfigurableField( |
261 | 279 | target=SetPrimaryFlagsTask, |
262 | 280 | doc="Task to add isPrimary and deblending-related flags to the catalog." |
@@ -430,6 +448,8 @@ def __init__(self, **kwargs): |
430 | 448 | if self.config.doMaskStreaks: |
431 | 449 | self.makeSubtask("maskStreaks") |
432 | 450 | self.makeSubtask("streakDetection") |
| 451 | + self.makeSubtask("findGlints") |
| 452 | + self.schema.addField("trailed_glint", "Flag", "DiaSource is part of a glint trail.") |
433 | 453 |
|
434 | 454 | # To get the "merge_*" fields in the schema; have to re-initialize |
435 | 455 | # this later, once we have a peak schema post-detection. |
@@ -467,6 +487,7 @@ def runQuantum(self, butlerQC: pipeBase.QuantumContext, |
467 | 487 | measurementResults.subtractedMeasuredExposure, |
468 | 488 | measurementResults.diaSources, |
469 | 489 | measurementResults.maskedStreaks, |
| 490 | + measurementResults.trailedGlintInfo, |
470 | 491 | log=self.log |
471 | 492 | ) |
472 | 493 | butlerQC.put(measurementResults, outputRefs) |
@@ -690,6 +711,13 @@ def processResults(self, science, matchedTemplate, difference, sources, idFactor |
690 | 711 | initialDiaSources = initialDiaSources.copy(deep=True) |
691 | 712 |
|
692 | 713 | self.measureDiaSources(initialDiaSources, science, difference, matchedTemplate) |
| 714 | + |
| 715 | + # Add a column for trailed glint diaSources, but do not remove them |
| 716 | + initialDiaSources, trail_parameters = self._find_trailed_glints(initialDiaSources) |
| 717 | + if self.config.writeGlintInfo: |
| 718 | + measurementResults.mergeItems(trail_parameters, 'trailedGlintInfo') |
| 719 | + |
| 720 | + # Remove unphysical diaSources per config.badSourceFlags |
693 | 721 | diaSources = self._removeBadSources(initialDiaSources) |
694 | 722 |
|
695 | 723 | if self.config.doForcedMeasurement: |
@@ -807,6 +835,39 @@ def _removeBadSources(self, diaSources): |
807 | 835 | self.log.info("Removed %d unphysical sources.", nBadTotal) |
808 | 836 | return diaSources[selector].copy(deep=True) |
809 | 837 |
|
| 838 | + def _find_trailed_glints(self, diaSources): |
| 839 | + """Define a new flag column for diaSources that are in a glint trail. |
| 840 | +
|
| 841 | + Parameters |
| 842 | + ---------- |
| 843 | + diaSources : `lsst.afw.table.SourceCatalog` |
| 844 | + The catalog of detected sources. |
| 845 | +
|
| 846 | + Returns |
| 847 | + ------- |
| 848 | + diaSources : `lsst.afw.table.SourceCatalog` |
| 849 | + The updated catalog of detected sources, with a new bool column |
| 850 | + called 'trailed_glint' added. |
| 851 | +
|
| 852 | + trail_parameters : `dict` |
| 853 | + Parameters of all the trails that were found. |
| 854 | + """ |
| 855 | + trailed_glints = self.findGlints.run(diaSources) |
| 856 | + glint_mask = [True if id in trailed_glints.trailed_ids else False for id in diaSources['id']] |
| 857 | + diaSources['trailed_glint'] = np.array(glint_mask) |
| 858 | + |
| 859 | + slopes = np.array([trail.slope for trail in trailed_glints.parameters]) |
| 860 | + intercepts = np.array([trail.intercept for trail in trailed_glints.parameters]) |
| 861 | + stderrs = np.array([trail.stderr for trail in trailed_glints.parameters]) |
| 862 | + lengths = np.array([trail.length for trail in trailed_glints.parameters]) |
| 863 | + angles = np.array([trail.angle for trail in trailed_glints.parameters]) |
| 864 | + parameters = {'slopes': slopes, 'intercepts': intercepts, 'stderrs': stderrs, 'lengths': lengths, |
| 865 | + 'angles': angles} |
| 866 | + |
| 867 | + trail_parameters = pipeBase.Struct(trailedGlintInfo=parameters) |
| 868 | + |
| 869 | + return diaSources, trail_parameters |
| 870 | + |
810 | 871 | def addSkySources(self, diaSources, mask, seed, |
811 | 872 | subtask=None): |
812 | 873 | """Add sources in empty regions of the difference image |
|
0 commit comments