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
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-25 00:24 -0700
1import unittest
2import numpy as np
4import lsst.utils.tests
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
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
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)))
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
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"
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
71 def tearDown(self):
72 del self.exposure
74 def check(self, expectFactor):
75 schema = SourceTable.makeMinimalSchema()
76 task = DynamicDetectionTask(config=self.config, schema=schema)
77 table = SourceTable.make(schema)
79 results = task.run(table, self.exposure, expId=12345)
80 self.assertFloatsAlmostEqual(results.factor, expectFactor, rtol=self.rtol)
82 def testVanilla(self):
83 """Dynamic detection used as normal detection."""
84 self.check(1.0)
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))
94 def testNoSources(self):
95 self.config.skyObjects.nSources = (
96 int(self.config.minFractionSources*self.config.skyObjects.nSources) - 1)
97 self.check(1.0)
100class TestMemory(lsst.utils.tests.MemoryTestCase):
101 pass
104def setup_module(module):
105 lsst.utils.tests.init()
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()