Coverage for tests/test_brighterFatterKernel.py: 22%

79 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-04-24 03:56 -0700

1# 

2# LSST Data Management System 

3# 

4# Copyright 2008-2017 AURA/LSST. 

5# 

6# This product includes software developed by the 

7# LSST Project (http://www.lsst.org/). 

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 LSST License Statement and 

20# the GNU General Public License along with this program. If not, 

21# see <https://www.lsstcorp.org/LegalNotices/>. 

22# 

23"""Test cases for lsst.cp.pipe.BrighterFatterKernelSolveTask. 

24""" 

25 

26import unittest 

27import numpy as np 

28 

29import lsst.utils 

30import lsst.utils.tests 

31 

32import lsst.ip.isr as ipIsr 

33import lsst.cp.pipe as cpPipe 

34import lsst.afw.cameraGeom as cameraGeom 

35 

36 

37class BfkSolveTaskTestCase(lsst.utils.tests.TestCase): 

38 """A test case for the brighter fatter kernel solver. 

39 """ 

40 

41 def setUp(self): 

42 """Set up a plausible PTC dataset, with 1% of the expected variance 

43 shifted into covariance terms. 

44 """ 

45 cameraBuilder = cameraGeom.Camera.Builder('fake camera') 

46 detectorWrapper = cameraGeom.testUtils.DetectorWrapper(numAmps=1, cameraBuilder=cameraBuilder) 

47 self.detector = detectorWrapper.detector 

48 self.camera = cameraBuilder.finish() 

49 

50 self.defaultConfig = cpPipe.BrighterFatterKernelSolveConfig() 

51 self.ptc = ipIsr.PhotonTransferCurveDataset(ampNames=['amp 1'], ptcFitType='FULLCOVARIANCE', 

52 covMatrixSide=3) 

53 self.ptc.expIdMask['amp 1'] = np.array([False, True, True, True, True, True, True, True, True, True]) 

54 self.ptc.rawMeans['amp 1'] = np.array([1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000]) 

55 self.ptc.finalMeans['amp 1'] = self.ptc.rawMeans['amp 1'][self.ptc.expIdMask['amp 1']] 

56 self.ptc.rawVars['amp 1'] = 0.99 * np.array(self.ptc.rawMeans['amp 1'], dtype=float) 

57 self.ptc.finalVars['amp 1'] = self.ptc.rawVars['amp 1'][self.ptc.expIdMask['amp 1']] 

58 self.ptc.covariances['amp 1'] = [] 

59 for mean, variance in zip(self.ptc.rawMeans['amp 1'], self.ptc.rawVars['amp 1']): 

60 residual = mean - variance 

61 covariance = [[variance, 0.5 * residual, 0.1 * residual], 

62 [0.2 * residual, 0.1 * residual, 0.05 * residual], 

63 [0.025 * residual, 0.015 * residual, 0.01 * residual]] 

64 self.ptc.covariances['amp 1'].append(covariance) 

65 

66 self.ptc.covariancesModel = self.ptc.covariances 

67 self.ptc.gain['amp 1'] = 1.0 

68 self.ptc.noise['amp 1'] = 5.0 

69 self.ptc.noiseMatrix['amp 1'] = np.zeros((3, 3)) 

70 self.ptc.noiseMatrix['amp 1'][0][0] = self.ptc.noise['amp 1'] 

71 

72 # This is empirically determined from the above parameters. 

73 self.ptc.aMatrix['amp 1'] = np.array([[2.14329806e-06, -4.28659612e-07, -5.35824515e-08], 

74 [-1.07164903e-06, -2.14329806e-07, -3.21494709e-08], 

75 [-2.14329806e-07, -1.07164903e-07, -2.14329806e-08]]) 

76 

77 # This is empirically determined from the above parameters. 

