Coverage for tests/test_RBTransiNetTask.py: 97%

94 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-21 09:18 +0000

1# This file is part of meas_transiNet. 

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 

24 

25import lsst.afw.table 

26from lsst.geom import Extent2I, Point2I, Point2D, Box2I 

27from lsst.images import Image 

28import lsst.meas.base.tests 

29import lsst.utils.tests 

30 

31from lsst.meas.transiNet import RBTransiNetTask 

32 

33 

34class TestRBTransiNetTask(lsst.utils.tests.TestCase): 

35 def create_sample_datasets(self): 

36 bbox = Box2I(Point2I(0, 0), Point2I(400, 400)) 

37 dataset = lsst.meas.base.tests.TestDataset(bbox) 

38 dataset.addSource(5000, Point2D(50, 50.)) 

39 # TODO: make one of these centered in a different corner of the pixel, 

40 # to test that the cutout is properly centered. 

41 dataset.addSource(10000, Point2D(100, 50.)) 

42 dataset.addSource(20000, Point2D(1, 1)) # close-to-border source 

43 self.exposure, self.catalog = dataset.realize(10.0, dataset.makeMinimalSchema()) 

44 self.image = Image.from_legacy(self.exposure.image) 

45 

46 def setUp(self): 

47 self.create_sample_datasets() 

48 

49 # Task configuration 

50 self.config = RBTransiNetTask.ConfigClass() 

51 self.config.modelPackageName = "dummy" 

52 self.config.modelPackageStorageMode = "local" 

53 self.config.cutoutSize = 256 

54 

55 def test_make_cutouts(self): 

56 task = RBTransiNetTask(config=self.config) 

57 for record in self.catalog: 

58 result = task._make_cutouts(self.image, self.image, self.image, record) 

59 self._check_cutout(result.science, task.config.cutoutSize) 

60 self._check_cutout(result.template, task.config.cutoutSize) 

61 self._check_cutout(result.difference, task.config.cutoutSize) 

62 

63 if record.getX() == 1 and record.getY() == 1: # This is the "border"-source 

64 self._check_empty_cutout(result.science) 

65 self._check_empty_cutout(result.template) 

66 self._check_empty_cutout(result.difference) 

67 

68 def test_cutout_pixels(self): 

69 """Test that a cutout holds the pixels of an afw cutout of the same 

70 box. 

71 """ 

72 self.config.cutoutSize = 51 

73 task = RBTransiNetTask(config=self.config) 

74 record = self.catalog[0] 

75 box = Box2I.makeCenteredBox(record.getCentroid(), Extent2I(self.config.cutoutSize)) 

76 science = self.exposure.image 

77 template = self.exposure.image.clone() 

78 template *= 2. 

79 difference = self.exposure.image.clone() 

80 difference *= 3. 

81 scienceCutout = self.exposure.image.Factory(science, box).array 

82 templateCutout = self.exposure.image.Factory(template, box).array 

83 differenceCutout = self.exposure.image.Factory(difference, box).array 

84 result = task._make_cutouts(Image.from_legacy(template), 

85 Image.from_legacy(science), 

86 Image.from_legacy(difference), 

87 record) 

88 np.testing.assert_array_equal(result.science, scienceCutout) 

89 np.testing.assert_array_equal(result.template, templateCutout) 

90 np.testing.assert_array_equal(result.difference, differenceCutout) 

91 

92 def test_connections(self): 

93 """Test that the image inputs read the image component as 

94 ``ImageV2``. 

95 """ 

96 config = RBTransiNetTask.ConfigClass() 

97 connections = config.connections.ConnectionsClass(config=config) 

98 self.assertEqual(connections.science.name, "calexp.image") 

99 self.assertEqual(connections.template.name, "deepDiff_templateExp.image") 

100 self.assertEqual(connections.difference.name, "deepDiff_differenceExp.image") 

101 for name in ("science", "template", "difference"): 

102 self.assertEqual(getattr(connections, name).storageClass, "ImageV2") 

103 

104 def _check_cutout(self, image, size): 

105 """Test that the image cutout was made correctly. 

106 

107 Parameters 

108 ---------- 

109 image : `np.ndarray` (N, 2) 

110 Square cutout made from image. 

111 size : `int` 

112 Expected size of the cutout. 

113 """ 

114 self.assertEqual(image.shape, (size, size)) 

115 return 

116 

117 # TODO: below test should be removed/fixed -- disabled for now. 

118 # It only passes with very specific cutout dimensions and in 

119 # very specific configurations. 

120 # See https://jira.lsstcorp.org/browse/DM-35635 for more info. 

121 

122 max_index = np.unravel_index(image.argmax(), image.shape) 

123 # TODO: I'm not comfortable with this particular test: the exact 

124 # position of the max pixel depends on where in that pixel the 

125 # centroid is. We can assume Box2I.makeCenteredBox works correctly... 

126 self.assertEqual(max_index, ((size/2)-1, (size/2)-1)) 

127 

128 def _check_empty_cutout(self, cutout): 

129 """Test that the cutout is empty. 

130 

131 Parameters 

132 ---------- 

133 cutout : `np.ndarray` (N, 2) 

134 Square cutout made from image. 

135 """ 

136 np.testing.assert_array_equal(cutout, np.zeros_like(cutout)) 

137 

138 def test_run(self): 

139 """Test that run passes an appropriate object to the interface. 

140 """ 

141 task = RBTransiNetTask(config=self.config) 

142 result = task.run(self.image, self.image, self.image, self.catalog) 

143 self.assertIsInstance(result.classifications, lsst.afw.table.BaseCatalog) 

144 np.testing.assert_array_equal(self.catalog["id"], result.classifications["id"]) 

145 np.testing.assert_equal("0.0", result.classifications[0]["version"]) 

146 

147 def test_config_butlerblock(self): 

148 config = RBTransiNetTask.ConfigClass() 

149 config.modelPackageName = "dummy" 

150 config.modelPackageStorageMode = "butler" 

151 with self.assertRaises(ValueError): 

152 config.validate() 

153 

154 def test_config_butlerpass_none(self): 

155 config = RBTransiNetTask.ConfigClass() 

156 config.modelPackageName = None 

157 config.modelPackageStorageMode = "butler" 

158 # Should not raise 

159 config.validate() 

160 

161 def test_config_butlerblock_empty(self): 

162 config = RBTransiNetTask.ConfigClass() 

163 config.modelPackageName = "" # Want *only* None for butler packages 

164 config.modelPackageStorageMode = "butler" 

165 with self.assertRaises(ValueError): 

166 config.validate() 

167 

168 

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

170 pass 

171 

172 

173def setup_module(module): 

174 lsst.utils.tests.init() 

175 

176 

177if __name__ == "__main__": 177 ↛ 178line 177 didn't jump to line 178 because the condition on line 177 was never true

178 lsst.utils.tests.init() 

179 unittest.main()