Coverage for tests/test_NoiseReplacer.py: 37%

77 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-16 03:37 -0700

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.afw.detection 

29import lsst.afw.table 

30import lsst.meas.base.tests 

31import lsst.utils.tests 

32from lsst.daf.base import PropertyList 

33from lsst.utils.tests import methodParameters 

34 

35 

36@lsst.meas.base.register("test_NoiseReplacer") 

37class NoiseReplacerTestPlugin(lsst.meas.base.SingleFramePlugin): 

38 """Plugin that sums instFlux inside and outside the source footprint. 

39 """ 

40 

41 @staticmethod 

42 def getExecutionOrder(): 

43 return 2.0 

44 

45 def __init__(self, config, name, schema, metadata): 

46 lsst.meas.base.SingleFramePlugin.__init__(self, config, name, schema, metadata) 

47 self.insideKey = schema.addField("%s_inside" % (name,), type=np.float64, 

48 doc="instFlux inside footprint") 

49 self.outsideKey = schema.addField("%s_outside" % (name,), type=np.float64, 

50 doc="instFlux outside footprint") 

51 

52 def measure(self, measRecord, exposure): 

53 footprint = measRecord.getFootprint() 

54 fullArray = exposure.image.array 

55 insideArray = np.zeros(footprint.getArea(), dtype=fullArray.dtype) 

56 footprint.spans.flatten(insideArray, fullArray, exposure.getXY0()) 

57 insideFlux = float(insideArray.sum()) 

58 outsideFlux = float(fullArray.sum()) - insideFlux 

59 measRecord.set(self.insideKey, insideFlux) 

60 measRecord.set(self.outsideKey, outsideFlux) 

61 

62 

63class NoiseReplacerTestCase(lsst.meas.base.tests.AlgorithmTestCase, lsst.utils.tests.TestCase): 

64 

65 def setUp(self): 

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

67 lsst.geom.Extent2I(240, 260)) 

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

69 # first source is a point 

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

71 # second source is extended 

72 self.dataset.addSource(120000.0, lsst.geom.Point2D(149.9, 50.3), 

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

74 with self.dataset.addBlend() as family: 

75 family.addChild(110000.0, lsst.geom.Point2D(65.2, 150.7), 

76 lsst.afw.geom.Quadrupole(7, 5, -1)) 

77 family.addChild(140000.0, lsst.geom.Point2D(72.3, 149.1)) 

78 family.addChild(90000.0, lsst.geom.Point2D(68.5, 156.9)) 

79 

80 @methodParameters(noiseSource=['measure', 'variance', 'meta', 'variance_median'], 

81 variance=[1.0, 1.0, 2.0, 1.0]) 

82 def testNoiseReplacer(self, noiseSource, variance): 

83 """Test noise replacement in SFM with ''measure'' mode. 

84 

85 We compare the instFlux inside and outside source Footprints on an 

86 extremely high S/N image. 

87 """ 

88 # We choose a random seed which causes the test to pass. 

89 task = self.makeSingleFrameMeasurementTask("test_NoiseReplacer") 

90 task.config.noiseReplacer.noiseSource = noiseSource 

91 exposure, catalog = self.dataset.realize(variance, task.schema, randomSeed=0) 

92 if noiseSource == 'meta': 

93 md = PropertyList() 

94 md['BGMEAN'] = variance 

95 exposure.setMetadata(md) 

96 task.run(catalog, exposure) 

97 sumVariance = exposure.variance.array.sum() 

98 for record in catalog: 

99 self.assertFloatsAlmostEqual(record.get("test_NoiseReplacer_inside"), 

100 record.get("truth_instFlux"), rtol=1E-3) 

101 

102 # N.B. Next line checks that a random value is correct to a 

103 # statistical 1-sigma prediction; some RNG seeds may cause it to 

104 # fail (indeed, 67% should) 

105 self.assertLess(record.get("test_NoiseReplacer_outside"), np.sqrt(sumVariance)) 

106 

107 @methodParameters(noiseSource=['measure', 'variance', 'meta', 'variance_median'], 

108 variance=[1.0, 1.0, 2.0, 1.0]) 

109 def testNoiseReplacerExternalFootprints(self, noiseSource, variance): 

110 # We choose a random seed which causes the test to pass. 

111 task = self.makeSingleFrameMeasurementTask("test_NoiseReplacer") 

112 task.config.noiseReplacer.noiseSource = noiseSource 

113 exposure, catalog = self.dataset.realize(variance, task.schema, randomSeed=0) 

114 if noiseSource == 'meta': 

115 md = PropertyList() 

116 md['BGMEAN'] = variance 

117 exposure.setMetadata(md) 

118 footprints = task.getFootprintsFromCatalog(catalog) 

119 task.run(catalog, exposure, footprints=footprints) 

120 sumVariance = exposure.variance.array.sum() 

121 for record in catalog: 

122 self.assertFloatsAlmostEqual(record.get("test_NoiseReplacer_inside"), 

123 record.get("truth_instFlux"), rtol=1E-3) 

124 

125 # N.B. Next line checks that a random value is correct to a 

126 # statistical 1-sigma prediction; some RNG seeds may cause it to 

127 # fail (indeed, 67% should) 

128 self.assertLess(record.get("test_NoiseReplacer_outside"), np.sqrt(sumVariance)) 

129 

130 def tearDown(self): 

131 del self.bbox 

132 del self.dataset 

133 

134 

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

136 pass 

137 

138 

139def setup_module(module): 

140 lsst.utils.tests.init() 

141 

142 

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

144 lsst.utils.tests.init() 

145 unittest.main()