Coverage for tests/test_generalShapeletPsfApproxPlugins.py: 19%

161 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-18 02:35 -0800

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 

25import os 

26 

27import lsst.utils.tests 

28import lsst.shapelet 

29import lsst.geom 

30import lsst.afw.geom.ellipses 

31import lsst.afw.table 

32import lsst.afw.detection 

33import lsst.log 

34import lsst.utils.logging 

35import lsst.meas.modelfit 

36import lsst.meas.base 

37import lsst.meas.algorithms 

38 

39# Set trace to 0-5 to view debug messages. Level 5 enables all traces. 

40lsst.utils.logging.trace_set_at("lsst.meas.modelfit.optimizer.Optimizer", -1) 

41lsst.utils.logging.trace_set_at("lsst.meas.modelfit.optimizer.solveTrustRegion", -1) 

42 

43 

44class GeneralShapeletPsfApproxPluginsTestCase(lsst.utils.tests.TestCase): 

45 

46 def makeBlankConfig(self): 

47 config = lsst.meas.base.SingleFrameMeasurementTask.ConfigClass() 

48 config.slots.centroid = None 

49 config.slots.shape = None 

50 config.slots.psfFlux = None 

51 config.slots.apFlux = None 

52 config.slots.gaussianFlux = None 

53 config.slots.modelFlux = None 

54 config.slots.calibFlux = None 

55 config.doReplaceWithNoise = False 

56 return config 

57 

58 def setUp(self): 

59 numpy.random.seed(500) 

60 self.psfSigma = 2.0 

61 self.exposure = lsst.afw.image.ExposureF(41, 41) 

62 self.psf = lsst.afw.detection.GaussianPsf(19, 19, self.psfSigma) 

63 self.schema = lsst.afw.table.SourceTable.makeMinimalSchema() 

64 self.centroidKey = lsst.afw.table.Point2DKey.addFields(self.schema, "centroid", "centroid", "pixel") 

65 self.schema.getAliasMap().set("slot_Centroid", "centroid") 

66 self.psfDir = os.path.join(os.environ["MEAS_MODELFIT_DIR"], "tests", "data", "psfs") 

67 

68 def tearDown(self): 

69 del self.exposure 

70 del self.psf 

71 del self.schema 

72 del self.centroidKey 

73 del self.psfDir 

74 

75 def checkResult(self, msf): 

76 # Because we're fitting multiple shapelets to a single Gaussian (a single 0th-order shapelet) 

77 # we should be able to fit with zero residuals, aside from (single-precision) round-off error. 

78 pos = self.exposure.getPsf().getAveragePosition() 

79 dataImage = self.exposure.getPsf().computeImage(pos) 

80 modelImage = dataImage.Factory(dataImage.getBBox()) 

81 modelImage.getArray()[:, :] *= -1 

82 msf.evaluate().addToImage(modelImage) 

83 self.assertFloatsAlmostEqual(dataImage.getArray(), modelImage.getArray(), atol=1E-6, 

84 plotOnFailure=False) 

85 

86 def testSingleFrame(self): 

87 self.exposure.setPsf(self.psf) 

88 config = self.makeBlankConfig() 

89 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"] 

90 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["SingleGaussian"] 

91 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema) 

92 measCat = lsst.afw.table.SourceCatalog(self.schema) 

93 measRecord = measCat.addNew() 

94 measRecord.set(self.centroidKey, lsst.geom.Point2D(20.0, 20.0)) 

95 task.run(measCat, self.exposure) 

96 keySingleGaussian = lsst.shapelet.MultiShapeletFunctionKey( 

97 self.schema["modelfit"]["GeneralShapeletPsfApprox"]["SingleGaussian"] 

98 ) 

99 msfSingleGaussian = measRecord.get(keySingleGaussian) 

100 self.assertEqual(len(msfSingleGaussian.getComponents()), 1) 

101 self.checkResult(msfSingleGaussian) 

102 

103 def testForced(self): 

104 self.exposure.setPsf(self.psf) 

105 config = lsst.meas.base.ForcedMeasurementTask.ConfigClass() 

106 config.slots.centroid = "base_TransformedCentroid" 

107 config.slots.shape = None 

108 config.slots.psfFlux = None 

109 config.slots.apFlux = None 

110 config.slots.gaussianFlux = None 

111 config.slots.modelFlux = None 

112 config.doReplaceWithNoise = False 

113 config.slots.centroid = "base_TransformedCentroid" 

114 config.plugins.names = ["base_TransformedCentroid", "modelfit_GeneralShapeletPsfApprox"] 

115 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["SingleGaussian"] 

