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

353 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-24 08:53 +0000

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

46) 

47 

48from lsst.pex.config import Field 

49 

50from ..actions.plot import HistPanel, HistPlot, HistStatsPanel 

51from ..actions.plot.scatterplotWithTwoHists import ScatterPlotStatsAction, ScatterPlotWithTwoHists 

52from ..actions.plot.skyPlot import SkyPlot 

53from ..actions.scalar.scalarActions import ( 

54 CountAction, 

55 FracThreshold, 

56 MeanAction, 

57 MedianAction, 

58 MedianGradientAction, 

59 RmsAction, 

60 SigmaMadAction, 

61 StdevAction, 

62) 

63from ..actions.vector import ( 

64 AngularSeparation, 

65 CoaddPlotFlagSelector, 

66 ConvertFluxToMag, 

67 ConvertUnits, 

68 DownselectVector, 

69 LoadVector, 

70 MagDiff, 

71 RAcosDec, 

72 RangeSelector, 

73 SnSelector, 

74 StarSelector, 

75 SubtractVector, 

76 VisitPlotFlagSelector, 

77) 

78from ..contexts import CoaddContext, RefMatchContext, VisitContext 

79from ..interfaces import AnalysisTool 

80 

81 

82class TargetRefCatDelta(AnalysisTool): 

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

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

85 """ 

86 

87 parameterizedBand = Field[bool]( 

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

89 ) 

90 

91 def coaddContext(self) -> None: 

92 """Apply coadd options for the ref cat plots. 

93 Applies the coadd plot flag selector and sets 

94 flux types. 

95 """ 

96 self.prep.selectors.flagSelector = CoaddPlotFlagSelector() 

97 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux_target" 

98 self.prep.selectors.snSelector.threshold = 200 

99 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target" 

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

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

102 self.process.buildActions.patch = LoadVector() 

103 self.process.buildActions.patch.vectorKey = "patch_target" 

104 

105 def visitContext(self) -> None: 

106 """Apply visit options for the ref cat plots. 

107 Applies the visit plot flag selector and sets 

108 the flux types. 

109 """ 

110 self.parameterizedBand = False 

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

112 self.prep.selectors.starSelector.vectorKey = "extendedness_target" 

113 self.prep.selectors.snSelector.fluxType = "psfFlux_target" 

114 self.prep.selectors.snSelector.threshold = 50 

115 

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

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

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

119 

120 def setDefaults(self): 

121 super().setDefaults() 

122 

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

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

125 

126 

127class TargetRefCatDeltaScatterAstrom(TargetRefCatDelta): 

128 """Plot the difference in milliseconds between a target catalog and a 

129 reference catalog for the coordinate set in `setDefaults`. Plot it on 

130 a scatter plot. 

131 """ 

132 

133 def setDefaults(self): 

134 super().setDefaults() 

135 

136 self.process.buildActions.yStars = ConvertUnits( 

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

138 ) 

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

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

141 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars") 

142 self.process.calculateActions.stars.lowSNSelector.fluxType = "{band}_psfFlux_target" 

143 self.process.calculateActions.stars.highSNSelector.fluxType = "{band}_psfFlux_target" 

144 self.process.calculateActions.stars.fluxType = "{band}_psfFlux_target" 

145 

146 self.produce = ScatterPlotWithTwoHists() 

147 self.produce.plotTypes = ["stars"] 

148 self.produce.magLabel = "PSF Magnitude (mag$_{{AB}}$)" 

149 self.produce.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)" 

150 self.applyContext(CoaddContext) 

151 self.applyContext(RefMatchContext) 

152 

153 

154class TargetRefCatDeltaScatterAstromVisit(TargetRefCatDelta): 

155 """Plot the difference in milliseconds between a target catalog and a 

156 reference catalog for the coordinate set in `setDefaults`. Plot it on 

157 a scatter plot. 

