Coverage for tests/test_dynamicDetection.py: 32%

68 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-04-30 03:11 -0700

1import unittest 

2 

3import lsst.utils.tests 

4import numpy as np 

5from lsst.afw.geom import makeCdMatrix, makeSkyWcs 

6from lsst.afw.image import PARENT 

7from lsst.afw.table import SourceTable 

8from lsst.geom import Box2I, Extent2I, Point2D, Point2I, SpherePoint, degrees 

9from lsst.meas.algorithms import DynamicDetectionTask 

10from lsst.meas.algorithms.testUtils import plantSources 

11 

12 

13class DynamicDetectionTest(lsst.utils.tests.TestCase): 

14 def setUp(self): 

15 xy0 = Point2I(12345, 67890) # xy0 for image 

16 dims = Extent2I(2345, 2345) # Dimensions of image 

17 box = Box2I(xy0, dims) # Bounding box of image 

18 sigma = 3.21 # PSF sigma 

19 buffer = 4.0 # Buffer for star centers around edge 

20 nSigmaForKernel = 5.0 # Number of PSF sigmas for kernel 

21 sky = 12345.6 # Sky level 

22 numStars = 100 # Number of stars 

23 noise = np.sqrt(sky)*np.pi*sigma**2 # Poisson noise per PSF 

24 faint = 1.0*noise # Faintest level for star fluxes 

25 bright = 100.0*noise # Brightest level for star fluxes 

26 starBox = Box2I(box) # Area on image in which we can put star centers 

27 starBox.grow(-int(buffer*sigma)) 

28 scale = 1.0e-5*degrees # Pixel scale 

29 

30 np.random.seed(12345) 

31 stars = [(xx, yy, ff, sigma) for xx, yy, ff in 

32 zip(np.random.uniform(starBox.getMinX(), starBox.getMaxX(), numStars), 

33 np.random.uniform(starBox.getMinY(), starBox.getMaxY(), numStars), 

34 np.linspace(faint, bright, numStars))] 

35 self.exposure = plantSources(box, 2*int(nSigmaForKernel*sigma) + 1, sky, stars, True) 

36 self.exposure.setWcs(makeSkyWcs(crpix=Point2D(0, 0), 

37 crval=SpherePoint(0, 0, degrees), 

38 cdMatrix=makeCdMatrix(scale=scale))) 

39 

40 # Make a large area of extra background; we should be robust against 

41 # it. Unfortunately, some tuning is required here to get something 

42 # challenging but not impossible: 

43 # * A very large box will cause failures because the "extra" and the 

44 # "normal" are reversed. 

45 # * A small box will not be challenging because it's simple to clip 

46 # out. 

47 # * A large value will cause failures because it produces large edges 

48 # in background-subtrction that broaden flux distributions. 

49 # * A small value will not be challenging because it has little effect. 

50 extraBox = Box2I(xy0 + Extent2I(345, 456), Extent2I(1234, 1234)) # Box for extra background 

51 extraValue = 0.5*noise # Extra background value to add in 

52 self.exposure.image[extraBox, PARENT] += extraValue 

53 

54 self.config = DynamicDetectionTask.ConfigClass() 

55 self.config.skyObjects.nSources = 300 

56 self.config.reEstimateBackground = False 

57 self.config.doTempWideBackground = True 

58 self.config.thresholdType = "pixel_stdev" 

59 

60 # Relative tolerance for tweak factor. 

61 # Not sure why this isn't smaller; maybe due to use of Poisson instead 

62 # of Gaussian noise? 

63 # It seems as if some sky objects are being placed in the extra 

64 # background region, which is causing the offset between the expected 

65 # factor and the measured factor to be larger than otherwise expected. 

66 # This relative tolerance was increased from 0.1 to 0.15 on DM-23781 to 

67 # account for this. 

68 self.rtol = 0.15 

69 

70 def tearDown(self): 

71 del self.exposure 

72 

73 def check(self, expectFactor): 

74 schema = SourceTable.makeMinimalSchema() 

75 task = DynamicDetectionTask(config=self.config, schema=schema) 

76 table = SourceTable.make(schema) 

77 

78 results = task.run(table, self.exposure, expId=12345) 

79 self.assertFloatsAlmostEqual(results.factor, expectFactor, rtol=self.rtol) 

80 

81 def testVanilla(self): 

82 """Dynamic detection used as normal detection.""" 

83 self.check(1.0) 

84 

85 def testDynamic(self): 

86 """Modify the variance plane, and see if the task is able to determine 

87 what we did. 

88 """ 

89 factor = 2.0 

90 self.exposure.maskedImage.variance /= factor 

91 self.check(1.0/np.sqrt(factor)) 

92 

93 def testNoWcs(self): 

94 """Check that dynamic detection runs when the exposure wcs is None.""" 

95 self.exposure.setWcs(None) 

96 self.check(1.0) 

97 

98 def testMinimalSkyObjects(self): 

99 """Check that dynamic detection runs when there are a relatively small 

100 number of sky objects. 

101 """ 

102 self.config.skyObjects.nSources = int(0.1 * self.config.skyObjects.nSources) 

103 self.check(1.0) 

104 

105 def testNoSkyObjects(self): 

106 """Check that dynamic detection runs when there are no sky objects. 

107 

108 Notes 

109 ----- 

110 This test, originally named 'testNoSources', was deactivated on 

111 DM-39809 because the dynamic detection task is not able to function 

112 without any sky objects. This test should be reactivated once DM-39826 

113 has been completed. 

114 """ 

115 pass 

116 

117 

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

119 pass 

120 

121 

122def setup_module(module): 

123 lsst.utils.tests.init() 

124 

125 

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

127 import sys 

128 setup_module(sys.modules['__main__']) 

129 unittest.main()