Coverage for tests/test_snapCombine.py: 15%
109 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-23 10:59 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-23 10:59 +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
24import numpy as np
26import lsst.utils.tests
27import lsst.afw.image as afwImage
28from lsst.coadd.utils import setCoaddEdgeBits
29from lsst.pipe.tasks.snapCombine import SnapCombineTask
31np.random.seed(1)
34def makeRandomExposure(width, height, imMean, varMean, maxMask):
35 """Make a random exposure with Poisson distribution for image and variance
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)
50 return exp
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()
62 weightMap = afwImage.ImageF(exp0.getDimensions())
63 weightArr = weightMap.getArray()
65 good0 = np.bitwise_and(maskArr0, badPixelMask) == 0
66 good1 = np.bitwise_and(maskArr1, badPixelMask) == 0
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)
73 miRes /= weightMap
74 miRes *= 2 # want addition, not mean, where both pixels are valid
76 setCoaddEdgeBits(miRes.getMask(), weightMap)
78 return expRes
81class SnapCombineTestCase(lsst.utils.tests.TestCase):
83 """A test case for SnapCombineTask."""
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)
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()
100 predExp = simpleAdd(snap0, snap1, badPixelMask)
101 predMi = predExp.getMaskedImage()
102 self.assertMaskedImagesAlmostEqual(resMi, predMi)
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)
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()
117 predMi = snap0.getMaskedImage().Factory(snap0.getMaskedImage(), True)
118 predMi += snap1.getMaskedImage()
119 self.assertMaskedImagesAlmostEqual(resMi, predMi)
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)
135 snap0 = makeRandomExposure(5, 5, 10000, 5000, 0)
136 snap1 = makeRandomExposure(5, 5, 10000, 5000, 0)
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)
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
163 resExp = task.run(snap0, snap1).exposure
164 resMetadata = resExp.getMetadata()
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))
178class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
179 pass
182def setup_module(module):
183 lsst.utils.tests.init()
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()