158 """ 

159 

160 def setDefaults(self): 

161 super().setDefaults() 

162 

163 self.process.buildActions.yStars = ConvertUnits( 

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

165 ) 

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

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

168 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars") 

169 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux_target" 

170 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux_target" 

171 self.process.calculateActions.stars.fluxType = "psfFlux_target" 

172 

173 self.produce = ScatterPlotWithTwoHists() 

174 self.produce.addSummaryPlot = False 

175 self.produce.plotTypes = ["stars"] 

176 self.produce.magLabel = "PSF Magnitude (mag$_{{AB}}$)" 

177 self.produce.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)" 

178 self.applyContext(VisitContext) 

179 self.applyContext(RefMatchContext) 

180 

181 

182class TargetRefCatDeltaScatterPhotom(TargetRefCatDelta): 

183 """Plot the difference in millimags between a target catalog and a 

184 reference catalog for the flux type set in `setDefaults`. 

185 """ 

186 

187 def setDefaults(self): 

188 super().setDefaults() 

189 

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

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

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

193 

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

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

196 

197 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars") 

198 self.process.calculateActions.stars.lowSNSelector.fluxType = "{band}_psfFlux_target" 

199 self.process.calculateActions.stars.highSNSelector.fluxType = "{band}_psfFlux_target" 

200 self.process.calculateActions.stars.fluxType = "{band}_psfFlux_target" 

201 

202 self.produce = ScatterPlotWithTwoHists() 

203 self.produce.plotTypes = ["stars"] 

204 self.produce.magLabel = "PSF Magnitude (mag$_{{AB}}$)" 

205 self.produce.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)" 

206 self.produce.yAxisLabel = "Output Mag - Ref Mag (mmag)" 

207 self.applyContext(CoaddContext) 

208 self.applyContext(RefMatchContext) 

209 

210 

211class TargetRefCatDeltaScatterPhotomVisit(TargetRefCatDelta): 

212 """Plot the difference in millimags between a target catalog and a 

213 reference catalog for the flux type set in `setDefaults`. 

214 """ 

215 

216 def setDefaults(self): 

217 super().setDefaults() 

218 

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

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

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

222 

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

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

225 

226 self.process.calculateActions.stars = ScatterPlotStatsAction(vectorKey="yStars") 

227 self.process.calculateActions.stars.lowSNSelector.fluxType = "psfFlux_target" 

228 self.process.calculateActions.stars.highSNSelector.fluxType = "psfFlux_target" 

229 self.process.calculateActions.stars.fluxType = "psfFlux_target" 

230 

231 self.produce = ScatterPlotWithTwoHists() 

232 self.produce.addSummaryPlot = False 

233 self.produce.plotTypes = ["stars"] 

234 self.produce.magLabel = "PSF Magnitude (mag$_{{AB}}$)" 

235 self.produce.xAxisLabel = "PSF Magnitude (mag$_{{AB}}$)" 

236 self.produce.yAxisLabel = "Output Mag - Ref Mag (mmag)" 

237 self.applyContext(VisitContext) 

238 self.applyContext(RefMatchContext) 

239 

240 

241class TargetRefCatDeltaPsfScatterPlot(TargetRefCatDeltaScatterPhotom): 

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

243 of a target catalog and a reference catalog 

244 """ 

245 

246 def setDefaults(self): 

247 super().setDefaults() 

248 

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

250 

251 

252class TargetRefCatDeltaCModelScatterPlot(TargetRefCatDeltaScatterPhotom): 

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

254 of a target catalog and a reference catalog. 

255 """ 

256 

257 def setDefaults(self): 

258 super().setDefaults() 

259 

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

261 

262 

263class TargetRefCatDeltaPsfScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit): 

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

265 of a target catalog and a reference catalog 

266 """ 

267 

268 def setDefaults(self): 

269 super().setDefaults() 

270 

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

272 

273 

274class TargetRefCatDeltaAp09ScatterVisitPlot(TargetRefCatDeltaScatterPhotomVisit): 

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

276 of a target catalog and a reference catalog. 

277 """ 

278 

279 def setDefaults(self): 

280 super().setDefaults() 

281 

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

283 

284 

285class TargetRefCatDeltaRAScatterPlot(TargetRefCatDeltaScatterAstrom): 

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

287 and a reference catalog 

288 """ 

289 

290 def setDefaults(self): 

291 super().setDefaults() 

292 self.process.buildActions.yStars.buildAction.actionA = RAcosDec( 

293 raKey="coord_ra_target", decKey="coord_dec_target" 

294 ) 

295 self.process.buildActions.yStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref") 

296 

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

298 

299 

300class TargetRefCatDeltaRAScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit): 

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

