Coverage for tests/test_stamps.py: 22%
118 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-27 02:15 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-27 02:15 -0700
1# This file is part of meas_algorithms.
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
23import numpy as np
24import tempfile
25import os
27from lsst.meas.algorithms import stamps
28from lsst.afw import image as afwImage
29from lsst.afw.geom.testUtils import TransformTestBaseClass
30from lsst.daf.base import PropertyList
31import lsst.geom as geom
32import lsst.afw.geom.transformFactory as tF
33import lsst.utils.tests
35np.random.seed(90210)
38def make_stamps(n_stamps=3, use_archive=False):
39 stampSize = 25
40 # create dummy stamp stamps
41 stampImages = [afwImage.maskedImage.MaskedImageF(stampSize, stampSize)
42 for _ in range(n_stamps)]
43 for stampIm in stampImages:
44 stampImArray = stampIm.image.array
45 stampImArray += np.random.rand(stampSize, stampSize)
46 stampMaskArray = stampIm.mask.array
47 stampMaskArray += 10
48 stampVarArray = stampIm.variance.array
49 stampVarArray += 1000.
50 ras = np.random.rand(n_stamps)*360.
51 decs = np.random.rand(n_stamps)*180 - 90
52 archive_elements = [tF.makeTransform(geom.AffineTransform(np.random.rand(2))) if use_archive else None
53 for _ in range(n_stamps)]
54 stamp_list = [stamps.Stamp(stamp_im=stampIm,
55 position=geom.SpherePoint(geom.Angle(ra, geom.degrees),
56 geom.Angle(dec, geom.degrees)),
57 archive_element=ae)
58 for stampIm, ra, dec, ae in zip(stampImages, ras, decs, archive_elements)]
59 metadata = PropertyList()
60 metadata['RA_DEG'] = ras
61 metadata['DEC_DEG'] = decs
63 return stamps.Stamps(stamp_list, metadata=metadata, use_archive=True)
66class TransformTestClass(TransformTestBaseClass):
67 """Class for unit tests for Transform<X>To<Y> within meas_algorithms.
69 Inherits from `lsst.afw.geom.testUtils.TransformTestBaseClass`.
70 """
71 def getTestDir(self):
72 """Returns the test directory of the `meas_algorithms` package.
74 If a similar test is needed in another package, inherit from
75 `TransformTestBaseClass` and overwrite this method; see the docstrings
76 in the parent class.
77 """
78 return os.path.join(lsst.utils.getPackageDir("meas_algorithms"), "tests")
81class StampsBaseTestCase(lsst.utils.tests.TestCase):
82 """Test StampsBase.
83 """
84 def testReadFitsWithOptionsNotImplementedErrorRaised(self):
85 """
86 Test that subclasses have their own version
87 of this implemented or an error is raised.
88 """
89 class FakeStampsBase(stamps.StampsBase):
90 def __init__(self):
91 return
93 with self.assertRaises(NotImplementedError):
94 FakeStampsBase.readFitsWithOptions('noFile', {})
96 def testReadFitsWithOptionsMetadataError(self):
97 """Test that error is raised when STAMPCLS returns None
98 """
99 with tempfile.NamedTemporaryFile() as f:
100 ss = make_stamps()
101 emptyMetadata = PropertyList()
102 stamps.writeFits(
103 f.name, [ss[0]], emptyMetadata, None, True, True
104 )
105 with self.assertRaises(RuntimeError):
106 stamps.StampsBase.readFits(f.name)
108 def testReadFitsReturnsNewClass(self):
109 """Test that readFits will return subclass
110 """
111 class FakeStampsBase(stamps.StampsBase):
112 def __init__(self):
113 self._metadata = {}
114 return
116 @classmethod
117 def readFitsWithOptions(cls, filename, options):
118 return cls()
120 def _refresh_metadata(self):
121 self._metadata = {}
123 fakeStamps = FakeStampsBase.readFitsWithOptions('noFile', {})
124 self.assertEqual(type(fakeStamps), FakeStampsBase)
127class StampsTestCase(lsst.utils.tests.TestCase):
128 """Test Stamps.
129 """
130 def testAppend(self):
131 """Test ability to append to a Stamps object
132 """
133 ss = make_stamps()
134 s = ss[-1]
135 ss.append(s)
136 self.roundtrip(ss)
137 # check if appending something other than a Stamp raises
138 with self.assertRaises(ValueError):
139 ss.append('hello world')
141 def testExtend(self):
142 ss = make_stamps()
143 ss2 = make_stamps()
144 ss.extend([s for s in ss2])
145 # check if extending with something other than a Stamps
146 # object raises
147 with self.assertRaises(ValueError):
148 ss.extend(['hello', 'world'])
150 def testIO(self):
151 """Test the class' write and readFits methods.
152 """
153 self.roundtrip(make_stamps())
155 def testIOone(self):
156 """Test the class' write and readFits methods for the special case of
157 one stamp.
158 """
159 self.roundtrip(make_stamps(1))
161 def testIOsub(self):
162 """Test the class' write and readFits when passing on a bounding box.
163 """
164 bbox = geom.Box2I(geom.Point2I(3, 9), geom.Extent2I(11, 7))
165 ss = make_stamps()
166 with tempfile.NamedTemporaryFile() as f:
167 ss.writeFits(f.name)
168 options = {'bbox': bbox}
169 subStamps = stamps.Stamps.readFitsWithOptions(f.name, options)
170 for s1, s2 in zip(ss, subStamps):
171 self.assertEqual(bbox.getDimensions(), s2.stamp_im.getDimensions())
172 self.assertMaskedImagesAlmostEqual(s1.stamp_im[bbox], s2.stamp_im)
174 def testIOarchive(self):
175 """Test the class' write and readFits when Stamps contain Persistables.
176 """
177 self.roundtripWithArchive(make_stamps(use_archive=True))
179 def roundtrip(self, ss):
180 """Round trip a Stamps object to disk and check values
181 """
182 with tempfile.NamedTemporaryFile() as f:
183 ss.writeFits(f.name)
184 options = PropertyList()
185 ss2 = stamps.Stamps.readFitsWithOptions(f.name, options)
186 self.assertEqual(len(ss), len(ss2))
187 for s1, s2 in zip(ss, ss2):
188 self.assertMaskedImagesAlmostEqual(s1.stamp_im, s2.stamp_im)
189 self.assertAlmostEqual(s1.position.getRa().asDegrees(),
190 s2.position.getRa().asDegrees())
191 self.assertAlmostEqual(s1.position.getDec().asDegrees(),
192 s2.position.getDec().asDegrees())
194 def roundtripWithArchive(self, ss):
195 """Round trip a Stamps object, including Archive elements, and check values
196 """
197 transformTest = TransformTestClass()
198 with tempfile.NamedTemporaryFile() as f:
199 ss.writeFits(f.name)
200 options = PropertyList()
201 ss2 = stamps.Stamps.readFitsWithOptions(f.name, options)
202 self.assertEqual(len(ss), len(ss2))
203 for s1, s2 in zip(ss, ss2):
204 self.assertMaskedImagesAlmostEqual(s1.stamp_im, s2.stamp_im)
205 self.assertAlmostEqual(s1.position.getRa().asDegrees(),
206 s2.position.getRa().asDegrees())
207 self.assertAlmostEqual(s1.position.getDec().asDegrees(),
208 s2.position.getDec().asDegrees())
209 transformTest.assertTransformsEqual(s1.archive_element, s2.archive_element)
212class MemoryTester(lsst.utils.tests.MemoryTestCase):
213 pass
216def setup_module(module):
217 lsst.utils.tests.init()
220if __name__ == "__main__": 220 ↛ 221line 220 didn't jump to line 221, because the condition on line 220 was never true
221 lsst.utils.tests.init()
222 unittest.main()