Coverage for tests/test_dynamicDetection.py: 32%
68 statements
« prev ^ index » next coverage.py v7.4.3, created at 2024-03-13 10:34 +0000
« prev ^ index » next coverage.py v7.4.3, created at 2024-03-13 10:34 +0000
1import unittest
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
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
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)))
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
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"
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
70 def tearDown(self):
71 del self.exposure
73 def check(self, expectFactor):
74 schema = SourceTable.makeMinimalSchema()
75 task = DynamicDetectionTask(config=self.config, schema=schema)
76 table = SourceTable.make(schema)
78 results = task.run(table, self.exposure, expId=12345)
79 self.assertFloatsAlmostEqual(results.factor, expectFactor, rtol=self.rtol)
81 def testVanilla(self):
82 """Dynamic detection used as normal detection."""
83 self.check(1.0)
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))
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)
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)
105 def testNoSkyObjects(self):
106 """Check that dynamic detection runs when there are no sky objects.
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
118class TestMemory(lsst.utils.tests.MemoryTestCase):
119 pass
122def setup_module(module):
123 lsst.utils.tests.init()
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()