302 and a reference catalog 

303 """ 

304 

305 def setDefaults(self): 

306 super().setDefaults() 

307 self.process.buildActions.yStars.buildAction.actionA = RAcosDec( 

308 raKey="coord_ra_target", decKey="coord_dec_target" 

309 ) 

310 self.process.buildActions.yStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref") 

311 

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

313 

314 

315class TargetRefCatDeltaDecScatterVisitPlot(TargetRefCatDeltaScatterAstromVisit): 

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

317 and a reference catalog 

318 """ 

319 

320 def setDefaults(self): 

321 super().setDefaults() 

322 self.process.buildActions.yStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target") 

323 self.process.buildActions.yStars.buildAction.actionB = LoadVector(vectorKey="dec_ref") 

324 

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

326 

327 

328class TargetRefCatDeltaDecScatterPlot(TargetRefCatDeltaScatterAstrom): 

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

330 and a reference catalog 

331 """ 

332 

333 def setDefaults(self): 

334 super().setDefaults() 

335 self.process.buildActions.yStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target") 

336 self.process.buildActions.yStars.buildAction.actionB = LoadVector(vectorKey="dec_ref") 

337 

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

339 

340 

341class TargetRefCatDeltaSkyPlot(TargetRefCatDelta): 

342 """Base class for plotting the RA/Dec distribution of stars, with the 

343 difference of the quantity defined in the vector key parameter between 

344 the target and reference catalog as the color. 

345 """ 

346 

347 parameterizedBand = Field[bool]( 

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

349 ) 

350 

351 def setDefaults(self): 

352 super().setDefaults() 

353 

354 self.process.buildActions.xStars = LoadVector() 

355 self.process.buildActions.xStars.vectorKey = "coord_ra_target" 

356 self.process.buildActions.yStars = LoadVector() 

357 self.process.buildActions.yStars.vectorKey = "coord_dec_target" 

358 

359 self.produce = SkyPlot() 

360 self.produce.plotTypes = ["stars"] 

361 self.produce.xAxisLabel = "R.A. (deg)" 

362 self.produce.yAxisLabel = "Dec. (deg)" 

363 self.produce.plotOutlines = False 

364 

365 

366class TargetRefCatDeltaSkyPlotAstrom(TargetRefCatDeltaSkyPlot): 

367 """Base class for plotting the RA/Dec distribution of stars, with the 

368 difference between the RA or Dec of the target and reference catalog as 

369 the color. 

370 """ 

371 

372 def setDefaults(self): 

373 super().setDefaults() 

374 

375 self.process.buildActions.zStars = ConvertUnits( 

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

377 ) 

378 

379 self.applyContext(CoaddContext) 

380 self.applyContext(RefMatchContext) 

381 

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

383 

384 

385class TargetRefCatDeltaSkyPlotAstromVisit(TargetRefCatDeltaSkyPlot): 

386 """Base class for plotting the RA/Dec distribution of stars at 

387 the visit level, with the difference between the RA or Dec of 

388 the target and reference catalog as the color. 

389 """ 

390 

391 def setDefaults(self): 

392 super().setDefaults() 

393 

394 self.process.buildActions.zStars = ConvertUnits( 

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

396 ) 

397 

398 self.applyContext(VisitContext) 

399 self.applyContext(RefMatchContext) 

400 

401 

402class TargetRefCatDeltaSkyPlotPhotomVisit(TargetRefCatDeltaSkyPlot): 

403 """Base class for plotting the RA/Dec distribution of stars, with the 

404 difference between the photometry of the target and reference catalog as 

405 the color. 

406 """ 

407 

408 def setDefaults(self): 

409 super().setDefaults() 

410 

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

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

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

414 

415 self.produce.plotName = "photomDiffSky" 

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

417 self.applyContext(VisitContext) 

418 self.applyContext(RefMatchContext) 

419 

420 

421class TargetRefCatDeltaSkyPlotPhotom(TargetRefCatDeltaSkyPlot): 

422 """Base class for plotting the RA/Dec distribution of stars, with the 

423 difference between the photometry of the target and reference catalog as 

424 the color. 

