Coverage for python/lsst/analysis/tools/atools/refCatMatchPlots.py: 24%
315 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-16 04:37 -0700
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-16 04:37 -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/>.
21from __future__ import annotations
23__all__ = (
24 "TargetRefCatDeltaRAScatterPlot",
25 "TargetRefCatDeltaDecScatterPlot",
26 "TargetRefCatDeltaRASkyPlot",
27 "TargetRefCatDeltaDecSkyPlot",
28 "TargetRefCatDeltaScatterPhotom",
29 "TargetRefCatDeltaScatterAstrom",
30 "TargetRefCatDeltaSkyPlotPhotom",
31 "TargetRefCatDeltaPsfScatterPlot",
32 "TargetRefCatDeltaCModelScatterPlot",
33 "TargetRefCatDeltaCModelSkyPlot",
34 "TargetRefCatDeltaPsfSkyPlot",
35 "TargetRefCatDeltaRASkyVisitPlot",
36 "TargetRefCatDeltaAp09ScatterVisitPlot",
37 "TargetRefCatDeltaPsfScatterVisitPlot",
38 "TargetRefCatDeltaAp09SkyVisitPlot",
39 "TargetRefCatDeltaPsfSkyVisitPlot",
40 "TargetRefCatDeltaDecSkyVisitPlot",
41 "TargetRefCatDeltaRAScatterVisitPlot",
42 "TargetRefCatDeltaDecScatterVisitPlot",
43 "TargetRefCatDeltaMetrics",
44 "TargetRefCatDeltaColorMetrics",
45)
47from lsst.pex.config import Field
49from ..actions.plot import HistPanel, HistPlot, HistStatsPanel
50from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists
51from ..actions.plot.skyPlot import SkyPlot
52from ..actions.scalar.scalarActions import CountAction, FracThreshold, MedianAction, RmsAction, SigmaMadAction
53from ..actions.vector import (
54 AngularSeparation,
55 CoaddPlotFlagSelector,
56 ConvertFluxToMag,
57 ConvertUnits,
58 DownselectVector,
59 LoadVector,
60 MagDiff,
61 RAcosDec,
62 RangeSelector,
63 SnSelector,
64 StarSelector,
65 SubtractVector,
66 VisitPlotFlagSelector,
67)
68from ..contexts import CoaddContext, RefMatchContext, VisitContext
69from ..interfaces import AnalysisTool
72class TargetRefCatDelta(AnalysisTool):
73 """Plot the difference between a target catalog and a
74 reference catalog for the quantity set in `setDefaults`.
75 """
77 parameterizedBand = Field[bool](
78 doc="Does this AnalysisTool support band as a name parameter", default=True
79 )
81 def coaddContext(self) -> None:
82 """Apply coadd options for the ref cat plots.
83 Applies the coadd plot flag selector and sets
84 flux types.
85 """
86 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
87 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux_target"
88 self.prep.selectors.snSelector.threshold = 200
89 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target"
90 self.process.buildActions.starStatMask = SnSelector()
91 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux_target"
92 self.process.buildActions.patch = LoadVector()
93 self.process.buildActions.patch.vectorKey = "patch_target"
95 def visitContext(self) -> None:
96 """Apply visit options for the ref cat plots.
97 Applies the visit plot flag selector and sets
98 the flux types.
99 """
100 self.parameterizedBand = False
101 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
102 self.prep.selectors.starSelector.vectorKey = "extendedness_target"
103 self.prep.selectors.snSelector.fluxType = "psfFlux_target"
104 self.prep.selectors.snSelector.threshold = 50
106 self.process.buildActions.starStatMask = SnSelector()
107 self.process.buildActions.starStatMask.fluxType = "psfFlux_target"
108 self.process.buildActions.starStatMask.threshold = 200
110 def setDefaults(self):
111 super().setDefaults()
113 self.prep.selectors.snSelector = SnSelector()
114 self.prep.selectors.starSelector = StarSelector()
117class TargetRefCatDeltaScatterAstrom(TargetRefCatDelta):
118 """Plot the difference in milliseconds between a target catalog and a
119 reference catalog for the coordinate set in `setDefaults`. Plot it on
120 a scatter plot.
121 """
123 def setDefaults(self):
124 super().setDefaults()
126 self.process.buildActions.yStars = ConvertUnits(
127 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
128 )
129 self.process.buildActions.xStars = ConvertFluxToMag()
130 self.process.buildActions.xStars.vectorKey = "{band}_psfFlux_target"
131 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
132 self.process.calculateActions.stars.lowSNSelector.fluxType = "{band}_psfFlux_target"
133 self.process.calculateActions.stars.highSNSelector.fluxType = "{band}_psfFlux_target"
134 self.process.calculateActions.stars.fluxType = "{band}_psfFlux_target"
136 self.produce = ScatterPlotWithTwoHists()
137 self.produce.plotTypes = ["stars"]
138 self.produce.magLabel = "PSF Magnitude (mag)"
139 self.produce.xAxisLabel = "PSF Magnitude (mag)"
140 self.applyContext(CoaddContext)
141 self.applyContext(RefMatchContext)
144class TargetRefCatDeltaScatterAstromVisit(TargetRefCatDelta):
145 """Plot the difference in milliseconds between a target catalog and a
146 reference catalog for the coordinate set in `setDefaults`. Plot it on
147 a scatter plot.
148 """
150 def setDefaults(self):
151 super().setDefaults()
153 self.process.buildActions.yStars = ConvertUnits(
154 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
155 )
156 self.process.buildActions.xStars = ConvertFluxToMag()
157 self.process.buildActions.xStars.vectorKey = "psfFlux_target"
158 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
159 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux_target"
160 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux_target"
161 self.process.calculateActions.stars.fluxType = "psfFlux_target"
163 self.produce = ScatterPlotWithTwoHists()
164 self.produce.addSummaryPlot = False
165 self.produce.plotTypes = ["stars"]
166 self.produce.magLabel = "PSF Magnitude (mag)"
167 self.produce.xAxisLabel = "PSF Magnitude (mag)"
168 self.applyContext(VisitContext)
169 self.applyContext(RefMatchContext)
172class TargetRefCatDeltaScatterPhotom(TargetRefCatDelta):
173 """Plot the difference in millimags between a target catalog and a
174 reference catalog for the flux type set in `setDefaults`.
175 """
177 def setDefaults(self):
178 super().setDefaults()
180 self.process.buildActions.yStars = MagDiff()
181 self.process.buildActions.yStars.col2 = "{band}_mag_ref"
182 self.process.buildActions.yStars.fluxUnits2 = "mag(AB)"
184 self.process.buildActions.xStars = ConvertFluxToMag()
185 self.process.buildActions.xStars.vectorKey = "{band}_psfFlux_target"
187 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
188 self.process.calculateActions.stars.lowSNSelector.fluxType = "{band}_psfFlux_target"
189 self.process.calculateActions.stars.highSNSelector.fluxType = "{band}_psfFlux_target"
190 self.process.calculateActions.stars.fluxType = "{band}_psfFlux_target"
192 self.produce = ScatterPlotWithTwoHists()
193 self.produce.plotTypes = ["stars"]
194 self.produce.magLabel = "PSF Magnitude (mag)"
195 self.produce.xAxisLabel = "PSF Magnitude (mag)"
196 self.produce.yAxisLabel = "Output Mag - Ref Mag (mmag)"
197 self.applyContext(CoaddContext)
198 self.applyContext(RefMatchContext)
201class TargetRefCatDeltaScatterPhotomVisit(TargetRefCatDelta):
202 """Plot the difference in millimags between a target catalog and a
203 reference catalog for the flux type set in `setDefaults`.
204 """
206 def setDefaults(self):
207 super().setDefaults()
209 self.process.buildActions.yStars = MagDiff()
210 self.process.buildActions.yStars.col2 = "mag_ref"
211 self.process.buildActions.yStars.fluxUnits2 = "mag(AB)"
213 self.process.buildActions.xStars = ConvertFluxToMag()
214 self.process.buildActions.xStars.vectorKey = "psfFlux_target"
216 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars")
217 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux_target"
218 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux_target"
219 self.process.calculateActions.stars.fluxType = "psfFlux_target"
221 self.produce = ScatterPlotWithTwoHists()
222 self.produce.addSummaryPlot = False
223 self.produce.plotTypes = ["stars"]
224 self.produce.magLabel = "PSF Magnitude (mag)"
225 self.produce.xAxisLabel = "PSF Magnitude (mag)"
226 self.produce.yAxisLabel = "Output Mag - Ref Mag (mmag)"
227 self.applyContext(VisitContext)
228 self.applyContext(RefMatchContext)
231class TargetRefCatDeltaPsfScatterPlot(TargetRefCatDeltaScatterPhotom):
232 """Plot the difference in millimags between the PSF flux
233 of a target catalog and a reference catalog
234 """
236 def setDefaults(self):
237 super().setDefaults()
239 self.process.buildActions.yStars.col1 = "{band}_psfFlux_target"
242class TargetRefCatDeltaCModelScatterPlot(TargetRefCatDeltaScatterPhotom):
243 """Plot the difference in millimags between the CModel flux
244 of a target catalog and a reference catalog.
245 """
247 def setDefaults(self):
248 super().setDefaults()
250 self.process.buildActions.yStars.col1 = "{band}_cModelFlux_target"
253class TargetRefCatDeltaPsfScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit):
254 """Plot the difference in millimags between the PSF flux
255 of a target catalog and a reference catalog
256 """
258 def setDefaults(self):
259 super().setDefaults()
261 self.process.buildActions.yStars.col1 = "psfFlux_target"
264class TargetRefCatDeltaAp09ScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit):
265 """Plot the difference in millimags between the aper 09 flux
266 of a target catalog and a reference catalog.
267 """
269 def setDefaults(self):
270 super().setDefaults()
272 self.process.buildActions.yStars.col1 = "ap09Flux_target"
275class TargetRefCatDeltaRAScatterPlot(TargetRefCatDeltaScatterAstrom):
276 """Plot the difference in milliseconds between the RA of a target catalog
277 and a reference catalog
278 """
280 def setDefaults(self):
281 super().setDefaults()
282 self.process.buildActions.yStars.buildAction.actionA = RAcosDec(
283 raKey="coord_ra_target", decKey="coord_dec_target"
284 )
285 self.process.buildActions.yStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
287 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)"
290class TargetRefCatDeltaRAScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit):
291 """Plot the difference in milliseconds between the RA of a target catalog
292 and a reference catalog
293 """
295 def setDefaults(self):
296 super().setDefaults()
297 self.process.buildActions.yStars.buildAction.actionA = RAcosDec(
298 raKey="coord_ra_target", decKey="coord_dec_target"
299 )
300 self.process.buildActions.yStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
302 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)"
305class TargetRefCatDeltaDecScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit):
306 """Plot the difference in milliseconds between the Decs of a target catalog
307 and a reference catalog
308 """
310 def setDefaults(self):
311 super().setDefaults()
312 self.process.buildActions.yStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
313 self.process.buildActions.yStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
315 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)"
318class TargetRefCatDeltaDecScatterPlot(TargetRefCatDeltaScatterAstrom):
319 """Plot the difference in milliseconds between the Dec of a target catalog
320 and a reference catalog
321 """
323 def setDefaults(self):
324 super().setDefaults()
325 self.process.buildActions.yStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
326 self.process.buildActions.yStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
328 self.produce.yAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (marcsec)"
331class TargetRefCatDeltaSkyPlot(TargetRefCatDelta):
332 """Base class for plotting the RA/Dec distribution of stars, with the
333 difference of the quantity defined in the vector key parameter between
334 the target and reference catalog as the color.
335 """
337 parameterizedBand = Field[bool](
338 doc="Does this AnalysisTool support band as a name parameter", default=True
339 )
341 def setDefaults(self):
342 super().setDefaults()
344 self.process.buildActions.xStars = LoadVector()
345 self.process.buildActions.xStars.vectorKey = "coord_ra_target"
346 self.process.buildActions.yStars = LoadVector()
347 self.process.buildActions.yStars.vectorKey = "coord_dec_target"
349 self.produce = SkyPlot()
350 self.produce.plotTypes = ["stars"]
351 self.produce.xAxisLabel = "R.A. (degrees)"
352 self.produce.yAxisLabel = "Dec. (degrees)"
353 self.produce.plotOutlines = False
356class TargetRefCatDeltaSkyPlotAstrom(TargetRefCatDeltaSkyPlot):
357 """Base class for plotting the RA/Dec distribution of stars, with the
358 difference between the RA or Dec of the target and reference catalog as
359 the color.
360 """
362 def setDefaults(self):
363 super().setDefaults()
365 self.process.buildActions.zStars = ConvertUnits(
366 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
367 )
369 self.applyContext(CoaddContext)
370 self.applyContext(RefMatchContext)
372 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux_target"
375class TargetRefCatDeltaSkyPlotAstromVisit(TargetRefCatDeltaSkyPlot):
376 """Base class for plotting the RA/Dec distribution of stars at
377 the visit level, with the difference between the RA or Dec of
378 the target and reference catalog as the color.
379 """
381 def setDefaults(self):
382 super().setDefaults()
384 self.process.buildActions.zStars = ConvertUnits(
385 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
386 )
388 self.applyContext(VisitContext)
389 self.applyContext(RefMatchContext)
392class TargetRefCatDeltaSkyPlotPhotomVisit(TargetRefCatDeltaSkyPlot):
393 """Base class for plotting the RA/Dec distribution of stars, with the
394 difference between the photometry of the target and reference catalog as
395 the color.
396 """
398 def setDefaults(self):
399 super().setDefaults()
401 self.process.buildActions.zStars = MagDiff()
402 self.process.buildActions.zStars.col2 = "mag_ref"
403 self.process.buildActions.zStars.fluxUnits2 = "mag(AB)"
405 self.produce.plotName = "photomDiffSky"
406 self.produce.zAxisLabel = "Output Mag - Ref Mag (mmag)"
407 self.applyContext(VisitContext)
408 self.applyContext(RefMatchContext)
411class TargetRefCatDeltaSkyPlotPhotom(TargetRefCatDeltaSkyPlot):
412 """Base class for plotting the RA/Dec distribution of stars, with the
413 difference between the photometry of the target and reference catalog as
414 the color.
415 """
417 def setDefaults(self):
418 super().setDefaults()
420 self.process.buildActions.zStars = MagDiff()
421 self.process.buildActions.zStars.col2 = "{band}_mag_ref"
422 self.process.buildActions.zStars.fluxUnits2 = "mag(AB)"
424 self.produce.plotName = "photomDiffSky_{band}"
425 self.produce.zAxisLabel = "Output Mag - Ref Mag (mmag)"
426 self.applyContext(CoaddContext)
427 self.applyContext(RefMatchContext)
430class TargetRefCatDeltaPsfSkyPlot(TargetRefCatDeltaSkyPlotPhotom):
431 """Plot the RA/Dec distribution of stars, with the
432 difference between the PSF photometry of the target and reference
433 catalog as the color.
434 """
436 def setDefaults(self):
437 super().setDefaults()
439 self.process.buildActions.zStars.col1 = "{band}_psfFlux_target"
442class TargetRefCatDeltaPsfSkyVisitPlot(TargetRefCatDeltaSkyPlotPhotomVisit):
443 """Plot the RA/Dec distribution of stars, with the
444 difference between the PSF photometry of the target and reference
445 catalog as the color.
446 """
448 def setDefaults(self):
449 super().setDefaults()
451 self.process.buildActions.zStars.col1 = "psfFlux_target"
454class TargetRefCatDeltaAp09SkyVisitPlot(TargetRefCatDeltaSkyPlotPhotomVisit):
455 """Plot the RA/Dec distribution of stars, with the
456 difference between the Ap09 photometry of the target and reference
457 catalog as the color.
458 """
460 def setDefaults(self):
461 super().setDefaults()
463 self.process.buildActions.zStars.col1 = "ap09Flux_target"
466class TargetRefCatDeltaCModelSkyPlot(TargetRefCatDeltaSkyPlotPhotom):
467 """Plot the RA/Dec distribution of stars, with the
468 difference between the CModel photometry of the target and reference
469 catalog as the color.
470 """
472 def setDefaults(self):
473 super().setDefaults()
475 self.process.buildActions.zStars.col1 = "{band}_cModelFlux_target"
478class TargetRefCatDeltaRASkyPlot(TargetRefCatDeltaSkyPlotAstrom):
479 """Plot the RA/Dec distribution of stars, with the
480 difference between the RA of the target and reference catalog as
481 the color.
482 """
484 def setDefaults(self):
485 super().setDefaults()
486 self.process.buildActions.zStars.buildAction.actionA = RAcosDec(
487 raKey="coord_ra_target", decKey="coord_dec_target"
488 )
489 self.process.buildActions.zStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
491 self.produce.plotName = "astromDiffSky_RA"
492 self.produce.zAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)"
495class TargetRefCatDeltaRASkyVisitPlot(TargetRefCatDeltaSkyPlotAstromVisit):
496 """Plot the RA/Dec distribution of stars, with the
497 difference between the RA of the target and reference catalog as
498 the color.
499 """
501 def setDefaults(self):
502 super().setDefaults()
503 self.process.buildActions.zStars.buildAction.actionA = RAcosDec(
504 raKey="coord_ra_target", decKey="coord_dec_target"
505 )
506 self.process.buildActions.zStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref")
507 self.produce.plotName = "astromDiffSky_RA"
508 self.produce.zAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)"
511class TargetRefCatDeltaDecSkyVisitPlot(TargetRefCatDeltaSkyPlotAstromVisit):
512 """Plot the RA/Dec distribution of stars, with the
513 difference between the RA of the target and reference catalog as
514 the color.
515 """
517 def setDefaults(self):
518 super().setDefaults()
519 self.process.buildActions.zStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
520 self.process.buildActions.zStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
522 self.produce.plotName = "astromDiffSky_Dec"
523 self.produce.zAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (marcsec)"
526class TargetRefCatDeltaDecSkyPlot(TargetRefCatDeltaSkyPlotAstrom):
527 """Plot the RA/Dec distribution of stars, with the
528 difference between the Dec of the target and reference catalog as
529 the color.
530 """
532 def setDefaults(self):
533 super().setDefaults()
534 self.process.buildActions.zStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
535 self.process.buildActions.zStars.buildAction.actionB = LoadVector(vectorKey="dec_ref")
537 self.produce.plotName = "astromDiffSky_Dec"
538 self.produce.zAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (marcsec)"
541class TargetRefCatDeltaMetrics(AnalysisTool):
542 """Calculate the AA1 metric and the sigma MAD from the difference between
543 the target and reference catalog coordinates.
544 """
546 parameterizedBand = Field[bool](
547 doc="Does this AnalysisTool support band as a name parameter", default=True
548 )
550 def coaddContext(self) -> None:
551 """Apply coadd options for the metrics. Applies the coadd plot flag
552 selector and sets flux types.
553 """
554 self.prep.selectors.flagSelector = CoaddPlotFlagSelector()
555 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target"
557 self.applyContext(RefMatchContext)
559 self.process.buildActions.mags.vectorKey = "{band}_psfFlux_target"
561 self.produce.metric.newNames = {
562 "AA1_RA": "{band}_AA1_RA_coadd",
563 "AA1_sigmaMad_RA": "{band}_AA1_sigmaMad_RA_coadd",
564 "AA1_Dec": "{band}_AA1_Dec_coadd",
565 "AA1_sigmaMad_Dec": "{band}_AA1_sigmaMad_Dec_coadd",
566 "AA1_tot": "{band}_AA1_tot_coadd",
567 "AA1_sigmaMad_tot": "{band}_AA1_sigmaMad_tot_coadd",
568 }
570 def visitContext(self) -> None:
571 """Apply visit options for the metrics. Applies the visit plot flag
572 selector and sets flux types.
573 """
574 self.parameterizedBand = False
575 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
576 self.prep.selectors.starSelector.vectorKey = "extendedness_target"
578 self.applyContext(RefMatchContext)
580 self.process.buildActions.mags.vectorKey = "psfFlux_target"
582 def setDefaults(self):
583 super().setDefaults()
585 self.prep.selectors.starSelector = StarSelector()
587 # Calculate difference in RA
588 self.process.buildActions.astromDiffRA = ConvertUnits(
589 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
590 )
591 self.process.buildActions.astromDiffRA.buildAction.actionA = RAcosDec(
592 raKey="coord_ra_target", decKey="dec_ref"
593 )
594 self.process.buildActions.astromDiffRA.buildAction.actionB = RAcosDec(
595 raKey="ra_ref", decKey="dec_ref"
596 )
597 # Calculate difference in Dec
598 self.process.buildActions.astromDiffDec = ConvertUnits(
599 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
600 )
601 self.process.buildActions.astromDiffDec.buildAction.actionA = LoadVector(vectorKey="coord_dec_target")
602 self.process.buildActions.astromDiffDec.buildAction.actionB = LoadVector(vectorKey="dec_ref")
603 # Calculate total difference (using astropy)
604 self.process.buildActions.astromDiffTot = AngularSeparation(
605 raKey_A="coord_ra_target",
606 decKey_A="coord_dec_target",
607 raKey_B="ra_ref",
608 decKey_B="dec_ref",
609 )
611 self.process.buildActions.mags = ConvertFluxToMag()
613 # Filter down to only objects with mag 17-21.5
614 self.process.filterActions.brightStarsRA = DownselectVector(vectorKey="astromDiffRA")
615 self.process.filterActions.brightStarsRA.selector = RangeSelector(
616 vectorKey="mags", minimum=17, maximum=21.5
617 )
619 self.process.filterActions.brightStarsDec = DownselectVector(vectorKey="astromDiffDec")
620 self.process.filterActions.brightStarsDec.selector = RangeSelector(
621 vectorKey="mags", minimum=17, maximum=21.5
622 )
624 self.process.filterActions.brightStarsTot = DownselectVector(vectorKey="astromDiffTot")
625 self.process.filterActions.brightStarsTot.selector = RangeSelector(
626 vectorKey="mags", minimum=17, maximum=21.5
627 )
629 # Calculate median and sigmaMad
630 self.process.calculateActions.AA1_RA = MedianAction(vectorKey="brightStarsRA")
631 self.process.calculateActions.AA1_sigmaMad_RA = SigmaMadAction(vectorKey="brightStarsRA")
633 self.process.calculateActions.AA1_Dec = MedianAction(vectorKey="brightStarsDec")
634 self.process.calculateActions.AA1_sigmaMad_Dec = SigmaMadAction(vectorKey="brightStarsDec")
636 self.process.calculateActions.AA1_tot = MedianAction(vectorKey="brightStarsTot")
637 self.process.calculateActions.AA1_sigmaMad_tot = SigmaMadAction(vectorKey="brightStarsTot")
639 self.produce.metric.units = {
640 "AA1_RA": "mas",
641 "AA1_sigmaMad_RA": "mas",
642 "AA1_Dec": "mas",
643 "AA1_sigmaMad_Dec": "mas",
644 "AA1_tot": "mas",
645 "AA1_sigmaMad_tot": "mas",
646 }
649class TargetRefCatDeltaColorMetrics(AnalysisTool):
650 """Calculate the AB1 and ABF1 metrics from the difference between the
651 target and reference catalog coordinates.
652 """
654 AB2 = Field[float](
655 doc=(
656 "Separation in milliarcseconds used to calculate the ABF1 metric. ABF1 is the percentage of"
657 " sources whose distance from the reference is greater than AB2 mas from the mean."
658 ),
659 default=20,
660 )
662 def setDefaults(self):
663 super().setDefaults()
665 self.prep.selectors.flagSelector = VisitPlotFlagSelector()
666 self.prep.selectors.starSelector = StarSelector()
667 self.prep.selectors.starSelector.vectorKey = "extendedness"
669 # Calculate difference in RA
670 self.process.buildActions.astromDiffRA = ConvertUnits(
671 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
672 )
673 self.process.buildActions.astromDiffRA.buildAction.actionA = RAcosDec(
674 raKey="coord_ra", decKey="coord_dec"
675 )
676 self.process.buildActions.astromDiffRA.buildAction.actionB = RAcosDec(raKey="r_ra", decKey="r_dec")
677 # Calculate difference in Dec
678 self.process.buildActions.astromDiffDec = ConvertUnits(
679 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond"
680 )
681 self.process.buildActions.astromDiffDec.buildAction.actionA = LoadVector(vectorKey="dec")
682 self.process.buildActions.astromDiffDec.buildAction.actionB = LoadVector(vectorKey="r_dec")
684 # Calculate total difference (using astropy)
685 self.process.buildActions.astromDiffTot = AngularSeparation(
686 raKey_A="coord_ra",
687 decKey_A="coord_dec",
688 raKey_B="r_ra",
689 decKey_B="r_dec",
690 )
692 self.process.buildActions.mags = ConvertFluxToMag()
693 self.process.buildActions.mags.vectorKey = "psfFlux"
695 # Filter down to only objects with mag 17-21.5
696 self.process.filterActions.brightStarsRA = DownselectVector(vectorKey="astromDiffRA")
697 self.process.filterActions.brightStarsRA.selector = RangeSelector(
698 vectorKey="mags", minimum=17, maximum=21.5
699 )
701 self.process.filterActions.brightStarsDec = DownselectVector(vectorKey="astromDiffDec")
702 self.process.filterActions.brightStarsDec.selector = RangeSelector(
703 vectorKey="mags", minimum=17, maximum=21.5
704 )
706 self.process.filterActions.brightStarsTot = DownselectVector(vectorKey="astromDiffTot")
707 self.process.filterActions.brightStarsTot.selector = RangeSelector(
708 vectorKey="mags", minimum=17, maximum=21.5
709 )
711 # Calculate RMS annd number of sources
712 self.process.calculateActions.AB1_RA = RmsAction(vectorKey="brightStarsRA")
713 self.process.calculateActions.AB1_Dec = RmsAction(vectorKey="brightStarsDec")
714 self.process.calculateActions.AB1_tot = RmsAction(vectorKey="brightStarsTot")
715 self.process.calculateActions.nSources = CountAction(vectorKey="brightStarsTot")
717 self.produce.metric.units = {
718 "AB1_RA": "mas",
719 "ABF1_RA": "percent",
720 "AB1_Dec": "mas",
721 "ABF1_Dec": "percent",
722 "AB1_tot": "mas",
723 "ABF1_tot": "percent",
724 }
726 self.produce.plot = HistPlot()
728 self.produce.plot.panels["panel_sep"] = HistPanel()
729 self.produce.plot.panels["panel_sep"].hists = dict(
730 brightStarsRA="Separations in RA",
731 brightStarsDec="Separations in Dec",
732 brightStarsTot="Total separations",
733 )
734 self.produce.plot.panels["panel_sep"].label = "Separation Distances (marcsec)"
736 self.produce.plot.panels["panel_sep"].statsPanel = HistStatsPanel()
737 self.produce.plot.panels["panel_sep"].statsPanel.statsLabels = ["N", "AB1", "ABF1 %"]
738 self.produce.plot.panels["panel_sep"].statsPanel.stat1 = ["nSources", "nSources", "nSources"]
739 self.produce.plot.panels["panel_sep"].statsPanel.stat2 = ["AB1_RA", "AB1_Dec", "AB1_tot"]
740 self.produce.plot.panels["panel_sep"].statsPanel.stat3 = ["ABF1_RA", "ABF1_Dec", "ABF1_tot"]
742 def finalize(self):
743 super().finalize()
745 # Calculate the percentage of outliers above the AB2 threshold
746 self.process.calculateActions.ABF1_RA = FracThreshold(
747 vectorKey="brightStarsRA",
748 op="gt",
749 threshold=self.AB2,
750 relative_to_median=True,
751 percent=True,
752 use_absolute_value=True,
753 )
754 self.process.calculateActions.ABF1_Dec = FracThreshold(
755 vectorKey="brightStarsDec",
756 threshold=self.AB2,
757 op="gt",
758 relative_to_median=True,
759 percent=True,
760 use_absolute_value=True,
761 )
762 self.process.calculateActions.ABF1_tot = FracThreshold(
763 vectorKey="brightStarsTot", threshold=self.AB2, op="gt", percent=True
764 )