Coverage for python/lsst/analysis/tools/atools/shapes.py: 29%
91 statements
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-02 11:54 -0700
« prev ^ index » next coverage.py v7.2.5, created at 2023-05-02 11:54 -0700
1# This file is part of analysis_tools.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22from __future__ import annotations
24__all__ = (
25 "ShapeSizeFractionalScalars",
26 "BasePsfResidual",
27 "ShapeSizeFractionalDiff",
28 "E1Diff",
29 "E2Diff",
30 "RhoStatistics",
31)
33from lsst.pex.config import Field
34from lsst.pex.config.configurableActions import ConfigurableActionField
36from ..actions.keyedData import KeyedScalars
37from ..actions.plot.rhoStatisticsPlot import RhoStatisticsPlotAction
38from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
39from ..actions.scalar import CountAction, MedianAction, SigmaMadAction
40from ..actions.vector import (
41 CalcE,
42 CalcEDiff,
43 CalcRhoStatistics,
44 CalcShapeSize,
45 CoaddPlotFlagSelector,
46 DownselectVector,
47 FlagSelector,
48 FractionalDifference,
49 LoadVector,
50 MagColumnNanoJansky,
51 SnSelector,
52 StarSelector,
53 VectorSelector,
54)
55from ..interfaces import AnalysisTool, KeyedData, VectorAction
58class ShapeSizeFractionalScalars(KeyedScalars):
59 vectorKey = Field[str](doc="Column key to compute scalars")
61 snFluxType = Field[str](doc="column key for the flux type used in SN selection")
63 selector = ConfigurableActionField[VectorAction](doc="Selector to use before computing Scalars")
65 def setDefaults(self):
66 super().setDefaults()
67 self.scalarActions.median = MedianAction(vectorKey=self.vectorKey) # type: ignore
68 self.scalarActions.sigmaMad = SigmaMadAction(vectorKey=self.vectorKey) # type: ignore
69 self.scalarActions.count = CountAction(vectorKey=self.vectorKey) # type: ignore
70 self.scalarActions.approxMag = MedianAction(vectorKey=self.snFluxType) # type: ignore
72 def __call__(self, data: KeyedData, **kwargs) -> KeyedData:
73 mask = kwargs.get("mask")
74 selection = self.selector(data, **kwargs)
75 if mask is not None:
76 mask &= selection
77 else:
78 mask = selection
79 return super().__call__(data, **kwargs | dict(mask=mask))
82class BasePsfResidual(AnalysisTool):
83 """Shared configuration for `prep` and `process` stages of PSF residuals.
85 This is a mixin class used by `BasePsfResidualScatterPlot` and
86 `BasePsfResidualMetric` to share common default configuration.
87 """
89 def setDefaults(self):
90 super().setDefaults()
91 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
92 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
94 self.process.buildActions.patchWhole = LoadVector()
95 self.process.buildActions.patchWhole.vectorKey = "patch"
97 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
99 self.process.buildActions.fracDiff = FractionalDifference(
100 actionA=CalcShapeSize(colXx="{band}_ixx", colYy="{band}_iyy", colXy="{band}_ixy"),
101 actionB=CalcShapeSize(colXx="{band}_ixxPSF", colYy="{band}_iyyPSF", colXy="{band}_ixyPSF"),
102 )
103 # Define an eDiff action and let e1Diff and e2Diff differ only in
104 # component.
105 self.process.buildActions.eDiff = CalcEDiff(
106 colA=CalcE(colXx="{band}_ixx", colYy="{band}_iyy", colXy="{band}_ixy"),
107 colB=CalcE(colXx="{band}_ixxPSF", colYy="{band}_iyyPSF", colXy="{band}_ixyPSF"),
108 )
109 self.process.buildActions.e1Diff = self.process.buildActions.eDiff
110 self.process.buildActions.e1Diff.component = "1"
111 self.process.buildActions.e2Diff = self.process.buildActions.eDiff
112 self.process.buildActions.e2Diff.component = "2"
113 # pre-compute a stellar selector mask so it can be used in the filter
114 # actions while only being computed once, alternatively the stellar
115 # selector could be calculated and applied twice in the filter stage
116 self.process.buildActions.starSelector = StarSelector()
118 self.process.filterActions.xStars = DownselectVector(
119 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
120 )
121 # downselect the psfFlux as well
122 self.process.filterActions.psfFlux = DownselectVector(
123 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
124 )
125 self.process.filterActions.psfFluxErr = DownselectVector(
126 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
127 )
129 self.process.filterActions.patch = DownselectVector(
130 vectorKey="patchWhole", selector=VectorSelector(vectorKey="starSelector")
131 )
133 self.process.calculateActions.stars = ScatterPlotStatsAction(
134 vectorKey="yStars",
135 )
136 # use the downselected psfFlux
137 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux"
138 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux"
139 self.process.calculateActions.stars.fluxType = "psfFlux"
141 self.produce.metric.units = {
142 "{band}_highSNStars_median": "pixel",
143 "{band}_highSNStars_sigmaMad": "pixel",
144 "{band}_highSNStars_count": "count",
145 "{band}_lowSNStars_median": "pixel",
146 "{band}_lowSNStars_sigmaMad": "pixel",
147 "{band}_lowSNStars_count": "count",
148 }
150 self.produce.plot = ScatterPlotWithTwoHists()
152 self.produce.plot.plotTypes = ["stars"]
153 self.produce.plot.xAxisLabel = "PSF Magnitude (mag)"
154 self.produce.plot.magLabel = "PSF Magnitude (mag)"
155 self.produce.plot.addSummaryPlot = True
158class ShapeSizeFractionalDiff(BasePsfResidual):
159 def setDefaults(self):
160 super().setDefaults()
161 self.process.filterActions.yStars = DownselectVector(
162 vectorKey="fracDiff", selector=VectorSelector(vectorKey="starSelector")
163 )
164 self.produce.plot.yAxisLabel = "Fractional size residuals (S/S_PSF - 1)"
167class E1Diff(BasePsfResidual):
168 def setDefaults(self):
169 super().setDefaults()
170 self.process.filterActions.yStars = DownselectVector(
171 vectorKey="e1Diff", selector=VectorSelector(vectorKey="starSelector")
172 )
173 self.produce.plot.yAxisLabel = "Ellipticty residuals (e1 - e1_PSF)"
176class E2Diff(BasePsfResidual):
177 def setDefaults(self):
178 super().setDefaults()
179 self.process.filterActions.yStars = DownselectVector(
180 vectorKey="e2Diff", selector=VectorSelector(vectorKey="starSelector")
181 )
182 self.produce.plot.yAxisLabel = "Ellipticty residuals (e2 - e2_PSF)"
185class RhoStatistics(AnalysisTool):
186 parameterizedBand: bool = True
188 def setDefaults(self):
189 super().setDefaults()
190 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
191 self.prep.selectors.snSelector = SnSelector(fluxType="{band}_psfFlux", threshold=100)
193 self.process.buildActions.patchWhole = LoadVector()
194 self.process.buildActions.patchWhole.vectorKey = "patch"
196 self.process.buildActions.mags = MagColumnNanoJansky(vectorKey="{band}_psfFlux")
197 # pre-compute a stellar selector mask so it can be used in the filter
198 # actions while only being computed once, alternatively the stellar
199 # selector could be calculated and applied twice in the filter stage
200 self.process.buildActions.starSelector = FlagSelector(selectWhenTrue=("{band}_calib_psf_used",))
202 self.process.filterActions.xStars = DownselectVector(
203 vectorKey="mags", selector=VectorSelector(vectorKey="starSelector")
204 )
205 # downselect the psfFlux as well
206 self.process.filterActions.psfFlux = DownselectVector(
207 vectorKey="{band}_psfFlux", selector=VectorSelector(vectorKey="starSelector")
208 )
209 self.process.filterActions.psfFluxErr = DownselectVector(
210 vectorKey="{band}_psfFluxErr", selector=VectorSelector(vectorKey="starSelector")
211 )
213 self.process.filterActions.patch = DownselectVector(
214 vectorKey="patchWhole", selector=VectorSelector(vectorKey="starSelector")
215 )
217 self.process.calculateActions.stars = CalcRhoStatistics()
219 self.process.calculateActions.stars.treecorr.nbins = 10
220 self.process.calculateActions.stars.treecorr.min_sep = 0.1
221 self.process.calculateActions.stars.treecorr.max_sep = 100.0
222 self.process.calculateActions.stars.treecorr.sep_units = "arcmin"
224 self.produce.plot = RhoStatisticsPlotAction()