425 """ 

426 

427 def setDefaults(self): 

428 super().setDefaults() 

429 

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

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

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

433 

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

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

436 self.applyContext(CoaddContext) 

437 self.applyContext(RefMatchContext) 

438 

439 

440class TargetRefCatDeltaPsfSkyPlot(TargetRefCatDeltaSkyPlotPhotom): 

441 """Plot the RA/Dec distribution of stars, with the 

442 difference between the PSF photometry of the target and reference 

443 catalog as the color. 

444 """ 

445 

446 def setDefaults(self): 

447 super().setDefaults() 

448 

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

450 

451 

452class TargetRefCatDeltaPsfSkyVisitPlot(TargetRefCatDeltaSkyPlotPhotomVisit): 

453 """Plot the RA/Dec distribution of stars, with the 

454 difference between the PSF photometry of the target and reference 

455 catalog as the color. 

456 """ 

457 

458 def setDefaults(self): 

459 super().setDefaults() 

460 

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

462 

463 

464class TargetRefCatDeltaAp09SkyVisitPlot(TargetRefCatDeltaSkyPlotPhotomVisit): 

465 """Plot the RA/Dec distribution of stars, with the 

466 difference between the Ap09 photometry of the target and reference 

467 catalog as the color. 

468 """ 

469 

470 def setDefaults(self): 

471 super().setDefaults() 

472 

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

474 

475 

476class TargetRefCatDeltaCModelSkyPlot(TargetRefCatDeltaSkyPlotPhotom): 

477 """Plot the RA/Dec distribution of stars, with the 

478 difference between the CModel photometry of the target and reference 

479 catalog as the color. 

480 """ 

481 

482 def setDefaults(self): 

483 super().setDefaults() 

484 

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

486 

487 

488class TargetRefCatDeltaRASkyPlot(TargetRefCatDeltaSkyPlotAstrom): 

489 """Plot the RA/Dec distribution of stars, with the 

490 difference between the RA of the target and reference catalog as 

491 the color. 

492 """ 

493 

494 def setDefaults(self): 

495 super().setDefaults() 

496 self.process.buildActions.zStars.buildAction.actionA = RAcosDec( 

497 raKey="coord_ra_target", decKey="coord_dec_target" 

498 ) 

499 self.process.buildActions.zStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref") 

500 

501 self.produce.plotName = "astromDiffSky_RA" 

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

503 

504 

505class TargetRefCatDeltaRASkyVisitPlot(TargetRefCatDeltaSkyPlotAstromVisit): 

506 """Plot the RA/Dec distribution of stars, with the 

507 difference between the RA of the target and reference catalog as 

508 the color. 

509 """ 

510 

511 def setDefaults(self): 

512 super().setDefaults() 

513 self.process.buildActions.zStars.buildAction.actionA = RAcosDec( 

514 raKey="coord_ra_target", decKey="coord_dec_target" 

515 ) 

516 self.process.buildActions.zStars.buildAction.actionB = RAcosDec(raKey="ra_ref", decKey="dec_ref") 

517 self.produce.plotName = "astromDiffSky_RA" 

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

519 

520 

521class TargetRefCatDeltaDecSkyVisitPlot(TargetRefCatDeltaSkyPlotAstromVisit): 

522 """Plot the RA/Dec distribution of stars, with the 

523 difference between the RA of the target and reference catalog as 

524 the color. 

525 """ 

526 

527 def setDefaults(self): 

528 super().setDefaults() 

529 self.process.buildActions.zStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target") 

530 self.process.buildActions.zStars.buildAction.actionB = LoadVector(vectorKey="dec_ref") 

531 

532 self.produce.plotName = "astromDiffSky_Dec" 

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

534 

535 

536class TargetRefCatDeltaDecSkyPlot(TargetRefCatDeltaSkyPlotAstrom): 

537 """Plot the RA/Dec distribution of stars, with the 

538 difference between the Dec of the target and reference catalog as 

539 the color. 

540 """ 

541 

542 def setDefaults(self): 

543 super().setDefaults() 

544 self.process.buildActions.zStars.buildAction.actionA = LoadVector(vectorKey="coord_dec_target") 

545 self.process.buildActions.zStars.buildAction.actionB = LoadVector(vectorKey="dec_ref") 

546 

547 self.produce.plotName = "astromDiffSky_Dec" 

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

549 

550 

551class TargetRefCatDeltaMetrics(AnalysisTool): 

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

553 the target and reference catalog coordinates. 

554 """ 