116 config.copyColumns = {"id": "objectId", "parent": "parentObjectId"} 

117 refCat = lsst.afw.table.SourceCatalog(self.schema) 

118 refRecord = refCat.addNew() 

119 refRecord.set(self.centroidKey, lsst.geom.Point2D(20.0, 20.0)) 

120 refWcs = self.exposure.getWcs() # same as measurement Wcs 

121 task = lsst.meas.base.ForcedMeasurementTask(config=config, refSchema=self.schema) 

122 measCat = task.generateMeasCat(self.exposure, refCat, refWcs) 

123 task.run(measCat, self.exposure, refCat, refWcs) 

124 measRecord = measCat[0] 

125 measSchema = measCat.schema 

126 keySingleGaussian = lsst.shapelet.MultiShapeletFunctionKey( 

127 measSchema["modelfit"]["GeneralShapeletPsfApprox"]["SingleGaussian"] 

128 ) 

129 msfSingleGaussian = measRecord.get(keySingleGaussian) 

130 self.assertEqual(len(msfSingleGaussian.getComponents()), 1) 

131 self.checkResult(msfSingleGaussian) 

132 

133 def testNanFlag(self): 

134 config = self.makeBlankConfig() 

135 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"] 

136 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"] 

137 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema) 

138 measCat = lsst.afw.table.SourceCatalog(self.schema) 

139 measRecord = measCat.addNew() 

140 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits")) 

141 psfImage.getArray()[0, 0] = numpy.nan 

142 psfImage.setXY0(lsst.geom.Point2I(0, 0)) 

143 kernel = lsst.afw.math.FixedKernel(psfImage) 

144 psf = lsst.meas.algorithms.KernelPsf(kernel) 

145 self.exposure.setPsf(psf) 

146 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2) 

147 measRecord.set(self.centroidKey, center) 

148 task.run(measCat, self.exposure) 

149 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag")) 

150 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan")) 

151 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations")) 

152 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations")) 

153 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception")) 

154 

155 def testInnerIterationsFlag(self): 

156 config = self.makeBlankConfig() 

157 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"] 

158 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"] 

159 config.plugins["modelfit_GeneralShapeletPsfApprox"].models["Full"].optimizer.maxInnerIterations = 1 

160 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema) 

161 measCat = lsst.afw.table.SourceCatalog(self.schema) 

162 measRecord = measCat.addNew() 

163 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits")) 

164 psfImage.setXY0(lsst.geom.Point2I(0, 0)) 

165 kernel = lsst.afw.math.FixedKernel(psfImage) 

166 psf = lsst.meas.algorithms.KernelPsf(kernel) 

167 self.exposure.setPsf(psf) 

168 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2) 

169 measRecord.set(self.centroidKey, center) 

170 task.run(measCat, self.exposure) 

171 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag")) 

172 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan")) 

173 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations")) 

174 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations")) 

175 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception")) 

176 

177 def testOuterIterationsFlag(self): 

178 config = self.makeBlankConfig() 

179 config.plugins.names = ["modelfit_GeneralShapeletPsfApprox"] 

180 config.plugins["modelfit_GeneralShapeletPsfApprox"].sequence = ["Full"] 

181 config.plugins["modelfit_GeneralShapeletPsfApprox"].models["Full"].optimizer.maxOuterIterations = 1 

182 task = lsst.meas.base.SingleFrameMeasurementTask(config=config, schema=self.schema) 

183 measCat = lsst.afw.table.SourceCatalog(self.schema) 

184 measRecord = measCat.addNew() 

185 psfImage = lsst.afw.image.ImageD(os.path.join(self.psfDir, "galsimPsf_0.9.fits")) 

186 psfImage.setXY0(lsst.geom.Point2I(0, 0)) 

187 kernel = lsst.afw.math.FixedKernel(psfImage) 

188 psf = lsst.meas.algorithms.KernelPsf(kernel) 

189 self.exposure.setPsf(psf) 

190 center = lsst.geom.Point2D(psfImage.getArray().shape[0]/2, psfImage.getArray().shape[1]/2) 

191 measRecord.set(self.centroidKey, center) 

192 task.run(measCat, self.exposure) 

193 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag")) 

194 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_contains_nan")) 

195 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_inner_iterations")) 

196 self.assertTrue(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_max_outer_iterations")) 

197 self.assertFalse(measRecord.get("modelfit_GeneralShapeletPsfApprox_Full_flag_exception")) 

198 

199 

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

201 pass 

202 

203 

204def setup_module(module): 

205 lsst.utils.tests.init() 

206 

207 

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

209 lsst.utils.tests.init() 

210 unittest.main()