Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# 

2# This file is part of obs_decam. 

3# 

4# Developed for the LSST Data Management System. 

5# This product includes software developed by the LSST Project 

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

7# See the COPYRIGHT file at the top-level directory of this distribution 

8# for details of code ownership. 

9# 

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

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

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

13# (at your option) any later version. 

14# 

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

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

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

18# GNU General Public License for more details. 

19# 

20# You should have received a copy of the GNU General Public License 

21# along with this program. If not, see <http://www.gnu.org/licenses/>. 

22# 

23 

24import os 

25import warnings 

26import unittest 

27import lsst.utils.tests 

28 

29from lsst.utils import getPackageDir 

30import lsst.pex.exceptions as pexExcept 

31import lsst.geom as geom 

32import lsst.daf.persistence as dafPersist 

33from lsst.ip.isr.isrTask import IsrTask 

34 

35obsDecamDir = getPackageDir('obs_decam') 

36displayDiffs = False 

37 

38 

39def getObsDecamConfig(TaskClass): 

40 """Helper function to get a command-line task config customized by obs_decam. 

41 

42 Borrowed from test_processCcd.py. 

43 """ 

44 config = TaskClass.ConfigClass() 

45 filename = os.path.join(obsDecamDir, 'config', TaskClass._DefaultName + '.py') 

46 if os.path.exists(filename): 

47 config.load(filename) 

48 return config 

49 

50 

51class CrosstalkTestCase(lsst.utils.tests.TestCase): 

52 """A set of tests for DECam crosstalk correction. 

53 """ 

54 

55 def setUp(self): 

56 try: 

57 datadir = getPackageDir('testdata_decam') 

58 except pexExcept.NotFoundError: 

59 message = "testdata_decam not setup. Skipping." 

60 warnings.warn(message) 

61 raise unittest.SkipTest(message) 

62 

63 self.repoPath = os.path.join(datadir, 'rawData') 

64 self.calibPath = os.path.join(datadir, 'rawData/cpCalib') 

65 self.butler = dafPersist.Butler( 

66 inputs={'root': self.repoPath, 'mapperArgs': {'calibRoot': self.calibPath}}, 

67 outputs=None 

68 ) 

69 self.dataId = {'visit': 229388, 'ccdnum': 1} 

70 # Location of pixels where crosstalk is appreciable in the test image 

71 self.xtalkX = 1810 

72 self.xtalkY = 2970 

73 self.xtalkRad = 100 

74 

75 def tearDown(self): 

76 del self.butler 

77 

78 def runIsr(self, doCrosstalk): 

79 """Run DecamCpIsrTask with or without crosstalk correction 

80 """ 

81 dataRef = self.butler.dataRef('raw', dataId=self.dataId) 

82 rawExposure = self.butler.get('raw', dataId=self.dataId) 

83 camera = dataRef.get('camera') 

84 config = getObsDecamConfig(IsrTask) 

85 config.doCrosstalk = doCrosstalk 

86 decamCpIsrTask = IsrTask(config=config) 

87 isrData = decamCpIsrTask.readIsrData(dataRef, rawExposure) 

88 isrResult = decamCpIsrTask.run(rawExposure, camera=camera, **isrData.getDict()) 

89 return isrResult 

90 

91 def testCrosstalk(self): 

92 """Compare DECam postISR images with and without crosstalk removal. 

93 

94 A region with known crosstalk from the neighbor amp is inspected to 

95 verify the crosstalk is removed, and we also test to see that the 

96 image statistics are altered as expected by crosstalk removal. 

97 This test requires running DecamCpIsrTask twice. 

98 """ 

99 # Run ISR with and without crosstalk correction 

100 expWithoutCrosstalkCorr = self.runIsr(doCrosstalk=False).exposure 

101 expWithCrosstalkCorr = self.runIsr(doCrosstalk=True).exposure 

102 image1 = expWithoutCrosstalkCorr.getMaskedImage().getImage() 

103 image2 = expWithCrosstalkCorr.getMaskedImage().getImage() 

104 

105 # Work with a small image chunk only 

106 pmin = geom.Point2I(self.xtalkX - self.xtalkRad, self.xtalkY - self.xtalkRad) 

107 pmax = geom.Point2I(self.xtalkX + self.xtalkRad, self.xtalkY + self.xtalkRad) 

108 box = geom.Box2I(pmin, pmax) 

109 chunk1 = image1.Factory(image1, box) 

110 chunk2 = image2.Factory(image2, box) 

111 chunkDiff = chunk1.clone() 

112 chunkDiff -= chunk2 

113 

114 # Check that the difference of the two image chunks is nonzero 

115 # (the non-crosstalk-corrected and crosstalk-corrected images should differ) 

116 all_zeros = not chunkDiff.getArray().any() 

117 self.assertFalse(all_zeros) 

118 

119 # Check that the standard deviation with crosstalk signatures still 

120 # present is larger than when it has been removed 

121 self.assertGreater(chunk1.getArray().std(), chunk2.getArray().std()) 

122 

123 # More specific tests for the exact image statistics expected 

124 self.assertAlmostEqual(chunk1.getArray().mean(), 3730.9656, places=2) 

125 self.assertAlmostEqual(chunk2.getArray().mean(), 3727.5552, places=2) 

126 self.assertAlmostEqual(chunkDiff.getArray().mean(), 3.41, places=2) 

127 self.assertAlmostEqual(chunk1.getArray().std(), 33.792892, places=2) 

128 self.assertAlmostEqual(chunk2.getArray().std(), 33.302906, places=2) 

129 self.assertAlmostEqual(chunkDiff.getArray().std(), 5.86, places=2) 

130 

131 # Option to display the portions of the image with/without crosstalk 

132 if displayDiffs: 

133 import lsst.afw.display.ds9 as ds9 

134 ds9.mtv(chunk1, frame=1) 

135 ds9.mtv(chunk2, frame=2) 

136 ds9.mtv(chunkDiff, frame=3) 

137 

138 

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

140 pass 

141 

142 

143def setup_module(module): 

144 lsst.utils.tests.init() 

145 

146 

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

148 lsst.utils.tests.init() 

149 unittest.main()