555 

556 parameterizedBand = Field[bool]( 

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

558 ) 

559 

560 def coaddContext(self) -> None: 

561 """Apply coadd options for the metrics. Applies the coadd plot flag 

562 selector and sets flux types. 

563 """ 

564 self.prep.selectors.flagSelector = CoaddPlotFlagSelector() 

565 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target" 

566 

567 self.applyContext(RefMatchContext) 

568 

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

570 

571 self.produce.metric.newNames = { 

572 "AA1_RA": "{band}_AA1_RA_coadd", 

573 "AA1_sigmaMad_RA": "{band}_AA1_sigmaMad_RA_coadd", 

574 "AA1_Dec": "{band}_AA1_Dec_coadd", 

575 "AA1_sigmaMad_Dec": "{band}_AA1_sigmaMad_Dec_coadd", 

576 "AA1_tot": "{band}_AA1_tot_coadd", 

577 "AA1_sigmaMad_tot": "{band}_AA1_sigmaMad_tot_coadd", 

578 } 

579 

580 def visitContext(self) -> None: 

581 """Apply visit options for the metrics. Applies the visit plot flag 

582 selector and sets flux types. 

583 """ 

584 self.parameterizedBand = False 

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

586 self.prep.selectors.starSelector.vectorKey = "extendedness_target" 

587 

588 self.applyContext(RefMatchContext) 

589 

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

591 

592 def setDefaults(self): 

593 super().setDefaults() 

594 

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

596 

597 # Calculate difference in RA 

598 self.process.buildActions.astromDiffRA = ConvertUnits( 

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

600 ) 

601 self.process.buildActions.astromDiffRA.buildAction.actionA = RAcosDec( 

602 raKey="coord_ra_target", decKey="dec_ref" 

603 ) 

604 self.process.buildActions.astromDiffRA.buildAction.actionB = RAcosDec( 

605 raKey="ra_ref", decKey="dec_ref" 

606 ) 

607 # Calculate difference in Dec 

608 self.process.buildActions.astromDiffDec = ConvertUnits( 

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

610 ) 

611 self.process.buildActions.astromDiffDec.buildAction.actionA = LoadVector(vectorKey="coord_dec_target") 

612 self.process.buildActions.astromDiffDec.buildAction.actionB = LoadVector(vectorKey="dec_ref") 

613 # Calculate total difference (using astropy) 

614 self.process.buildActions.astromDiffTot = AngularSeparation( 

615 raKey_A="coord_ra_target", 

616 decKey_A="coord_dec_target", 

617 raKey_B="ra_ref", 

618 decKey_B="dec_ref", 

619 ) 

620 

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

622 

623 # Filter down to only objects with mag 17-21.5 

624 self.process.filterActions.brightStarsRA = DownselectVector(vectorKey="astromDiffRA") 

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

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

627 ) 

628 

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

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

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

632 ) 

633 

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

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

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

637 ) 

638 

639 # Calculate median and sigmaMad 

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

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

642 

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

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

645 

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

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

648 

649 self.produce.metric.units = { 

650 "AA1_RA": "mas", 

651 "AA1_sigmaMad_RA": "mas", 

652 "AA1_Dec": "mas", 

653 "AA1_sigmaMad_Dec": "mas", 

654 "AA1_tot": "mas", 

655 "AA1_sigmaMad_tot": "mas", 

656 } 

657 

658 

659class TargetRefCatDeltaColorMetrics(AnalysisTool): 

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

661 target and reference catalog coordinates. 

