Coverage for tests/test_measureApCorr.py: 19%

150 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-11 01:39 -0700

1# 

2# LSST Data Management System 

3# 

4# Copyright 2008-2016 AURA/LSST. 

5# 

6# This product includes software developed by the 

7# LSST Project (http://www.lsst.org/). 

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 LSST License Statement and 

20# the GNU General Public License along with this program. If not, 

21# see <https://www.lsstcorp.org/LegalNotices/>. 

22# 

23import unittest 

24import numpy as np 

25 

26import lsst.geom 

27import lsst.afw.image as afwImage 

28import lsst.afw.table as afwTable 

29from lsst.afw.math import ChebyshevBoundedField 

30import lsst.pex.config 

31import lsst.meas.algorithms.measureApCorr as measureApCorr 

32from lsst.meas.base.apCorrRegistry import addApCorrName 

33import lsst.meas.base.tests 

34import lsst.utils.tests 

35 

36 

37def apCorrDefaultMap(value=None, bbox=None): 

38 default_coefficients = np.ones((1, 1), dtype=float) 

39 default_coefficients /= value 

40 default_apCorrMap = ChebyshevBoundedField(bbox, default_coefficients) 

41 default_fill = afwImage.ImageF(bbox) 

42 default_apCorrMap.fillImage(default_fill) 

43 return(default_fill) 

44 

45 

46class MeasureApCorrTestCase(lsst.meas.base.tests.AlgorithmTestCase, lsst.utils.tests.TestCase): 

47 

48 def makeCatalog(self, apCorrScale=1.0, numSources=5): 

49 sourceCat = afwTable.SourceCatalog(self.schema) 

50 inputFilterFlagKey = self.schema.find(self.meas_apCorr_task.config.sourceSelector.active.field).key 

51 

52 centroidKey = afwTable.Point2DKey(self.schema["slot_Centroid"]) 

53 x = np.random.rand(numSources)*self.exposure.getWidth() + self.exposure.getX0() 

54 y = np.random.rand(numSources)*self.exposure.getHeight() + self.exposure.getY0() 

55 for _i in range(numSources): 

56 source_test_instFlux = 5.1 

57 source_test_centroid = lsst.geom.Point2D(x[_i], y[_i]) 

58 source = sourceCat.addNew() 

59 source.set(centroidKey, source_test_centroid) 

60 source.set(inputFilterFlagKey, True) 

61 

62 for name in self.names: 

63 fluxName = name + "_instFlux" 

64 flagName = name + "_flag" 

65 fluxErrName = name + "_instFluxErr" 

66 apFluxName = name + self.apNameStr + "_instFlux" 

67 apFlagName = name + self.apNameStr + "_flag" 

68 apFluxErrName = name + self.apNameStr + "_instFluxErr" 

69 fluxKey = self.schema.find(fluxName).key 

70 flagKey = self.schema.find(flagName).key 

71 fluxErrKey = self.schema.find(fluxErrName).key 

72 apFluxKey = self.schema.find(apFluxName).key 

73 apFlagKey = self.schema.find(apFlagName).key 

74 apFluxErrKey = self.schema.find(apFluxErrName).key 

75 for source in sourceCat: 

76 source.set(fluxKey, source_test_instFlux) 

77 source.set(apFluxKey, source_test_instFlux * apCorrScale) 

78 source.set(fluxErrKey, 0.) 

79 source.set(apFluxErrKey, 0.) 

80 source.set(flagKey, False) 

81 source.set(apFlagKey, False) 

82 return(sourceCat) 

83 

84 def setUp(self): 

85 schema = afwTable.SourceTable.makeMinimalSchema() 

86 apNameStr = "Ap" 

87 calib_flag_name = "cal_source_use" 

88 # Add fields in anti-sorted order to try to impose a need for sorting 

89 # in the addition of the apCorr fields (may happen by fluke, but this 

90 # is the best we can do to test this here. 

91 names = ["test2", "test1"] 

92 for name in names: 

93 apName = name + apNameStr 

94 addApCorrName(apName) 

95 schema.addField(name + "_instFlux", type=float) 

96 schema.addField(name + "_instFluxErr", type=float) 

97 schema.addField(name + "_flag", type="Flag") 

98 schema.addField(apName + "_instFlux", type=float) 

99 schema.addField(apName + "_instFluxErr", type=float) 

100 schema.addField(apName + "_flag", type="Flag") 

101 schema.addField(names[0] + "_Centroid_x", type=float) 

102 schema.addField(names[0] + "_Centroid_y", type=float) 

103 schema.getAliasMap().set("slot_Centroid", names[0] + "_Centroid") 

104 schema.addField(calib_flag_name, type="Flag") 

105 config = measureApCorr.MeasureApCorrTask.ConfigClass() 

106 config.refFluxName = names[0] 

107 config.sourceSelector.active.field = calib_flag_name 

108 self.meas_apCorr_task = measureApCorr.MeasureApCorrTask(schema=schema, config=config) 

109 self.names = names 

110 self.apNameStr = apNameStr 

111 self.schema = schema 

112 self.exposure = lsst.afw.image.ExposureF(10, 10) 

113 

114 def tearDown(self): 

115 del self.schema 

116 del self.meas_apCorr_task 

117 del self.exposure 

118 

119 def testAddFields(self): 

120 """Instantiating the task should add one field to the schema.""" 

121 for name in self.names: 

