Coverage for tests / test_dynamicDetection.py: 26%
108 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-13 01:40 -0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-13 01:40 -0800
1import unittest
3import lsst.utils.tests
4import numpy as np
5from lsst.afw.geom import makeCdMatrix, makeSkyWcs
6from lsst.afw.table import SourceTable
7from lsst.geom import Box2I, Extent2I, Point2D, Point2I, SpherePoint, degrees
8from lsst.meas.algorithms import DynamicDetectionTask
9from lsst.meas.algorithms.testUtils import plantSources
10from lsst.pex.config import FieldValidationError
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 rng = np.random.Generator(np.random.MT19937(12345))
31 stars = [(xx, yy, ff, sigma) for xx, yy, ff in
32 zip(rng.uniform(starBox.getMinX(), starBox.getMaxX(), numStars),
33 rng.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 self.config = DynamicDetectionTask.ConfigClass()
41 self.rtol = 0.1
43 def tearDown(self):
44 del self.exposure
46 def check(self, expectFactor, config):
47 schema = SourceTable.makeMinimalSchema()
48 task = DynamicDetectionTask(config=config, schema=schema)
49 table = SourceTable.make(schema)
51 results = task.run(table, self.exposure, expId=12345)
52 self.assertFloatsAlmostEqual(results.factor, expectFactor, rtol=self.rtol)
54 def testVanilla(self):
55 """Dynamic detection used as normal detection."""
56 self.check(1.0, self.config)
58 def testDynamic(self):
59 """Modify the variance plane, and see if the task is able to determine
60 what we did.
61 """
62 factor = 2.0
63 self.exposure.maskedImage.variance /= factor
64 self.check(1.0/np.sqrt(factor), self.config)
66 def testNoWcs(self):
67 """Check that dynamic detection runs when the exposure wcs is None."""
68 self.exposure.setWcs(None)
69 self.check(1.0, self.config)
71 def testMinimalSkyObjects(self):
72 """Check that dynamic detection runs when there are a relatively small
73 number of sky objects.
74 """
75 config = DynamicDetectionTask.ConfigClass()
76 config.skyObjects.nSources = int(0.1 * self.config.skyObjects.nSources)
77 self.check(1.0, config)
79 def testDynamicNoLimits(self):
80 """Test setting the threshold scaling and background tweak limits to
81 None (i.e. no limits imposed).
82 """
83 config = DynamicDetectionTask.ConfigClass()
84 config.minThresholdScaleFactor = None
85 config.maxThresholdScaleFactor = None
86 config.minBackgroundTweak = None
87 config.maxBackgroundTweak = None
88 self.check(1.0, config)
90 def testNoThresholdScaling(self):
91 """Check that dynamic detection runs when doThresholdScaling is False.
92 """
93 config = DynamicDetectionTask.ConfigClass()
94 config.doThresholdScaling = False
95 self.check(1.0, config)
97 def testNoBackgroundTweak(self):
98 """Check that dynamic detection runs when doBackgroundTweak is False.
99 """
100 config = DynamicDetectionTask.ConfigClass()
101 config.doBackgroundTweak = False
102 self.check(1.0, config)
104 def testThresholdScalingAndNoBackgroundTweak(self):
105 """Check that dynamic detection runs when both doThresholdScaling and
106 doBackgroundTweak are False.
107 """
108 config = DynamicDetectionTask.ConfigClass()
109 config.doThresholdScaling = False
110 config.doBackgroundTweak = False
111 self.check(1.0, config)
113 def testThresholdsOutsideBounds(self):
114 """Check that dynamic detection properly sets threshold limits.
115 """
116 schema = SourceTable.makeMinimalSchema()
117 config = DynamicDetectionTask.ConfigClass()
118 config.minThresholdScaleFactor = 1.05
119 config.maxBackgroundTweak = -0.1
120 table = SourceTable.make(schema)
121 task = DynamicDetectionTask(config=config, schema=schema)
122 task.run(table, self.exposure, expId=12345)
124 config = DynamicDetectionTask.ConfigClass()
125 config.maxThresholdScaleFactor = 0.99
126 config.minBackgroundTweak = 0.1
127 table = SourceTable.make(schema)
128 task = DynamicDetectionTask(config=config, schema=schema)
129 task.run(table, self.exposure, expId=12345)
131 def testConfigValidation(self):
132 """Check that the field validation is working correctly.
133 """
134 schema = SourceTable.makeMinimalSchema()
135 config = DynamicDetectionTask.ConfigClass()
136 config.minThresholdScaleFactor = 1.05
137 config.maxThresholdScaleFactor = 1.01
138 with self.assertRaisesRegex(
139 FieldValidationError, "minThresholdScaleFactor must be <= maxThresholdScaleFactor"):
140 DynamicDetectionTask(config=config, schema=schema)
142 config = DynamicDetectionTask.ConfigClass()
143 config.minBackgroundTweak = 2.0
144 config.maxBackgroundTweak = 1.0
145 with self.assertRaisesRegex(
146 FieldValidationError, "minBackgroundTweak must be <= maxBackgroundTweak"):
147 DynamicDetectionTask(config=config, schema=schema)
149 def testNoSkyObjects(self):
150 """Check that dynamic detection runs when there are no sky objects.
152 Notes
153 -----
154 This test, originally named 'testNoSources', was deactivated on
155 DM-39809 because the dynamic detection task is not able to function
156 without any sky objects. This test should be reactivated once DM-39826
157 has been completed.
158 """
159 pass
162class TestMemory(lsst.utils.tests.MemoryTestCase):
163 pass
166def setup_module(module):
167 lsst.utils.tests.init()
170if __name__ == "__main__": 170 ↛ 171line 170 didn't jump to line 171 because the condition on line 170 was never true
171 import sys
172 setup_module(sys.modules['__main__'])
173 unittest.main()