Coverage for tests / test_isolated_source.py: 18%

73 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-22 09:11 +0000

1# This file is part of lsst.scarlet.lite. 

2# 

3# Developed for the LSST Data Management System. 

4# (https://www.lsst.org). 

5# See the COPYRIGHT file at the top-level directory of this distribution 

6# for details of code ownership. 

7# 

8# This program is free software: you can redistribute it and/or modify 

9# it under the terms of the GNU General Public License as published by 

10# the Free Software Foundation, either version 3 of the License, or 

11# (at your option) any later version. 

12# 

13# This program is distributed in the hope that it will be useful, 

14# but WITHOUT ANY WARRANTY; without even the implied warranty of 

15# This product includes software developed by the LSST Project 

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 

22from unittest import TestCase 

23 

24import numpy as np 

25 

26import lsst.meas.extensions.scarlet as mes 

27import lsst.scarlet.lite as scl 

28 

29 

30class ScarletTestCase(TestCase): 

31 """A base TestCase for scarlet tests. 

32 """ 

33 def setUp(self) -> None: 

34 super().setUp() 

35 self.bands = tuple("grizy") 

36 peak = (27, 32) 

37 bbox = scl.Box((15, 15), (20, 25)) 

38 morph = scl.utils.integrated_circular_gaussian(sigma=0.8).astype(np.float32) 

39 spectrum = np.arange(5, dtype=np.float32) 

40 model = morph[None, :, :] * spectrum[:, None, None] 

41 model_image = scl.Image(model, yx0=bbox.origin, bands=self.bands) 

42 self.component = scl.component.CubeComponent(model=model_image, peak=peak) 

43 

44 def test_constructor(self): 

45 source = mes.source.IsolatedSource( 

46 model=self.component._model, 

47 peak=self.component.peak, 

48 ) 

49 

50 np.testing.assert_array_equal( 

51 source.component._model.data, 

52 self.component._model.data, 

53 ) 

54 self.assertEqual(source.component.peak, self.component.peak) 

55 

56 def test_copy(self): 

57 source = mes.source.IsolatedSource( 

58 model=self.component._model, 

59 peak=self.component.peak, 

60 ) 

61 source_copy = source.copy() 

62 

63 self.assertIsNot(source_copy, source) 

64 self.assertIs( 

65 source_copy.component._model.data, 

66 source.component._model.data, 

67 ) 

68 self.assertEqual(source_copy.component.peak, source.component.peak) 

69 

70 def test_deep_copy(self): 

71 source = mes.source.IsolatedSource( 

72 model=self.component._model, 

73 peak=self.component.peak, 

74 ) 

75 source_copy = source.copy(deep=True) 

76 

77 self.assertTupleEqual(source_copy.component.peak, source.component.peak) 

78 

79 np.testing.assert_array_equal( 

80 source_copy.component._model.data, 

81 source.component._model.data, 

82 ) 

83 self.assertIsNot( 

84 source_copy.component._model.data, 

85 source.component._model.data, 

86 ) 

87 

88 with self.assertRaises(AssertionError): 

89 source_copy.component._model._data -= 1 

90 np.testing.assert_array_equal( 

91 source_copy.component._model.data, 

92 source.component._model.data, 

93 ) 

94 

95 def test_slice(self): 

96 source = mes.source.IsolatedSource(self.component._model, self.component.peak) 

97 source_sliced = source["g":"r"] 

98 self.assertTupleEqual(source_sliced.bands, ("g", "r")) 

99 np.testing.assert_array_equal( 

100 source_sliced.get_model().data, 

101 source.get_model().data[:2], 

102 ) 

103 

104 def test_reorder(self): 

105 source = mes.source.IsolatedSource(self.component._model, self.component.peak) 

106 indices = ("i", "g", "r") 

107 source_reordered = source[indices] 

108 self.assertTupleEqual(source_reordered.bands, indices) 

109 np.testing.assert_array_equal( 

110 source_reordered.get_model().data, 

111 source.get_model().data[[2, 0, 1]], 

112 ) 

113 

114 source_reordered = source["igr"] 

115 self.assertTupleEqual(source_reordered.bands, indices) 

116 np.testing.assert_array_equal( 

117 source_reordered.get_model().data, 

118 source.get_model().data[[2, 0, 1]], 

119 ) 

120 

121 def test_subset(self): 

122 source = mes.source.IsolatedSource(self.component._model, self.component.peak) 

123 source_subset = source[("r",)] 

124 self.assertTupleEqual(source_subset.bands, ("r",)) 

125 np.testing.assert_array_equal( 

126 source_subset.get_model().data, 

127 source.get_model().data[1:2], 

128 ) 

129 

130 def test_indexing_errors(self): 

131 source = mes.source.IsolatedSource(self.component._model, self.component.peak) 

132 with self.assertRaises(IndexError): 

133 # "x" is not an a band in the model 

134 source["x"] 

135 

136 with self.assertRaises(IndexError): 

137 # "x" is not an a band in the model 

138 source["r":"x"] 

139 

140 with self.assertRaises(IndexError): 

141 # "x" is not an a band in the model 

142 source["x":"i"] 

143 

144 with self.assertRaises(IndexError): 

145 # "x" is not an a band in the model 

146 source["g", "x", "i"] 

147 

148 with self.assertRaises(IndexError): 

149 # The box doesn't overlap with the model 

150 source[scl.Box((0, 0), (10, 10))] 

151 

152 with self.assertRaises(IndexError): 

153 # Users must provide a Box, not a tuple, for spatial dimensions 

154 source[:, 10:20, 10:20] 

155 

156 with self.assertRaises(IndexError): 

157 # Users must provide a Box, not a slice, for spatial dimensions 

158 source[1:] 

159 

160 with self.assertRaises(IndexError): 

161 # Users must provide a Box, not an int, for spatial dimensions 

162 source[1] 

163 

164 with self.assertRaises(IndexError): 

165 # Users must provide a Box, not a tuple, for spatial dimensions 

166 source[0, 1]