Coverage for tests/test_snapCombine.py: 17%

109 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-08-30 10:53 +0000

1# 

2# LSST Data Management System 

3# Copyright 2008, 2009, 2010 LSST Corporation. 

4# 

5# This product includes software developed by the 

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

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

16# GNU General Public License for more details. 

17# 

18# You should have received a copy of the LSST License Statement and 

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

20# see <http://www.lsstcorp.org/LegalNotices/>. 

21# 

22import unittest 

23 

24import numpy as np 

25 

26import lsst.utils.tests 

27import lsst.afw.image as afwImage 

28from lsst.coadd.utils import setCoaddEdgeBits 

29from lsst.pipe.tasks.snapCombine import SnapCombineTask 

30 

31np.random.seed(1) 

32 

33 

34def makeRandomExposure(width, height, imMean, varMean, maxMask): 

35 """Make a random exposure with Poisson distribution for image and variance 

36 

37 @param[in] width image width (pixels) 

38 @param[in] height image height (pixels) 

39 @param[in] imMean mean of image plane 

40 @param[in] varMean mean of variance plane 

41 @param[in] maxMask maximum mask value; values will be uniformly chosen in [0, maxMask] 

42 """ 

43 exp = afwImage.ExposureF(width, height) 

44 mi = exp.getMaskedImage() 

45 imArr, maskArr, varArr = mi.getArrays() 

46 imArr[:, :] = np.random.poisson(imMean, size=imArr.shape) 

47 varArr[:, :] = np.random.poisson(varMean, size=varArr.shape) 

48 maskArr[:, :] = np.random.randint(0, maxMask + 1, size=maskArr.shape) 

49 

50 return exp 

51 

52 

53def simpleAdd(exp0, exp1, badPixelMask): 

54 """Add two exposures, avoiding bad pixels 

55 """ 

56 imArr0, maskArr0, varArr0 = exp0.getMaskedImage().getArrays() 

57 imArr1, maskArr1, varArr1 = exp1.getMaskedImage().getArrays() 

58 expRes = exp0.Factory(exp0, True) 

59 miRes = expRes.getMaskedImage() 

60 imArrRes, maskArrRes, varArrRes = miRes.getArrays() 

61 

62 weightMap = afwImage.ImageF(exp0.getDimensions()) 

63 weightArr = weightMap.getArray() 

64 

65 good0 = np.bitwise_and(maskArr0, badPixelMask) == 0 

66 good1 = np.bitwise_and(maskArr1, badPixelMask) == 0 

67 

68 imArrRes[:, :] = np.where(good0, imArr0, 0) + np.where(good1, imArr1, 0) 

69 varArrRes[:, :] = np.where(good0, varArr0, 0) + np.where(good1, varArr1, 0) 

70 maskArrRes[:, :] = np.bitwise_or(np.where(good0, maskArr0, 0), np.where(good1, maskArr1, 0)) 

71 weightArr[:, :] = np.where(good0, 1, 0) + np.where(good1, 1, 0) 

72 

73 miRes /= weightMap 

74 miRes *= 2 # want addition, not mean, where both pixels are valid 

75 

76 setCoaddEdgeBits(miRes.getMask(), weightMap) 

77 

78 return expRes 

79 

80 

81class SnapCombineTestCase(lsst.utils.tests.TestCase): 

82 

83 """A test case for SnapCombineTask.""" 

84 

85 def testAddition(self): 

86 """Test addition with bad pixels 

87 """ 

88 config = SnapCombineTask.ConfigClass() 

89 config.doRepair = False 

90 config.doDiffIm = False 

91 config.badMaskPlanes = ("BAD", "SAT", "NO_DATA", "CR") 

92 badPixelMask = afwImage.MaskX.getPlaneBitMask(config.badMaskPlanes) 

93 task = SnapCombineTask(config=config) 

94 

95 snap0 = makeRandomExposure(25, 25, 10000, 5000, badPixelMask) 

96 snap1 = makeRandomExposure(25, 25, 10000, 5000, badPixelMask) 

97 resExp = task.run(snap0, snap1).exposure 

98 resMi = resExp.getMaskedImage() 

99 

100 predExp = simpleAdd(snap0, snap1, badPixelMask) 

