Coverage for tests/test_calibQuantityProfile.py: 93%

42 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-20 10:14 +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/>. 

21 

22"""Tests for the calibQuantityProfile tools on cp_verify results tables. 

23 

24These catch rows with no panel key (the per-detector and per-exposure rows, 

25masked in the amplifier column) breaking the repack, and with it 

26analyzeFlatDetCore's flatTestsByDate plot. 

27""" 

28 

29import unittest 

30 

31import matplotlib 

32import matplotlib.pyplot as plt 

33from astropy.table import Table, vstack 

34from matplotlib.figure import Figure 

35 

36import lsst.utils.tests 

37from lsst.analysis.tools.atools.calibQuantityProfile import CalibAmpScatterTool, SingleValueRepacker 

38 

39matplotlib.use("Agg") 

40 

41AMP_NAMES = [f"C{i}{j}" for i in (0, 1) for j in range(8)] 

42DETECTORS = (90, 91) 

43MJD = 61224.4 

44 

45 

46def makeResultsTable() -> Table: 

47 """Make a table shaped like cp_verify's ``verifyFlatResults``. 

48 

49 Returns 

50 ------- 

51 table : `astropy.table.Table` 

52 One row per amplifier per detector, plus a per-detector row for each 

53 detector and a per-exposure row. Those last have no amplifier, so are 

54 masked in the ``amplifier`` column. 

55 """ 

56 nAmpRows = len(DETECTORS) * len(AMP_NAMES) 

57 ampRows = Table( 

58 { 

59 "detector": [detector for detector in DETECTORS for _ in AMP_NAMES], 

60 "amplifier": AMP_NAMES * len(DETECTORS), 

61 "mjd": [MJD] * nAmpRows, 

62 "FLAT_VERIFY_NOISE": [True] * nAmpRows, 

63 } 

64 ) 

65 detectorRows = Table( 

66 {"detector": list(DETECTORS), "mjd": [MJD] * len(DETECTORS), "FLAT_DET_SCATTER": [0.01, 0.01]} 

67 ) 

68 exposureRow = Table({"detector": [DETECTORS[0]], "flat_SCATTER": [0.001]}) 

69 return vstack([ampRows, detectorRows, exposureRow]) 

70 

71 

72class SingleValueRepackerTestCase(lsst.utils.tests.TestCase): 

73 def testSkipsRowsWithoutPanelKey(self) -> None: 

74 # The rows with no amplifier used to raise 

75 # "TypeError: unhashable type: 'MaskedConstant'", so 

76 # analyzeFlatDetCore never wrote its plot. 

77 table = makeResultsTable() 

78 # Without masked rows in the fixture this test pins nothing. 

79 self.assertTrue(table["amplifier"].mask.any()) 

80 repacker = SingleValueRepacker(panelKey="amplifier", dataKey="mjd", quantityKey="FLAT_VERIFY_NOISE") 

81 repacked = repacker(table) 

82 self.assertEqual(set(repacked), {f"{amp}{suffix}" for amp in AMP_NAMES for suffix in ("", "_x")}) 

83 for amp in AMP_NAMES: 

84 self.assertEqual(repacked[f"{amp}_x"], [MJD] * len(DETECTORS)) 

85 self.assertEqual(repacked[amp], [True] * len(DETECTORS)) 

86 

87 

88class CalibAmpScatterToolTestCase(lsst.utils.tests.TestCase): 

89 def testPlotsResultsTable(self) -> None: 

90 # The whole tool, configured as analyzeFlatDetCore's flatTestsByDate 

91 # in cpCore.yaml: a masked amplifier anywhere along the way must not 

92 # stop the plot being made. 

93 tool = CalibAmpScatterTool() 

94 tool.prep.quantityKey = "FLAT_VERIFY_NOISE" 

95 tool.finalize() 

96 results = tool(makeResultsTable()) 

97 self.assertIsInstance(results["GridPlot"], Figure) 

98 plt.close(results["GridPlot"]) 

99 

100 

101class MemoryTester(lsst.utils.tests.MemoryTestCase): 

102 pass 

103 

104 

105def setup_module(module): 

106 lsst.utils.tests.init() 

107 

108 

109if __name__ == "__main__": 109 ↛ 110line 109 didn't jump to line 110 because the condition on line 109 was never true

110 lsst.utils.tests.init() 

111 unittest.main()