Coverage for tests/test_GaussianFlux.py: 27%

Shortcuts on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

80 statements  

1# This file is part of meas_base. 

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 

23 

24import numpy as np 

25 

26import lsst.geom 

27import lsst.afw.geom 

28import lsst.meas.base 

29import lsst.utils.tests 

30from lsst.meas.base.tests import (AlgorithmTestCase, FluxTransformTestCase, 

31 SingleFramePluginTransformSetupHelper) 

32 

33 

34class GaussianFluxTestCase(AlgorithmTestCase, lsst.utils.tests.TestCase): 

35 

36 def setUp(self): 

37 self.bbox = lsst.geom.Box2I(lsst.geom.Point2I(-20, -30), 

38 lsst.geom.Extent2I(240, 1600)) 

39 self.dataset = lsst.meas.base.tests.TestDataset(self.bbox) 

40 # first source is a point 

41 self.dataset.addSource(100000.0, lsst.geom.Point2D(50.1, 49.8)) 

42 # second source is extended 

43 self.dataset.addSource(100000.0, lsst.geom.Point2D(149.9, 50.3), 

44 lsst.afw.geom.Quadrupole(8, 9, 3)) 

45 

46 def tearDown(self): 

47 del self.bbox 

48 del self.dataset 

49 

50 def makeAlgorithm(self, ctrl=None): 

51 """Construct an algorithm and return both it and its schema. 

52 """ 

53 if ctrl is None: 

54 ctrl = lsst.meas.base.GaussianFluxControl() 

55 schema = lsst.meas.base.tests.TestDataset.makeMinimalSchema() 

56 algorithm = lsst.meas.base.GaussianFluxAlgorithm(ctrl, "base_GaussianFlux", schema) 

57 return algorithm, schema 

58 

59 def testGaussians(self): 

60 """Test for correct instFlux given known position and shape. 

61 """ 

62 task = self.makeSingleFrameMeasurementTask("base_GaussianFlux") 

63 # Results are RNG dependent; we choose a seed that is known to pass. 

64 exposure, catalog = self.dataset.realize(10.0, task.schema, randomSeed=0) 

65 task.run(catalog, exposure) 

66 for measRecord in catalog: 

67 self.assertFloatsAlmostEqual(measRecord.get("base_GaussianFlux_instFlux"), 

68 measRecord.get("truth_instFlux"), rtol=3E-3) 

69 

70 def testMonteCarlo(self): 

71 """Test an ideal simulation, with no noise. 

72 

73 Demonstrate that: 

74 

75 - We get exactly the right answer, and 

76 - The reported uncertainty agrees with a Monte Carlo test of the noise. 

77 """ 

78 algorithm, schema = self.makeAlgorithm() 

79 # Results are RNG dependent; we choose a seed that is known to pass. 

80 exposure, catalog = self.dataset.realize(1E-8, schema, randomSeed=1) 

81 record = catalog[0] 

82 instFlux = record.get("truth_instFlux") 

83 algorithm.measure(record, exposure) 

84 self.assertFloatsAlmostEqual(record.get("base_GaussianFlux_instFlux"), instFlux, rtol=1E-3) 

85 self.assertLess(record.get("base_GaussianFlux_instFluxErr"), 1E-3) 

86 for noise in (0.001, 0.01, 0.1): 

87 instFluxes = [] 

88 instFluxErrs = [] 

89 nSamples = 1000 

90 for repeat in range(nSamples): 

91 # By using ``repeat`` to seed the RNG, we get results which 

92 # fall within the tolerances defined below. If we allow this 

93 # test to be truly random, passing becomes RNG-dependent. 

94 exposure, catalog = self.dataset.realize(noise*instFlux, schema, randomSeed=repeat) 

95 record = catalog[1] 

96 algorithm.measure(record, exposure) 

97 instFluxes.append(record.get("base_GaussianFlux_instFlux")) 

98 instFluxErrs.append(record.get("base_GaussianFlux_instFluxErr")) 

99 instFluxMean = np.mean(instFluxes) 

100 instFluxErrMean = np.mean(instFluxErrs) 

101 instFluxStandardDeviation = np.std(instFluxes) 

102 self.assertFloatsAlmostEqual(instFluxErrMean, instFluxStandardDeviation, rtol=0.10) 

103 self.assertLess(abs(instFluxMean - instFlux), 2.0*instFluxErrMean / nSamples**0.5) 

104 

105 def testForcedPlugin(self): 

106 task = self.makeForcedMeasurementTask("base_GaussianFlux") 

107 # Results of this test are RNG dependent: we choose seeds that are 

108 # known to pass. 

109 measWcs = self.dataset.makePerturbedWcs(self.dataset.exposure.getWcs(), randomSeed=2) 

110 measDataset = self.dataset.transform(measWcs) 

111 exposure, truthCatalog = measDataset.realize(10.0, measDataset.makeMinimalSchema(), randomSeed=2) 

112 refWcs = self.dataset.exposure.getWcs() 

113 refCat = self.dataset.catalog 

114 measCat = task.generateMeasCat(exposure, refCat, refWcs) 

115 task.attachTransformedFootprints(measCat, refCat, exposure, refWcs) 

116 task.run(measCat, exposure, refCat, refWcs) 

117 for measRecord, truthRecord in zip(measCat, truthCatalog): 

118 # Centroid tolerances set to ~ single precision epsilon 

119 self.assertFloatsAlmostEqual(measRecord.get("slot_Centroid_x"), 

120 truthRecord.get("truth_x"), rtol=1E-7) 

121 self.assertFloatsAlmostEqual(measRecord.get("slot_Centroid_y"), 

122 truthRecord.get("truth_y"), rtol=1E-7) 

123 self.assertFalse(measRecord.get("base_GaussianFlux_flag")) 

124 # GaussianFlux isn't designed to do a good job in forced mode, 

125 # because it doesn't account for changes in the PSF (and in fact 

126 # confuses them with changes in the WCS). Hence, this is really 

127 # just a regression test, with the initial threshold set to just a 

128 # bit more than what it was found to be at one point. 

129 self.assertFloatsAlmostEqual(measRecord.get("base_GaussianFlux_instFlux"), 

130 truthCatalog.get("truth_instFlux"), rtol=0.3) 

131 self.assertLess(measRecord.get("base_GaussianFlux_instFluxErr"), 500.0) 

132 

133 

134class GaussianFluxTransformTestCase(FluxTransformTestCase, SingleFramePluginTransformSetupHelper, 

135 lsst.utils.tests.TestCase): 

136 controlClass = lsst.meas.base.GaussianFluxControl 

137 algorithmClass = lsst.meas.base.GaussianFluxAlgorithm 

138 transformClass = lsst.meas.base.GaussianFluxTransform 

139 singleFramePlugins = ('base_GaussianFlux',) 

140 forcedPlugins = ('base_GaussianFlux',) 

141 

142 

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

144 pass 

145 

146 

147def setup_module(module): 

148 lsst.utils.tests.init() 

149 

150 

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

152 lsst.utils.tests.init() 

153 unittest.main()