78 self.expectation = np.array([[4.88348887e-08, 1.01136877e-07, 1.51784114e-07, 

79 1.77570668e-07, 1.51784114e-07, 1.01136877e-07, 4.88348887e-08], 

80 [9.42026776e-08, 2.03928507e-07, 3.28428909e-07, 

81 4.06714446e-07, 3.28428909e-07, 2.03928507e-07, 9.42026776e-08], 

82 [1.24047315e-07, 2.70512582e-07, 4.44123665e-07, 

83 5.78099493e-07, 4.44123665e-07, 2.70512582e-07, 1.24047315e-07], 

84 [1.31474000e-07, 2.77801372e-07, 3.85123870e-07, 

85 -5.42128333e-08, 3.85123870e-07, 2.77801372e-07, 1.31474000e-07], 

86 [1.24047315e-07, 2.70512582e-07, 4.44123665e-07, 

87 5.78099493e-07, 4.44123665e-07, 2.70512582e-07, 1.24047315e-07], 

88 [9.42026776e-08, 2.03928507e-07, 3.28428909e-07, 

89 4.06714446e-07, 3.28428909e-07, 2.03928507e-07, 9.42026776e-08], 

90 [4.88348887e-08, 1.01136877e-07, 1.51784114e-07, 

91 1.77570668e-07, 1.51784114e-07, 1.01136877e-07, 4.88348887e-08]]) 

92 

93 def test_averaged(self): 

94 """Test "averaged" brighter-fatter kernel. 

95 """ 

96 task = cpPipe.BrighterFatterKernelSolveTask() 

97 

98 results = task.run(self.ptc, ['this is a dummy exposure'], self.camera, {'detector': 1}) 

99 self.assertFloatsAlmostEqual(results.outputBFK.ampKernels['amp 1'], self.expectation, atol=1e-5) 

100 

101 def test_aMatrix(self): 

102 """Test solution from Astier et al. 2019 "A" matrix 

103 """ 

104 config = cpPipe.BrighterFatterKernelSolveConfig() 

105 config.useAmatrix = True 

106 task = cpPipe.BrighterFatterKernelSolveTask(config=config) 

107 

108 results = task.run(self.ptc, ['this is a dummy exposure'], self.camera, {'detector': 1}) 

109 self.assertFloatsAlmostEqual(results.outputBFK.ampKernels['amp 1'], self.expectation, atol=1e-5) 

110 

111 def test_covSample(self): 

112 """Test solution from Broughton et al. 2024 eq. 4 preKernel 

113 """ 

114 config = cpPipe.BrighterFatterKernelSolveConfig() 

115 config.useCovModelSample = True 

116 config.covModelFluxSample = {'ALL_AMPS': 30000.} 

117 task = cpPipe.BrighterFatterKernelSolveTask(config=config) 

118 

119 results = task.run(self.ptc, ['this is a dummy exposure'], self.camera, {'detector': 1}) 

120 

121 expectation = np.array([[2.19577206e-08, 4.22977941e-08, 5.54871324e-08, 

122 5.85845588e-08, 5.54871324e-08, 4.22977941e-08, 

123 2.19577206e-08], 

124 [4.55330882e-08, 9.17463235e-08, 1.21066176e-07, 

125 1.23363971e-07, 1.21066176e-07, 9.17463235e-08, 

126 4.55330882e-08], 

127 [6.84283088e-08, 1.48088235e-07, 1.98667279e-07, 

128 1.67738971e-07, 1.98667279e-07, 1.48088235e-07, 

129 6.84283088e-08], 

130 [8.00919118e-08, 1.83511029e-07, 2.57775735e-07, 

131 -4.97426471e-08, 2.57775735e-07, 1.83511029e-07, 

132 8.00919118e-08], 

133 [6.84283088e-08, 1.48088235e-07, 1.98667279e-07, 

134 1.67738971e-07, 1.98667279e-07, 1.48088235e-07, 

135 6.84283088e-08], 

136 [4.55330882e-08, 9.17463235e-08, 1.21066176e-07, 

137 1.23363971e-07, 1.21066176e-07, 9.17463235e-08, 

138 4.55330882e-08], 

139 [2.19577206e-08, 4.22977941e-08, 5.54871324e-08, 

140 5.85845588e-08, 5.54871324e-08, 4.22977941e-08, 

141 2.19577206e-08]]) 

