Coverage for tests / test_assemble.py: 31%

82 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-01 08:49 +0000

1# This file is part of obs_lsst. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (http://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 <http://www.gnu.org/licenses/>. 

21 

22import numpy 

23import os 

24import sys 

25import unittest 

26 

27import lsst.utils.tests 

28from lsst.daf.butler import Butler 

29from lsst.afw.cameraGeom import Detector 

30from lsst.afw.image import ImageFitsReader 

31import lsst.obs.base.yamlCamera as yamlCamera 

32from lsst.ip.isr import AssembleCcdTask 

33from lsst.resources import ResourcePath 

34 

35from lsst.obs.lsst.utils import readRawFile 

36 

37TESTDIR = os.path.dirname(__file__) 

38LATISS_DATA_ROOT = os.path.join(TESTDIR, 'data', 'input', 'latiss') 

39BOT_DATA_ROOT = os.path.join(TESTDIR, 'data', 'input', 'bot') 

40E2V_DATA_ID = {'raft': 'R22', 'name_in_raft': 'S11', 'exposure': 3019103101985, 'instrument': 'LSSTCam'} 

41ITL_DATA_ID = {'raft': 'R02', 'name_in_raft': 'S02', 'exposure': 3019110102212, 'instrument': 'LSSTCam'} 

42TESTDATA_ROOT = os.path.join(TESTDIR, "data") 

43 

44 

45class RawAssemblyTestCase(lsst.utils.tests.TestCase): 

46 """Test assembly of each of data from each of the two 

47 manufacturers. Data come from BOT spot data runs. 

48 """ 

49 

50 def setUp(self): 

51 # E2V and ITL detecotrs and expected assembled images 

52 self.e2v = {'detector': Detector.readFits(os.path.join(TESTDATA_ROOT, 'e2v_detector.fits')), 

53 'expected': ImageFitsReader(os.path.join(TESTDATA_ROOT, 

54 'e2v_expected_assembled.fits.gz'))} 

55 self.itl = {'detector': Detector.readFits(os.path.join(TESTDATA_ROOT, 'itl_detector.fits')), 

56 'expected': ImageFitsReader(os.path.join(TESTDATA_ROOT, 

57 'itl_expected_assembled.fits.gz'))} 

58 self.roots = [BOT_DATA_ROOT, BOT_DATA_ROOT] 

59 self.ids = [E2V_DATA_ID, ITL_DATA_ID] 

60 self.expecteds = [self.e2v, self.itl] 

61 

62 def assertAmpRawBBoxesEqual(self, amp1, amp2): 

63 """Check that Raw bounding boxes match between amps. 

64 

65 Parameters 

66 ---------- 

67 amp1 : `~lsst.afw.cameraGeom.Amplifier` 

68 First amplifier. 

69 amp2 : `~lsst.afw.cameraGeom.Amplifier` 

70 Second amplifier. 

71 """ 

72 self.assertEqual(amp1.getRawBBox(), amp2.getRawBBox()) 

73 self.assertEqual(amp1.getRawHorizontalOverscanBBox(), amp2.getRawHorizontalOverscanBBox()) 

74 self.assertEqual(amp1.getRawVerticalOverscanBBox(), amp2.getRawVerticalOverscanBBox()) 

75 

76 def assertAmpRawBBoxesFlippablyEqual(self, amp1, amp2): 

77 """Check that amp1 can be self-consistently transformed to match amp2. 

78 

79 This method compares amplifier bounding boxes by confirming 

80 that they represent the same segment of the detector image. 

81 If the offsets or amplifier flips differ between the 

82 amplifiers, this method will pass even if the raw bounding 

83 boxes returned by the amplifier accessors are not equal. 

84 

85 Parameters 

86 ---------- 

87 amp1 : `~lsst.afw.cameraGeom.Amplifier` 

88 Amplifier to transform. 

89 amp2 : `~lsst.afw.cameraGeom.Amplifier` 

90 Reference amplifier. 

91 

92 """ 

93 xFlip = amp1.getRawFlipX() ^ amp2.getRawFlipX() 

94 yFlip = amp1.getRawFlipY() ^ amp2.getRawFlipY() 

95 XYOffset = amp1.getRawXYOffset() - amp2.getRawXYOffset() 

96 

97 testRawBox = amp1.getRawBBox() 

98 testHOSBox = amp1.getRawHorizontalOverscanBBox() 

99 testVOSBox = amp1.getRawVerticalOverscanBBox() 

100 

101 if xFlip: 

102 size = amp1.getRawBBox().getWidth() 

103 testRawBox.flipLR(size) 

104 testHOSBox.flipLR(size) 

105 testVOSBox.flipLR(size) 

106 if yFlip: 

107 size = amp1.getRawBBox().getHeight() 

108 testRawBox.flipTB(size) 

109 testHOSBox.flipTB(size) 

110 testVOSBox.flipTB(size) 

111 

112 testRawBox.shift(XYOffset) 

113 testHOSBox.shift(XYOffset) 

114 testVOSBox.shift(XYOffset) 

115 

116 self.assertEqual(testRawBox, amp2.getRawBBox()) 

117 self.assertEqual(testHOSBox, amp2.getRawHorizontalOverscanBBox()) 

118 self.assertEqual(testVOSBox, amp2.getRawVerticalOverscanBBox()) 

119 

120 def testDetectors(self): 

121 """Test that the detector returned by the butler is the same 

122 as the expected one. 

123 """ 

124 for root, did, expected in zip(self.roots, self.ids, self.expecteds): 

125 with Butler.from_config(root) as butler: 

126 raw = butler.get("raw", dataId=did, collections="LSSTCam/raw/all") 

127 for amp1, amp2 in zip(expected['detector'], raw.getDetector()): 

128 with self.subTest(amp=amp1.getName()): 

129 self.assertEqual(amp1.getName(), amp2.getName()) 

130 self.assertAmpRawBBoxesEqual(amp1, amp2) 

131 

132 def testAssemble(self): 

133 """Test the assembly of E2V and ITL sensors 

134 """ 

135 task = AssembleCcdTask() 

136 # exclude LATISS for this test since we don't have an expected output 

137 for root, did, expected in zip(self.roots, self.ids, self.expecteds): 

138 with Butler.from_config(root) as butler: 

139 raw = butler.get("raw", dataId=did, collections="LSSTCam/raw/all") 

140 assembled = task.assembleCcd(raw) 

141 count = numpy.sum(expected['expected'].read().array - assembled.getImage().array) 

142 self.assertEqual(count, 0) 

143 

144 

145class ReadRawFileTestCase(lsst.utils.tests.TestCase): 

146 def testReadRawLatissFile(self): 

147 fileName = os.path.join(LATISS_DATA_ROOT, "raw/2018-09-20/3018092000065-det000.fits") 

148 with ResourcePath( 

149 "resource://lsst.obs.lsst/resources/policy/latiss.yaml", forceDirectory=False 

150 ).as_local() as policy_file: 

151 camera = yamlCamera.makeCamera(policy_file.ospath) 

152 exposure = readRawFile(fileName, camera[0], dataId={"file": fileName}) 

153 self.assertIsInstance(exposure, lsst.afw.image.Exposure) 

154 md = exposure.getMetadata() 

155 self.assertIn("INSTRUME", md) 

156 

157 

158def setup_module(module): 

159 lsst.utils.tests.init() 

160 

161 

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

163 setup_module(sys.modules[__name__]) 

164 unittest.main()