Coverage for tests/test_transformBoundedField.py: 24%
101 statements
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-26 02:33 -0700
« prev ^ index » next coverage.py v6.4.4, created at 2022-08-26 02:33 -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/>.
22"""
23Tests for math.TransformBoundedField
25Run with:
26 python test_transformBoundedField.py
27or
28 pytest test_transformBoundedField.py
29"""
31import unittest
33import astshim
34import numpy as np
35from numpy.testing import assert_allclose
37import lsst.utils.tests
38import lsst.pex.exceptions
39import lsst.geom
40import lsst.afw.geom
41import lsst.afw.image
42from lsst.afw.math import TransformBoundedField
45CHEBYSHEV_T = [ 45 ↛ exitline 45 didn't jump to the function exit
46 lambda x: x**0,
47 lambda x: x,
48 lambda x: 2*x**2 - 1,
49 lambda x: (4*x**2 - 3)*x,
50 lambda x: (8*x**2 - 8)*x**2 + 1,
51 lambda x: ((16*x**2 - 20)*x**2 + 5)*x,
52]
55class TransformBoundedFieldTestCase(lsst.utils.tests.TestCase):
57 def setUp(self):
58 self.longMessage = True
60 # an arbitrary bounding box (not that this kind of field cares)
61 self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-3, 4),
62 lsst.geom.Extent2I(5, 30))
64 # a list of points contained in the bbox
65 self.pointList = lsst.geom.Box2D(self.bbox).getCorners()
66 self.pointList.append(lsst.geom.Box2D(self.bbox).getCenter())
67 self.xList = np.array([p[0] for p in self.pointList])
68 self.yList = np.array([p[1] for p in self.pointList])
70 # a simple polynomial mapping
71 coeff_f = np.array([
72 [1.5, 1, 0, 0],
73 [-0.5, 1, 1, 0],
74 [1.0, 1, 0, 1],
75 ])
76 polyMap = astshim.PolyMap(coeff_f, 1)
77 self.transform = lsst.afw.geom.TransformPoint2ToGeneric(polyMap)
78 self.boundedField = TransformBoundedField(self.bbox, self.transform)
80 def tearDown(self):
81 del self.transform
83 def testEvaluate(self):
84 """Test the various overloads of `evaluate`
85 """
86 for point in self.pointList:
87 # applylForward returns a vector with one entry per axis
88 # and in this case there is just one axis
89 predRes = self.transform.applyForward(point)[0]
91 res = self.boundedField.evaluate(point)
92 self.assertFloatsAlmostEqual(res, predRes)
94 x, y = point
95 res2 = self.boundedField.evaluate(x, y)
96 self.assertFloatsAlmostEqual(res2, predRes)
98 resArr = self.boundedField.evaluate(self.xList, self.yList)
99 # applylForward returns an array with one row of values per axis
100 # and in this case there is just one axis
101 predResArr = self.transform.applyForward(self.pointList)[0]
102 assert_allclose(resArr, predResArr)
104 def testMultiplyOperator(self):
105 """Test operator*
106 """
107 maxVal = np.max(np.abs(self.transform.applyForward(self.pointList)[0]))
108 for multFactor in (-9e99, -1.5e-7, 3.6e-7, 1.5, 9.23e99):
109 atol = abs(maxVal*multFactor*1e-15)
110 predResult = self.transform.applyForward(self.pointList)[0]*multFactor
112 scaledField1 = self.boundedField*multFactor
113 assert_allclose(scaledField1.evaluate(self.xList, self.yList), predResult, atol=atol)
115 scaledField2 = multFactor*self.boundedField
116 assert_allclose(scaledField2.evaluate(self.xList, self.yList), predResult, atol=atol)
118 def testBBox(self):
119 """The BBox should have no effect on the kind of transform being tested
121 Use an empty bbox as an extreme test of this
122 """
123 self.assertEqual(self.boundedField.getBBox(), self.bbox)
125 emptyBBox = lsst.geom.Box2I()
126 noBBoxField = TransformBoundedField(emptyBBox, self.transform)
127 self.assertEqual(noBBoxField.getBBox(), emptyBBox)
129 resArr = self.boundedField.evaluate(self.xList, self.yList)
130 resArrNoBBox = noBBoxField.evaluate(self.xList, self.yList)
131 assert_allclose(resArr, resArrNoBBox)
133 def testPersistenceAndEquality(self):
134 """Test persistence using writeFits and readFits
136 Also test operator==
137 """
138 with lsst.utils.tests.getTempFilePath(".fits") as filename:
139 self.boundedField.writeFits(filename)
140 readField = TransformBoundedField.readFits(filename)
142 self.assertTrue(self.boundedField == readField)
143 self.assertFalse(self.boundedField != readField)
144 self.assertEqual(self.boundedField, readField)
146 resArr = self.boundedField.evaluate(self.xList, self.yList)
147 readResArr = readField.evaluate(self.xList, self.yList)
148 assert_allclose(resArr, readResArr)
149 self.assertEqual(readField.getBBox(), self.bbox)
151 def testComplexPersistence(self):
152 """Test persistence of a TransformBoundedField whose string representation is huge
153 """
154 # DM-11964 shows that CFITSIO cannot handle string fields
155 # in binary tables that have more than 28799 characters
156 # make sure the test has plenty of margin
157 minChars = 10*28799
158 degree = 100 # make large enough that len(transform.writeString()) > minChars
159 n_coeffs = (degree + 1)*(degree + 2)//2
160 coeffs = np.zeros((n_coeffs, 4), dtype=float)
161 k = 0
162 for j in range(degree + 1):
163 for i in range(degree - j + 1):
164 coeffs[k][0] = np.random.random()
165 coeffs[k][1] = 1
166 coeffs[k][2] = i
167 coeffs[k][3] = j
168 k += 1
169 chebyMap = astshim.PolyMap(coeffs, 1)
170 transform = lsst.afw.geom.TransformPoint2ToGeneric(chebyMap)
171 lenTransformStr = len(transform.writeString())
172 print(f"len transform str={lenTransformStr}; minChars={minChars}")
173 self.assertGreater(lenTransformStr, minChars)
174 complexBoundedField = TransformBoundedField(self.bbox, transform)
175 with lsst.utils.tests.getTempFilePath(".fits") as filename:
176 complexBoundedField.writeFits(filename)
177 readField = TransformBoundedField.readFits(filename)
179 self.assertTrue(complexBoundedField == readField)
180 self.assertFalse(complexBoundedField != readField)
181 self.assertEqual(complexBoundedField, readField)
183 resArr = complexBoundedField.evaluate(self.xList, self.yList)
184 readResArr = readField.evaluate(self.xList, self.yList)
185 assert_allclose(resArr, readResArr)
186 self.assertEqual(readField.getBBox(), self.bbox)
189class MemoryTester(lsst.utils.tests.MemoryTestCase):
190 pass
193def setup_module(module):
194 lsst.utils.tests.init()
197if __name__ == "__main__": 197 ↛ 198line 197 didn't jump to line 198, because the condition on line 197 was never true
198 lsst.utils.tests.init()
199 unittest.main()