Coverage for tests/test_approximate.py: 17%
79 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-22 03:22 -0800
« prev ^ index » next coverage.py v6.5.0, created at 2023-02-22 03:22 -0800
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.afw.display as afwDisplay
28import lsst.geom
29import lsst.afw.image as afwImage
30import lsst.afw.math as afwMath
31import lsst.pex.exceptions as pexExcept
33afwDisplay.setDefaultMaskTransparency(75)
34# Set to True to display things
35display = False
38class ApproximateTestCase(lsst.utils.tests.TestCase):
39 def makeRamp(self, binsize=1):
40 """Make a linear ramp"""
41 ramp = afwImage.MaskedImageF(20, 40)
43 x = []
44 for i in range(ramp.getWidth()):
45 x.append((i + 0.5)*binsize - 0.5)
47 y = []
48 for j in range(ramp.getHeight()):
49 y.append((j + 0.5)*binsize - 0.5)
51 var = 1
52 rampCoeffs = (1000, 1, 1)
53 for i in range(ramp.getHeight()):
54 for j in range(ramp.getWidth()):
55 ramp[j, i, afwImage.LOCAL] = (rampCoeffs[0] + rampCoeffs[1]*x[j] + rampCoeffs[2]*y[i],
56 0x0, var)
58 return ramp, rampCoeffs, x, y
60 def testLinearRamp(self):
61 """Fit a ramp"""
63 binsize = 1
64 ramp, rampCoeffs, xVec, yVec = self.makeRamp(binsize)
65 # Add a (labelled) bad value
66 ramp[ramp.getWidth()//2, ramp.getHeight()//2, afwImage.LOCAL] = (0, 0x1, np.nan)
68 if display:
69 afwDisplay.Display(frame=0).mtv(ramp, title=self._testMethodName + ": Input")
70 # Here's the range that the approximation should be valid (and also the
71 # bbox of the image returned by getImage)
72 bbox = lsst.geom.BoxI(lsst.geom.PointI(0, 0),
73 lsst.geom.PointI(binsize*ramp.getWidth() - 1,
74 binsize*ramp.getHeight() - 1))
76 order = 3 # 1 would be enough to fit the ramp
77 actrl = afwMath.ApproximateControl(
78 afwMath.ApproximateControl.CHEBYSHEV, order)
79 approx = afwMath.makeApproximate(xVec, yVec, ramp, bbox, actrl)
81 for i, aim in enumerate([approx.getImage(),
82 approx.getMaskedImage().getImage(),
83 ]):
84 if i == 0 and display:
85 disp = afwDisplay.Display(frame=1)
86 disp.mtv(aim, title=self._testMethodName + ": Interpolated")
87 with disp.Buffering():
88 for x in xVec:
89 for y in yVec:
90 disp.dot('+', x, y, size=0.4)
92 for x, y in aim.getBBox().getCorners():
93 self.assertEqual(
94 aim[x, y, afwImage.LOCAL], rampCoeffs[0] + rampCoeffs[1]*x + rampCoeffs[1]*y)
96 def testChebyshevEqualOrder(self):
97 """Check that we enforce the condition orderX == orderY"""
99 self.assertRaises(pexExcept.InvalidParameterError,
100 lambda:
101 afwMath.ApproximateControl(afwMath.ApproximateControl.CHEBYSHEV, 1, 2))
103 def testNoFinitePoints(self):
104 """Check that makeApproximate throws a RuntimeError if grid has no finite points and weights to fit
105 """
106 binsize = 1
107 for badValue in [(3, 0x1, 0), (np.nan, 0x1, 1)]:
108 ramp, rampCoeffs, xVec, yVec = self.makeRamp(binsize)
109 ramp.set(badValue)
110 bbox = lsst.geom.BoxI(lsst.geom.PointI(0, 0), lsst.geom.PointI(binsize*ramp.getWidth() - 1,
111 binsize*ramp.getHeight() - 1))
112 order = 2
113 actrl = afwMath.ApproximateControl(
114 afwMath.ApproximateControl.CHEBYSHEV, order)
115 self.assertRaises(pexExcept.RuntimeError,
116 lambda: afwMath.makeApproximate(xVec, yVec, ramp, bbox, actrl))
118 def testLinearRampAsBackground(self):
119 """Fit a ramp"""
121 ramp, rampCoeffs = self.makeRamp()[0:2]
123 if display:
124 afwDisplay.Display(frame=0).mtv(ramp, title=self._testMethodName + ": Input")
125 # Here's the range that the approximation should be valid (and also the
126 # bbox of the image returned by getImage)
127 bkgd = afwMath.makeBackground(ramp, afwMath.BackgroundControl(10, 10))
129 orderMax = 3 # 1 would be enough to fit the ramp
130 for order in range(orderMax + 1):
131 actrl = afwMath.ApproximateControl(
132 afwMath.ApproximateControl.CHEBYSHEV, order)
134 approx = bkgd.getApproximate(actrl)
135 # Get the Image, the MaskedImage, and the Image with a truncated
136 # expansion
137 for i, aim in enumerate([approx.getImage(),
138 approx.getMaskedImage().getImage(),
139 approx.getImage(
140 order - 1 if order > 1 else -1),
141 ]):
142 if display and (i == 0 and order == 1):
143 afwDisplay.Display(frame=1).mtv(aim, title=self._testMethodName + ": Interpolated")
145 for x, y in aim.getBBox().getCorners():
146 val = np.mean(aim.getArray()) if order == 0 else \
147 rampCoeffs[0] + rampCoeffs[1]*x + rampCoeffs[1]*y
149 self.assertEqual(aim[x, y, afwImage.LOCAL], val)
150 # Check that we can't "truncate" the expansion to a higher order than
151 # we requested
152 self.assertRaises(pexExcept.InvalidParameterError,
153 lambda: approx.getImage(orderMax + 1, orderMax + 1))
156class MemoryTester(lsst.utils.tests.MemoryTestCase):
157 pass
160def setup_module(module):
161 lsst.utils.tests.init()
164if __name__ == "__main__": 164 ↛ 165line 164 didn't jump to line 165, because the condition on line 164 was never true
165 lsst.utils.tests.init()
166 unittest.main()