Coverage for python/lsst/analysis/tools/atools/refCatMatchPlots.py: 24%

315 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-04-24 04:09 -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 

22 

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) 

46 

47from lsst.pex.config import Field 

48 

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 

70 

71 

72class TargetRefCatDelta(AnalysisTool): 

73 """Plot the difference between a target catalog and a 

74 reference catalog for the quantity set in `setDefaults`. 

75 """ 

76 

77 parameterizedBand = Field[bool]( 

78 doc="Does this AnalysisTool support band as a name parameter", default=True 

79 ) 

80 

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" 

94 

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 

105 

106 self.process.buildActions.starStatMask = SnSelector() 

107 self.process.buildActions.starStatMask.fluxType = "psfFlux_target" 

108 self.process.buildActions.starStatMask.threshold = 200 

109 

110 def setDefaults(self): 

111 super().setDefaults() 

112 

113 self.prep.selectors.snSelector = SnSelector() 

114 self.prep.selectors.starSelector = StarSelector() 

115 

116 

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 """ 

122 

123 def setDefaults(self): 

124 super().setDefaults() 

125 

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" 

135 

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) 

142 

143 

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 """ 

149 

150 def setDefaults(self): 

151 super().setDefaults() 

152 

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" 

162 

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) 

170 

171 

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 """ 

176 

177 def setDefaults(self): 

178 super().setDefaults() 

179 

180 self.process.buildActions.yStars = MagDiff() 

181 self.process.buildActions.yStars.col2 = "{band}_mag_ref" 

182 self.process.buildActions.yStars.fluxUnits2 = "mag(AB)" 

183 

184 self.process.buildActions.xStars = ConvertFluxToMag() 

185 self.process.buildActions.xStars.vectorKey = "{band}_psfFlux_target" 

186 

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" 

191 

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) 

199 

200 

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 """ 

205 

206 def setDefaults(self): 

207 super().setDefaults() 

208 

209 self.process.buildActions.yStars = MagDiff() 

210 self.process.buildActions.yStars.col2 = "mag_ref" 

211 self.process.buildActions.yStars.fluxUnits2 = "mag(AB)" 

212 

213 self.process.buildActions.xStars = ConvertFluxToMag() 

214 self.process.buildActions.xStars.vectorKey = "psfFlux_target" 

215 

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" 

220 

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) 

229 

230 

231class TargetRefCatDeltaPsfScatterPlot(TargetRefCatDeltaScatterPhotom): 

232 """Plot the difference in millimags between the PSF flux 

233 of a target catalog and a reference catalog 

234 """ 

235 

236 def setDefaults(self): 

237 super().setDefaults() 

238 

239 self.process.buildActions.yStars.col1 = "{band}_psfFlux_target" 

240 

241 

242class TargetRefCatDeltaCModelScatterPlot(TargetRefCatDeltaScatterPhotom): 

243 """Plot the difference in millimags between the CModel flux 

244 of a target catalog and a reference catalog. 

245 """ 

246 

247 def setDefaults(self): 

248 super().setDefaults() 

249 

250 self.process.buildActions.yStars.col1 = "{band}_cModelFlux_target" 

251 

252 

253class TargetRefCatDeltaPsfScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit): 

254 """Plot the difference in millimags between the PSF flux 

255 of a target catalog and a reference catalog 

256 """ 

257 

258 def setDefaults(self): 

259 super().setDefaults() 

260 

261 self.process.buildActions.yStars.col1 = "psfFlux_target" 

262 

263 

264class TargetRefCatDeltaAp09ScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit): 

265 """Plot the difference in millimags between the aper 09 flux 

266 of a target catalog and a reference catalog. 

267 """ 

268 

269 def setDefaults(self): 

270 super().setDefaults() 

271 

272 self.process.buildActions.yStars.col1 = "ap09Flux_target" 

273 

274 

275class TargetRefCatDeltaRAScatterPlot(TargetRefCatDeltaScatterAstrom): 

276 """Plot the difference in milliseconds between the RA of a target catalog 

277 and a reference catalog 

278 """ 

279 

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") 

286 

287 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)" 

288 

289 

290class TargetRefCatDeltaRAScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit): 

291 """Plot the difference in milliseconds between the RA of a target catalog 

292 and a reference catalog 

293 """ 

294 

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") 

301 

302 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)" 

303 

304 

305class TargetRefCatDeltaDecScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit): 

306 """Plot the difference in milliseconds between the Decs of a target catalog 

307 and a reference catalog 

308 """ 

309 

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") 

314 

315 self.produce.yAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)" 

316 

317 

318class TargetRefCatDeltaDecScatterPlot(TargetRefCatDeltaScatterAstrom): 

319 """Plot the difference in milliseconds between the Dec of a target catalog 

320 and a reference catalog 

321 """ 

322 

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") 

327 

328 self.produce.yAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (marcsec)" 

329 

330 

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 """ 

336 

337 parameterizedBand = Field[bool]( 

338 doc="Does this AnalysisTool support band as a name parameter", default=True 

339 ) 

340 

341 def setDefaults(self): 

342 super().setDefaults() 

343 

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" 

348 

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 

354 

355 

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 """ 

361 

362 def setDefaults(self): 

363 super().setDefaults() 

364 

365 self.process.buildActions.zStars = ConvertUnits( 

366 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond" 

367 ) 

368 

369 self.applyContext(CoaddContext) 

370 self.applyContext(RefMatchContext) 

371 

372 self.process.buildActions.starStatMask.fluxType = "{band}_psfFlux_target" 

373 

374 

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 """ 

380 

381 def setDefaults(self): 

382 super().setDefaults() 

383 

384 self.process.buildActions.zStars = ConvertUnits( 

385 buildAction=SubtractVector, inUnit="degree", outUnit="milliarcsecond" 

386 ) 

387 

388 self.applyContext(VisitContext) 

389 self.applyContext(RefMatchContext) 

390 

391 

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 """ 

397 

398 def setDefaults(self): 

399 super().setDefaults() 

400 

401 self.process.buildActions.zStars = MagDiff() 

402 self.process.buildActions.zStars.col2 = "mag_ref" 

403 self.process.buildActions.zStars.fluxUnits2 = "mag(AB)" 

404 

405 self.produce.plotName = "photomDiffSky" 

406 self.produce.zAxisLabel = "Output Mag - Ref Mag (mmag)" 

407 self.applyContext(VisitContext) 

408 self.applyContext(RefMatchContext) 

409 

410 

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 """ 

416 

417 def setDefaults(self): 

418 super().setDefaults() 

419 

420 self.process.buildActions.zStars = MagDiff() 

421 self.process.buildActions.zStars.col2 = "{band}_mag_ref" 

422 self.process.buildActions.zStars.fluxUnits2 = "mag(AB)" 

423 

424 self.produce.plotName = "photomDiffSky_{band}" 

425 self.produce.zAxisLabel = "Output Mag - Ref Mag (mmag)" 

426 self.applyContext(CoaddContext) 

427 self.applyContext(RefMatchContext) 

428 

429 

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 """ 

435 

436 def setDefaults(self): 

437 super().setDefaults() 

438 

439 self.process.buildActions.zStars.col1 = "{band}_psfFlux_target" 

440 

441 

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 """ 

447 

448 def setDefaults(self): 

449 super().setDefaults() 

450 

451 self.process.buildActions.zStars.col1 = "psfFlux_target" 

452 

453 

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 """ 

459 

460 def setDefaults(self): 

461 super().setDefaults() 

462 

463 self.process.buildActions.zStars.col1 = "ap09Flux_target" 

464 

465 

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 """ 

471 

472 def setDefaults(self): 

473 super().setDefaults() 

474 

475 self.process.buildActions.zStars.col1 = "{band}_cModelFlux_target" 

476 

477 

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 """ 

483 

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") 

490 

491 self.produce.plotName = "astromDiffSky_RA" 

492 self.produce.zAxisLabel = "RA$_{{target}}$ - RA$_{{ref}}$ (marcsec)" 

493 

494 

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 """ 

500 

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)" 

509 

510 

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 """ 

516 

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") 

521 

522 self.produce.plotName = "astromDiffSky_Dec" 

