Coverage for tests/test_multiShapelet.py: 13%
125 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-30 02:42 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-30 02:42 -0800
1#
2# LSST Data Management System
3# Copyright 2008-2017 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#
23import pickle
24import unittest
26import numpy as np
28import lsst.utils.tests
29import lsst.afw.geom.ellipses
30import lsst.shapelet.tests
31import lsst.afw.image
34class MultiShapeletTestCase(lsst.shapelet.tests.ShapeletTestCase):
36 def setUp(self):
37 np.random.seed(500)
39 def testMoments(self):
40 x = np.linspace(-50, 50, 1001)
41 y = x
42 function = self.makeRandomMultiShapeletFunction()
43 x = np.linspace(-10, 10, 101)
44 y = x
45 z = self.makeImage(function, x, y)
46 self.checkMoments(function, x, y, z)
48 def testPickle(self):
49 function1 = self.makeRandomMultiShapeletFunction()
50 s = pickle.dumps(function1, protocol=2)
51 function2 = pickle.loads(s)
52 for component1, component2 in zip(function1.getComponents(), function2.getComponents()):
53 self.assertEqual(component1.getOrder(), component2.getOrder())
54 self.assertEqual(component1.getBasisType(), component2.getBasisType())
55 self.assertFloatsAlmostEqual(component1.getEllipse().getParameterVector(),
56 component2.getEllipse().getParameterVector())
57 self.assertFloatsAlmostEqual(component1.getCoefficients(), component2.getCoefficients())
59 def testConvolveGaussians(self):
60 sigma1 = [lsst.afw.geom.ellipses.Quadrupole(6.0, 5.0, 2.0),
61 lsst.afw.geom.ellipses.Quadrupole(8.0, 10.0, -1.0)]
62 sigma2 = [lsst.afw.geom.ellipses.Quadrupole(7.0, 12.0, -2.0),
63 lsst.afw.geom.ellipses.Quadrupole(7.0, 9.0, 1.0)]
64 alpha1 = [0.6, 0.4]
65 alpha2 = [0.35, 0.65]
66 sigma3 = []
67 alpha3 = []
69 def makeMultiShapeletFunction(alpha, sigma):
70 msf = lsst.shapelet.MultiShapeletFunction()
71 for a, s in zip(alpha, sigma):
72 f = lsst.shapelet.ShapeletFunction(0, lsst.shapelet.HERMITE,
73 lsst.afw.geom.ellipses.Ellipse(s))
74 f.getCoefficients()[0] = a / lsst.shapelet.ShapeletFunction.FLUX_FACTOR
75 msf.addComponent(f)
76 return msf
77 for a1, s1 in zip(alpha1, sigma1):
78 for a2, s2 in zip(alpha2, sigma2):
79 sigma3.append(lsst.afw.geom.ellipses.Quadrupole(s1.getIxx() + s2.getIxx(),
80 s1.getIyy() + s2.getIyy(),
81 s1.getIxy() + s2.getIxy()))
82 alpha3.append(a1 * a2)
83 msf1 = makeMultiShapeletFunction(alpha1, sigma1)
84 msf2 = makeMultiShapeletFunction(alpha2, sigma2)
85 msf3a = makeMultiShapeletFunction(alpha3, sigma3)
86 msf3b = msf1.convolve(msf2)
88 # Compare the parameters of the MultiShapeletFunctions
89 self.compareMultiShapeletFunctions(msf3a, msf3b)
91 # Just to be extra sure, we test that the images are also the same
92 x = np.linspace(-20, 20, 41)
93 y = np.linspace(-20, 20, 41)
94 image3a = self.makeImage(msf3a, x, y)
95 image3b = self.makeImage(msf3b, x, y)
96 self.assertFloatsAlmostEqual(image3a, image3b)
98 # Now we test against two test images: one implemented right here with numpy calls...
99 xg, yg = np.meshgrid(x, y)
101 def evalMultiGaussian(alpha, sigma):
102 matQ = np.array([[sigma.getIxx(), sigma.getIxy()],
103 [sigma.getIxy(), sigma.getIyy()]],
104 dtype=float)
105 invQ = np.linalg.inv(matQ)
106 norm = alpha / np.linalg.det(2.0 * np.pi * matQ)**0.5
107 return norm * np.exp(-0.5 * (invQ[0, 0]*xg**2 + 2.0*invQ[0, 1]*xg*yg + invQ[1, 1]*yg**2))
108 image3c = np.zeros(xg.shape, dtype=float)
109 for a, s in zip(alpha3, sigma3):
110 image3c += evalMultiGaussian(a, s)
111 self.assertFloatsAlmostEqual(image3c, image3a, rtol=1E-6, relTo=np.max(image3c),
112 printFailures=True, plotOnFailure=False)
114 # And the second produced by GalSim
115 if False:
116 # Print inputs to screen so we can make a test image with GalSim (see tests/data/generate.py)
117 # Output can be pasted into that file to generate the check image.
118 def printForGalSim(alpha, sigma):
119 print("galsim.Add([")
120 for a, s in zip(alpha, sigma):
121 e = lsst.afw.geom.ellipses.Separable[lsst.afw.geom.ellipses.Distortion,
122 lsst.afw.geom.ellipses.DeterminantRadius](s)
123 print(" makeGaussian(flux=%f, e1=%8.8f, e2=%8.8f, sigma=%8.8f),"
124 % (a, e.getE1(), e.getE2(), e.getRadius()))
125 print("])")
126 printForGalSim(alpha1, sigma1)
127 printForGalSim(alpha2, sigma2)
128 image3d = lsst.afw.image.ImageF("tests/data/gaussians.fits").getArray().astype(float)
129 self.assertFloatsAlmostEqual(image3d, image3a, rtol=1E-6, relTo=np.max(image3d),
130 printFailures=True, plotOnFailure=False)
132 def testBasisNormalize(self):
133 def makePositiveMatrix(*shape):
134 """Return a random basis matrix, but with a lot of power
135 in the zeroth component to ensure the integral is positve."""
136 a = np.random.randn(*shape)
137 a[0, :] += 4.0
138 return a
139 basis = lsst.shapelet.MultiShapeletBasis(2)
140 basis.addComponent(0.5, 1, makePositiveMatrix(3, 2))
141 basis.addComponent(1.0, 2, makePositiveMatrix(6, 2))
142 basis.addComponent(1.2, 0, makePositiveMatrix(1, 2))
143 basis.normalize()
144 for n in range(2):
145 coefficients = np.zeros(2, dtype=float)
146 coefficients[n] = 1.0
147 msf = basis.makeFunction(lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes()),
148 coefficients)
149 self.assertFloatsAlmostEqual(msf.evaluate().integrate(), 1.0)
151 def testBasisScale(self):
152 ellipse = lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes())
153 basis = lsst.shapelet.MultiShapeletBasis(2)
154 basis.addComponent(0.5, 1, np.random.randn(3, 2))
155 basis.addComponent(1.0, 2, np.random.randn(6, 2))
156 basis.addComponent(1.2, 0, np.random.randn(1, 2))
157 msf1 = [basis.makeFunction(ellipse, self.makeUnitVector(i, 2)) for i in range(2)]
158 basis.scale(2.0)
159 ellipse.getCore().scale(0.5)
160 msf2 = [basis.makeFunction(ellipse, self.makeUnitVector(i, 2)) for i in range(2)]
161 for a, b in zip(msf1, msf2):
162 self.compareMultiShapeletFunctions(a, b)
164 def testBasisMerge(self):
165 ellipse = lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes())
166 basis1 = lsst.shapelet.MultiShapeletBasis(2)
167 basis1.addComponent(0.5, 1, np.random.randn(3, 2))
168 basis1.addComponent(1.0, 2, np.random.randn(6, 2))
169 basis1.addComponent(1.2, 0, np.random.randn(1, 2))
170 basis2 = lsst.shapelet.MultiShapeletBasis(3)
171 basis2.addComponent(0.4, 1, np.random.randn(3, 3))
172 basis2.addComponent(1.1, 2, np.random.randn(6, 3))
173 basis2.addComponent(1.6, 0, np.random.randn(1, 3))
174 basis3 = lsst.shapelet.MultiShapeletBasis(basis1)
175 basis3.merge(basis2)
176 self.assertEqual(basis3.getSize(), 5)
177 msf1 = [basis1.makeFunction(ellipse, self.makeUnitVector(i, 2)) for i in range(2)]
178 msf2 = [basis2.makeFunction(ellipse, self.makeUnitVector(i, 3)) for i in range(3)]
179 msf3 = [basis3.makeFunction(ellipse, self.makeUnitVector(i, 5)) for i in range(5)]
180 for a, b in zip(msf3, msf1+msf2):
181 self.compareMultiShapeletFunctions(a, b)
184class MemoryTester(lsst.utils.tests.MemoryTestCase):
185 pass
188def setup_module(module):
189 lsst.utils.tests.init()
192if __name__ == "__main__": 192 ↛ 193line 192 didn't jump to line 193, because the condition on line 192 was never true
193 lsst.utils.tests.init()
194 unittest.main()