122 self.assertIn("apcorr_" + name + self.apNameStr + "_used", self.schema.getNames()) 

123 sortedNames = sorted(self.names) 

124 key0 = self.schema.find("apcorr_" + sortedNames[0] + self.apNameStr + "_used").key 

125 key1 = self.schema.find("apcorr_" + sortedNames[1] + self.apNameStr + "_used").key 

126 # Check that the apCorr fields were added in a sorted order (not 

127 # foolproof as this could have happened by fluke, but it's the best 

128 # we can do to test this here (having added the two fields in an anti- 

129 # sorted order). 

130 self.assertLess(key0.getOffset() + key0.getBit(), key1.getOffset() + key1.getBit()) 

131 

132 def testReturnApCorrMap(self): 

133 """The measureApCorr task should return a structure with a single key 'apCorrMap'.""" 

134 struct = self.meas_apCorr_task.run(catalog=self.makeCatalog(), exposure=self.exposure) 

135 self.assertEqual(list(struct.getDict().keys()), ['apCorrMap']) 

136 

137 def testApCorrMapKeys(self): 

138 """An apCorrMap structure should have two keys per name supplied to addApCorrName().""" 

139 key_names = [] 

140 for name in self.names: 

141 apFluxName = name + self.apNameStr + "_instFlux" 

142 apFluxErrName = name + self.apNameStr + "_instFluxErr" 

143 struct = self.meas_apCorr_task.run(catalog=self.makeCatalog(), exposure=self.exposure) 

144 key_names.append(apFluxName) 

145 key_names.append(apFluxErrName) 

146 self.assertEqual(set(struct.apCorrMap.keys()), set(key_names)) 

147 

148 def testTooFewSources(self): 

149 """ If there are too few sources, check that an exception is raised.""" 

150 catalog = afwTable.SourceCatalog(self.schema) 

151 with self.assertRaises(RuntimeError): 

152 self.meas_apCorr_task.run(catalog=catalog, exposure=self.exposure) 

153 # With the measurement algorithm declared as something that might fail, should not get an exception 

154 for name in self.names: 

155 self.meas_apCorr_task.config.allowFailure.append(name + self.apNameStr) 

156 self.meas_apCorr_task.run(catalog=catalog, exposure=self.exposure) 

157 

158 def testSourceNotUsed(self): 

159 """ Check that a source outside the bounding box is flagged as not used (False).""" 

160 fluxName = self.names[0] + "_instFlux" 

161 apCorrFlagKey = self.schema.find("apcorr_" + self.names[0] + "_used").key 

162 sourceCat = self.makeCatalog() 

163 source = sourceCat.addNew() 

164 source_test_instFlux = 5.1 

165 source_test_centroid = lsst.geom.Point2D(15, 7.1) 

166 fluxKey = self.schema.find(fluxName).key 

167 centroidKey = afwTable.Point2DKey(self.schema["slot_Centroid"]) 

168 source.set(fluxKey, source_test_instFlux) 

169 source.set(centroidKey, source_test_centroid) 

170 self.meas_apCorr_task.run(catalog=sourceCat, exposure=self.exposure) 

171 self.assertFalse(sourceCat[apCorrFlagKey][-1]) 

172 

173 def testSourceUsed(self): 

174 """Check that valid sources inside the bounding box that are used have their flags set to True.""" 

175 inputFilterFlagKey = self.schema.find(self.meas_apCorr_task.config.sourceSelector.active.field).key 

176 sourceCat = self.makeCatalog() 

177 self.meas_apCorr_task.run(catalog=sourceCat, exposure=self.exposure) 

178 self.assertTrue(sourceCat[inputFilterFlagKey].all()) 

179 

180 def testApertureMeasOnes(self): 

181 """ Check that sources with aperture fluxes exactly the same as their catalog fluxes 

182 returns an aperture correction map of 1s""" 

183 apFluxName = self.names[0] + self.apNameStr + "_instFlux" 

184 sourceCat = self.makeCatalog() 

185 struct = self.meas_apCorr_task.run(catalog=sourceCat, exposure=self.exposure) 

186 default_fill = apCorrDefaultMap(value=1.0, bbox=self.exposure.getBBox()) 

187 test_fill = afwImage.ImageF(self.exposure.getBBox()) 

188 struct.apCorrMap[apFluxName].fillImage(test_fill) 

189 np.testing.assert_allclose(test_fill.getArray(), default_fill.getArray()) 

190 

191 def testApertureMeasTens(self): 

192 """Check that aperture correction scales source fluxes in the correct direction.""" 

193 apCorr_factor = 10. 

194 sourceCat = self.makeCatalog(apCorrScale=apCorr_factor) 

195 apFluxName = self.names[0] + self.apNameStr + "_instFlux" 

196 struct = self.meas_apCorr_task.run(catalog=sourceCat, exposure=self.exposure) 

197 default_fill = apCorrDefaultMap(value=apCorr_factor, bbox=self.exposure.getBBox()) 

198 test_fill = afwImage.ImageF(self.exposure.getBBox()) 

199 struct.apCorrMap[apFluxName].fillImage(test_fill) 

200 np.testing.assert_allclose(test_fill.getArray(), default_fill.getArray()) 

201 

202 

203class TestMemory(lsst.utils.tests.MemoryTestCase): 

204 pass 

205 

206 

207def setup_module(module): 

208 lsst.utils.tests.init() 

209 

210 

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

212 lsst.utils.tests.init() 

213 unittest.main()