Coverage for tests/test_deferredCharge.py: 17%

104 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-04 03:25 -0700

1# This file is part of ip_isr. 

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/>. 

21import unittest 

22import numpy as np 

23import tempfile 

24import lsst.utils.tests 

25 

26from lsst.ip.isr import (DeferredChargeCalib, DeferredChargeTask, SerialTrap, 

27 IsrTaskConfig) 

28 

29 

30class SerialTrapTestCase(lsst.utils.tests.TestCase): 

31 def setUp(self): 

32 self.nx = 64 

33 self.ny = 128 

34 self.prescan = 8 

35 self.trapSize = 10.0 

36 self.trapDecay = 3.0 

37 self.trapPixel = self.nx + self.prescan - 3 

38 self.trapCoeffs = [5.0, 1e-3] 

39 

40 def testTrapsLinear(self): 

41 trap = SerialTrap(self.trapSize, self.trapDecay, 

42 self.trapPixel, 'linear', self.trapCoeffs) 

43 trap.initialize(self.ny, self.nx, self.prescan) 

44 

45 signals = np.full((self.ny, self.nx + self.prescan), 100.0) 

46 signals[:, 0:self.prescan] = 0.0 

47 

48 freeCharge = np.full((self.ny, self.nx + self.prescan), 100.0) 

49 freeCharge[:, 0:self.prescan] = 0.0 

50 

51 # Captured charge is of size trapSize, stored in column 

52 # trapPixel, and introduced to all rows. 

53 capturedCharge = trap.trap_charge(signals) 

54 self.assertEqual(capturedCharge.shape, (self.ny, self.nx + self.prescan)) 

55 self.assertEqual(np.sum(capturedCharge), self.trapSize * (self.ny)) 

56 

57 # Released charge is the amount released after one decay. 

58 releasedCharge = trap.release_charge() 

59 self.assertEqual(releasedCharge.shape, (self.ny, self.nx + self.prescan)) 

60 self.assertAlmostEqual(np.sum(releasedCharge), 362.839922, 4) 

61 

62 def testTrapsLogistic(self): 

63 trap = SerialTrap(self.trapSize, self.trapDecay, 

64 self.trapPixel, 'logistic', self.trapCoeffs) 

65 trap.initialize(self.ny, self.nx, self.prescan) 

66 

67 signals = np.full((self.ny, self.nx + self.prescan), 100.0) 

68 freeCharge = np.full((self.ny, self.nx + self.prescan), 100.0) 

69 signals[:, 0:self.prescan] = 0.0 

70 freeCharge[:, 0:self.prescan] = 0.0 

71 

72 # Captured charge is of size trapSize, stored in column 

73 # trapPixel, and introduced to all rows. 

74 capturedCharge = trap.trap_charge(signals) 

75 self.assertEqual(capturedCharge.shape, (self.ny, self.nx + self.prescan)) 

76 self.assertAlmostEqual(np.sum(capturedCharge), 5.23732154 * (self.ny), 4) 

77 

78 # Released charge is the amount released after one decay. 

79 releasedCharge = trap.release_charge() 

80 self.assertEqual(releasedCharge.shape, (self.ny, self.nx + self.prescan)) 

81 self.assertAlmostEqual(np.sum(releasedCharge), 190.030934, 4) 

82 

83 

84class DeferredChargeTestCase(lsst.utils.tests.TestCase): 

85 def setUp(self): 

86 self.nx = 64 

87 self.ny = 128 

88 self.prescan = 8 

89 self.overscan = 16 

90 self.trapSize = 10.0 

91 self.trapDecay = 3.0 

92 self.trapPixel = self.nx//2 + self.prescan 

93 self.trapCoeffs = [5.0, 1e-3] 

94 self.calib = DeferredChargeCalib() 

95 

96 self.calib.driftScale['amp0'] = 1.8e-4 

97 self.calib.driftScale['amp1'] = 2.8e-4 

98 self.calib.decayTime['amp0'] = 3.1 

99 self.calib.decayTime['amp1'] = 3.2 

100 self.calib.globalCti['amp0'] = 1.4e-7 

101 self.calib.globalCti['amp1'] = 1.5e-7 

102 

103 self.calib.serialTraps['amp0'] = SerialTrap(self.trapSize, self.trapDecay, 

104 self.trapPixel, 'linear', self.trapCoeffs) 

105 self.calib.serialTraps['amp0'] = SerialTrap(self.trapSize, self.trapDecay, 

106 self.trapPixel, 'logistic', self.trapCoeffs) 

107 

108 def testFullyPopulated(self): 

109 # Do IO tests. 

110 outPath = tempfile.mktemp() + '.yaml' 

111 self.calib.writeText(outPath) 

112 newCalib = DeferredChargeCalib().readText(outPath) 

113 self.assertEqual(self.calib, newCalib) 

114 

115 outPath = tempfile.mktemp() + '.fits' 

116 self.calib.writeFits(outPath) 

117 newCalib = DeferredChargeCalib().readFits(outPath) 

118 self.assertEqual(self.calib, newCalib) 

119 

120 def testTaskMethods(self): 

121 task = DeferredChargeTask() 

122 

123 image = np.full((self.ny, self.nx + self.prescan + self.overscan), 100.0) 

124 image[:, 0:self.prescan] = 0.0 

125 image[:, -self.overscan:] = 1.0 

126 

127 corrected = task.local_offset_inverse(image, self.calib.driftScale['amp0'], 

128 self.calib.decayTime['amp0'], 

129 num_previous_pixels=15) 

130 # 64*128*100 + 16*64 * ~(1 - driftScale) 

131 self.assertAlmostEqual(np.sum(corrected), 821094.5118501, 5) 

132 

133 corrected = task.local_trap_inverse(corrected, self.calib.serialTraps['amp0'], 

134 self.calib.globalCti['amp0'], 

135 num_previous_pixels=6) 

136 # As above + ~320 deposited in prescan 

137 self.assertAlmostEqual(np.sum(corrected), 821733.2317048, 5) 

138 

139 def testConfigLogic(self): 

140 config = IsrTaskConfig() 

141 config.doFlat = False 

142 config.doCalculateStatistics = True 

143 config.isrStats.doCtiStatistics = True 

144 

145 # Confirm that image and overscan are treated the same. 

146 config.doApplyGains = True 

147 config.isrStats.doApplyGainsForCtiStatistics = False 

148 with self.assertRaises(ValueError): 

149 config.validate() 

150 

151 config.doApplyGains = False 

152 config.isrStats.doApplyGainsForCtiStatistics = True 

153 with self.assertRaises(ValueError): 

154 config.validate() 

155 

156 # these should not raise 

157 config.doApplyGains = True 

158 config.isrStats.doApplyGainsForCtiStatistics = True 

159 config.validate() 

160 

161 config.doApplyGains = False 

162 config.isrStats.doApplyGainsForCtiStatistics = False 

163 config.validate() 

164 

165 

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

167 pass 

168 

169 

170def setup_module(module): 

171 lsst.utils.tests.init() 

172 

173 

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

175 import sys 

176 setup_module(sys.modules[__name__]) 

177 unittest.main()