Coverage for tests/test_dynamicDetection.py: 31%

63 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-04-25 00:24 -0700

1import unittest 

2import numpy as np 

3 

4import lsst.utils.tests 

5 

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

7from lsst.afw.geom import makeCdMatrix, makeSkyWcs 

8from lsst.afw.image import PARENT 

9from lsst.afw.table import SourceTable 

10from lsst.meas.algorithms import DynamicDetectionTask 

11from lsst.meas.algorithms.testUtils import plantSources 

12 

13 

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

15 def setUp(self): 

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

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

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

19 sigma = 3.21 # PSF sigma 

20 buffer = 4.0 # Buffer for star centers around edge 

21 nSigmaForKernel = 5.0 # Number of PSF sigmas for kernel 

22 sky = 12345.6 # Sky level 

23 numStars = 100 # Number of stars 

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

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

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

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

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

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

30 

31 np.random.seed(12345) 

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

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

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

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

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

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

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

39 cdMatrix=makeCdMatrix(scale=scale))) 

40 

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

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

43 # challenging but not impossible: 

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

45 # "normal" are reversed. 

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

47 # out. 

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

49 # in background-subtrction that broaden flux distributions. 

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

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

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

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

54 

55 self.config = DynamicDetectionTask.ConfigClass() 

56 self.config.skyObjects.nSources = 300 

57 self.config.reEstimateBackground = False 

58 self.config.doTempWideBackground = True 

59 self.config.thresholdType = "pixel_stdev" 

60 

61 # Relative tolerance for tweak factor. 

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

63 # of Gaussian noise? 

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

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

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

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

68 # account for this. 

69 self.rtol = 0.15 

70 

71 def tearDown(self): 

72 del self.exposure 

73 

74 def check(self, expectFactor): 

75 schema = SourceTable.makeMinimalSchema() 

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

77 table = SourceTable.make(schema) 

78 

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

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

81 

82 def testVanilla(self): 

83 """Dynamic detection used as normal detection.""" 

84 self.check(1.0) 

85 

86 def testDynamic(self): 

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

88 what we did. 

89 """ 

90 factor = 2.0 

91 self.exposure.maskedImage.variance /= factor 

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

93 

94 def testNoSources(self): 

95 self.config.skyObjects.nSources = ( 

96 int(self.config.minFractionSources*self.config.skyObjects.nSources) - 1) 

97 self.check(1.0) 

98 

99 

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

101 pass 

102 

103 

104def setup_module(module): 

105 lsst.utils.tests.init() 

106 

107 

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

109 import sys 

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

111 unittest.main()