Coverage for tests/test_gaussianPsf.py: 28%
77 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-08 03:13 -0700
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-08 03:13 -0700
1# This file is part of afw.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
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 GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import unittest
24import numpy as np
26import lsst.utils.tests
27import lsst.pex.exceptions
28import lsst.geom
29import lsst.afw.table
30import lsst.afw.fits
31import lsst.afw.image
32import lsst.afw.detection
35def makeGaussianImage(bbox, sigma, xc=0.0, yc=0.0):
36 image = lsst.afw.image.ImageD(bbox)
37 array = image.getArray()
38 for yi, yv in enumerate(range(bbox.getBeginY(), bbox.getEndY())):
39 for xi, xv in enumerate(range(bbox.getBeginX(), bbox.getEndX())):
40 array[yi, xi] = np.exp(-0.5*((xv - xc)**2 + (yv - yc)**2)/sigma**2)
41 array /= array.sum()
42 return image
45def computeNaiveApertureFlux(image, radius, xc=0.0, yc=0.0):
46 bbox = image.getBBox()
47 array = image.getArray()
48 s = 0.0
49 for yi, yv in enumerate(range(bbox.getBeginY(), bbox.getEndY())):
50 for xi, xv in enumerate(range(bbox.getBeginX(), bbox.getEndX())):
51 if (xv - xc)**2 + (yv - yc)**2 < radius**2:
52 s += array[yi, xi]
53 return s
56class GaussianPsfTestCase(lsst.utils.tests.TestCase):
58 def setUp(self):
59 self.kernelSize = 51
60 self.psf = lsst.afw.detection.GaussianPsf(
61 self.kernelSize, self.kernelSize, 4.0)
63 def tearDown(self):
64 del self.psf
66 def testKernelImage(self):
67 image = self.psf.computeKernelImage(self.psf.getAveragePosition())
68 check = makeGaussianImage(image.getBBox(), self.psf.getSigma())
69 self.assertFloatsAlmostEqual(image.getArray(), check.getArray())
70 self.assertFloatsAlmostEqual(image.getArray().sum(), 1.0, atol=1E-14)
72 def testOffsetImage(self):
73 image = self.psf.computeImage(lsst.geom.Point2D(0.25, 0.25))
74 check = makeGaussianImage(
75 image.getBBox(), self.psf.getSigma(), 0.25, 0.25)
76 self.assertFloatsAlmostEqual(image.getArray(), check.getArray(), atol=1E-4, rtol=1E-4,
77 plotOnFailure=True)
79 def testApertureFlux(self):
80 image = self.psf.computeKernelImage(lsst.geom.Point2D(0.0, 0.0))
81 # test aperture implementation is very crude; can only test to about 10%
82 self.assertFloatsAlmostEqual(
83 self.psf.computeApertureFlux(5.0, self.psf.getAveragePosition()),
84 computeNaiveApertureFlux(image, 5.0),
85 rtol=0.1
86 )
87 self.assertFloatsAlmostEqual(
88 self.psf.computeApertureFlux(7.0, self.psf.getAveragePosition()),
89 computeNaiveApertureFlux(image, 7.0),
90 rtol=0.1
91 )
93 def testShape(self):
94 self.assertFloatsAlmostEqual(
95 self.psf.computeShape(self.psf.getAveragePosition()).getDeterminantRadius(), 4.0)
97 def testPersistence(self):
98 with lsst.utils.tests.getTempFilePath(".fits") as filename:
99 self.psf.writeFits(filename)
100 psf = lsst.afw.detection.GaussianPsf.readFits(filename)
101 self.assertEqual(self.psf.getSigma(), psf.getSigma())
102 self.assertEqual(self.psf.getDimensions(), psf.getDimensions())
104 def testBBox(self):
106 self.assertEqual(self.psf.computeKernelImage(self.psf.getAveragePosition()).getBBox(),
107 self.psf.computeBBox(self.psf.getAveragePosition()))
109 self.assertEqual(
110 self.psf.computeBBox(self.psf.getAveragePosition()).getWidth(),
111 self.kernelSize
112 )
114 # Test interface. GaussianPsf does not vary spatially
115 self.assertEqual(self.psf.computeKernelImage(lsst.geom.Point2D(0.0, 0.0)).getBBox(),
116 self.psf.computeBBox(lsst.geom.Point2D(0.0, 0.0)))
118 self.assertEqual(self.psf.computeImage(self.psf.getAveragePosition()).getBBox(),
119 self.psf.computeImageBBox(self.psf.getAveragePosition()))
121 def testResized(self):
122 for pad in [0, -10, 10]:
123 newLen = self.kernelSize - pad
124 resizedPsf = self.psf.resized(newLen, newLen)
125 newBBox = resizedPsf.computeBBox(resizedPsf.getAveragePosition())
126 self.assertEqual(newBBox.getWidth(), newLen)
127 self.assertEqual(newBBox.getHeight(), newLen)
128 self.assertEqual(resizedPsf.getSigma(), self.psf.getSigma())
130 image = resizedPsf.computeKernelImage(resizedPsf.getAveragePosition())
131 check = makeGaussianImage(newBBox, self.psf.getSigma())
132 self.assertFloatsAlmostEqual(image.getArray(), check.getArray())
133 # tolerance same as in self.testKernelImage
134 self.assertFloatsAlmostEqual(image.getArray().sum(), 1.0, atol=1E-14)
137class MemoryTester(lsst.utils.tests.MemoryTestCase):
138 pass
141def setup_module(module):
142 lsst.utils.tests.init()
145if __name__ == "__main__": 145 ↛ 146line 145 didn't jump to line 146, because the condition on line 145 was never true
146 lsst.utils.tests.init()
147 unittest.main()