Coverage for tests/test_crosstalk.py : 27%

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#
24import os
25import warnings
26import unittest
27import lsst.utils.tests
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
35obsDecamDir = getPackageDir('obs_decam')
36displayDiffs = False
39def getObsDecamConfig(TaskClass):
40 """Helper function to get a command-line task config customized by obs_decam.
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
51class CrosstalkTestCase(lsst.utils.tests.TestCase):
52 """A set of tests for DECam crosstalk correction.
53 """
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)
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
75 def tearDown(self):
76 del self.butler
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
91 def testCrosstalk(self):
92 """Compare DECam postISR images with and without crosstalk removal.
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()
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
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)
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())
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)
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)
139class MemoryTester(lsst.utils.tests.MemoryTestCase):
140 pass
143def setup_module(module):
144 lsst.utils.tests.init()
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()