Coverage for tests/test_dynamicDetection.py: 31%

66 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-05-03 03:09 -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 testNoWcs(self): 

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

96 self.exposure.setWcs(None) 

97 self.check(1.0) 

98 

99 def testNoSources(self): 

100 self.config.skyObjects.nSources = ( 

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

102 self.check(1.0) 

103 

104 

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

106 pass 

107 

108 

109def setup_module(module): 

110 lsst.utils.tests.init() 

111 

112 

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

114 import sys 

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

116 unittest.main()