Coverage for tests/test_kernelIo1.py: 10%
201 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-15 02:24 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-15 02:24 -0700
2#
3# LSST Data Management System
4# Copyright 2008, 2009, 2010 LSST Corporation.
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 <http://www.lsstcorp.org/LegalNotices/>.
22#
24import unittest
25import os
27import numpy as np
29import lsst.utils.tests
30import lsst.geom
31import lsst.afw.image as afwImage
32import lsst.afw.math as afwMath
33from lsst.log import Log
35# Change the level to Log.DEBUG to see debug messages
36Log.getLogger("lsst.afw.math.KernelFormatter").setLevel(Log.INFO)
39testPath = os.path.abspath(os.path.dirname(__file__))
42class KernelIOTestCase(unittest.TestCase):
43 """A test case for Kernel I/O"""
45 def kernelCheck(self, k1, k2):
46 self.assertEqual(k1.getWidth(), k2.getWidth())
47 self.assertEqual(k1.getHeight(), k2.getHeight())
48 self.assertEqual(k1.getCtr(), k2.getCtr())
49 self.assertEqual(k1.getNKernelParameters(), k2.getNKernelParameters())
50 self.assertEqual(k1.getNSpatialParameters(),
51 k2.getNSpatialParameters())
52 self.assertEqual(k1.getKernelParameters(), k2.getKernelParameters())
53 self.assertEqual(k1.getSpatialParameters(), k2.getSpatialParameters())
54 self.assertEqual(k1.isSpatiallyVarying(), k2.isSpatiallyVarying())
55 self.assertEqual(k1.toString(), k2.toString())
57 def testFixedKernel(self):
58 """Test FixedKernel using a ramp function
59 """
60 kWidth = 5
61 kHeight = 6
63 inArr = np.arange(kWidth * kHeight, dtype=float)
64 inArr.shape = [kWidth, kHeight]
66 inImage = afwImage.ImageD(lsst.geom.Extent2I(kWidth, kHeight))
67 for row in range(inImage.getHeight()):
68 for col in range(inImage.getWidth()):
69 inImage[col, row, afwImage.LOCAL] = inArr[col, row]
71 k = afwMath.FixedKernel(inImage)
73 with lsst.utils.tests.getTempFilePath(".fits") as filename:
74 k.writeFits(filename)
75 k2 = afwMath.FixedKernel.readFits(filename)
77 self.kernelCheck(k, k2)
79 outImage = afwImage.ImageD(k2.getDimensions())
80 k2.computeImage(outImage, False)
82 outArr = outImage.getArray().transpose()
83 if not np.allclose(inArr, outArr):
84 self.fail(f"{k2.__class__.__name__} = {inArr} != {outArr} (not normalized)")
85 normInArr = inArr / inArr.sum()
86 normOutImage = afwImage.ImageD(k2.getDimensions())
87 k2.computeImage(normOutImage, True)
88 normOutArr = normOutImage.getArray().transpose()
89 if not np.allclose(normOutArr, normInArr):
90 self.fail(f"{k2.__class__.__name__} = {normInArr} != {normOutArr} (normalized)")
92 def testAnalyticKernel(self):
93 """Test AnalyticKernel using a Gaussian function
94 """
95 kWidth = 5
96 kHeight = 8
98 gaussFunc = afwMath.GaussianFunction2D(1.0, 1.0, 0.0)
99 k = afwMath.AnalyticKernel(kWidth, kHeight, gaussFunc)
100 center = k.getCtr()
101 fArr = np.zeros(shape=[k.getWidth(), k.getHeight()], dtype=float)
102 for xsigma in (0.1, 1.0, 3.0):
103 for ysigma in (0.1, 1.0, 3.0):
104 for angle in (0.0, 0.4, 1.1):
105 gaussFunc.setParameters((xsigma, ysigma, angle))
106 # compute array of function values and normalize
107 for row in range(k.getHeight()):
108 y = row - center.getY()
109 for col in range(k.getWidth()):
110 x = col - center.getX()
111 fArr[col, row] = gaussFunc(x, y)
112 fArr /= fArr.sum()
114 k.setKernelParameters((xsigma, ysigma, angle))
116 with lsst.utils.tests.getTempFilePath(".fits") as filename:
117 k.writeFits(filename)
118 k2 = afwMath.AnalyticKernel.readFits(filename)
120 self.kernelCheck(k, k2)
122 kImage = afwImage.ImageD(k2.getDimensions())
123 k2.computeImage(kImage, True)
124 kArr = kImage.getArray().transpose()
125 if not np.allclose(fArr, kArr):
126 self.fail(f"{k2.__class__.__name__} = {kArr} != {fArr} "
127 f"for xsigma={xsigma}, ysigma={ysigma}")
129 def testDeltaFunctionKernel(self):
130 """Test DeltaFunctionKernel
131 """
132 for kWidth in range(1, 4):
133 for kHeight in range(1, 4):
134 for activeCol in range(kWidth):
135 for activeRow in range(kHeight):
136 kernel = afwMath.DeltaFunctionKernel(kWidth, kHeight,
137 lsst.geom.Point2I(activeCol, activeRow))
139 with lsst.utils.tests.getTempFilePath(".fits") as filename:
140 kernel.writeFits(filename)
141 k2 = afwMath.DeltaFunctionKernel.readFits(filename)
143 self.kernelCheck(kernel, k2)
144 self.assertEqual(kernel.getPixel(), k2.getPixel())
146 kImage = afwImage.ImageD(k2.getDimensions())
147 kSum = k2.computeImage(kImage, False)
148 self.assertEqual(kSum, 1.0)
149 kArr = kImage.getArray().transpose()
150 self.assertEqual(kArr[activeCol, activeRow], 1.0)
151 kArr[activeCol, activeRow] = 0.0
152 self.assertEqual(kArr.sum(), 0.0)
154 @unittest.skip("SeparableKernel does not yet support table persistence")
155 def testSeparableKernel(self):
156 """Test SeparableKernel using a Gaussian function
157 """
158 kWidth = 5
159 kHeight = 8
161 gaussFunc1 = afwMath.GaussianFunction1D(1.0)
162 k = afwMath.SeparableKernel(kWidth, kHeight, gaussFunc1, gaussFunc1)
163 center = k.getCtr()
164 fArr = np.zeros(shape=[k.getWidth(), k.getHeight()], dtype=float)
165 np.zeros(shape=[k.getWidth(), k.getHeight()], dtype=float)
166 gaussFunc = afwMath.GaussianFunction2D(1.0, 1.0, 0.0)
167 for xsigma in (0.1, 1.0, 3.0):
168 gaussFunc1.setParameters((xsigma,))
169 for ysigma in (0.1, 1.0, 3.0):
170 gaussFunc.setParameters((xsigma, ysigma, 0.0))
171 # compute array of function values and normalize
172 for row in range(k.getHeight()):
173 y = row - center.getY()
174 for col in range(k.getWidth()):
175 x = col - center.getX()
176 fArr[col, row] = gaussFunc(x, y)
177 fArr /= fArr.sum()
179 k.setKernelParameters((xsigma, ysigma))
181 with lsst.utils.tests.getTempFilePath(".fits") as filename:
182 k.writeFits(filename)
183 k2 = afwMath.SeparableKernel.readFits(filename)
185 self.kernelCheck(k, k2)
187 kImage = afwImage.ImageD(k2.getDimensions())
188 k2.computeImage(kImage, True)
189 kArr = kImage.getArray().transpose()
190 if not np.allclose(fArr, kArr):
191 self.fail(f"{k2.__class__.__name__} = {kArr} != {fArr} "
192 f"for xsigma={xsigma}, ysigma={ysigma}")
194 def testLinearCombinationKernel(self):
195 """Test LinearCombinationKernel using a set of delta basis functions
196 """
197 kWidth = 3
198 kHeight = 2
200 # create list of kernels
201 basisImArrList = []
202 kVec = []
203 for row in range(kHeight):
204 for col in range(kWidth):
205 kernel = afwMath.DeltaFunctionKernel(
206 kWidth, kHeight, lsst.geom.Point2I(col, row))
207 basisImage = afwImage.ImageD(kernel.getDimensions())
208 kernel.computeImage(basisImage, True)
209 basisImArrList.append(basisImage.getArray().transpose().copy())
210 kVec.append(kernel)
212 kParams = [0.0]*len(kVec)
213 k = afwMath.LinearCombinationKernel(kVec, kParams)
214 for ii in range(len(kVec)):
215 kParams = [0.0]*len(kVec)
216 kParams[ii] = 1.0
217 k.setKernelParameters(kParams)
219 with lsst.utils.tests.getTempFilePath(".fits") as filename:
220 k.writeFits(filename)
221 k2 = afwMath.LinearCombinationKernel.readFits(filename)
223 self.kernelCheck(k, k2)
225 kIm = afwImage.ImageD(k2.getDimensions())
226 k2.computeImage(kIm, True)
227 kImArr = kIm.getArray().transpose()
228 if not np.allclose(kImArr, basisImArrList[ii]):
229 self.fail(f"{k2.__class__.__name__} = {kImArr} != {basisImArrList[ii]} "
230 f"for the {ii}'th basis kernel")
232 def testSVLinearCombinationKernel(self):
233 """Test a spatially varying LinearCombinationKernel
234 """
235 kWidth = 3
236 kHeight = 2
238 # create image arrays for the basis kernels
239 basisImArrList = []
240 imArr = np.zeros((kWidth, kHeight), dtype=float)
241 imArr += 0.1
242 imArr[kWidth//2, :] = 0.9
243 basisImArrList.append(imArr)
244 imArr = np.zeros((kWidth, kHeight), dtype=float)
245 imArr += 0.2
246 imArr[:, kHeight//2] = 0.8
247 basisImArrList.append(imArr)
249 # create a list of basis kernels from the images
250 kVec = []
251 for basisImArr in basisImArrList:
252 basisImage = afwImage.makeImageFromArray(
253 basisImArr.transpose().copy())
254 kernel = afwMath.FixedKernel(basisImage)
255 kVec.append(kernel)
257 # create spatially varying linear combination kernel
258 spFunc = afwMath.PolynomialFunction2D(1)
260 # spatial parameters are a list of entries, one per kernel parameter;
261 # each entry is a list of spatial parameters
262 sParams = (
263 (0.0, 1.0, 0.0),
264 (0.0, 0.0, 1.0),
265 )
267 k = afwMath.LinearCombinationKernel(kVec, spFunc)
268 k.setSpatialParameters(sParams)
270 with lsst.utils.tests.getTempFilePath(".fits") as filename:
271 k.writeFits(filename)
272 k2 = afwMath.LinearCombinationKernel.readFits(filename)
274 self.kernelCheck(k, k2)
276 kImage = afwImage.ImageD(lsst.geom.Extent2I(kWidth, kHeight))
277 for colPos, rowPos, coeff0, coeff1 in [
278 (0.0, 0.0, 0.0, 0.0),
279 (1.0, 0.0, 1.0, 0.0),
280 (0.0, 1.0, 0.0, 1.0),
281 (1.0, 1.0, 1.0, 1.0),
282 (0.5, 0.5, 0.5, 0.5),
283 ]:
284 k2.computeImage(kImage, False, colPos, rowPos)
285 kImArr = kImage.getArray().transpose()
286 refKImArr = (basisImArrList[0] * coeff0) + \
287 (basisImArrList[1] * coeff1)
288 if not np.allclose(kImArr, refKImArr):
289 self.fail(f"{k2.__class__.__name__} = {kImArr} != {refKImArr} "
290 f"at colPos={colPos}, rowPos={rowPos}")
292 def testSetCtr(self):
293 """Test setCtrCol/Row"""
294 kWidth = 3
295 kHeight = 4
297 gaussFunc = afwMath.GaussianFunction2D(1.0, 1.0, 0.0)
298 k = afwMath.AnalyticKernel(kWidth, kHeight, gaussFunc)
299 for xCtr in range(kWidth):
300 for yCtr in range(kHeight):
301 ctr = lsst.geom.Point2I(xCtr, yCtr)
302 k.setCtr(ctr)
304 with lsst.utils.tests.getTempFilePath(".fits") as filename:
305 k.writeFits(filename)
306 k2 = afwMath.AnalyticKernel.readFits(filename)
308 self.kernelCheck(k, k2)
310 self.assertEqual(k2.getCtr(), ctr)
313class TestMemory(lsst.utils.tests.MemoryTestCase):
314 pass
317def setup_module(module):
318 lsst.utils.tests.init()
321if __name__ == "__main__": 321 ↛ 322line 321 didn't jump to line 322, because the condition on line 321 was never true
322 lsst.utils.tests.init()
323 unittest.main()