142 

143 self.assertFloatsAlmostEqual(results.outputBFK.ampKernels['amp 1'], expectation, atol=1e-5) 

144 

145 def test_quadratic(self): 

146 """Test quadratic correlation solver. 

147 

148 This requires a different model for the variance, so cannot 

149 use the one generated by setUp. This model is not entirely 

150 physical, but will ensure that accidental code changes are 

151 detected. 

152 """ 

153 config = cpPipe.BrighterFatterKernelSolveConfig() 

154 config.correlationQuadraticFit = True 

155 config.forceZeroSum = True 

156 task = cpPipe.BrighterFatterKernelSolveTask(config=config) 

157 

158 ptc = ipIsr.PhotonTransferCurveDataset(ampNames=['amp 1'], ptcFitType='FULLCOVARIANCE', 

159 covMatrixSide=3) 

160 ptc.expIdMask['amp 1'] = np.array([False, True, True, True, True, True, True, True, True, True]) 

161 ptc.rawMeans['amp 1'] = np.array([1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000]) 

162 ptc.finalMeans['amp 1'] = ptc.rawMeans['amp 1'][ptc.expIdMask['amp 1']] 

163 ptc.rawVars['amp 1'] = 9e-5 * np.square(np.array(ptc.rawMeans['amp 1'], dtype=float)) 

164 ptc.finalVars['amp 1'] = ptc.rawVars['amp 1'][ptc.expIdMask['amp 1']] 

165 ptc.covariances['amp 1'] = [] 

166 for mean, variance in zip(ptc.rawMeans['amp 1'], ptc.rawVars['amp 1']): 

167 residual = variance 

168 covariance = [[variance, 0.5 * residual, 0.1 * residual], 

169 [0.2 * residual, 0.1 * residual, 0.05 * residual], 

170 [0.025 * residual, 0.015 * residual, 0.01 * residual]] 

171 ptc.covariances['amp 1'].append(covariance) 

172 

173 ptc.gain['amp 1'] = 1.0 

174 ptc.noise['amp 1'] = 5.0 

175 

176 results = task.run(ptc, ['this is a dummy exposure'], self.camera, {'detector': 1}) 

177 

178 expectation = np.array([[4.05330882e-08, 2.26654412e-07, 5.66636029e-07, 7.56066176e-07, 

179 5.66636029e-07, 2.26654412e-07, 4.05330882e-08], 

180 [-6.45220588e-08, 2.99448529e-07, 1.28382353e-06, 1.89099265e-06, 

181 1.28382353e-06, 2.99448529e-07, -6.45220588e-08], 

182 [-5.98069853e-07, -1.14816176e-06, -2.12178309e-06, -4.75974265e-06, 

183 -2.12178309e-06, -1.14816176e-06, -5.98069853e-07], 

184 [-1.17959559e-06, -3.52224265e-06, -1.28630515e-05, -6.16863971e-05, 

185 -1.28630515e-05, -3.52224265e-06, -1.17959559e-06], 

186 [-5.98069853e-07, -1.14816176e-06, -2.12178309e-06, -4.75974265e-06, 

187 -2.12178309e-06, -1.14816176e-06, -5.98069853e-07], 

188 [-6.45220588e-08, 2.99448529e-07, 1.28382353e-06, 1.89099265e-06, 

189 1.28382353e-06, 2.99448529e-07, -6.45220588e-08], 

190 [4.05330882e-08, 2.26654412e-07, 5.66636029e-07, 7.56066176e-07, 

191 5.66636029e-07, 2.26654412e-07, 4.05330882e-08]]) 

192 self.assertFloatsAlmostEqual(results.outputBFK.ampKernels['amp 1'], expectation, atol=1e-5) 

193 

194 

195class TestMemory(lsst.utils.tests.MemoryTestCase): 

196 pass 

197 

198 

199def setup_module(module): 

200 lsst.utils.tests.init() 

201 

202 

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

204 lsst.utils.tests.init() 

205 unittest.main()