523 self.produce.zAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (marcsec)" 

524 

525 

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 """ 

531 

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") 

536 

537 self.produce.plotName = "astromDiffSky_Dec" 

538 self.produce.zAxisLabel = "Dec$_{{target}}$ - Dec$_{{ref}}$ (marcsec)" 

539 

540 

541class TargetRefCatDeltaMetrics(AnalysisTool): 

542 """Calculate the AA1 metric and the sigma MAD from the difference between 

543 the target and reference catalog coordinates. 

544 """ 

545 

546 parameterizedBand = Field[bool]( 

547 doc="Does this AnalysisTool support band as a name parameter", default=True 

548 ) 

549 

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" 

556 

557 self.applyContext(RefMatchContext) 

558 

559 self.process.buildActions.mags.vectorKey = "{band}_psfFlux_target" 

560 

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 } 

569 

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" 

577 

578 self.applyContext(RefMatchContext) 

579 

580 self.process.buildActions.mags.vectorKey = "psfFlux_target" 

581 

582 def setDefaults(self): 

583 super().setDefaults() 

584 

585 self.prep.selectors.starSelector = StarSelector() 

586 

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 ) 

610 

611 self.process.buildActions.mags = ConvertFluxToMag() 

612 

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 ) 

618 

619 self.process.filterActions.brightStarsDec = DownselectVector(vectorKey="astromDiffDec") 

620 self.process.filterActions.brightStarsDec.selector = RangeSelector( 

621 vectorKey="mags", minimum=17, maximum=21.5 

622 ) 

623 

624 self.process.filterActions.brightStarsTot = DownselectVector(vectorKey="astromDiffTot") 

625 self.process.filterActions.brightStarsTot.selector = RangeSelector( 

626 vectorKey="mags", minimum=17, maximum=21.5 

627 ) 

628 

629 # Calculate median and sigmaMad 

630 self.process.calculateActions.AA1_RA = MedianAction(vectorKey="brightStarsRA") 

631 self.process.calculateActions.AA1_sigmaMad_RA = SigmaMadAction(vectorKey="brightStarsRA") 

632 

633 self.process.calculateActions.AA1_Dec = MedianAction(vectorKey="brightStarsDec") 

634 self.process.calculateActions.AA1_sigmaMad_Dec = SigmaMadAction(vectorKey="brightStarsDec") 

635 

636 self.process.calculateActions.AA1_tot = MedianAction(vectorKey="brightStarsTot") 

637 self.process.calculateActions.AA1_sigmaMad_tot = SigmaMadAction(vectorKey="brightStarsTot") 

638 

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 } 

647 

648 

649class TargetRefCatDeltaColorMetrics(AnalysisTool): 

650 """Calculate the AB1 and ABF1 metrics from the difference between the 

651 target and reference catalog coordinates. 

652 """ 

653 

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 ) 

661 

662 def setDefaults(self): 

663 super().setDefaults() 

664 

665 self.prep.selectors.flagSelector = VisitPlotFlagSelector() 

666 self.prep.selectors.starSelector = StarSelector() 

667 self.prep.selectors.starSelector.vectorKey = "extendedness" 

668 

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") 

683 

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 ) 

691 

692 self.process.buildActions.mags = ConvertFluxToMag() 

693 self.process.buildActions.mags.vectorKey = "psfFlux" 

694 

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 ) 

700 

701 self.process.filterActions.brightStarsDec = DownselectVector(vectorKey="astromDiffDec") 

702 self.process.filterActions.brightStarsDec.selector = RangeSelector( 

703 vectorKey="mags", minimum=17, maximum=21.5 

704 ) 

705 

706 self.process.filterActions.brightStarsTot = DownselectVector(vectorKey="astromDiffTot") 

707 self.process.filterActions.brightStarsTot.selector = RangeSelector( 

708 vectorKey="mags", minimum=17, maximum=21.5 

709 ) 

710 

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") 

716 

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 } 

725 

726 self.produce.plot = HistPlot() 

727 

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)" 

735 

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"] 

741 

742 def finalize(self): 

743 super().finalize() 

744 

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 )