662 """ 

663 

664 parameterizedBand: bool = False 

665 

666 AB2 = Field[float]( 

667 doc=( 

668 "Separation in milliarcseconds used to calculate the ABF1 metric. ABF1 is the percentage of" 

669 " sources whose distance from the reference is greater than AB2 mas from the mean." 

670 ), 

671 default=20, 

672 ) 

673 

674 def setDefaults(self): 

675 super().setDefaults() 

676 

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

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

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

680 

681 # Calculate difference in RA 

682 self.process.buildActions.astromDiffRA = ConvertUnits( 

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

684 ) 

685 self.process.buildActions.astromDiffRA.buildAction.actionA = RAcosDec( 

686 raKey="coord_ra", decKey="coord_dec" 

687 ) 

688 self.process.buildActions.astromDiffRA.buildAction.actionB = RAcosDec(raKey="r_ra", decKey="r_dec") 

689 # Calculate difference in Dec 

690 self.process.buildActions.astromDiffDec = ConvertUnits( 

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

692 ) 

693 self.process.buildActions.astromDiffDec.buildAction.actionA = LoadVector(vectorKey="dec") 

694 self.process.buildActions.astromDiffDec.buildAction.actionB = LoadVector(vectorKey="r_dec") 

695 

696 # Calculate total difference (using astropy) 

697 self.process.buildActions.astromDiffTot = AngularSeparation( 

698 raKey_A="coord_ra", 

699 decKey_A="coord_dec", 

700 raKey_B="r_ra", 

701 decKey_B="r_dec", 

702 ) 

703 

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

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

706 

707 # Filter down to only objects with mag 17-21.5 

708 self.process.filterActions.brightStarsRA = DownselectVector(vectorKey="astromDiffRA") 

709 self.process.filterActions.brightStarsRA.selector = RangeSelector( 

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

711 ) 

712 

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

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

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

716 ) 

717 

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

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

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

721 ) 

722 

723 # Calculate RMS annd number of sources 

724 self.process.calculateActions.AB1_RA = RmsAction(vectorKey="brightStarsRA") 

725 self.process.calculateActions.AB1_Dec = RmsAction(vectorKey="brightStarsDec") 

726 self.process.calculateActions.AB1_tot = RmsAction(vectorKey="brightStarsTot") 

727 self.process.calculateActions.nSources = CountAction(vectorKey="brightStarsTot") 

728 

729 self.produce.metric.units = { 

730 "AB1_RA": "mas", 

731 "ABF1_RA": "percent", 

732 "AB1_Dec": "mas", 

733 "ABF1_Dec": "percent", 

734 "AB1_tot": "mas", 

735 "ABF1_tot": "percent", 

736 } 

737 

738 self.produce.plot = HistPlot() 

739 

740 self.produce.plot.panels["panel_sep"] = HistPanel() 

741 self.produce.plot.panels["panel_sep"].hists = dict( 

742 brightStarsRA="Separations in RA", 

743 brightStarsDec="Separations in Dec", 

744 brightStarsTot="Total separations", 

745 ) 

746 self.produce.plot.panels["panel_sep"].label = "Separation Distances (mas)" 

747 

748 self.produce.plot.panels["panel_sep"].statsPanel = HistStatsPanel() 

749 self.produce.plot.panels["panel_sep"].statsPanel.statsLabels = ["N", "AB1", "ABF1 %"] 

750 self.produce.plot.panels["panel_sep"].statsPanel.stat1 = ["nSources", "nSources", "nSources"] 

751 self.produce.plot.panels["panel_sep"].statsPanel.stat2 = ["AB1_RA", "AB1_Dec", "AB1_tot"] 

752 self.produce.plot.panels["panel_sep"].statsPanel.stat3 = ["ABF1_RA", "ABF1_Dec", "ABF1_tot"] 

753 

754 def finalize(self): 

755 super().finalize() 

756 

757 # Calculate the percentage of outliers above the AB2 threshold 

758 self.process.calculateActions.ABF1_RA = FracThreshold( 

759 vectorKey="brightStarsRA", 

760 op="gt", 

761 threshold=self.AB2, 

762 relative_to_median=True, 

763 percent=True, 

764 use_absolute_value=True, 

765 ) 

766 self.process.calculateActions.ABF1_Dec = FracThreshold( 

767 vectorKey="brightStarsDec", 

768 threshold=self.AB2, 

769 op="gt", 

770 relative_to_median=True, 

771 percent=True, 

772 use_absolute_value=True, 

773 ) 

774 self.process.calculateActions.ABF1_tot = FracThreshold( 

775 vectorKey="brightStarsTot", threshold=self.AB2, op="gt", percent=True 

776 ) 

777 

778 

779class TargetRefCatDeltaPhotomMetrics(TargetRefCatDeltaMetrics): 

780 """Calculate statistics from the differences between 

781 the target and reference catalog magnitudes. 

782 """ 

783 

784 parameterizedBand = Field[bool]( 

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

786 ) 

787 

788 def coaddContext(self) -> None: 

789 """Apply coadd options for the metrics. Applies the coadd plot flag 

