Coverage for tests/test_stamps.py: 25%

118 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-03 08:48 +0000

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/>. 

21 

22import unittest 

23import numpy as np 

24import tempfile 

25import os 

26 

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 

34 

35np.random.seed(90210) 

36 

37 

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 

62 

63 return stamps.Stamps(stamp_list, metadata=metadata, use_archive=True) 

64 

65 

66class TransformTestClass(TransformTestBaseClass): 

67 """Class for unit tests for Transform<X>To<Y> within meas_algorithms. 

68 

69 Inherits from `lsst.afw.geom.testUtils.TransformTestBaseClass`. 

70 """ 

71 def getTestDir(self): 

72 """Returns the test directory of the `meas_algorithms` package. 

73 

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") 

79 

80 

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 

92 

93 with self.assertRaises(NotImplementedError): 

94 FakeStampsBase.readFitsWithOptions('noFile', {}) 

95 

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) 

107 

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 

115 

116 @classmethod 

117 def readFitsWithOptions(cls, filename, options): 

118 return cls() 

119 

120 def _refresh_metadata(self): 

121 self._metadata = {} 

122 

123 fakeStamps = FakeStampsBase.readFitsWithOptions('noFile', {}) 

124 self.assertEqual(type(fakeStamps), FakeStampsBase) 

125 

126 

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') 

140 

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']) 

149 

150 def testIO(self): 

151 """Test the class' write and readFits methods. 

152 """ 

153 self.roundtrip(make_stamps()) 

154 

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)) 

160 

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) 

173 

174 def testIOarchive(self): 

175 """Test the class' write and readFits when Stamps contain Persistables. 

176 """ 

177 self.roundtripWithArchive(make_stamps(use_archive=True)) 

178 

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()) 

193 

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) 

210 

211 

212class MemoryTester(lsst.utils.tests.MemoryTestCase): 

213 pass 

214 

215 

216def setup_module(module): 

217 lsst.utils.tests.init() 

218 

219 

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()