Coverage for tests/test_dynamicDetection.py: 31%
66 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-09 03:05 -0700
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-09 03:05 -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 testNoWcs(self):
95 """Check that dynamic detection runs when the exposure wcs is None."""
96 self.exposure.setWcs(None)
97 self.check(1.0)
99 def testNoSources(self):
100 self.config.skyObjects.nSources = (
101 int(self.config.minFractionSources*self.config.skyObjects.nSources) - 1)
102 self.check(1.0)
105class TestMemory(lsst.utils.tests.MemoryTestCase):
106 pass
109def setup_module(module):
110 lsst.utils.tests.init()
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()