790 selector and sets flux types. 

791 """ 

792 self.prep.selectors.flagSelector = CoaddPlotFlagSelector() 

793 self.prep.selectors.starSelector.vectorKey = "{band}_extendedness_target" 

794 self.prep.selectors.snSelector.fluxType = "{band}_psfFlux_target" 

795 

796 # Calculate magnitude difference 

797 self.process.buildActions.srcRefMagdiffStars.col1 = "{band}_psfFlux_target" 

798 self.process.buildActions.srcRefMagdiffStars.col2 = "{band}_mag_ref" 

799 self.process.buildActions.psfMag = ConvertFluxToMag( 

800 vectorKey="{band}_psfFlux_target", returnMillimags=True 

801 ) 

802 

803 self.applyContext(RefMatchContext) 

804 

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

806 

807 self.produce.metric.newNames = { 

808 "ref_photom_offset": "{band}_ref_photom_offset_coadd", 

809 "ref_photom_offset_mean": "{band}_ref_photom_offset_mean_coadd", 

810 "ref_photom_offset_stdev": "{band}_ref_photom_offset_stdev_coadd", 

811 "ref_photom_offset_sigmaMad": "{band}_ref_photom_offset_sigmaMad_coadd", 

812 "ref_photom_offset_rms": "{band}_ref_photom_offset_rms_coadd", 

813 "ref_photom_offset_nstars": "{band}_ref_photom_offset_nstars_coadd", 

814 "ref_photom_offset_gradient": "{band}_ref_photom_offset_gradient_coadd", 

815 } 

816 

817 def visitContext(self) -> None: 

818 """Apply visit options for the metrics. Applies the visit plot flag 

819 selector and sets flux types. 

820 """ 

821 self.parameterizedBand = False 

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

823 self.prep.selectors.starSelector.vectorKey = "extendedness_target" 

824 

825 self.applyContext(RefMatchContext) 

826 

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

828 

829 def setDefaults(self): 

830 super().setDefaults() 

831 

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

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

834 self.prep.selectors.snSelector.fluxType = "psfFlux_target" 

835 self.prep.selectors.snSelector.threshold = 200 

836 

837 # Calculate magnitude difference 

838 self.process.buildActions.srcRefMagdiffStars = MagDiff() 

839 self.process.buildActions.srcRefMagdiffStars.col1 = "psfFlux_target" 

840 self.process.buildActions.srcRefMagdiffStars.col2 = "mag_ref" 

841 self.process.buildActions.srcRefMagdiffStars.fluxUnits2 = "mag(AB)" 

842 

843 self.process.buildActions.psfMag = ConvertFluxToMag(vectorKey="psfFlux_target", returnMillimags=True) 

844 

845 # Calculate median, std, sigmaMad, RMS, and number counts: 

846 self.process.calculateActions.ref_photom_offset = MedianAction(vectorKey="srcRefMagdiffStars") 

847 self.process.calculateActions.ref_photom_offset_mean = MeanAction(vectorKey="srcRefMagdiffStars") 

848 self.process.calculateActions.ref_photom_offset_stdev = StdevAction(vectorKey="srcRefMagdiffStars") 

849 self.process.calculateActions.ref_photom_offset_sigmaMad = SigmaMadAction( 

850 vectorKey="srcRefMagdiffStars" 

851 ) 

852 self.process.calculateActions.ref_photom_offset_rms = RmsAction(vectorKey="srcRefMagdiffStars") 

853 self.process.calculateActions.ref_photom_offset_nstars = CountAction(vectorKey="srcRefMagdiffStars") 

854 self.process.calculateActions.ref_photom_offset_gradient = MedianGradientAction( 

855 xsVectorKey="psfMag", ysVectorKey="srcRefMagdiffStars" 

856 ) 

857 

858 self.produce.metric.units = { 

859 "ref_photom_offset": "mmag", 

860 "ref_photom_offset_mean": "mmag", 

861 "ref_photom_offset_stdev": "mmag", 

862 "ref_photom_offset_sigmaMad": "mmag", 

863 "ref_photom_offset_rms": "mmag", 

864 "ref_photom_offset_nstars": "ct", 

865 "ref_photom_offset_gradient": "", 

866 }