101 predMi = predExp.getMaskedImage() 

102 self.assertMaskedImagesAlmostEqual(resMi, predMi) 

103 

104 def testAdditionAllGood(self): 

105 """Test the case where all pixels are valid 

106 """ 

107 config = SnapCombineTask.ConfigClass() 

108 config.doRepair = False 

109 config.doDiffIm = False 

110 task = SnapCombineTask(config=config) 

111 

112 snap0 = makeRandomExposure(25, 25, 10000, 5000, 0) 

113 snap1 = makeRandomExposure(25, 25, 10000, 5000, 0) 

114 resExp = task.run(snap0, snap1).exposure 

115 resMi = resExp.getMaskedImage() 

116 

117 predMi = snap0.getMaskedImage().Factory(snap0.getMaskedImage(), True) 

118 predMi += snap1.getMaskedImage() 

119 self.assertMaskedImagesAlmostEqual(resMi, predMi) 

120 

121 def testMetadata(self): 

122 """Test more advanced metadata handling 

123 """ 

124 config = SnapCombineTask.ConfigClass() 

125 config.doRepair = False 

126 config.doDiffIm = False 

127 # the MISS<N> keys are missing from metadata<N> 

128 # and so cannot be summed or averaged 

129 # MISS0 keys will be copied without alterate 

130 # MISS1 keys will be missing from the result 

131 config.averageKeys = ("AVG0", "AVG1", "MISS0AVG", "MISS1AVG") 

132 config.sumKeys = ("SUM0", "SUM1", "MISS0SUM", "MISS1SUM") 

133 task = SnapCombineTask(config=config) 

134 

135 snap0 = makeRandomExposure(5, 5, 10000, 5000, 0) 

136 snap1 = makeRandomExposure(5, 5, 10000, 5000, 0) 

137 

138 metadata0 = snap0.getMetadata() 

139 metadata1 = snap1.getMetadata() 

140 metadata0.set("NUM0", 45.2) 

141 metadata0.set("ASTR", "this is a string") 

142 metadata0.set("AVG0", 10.5) 

143 metadata1.set("AVG0", 9.5) 

144 metadata0.set("AVG1", -0.7) 

145 metadata1.set("AVG1", 0.2) 

146 metadata0.set("MISS0AVG", 2.3523) 

147 metadata1.set("MISS1AVG", 8.23) 

148 metadata0.set("SUM0", 1.23) 

149 metadata1.set("SUM0", 4.56) 

150 metadata0.set("SUM1", 9814) 

151 metadata1.set("SUM1", 3) 

152 metadata0.set("MISS0SUM", 75.4) 

153 metadata1.set("MISS1SUM", -234.3) 

154 

155 allKeys = set(metadata0.names()) | set(metadata1.names()) 

156 miss0Keys = set(key for key in allKeys if key.startswith("MISS0")) 

157 miss1Keys = set(key for key in allKeys if key.startswith("MISS1")) 

158 missKeys = miss0Keys | miss1Keys 

159 avgKeys = set(config.averageKeys) - missKeys # keys that will be averaged 

160 sumKeys = set(config.sumKeys) - missKeys # keys that will be summed 

161 sameKeys = allKeys - (avgKeys | sumKeys | miss1Keys) # keys that will be the same 

162 

163 resExp = task.run(snap0, snap1).exposure 

164 resMetadata = resExp.getMetadata() 

165 

166 for key in sameKeys: 

167 self.assertEqual(resMetadata.getScalar(key), metadata0.getScalar(key)) 

168 for key in avgKeys: 

169 self.assertAlmostEqual(resMetadata.getScalar(key), 

170 (metadata0.getScalar(key) + metadata1.getScalar(key)) / 2.0) 

171 for key in sumKeys: 

172 self.assertAlmostEqual(resMetadata.getScalar(key), 

173 metadata0.getScalar(key) + metadata1.getScalar(key)) 

174 for key in miss1Keys: 

175 self.assertFalse(resMetadata.exists(key)) 

176 

177 

178class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase): 

179 pass 

180 

181 

182def setup_module(module): 

183 lsst.utils.tests.init() 

184 

185 

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

187 lsst.utils.tests.init() 

188 unittest.main()