Coverage for tests/test_diaForcedSource.py: 17%
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of ap_association.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22import numpy as np
23import unittest
24import unittest.mock
26import pandas
28from lsst.afw.cameraGeom.testUtils import DetectorWrapper
29import lsst.afw.geom as afwGeom
30import lsst.afw.image as afwImage
31import lsst.daf.base as dafBase
32import lsst.meas.algorithms as measAlg
33from lsst.ap.association import DiaForcedSourceTask
34import lsst.utils.tests
37def create_test_dia_objects(n_points, wcs, startPos=100):
38 """Create dummy DIASources or DIAObjects for use in our tests.
40 Parameters
41 ----------
42 n_points : `int`
43 Number of DiaObject test points to create.
44 wcs : `lsst.afw.geom.SkyWcs`
45 Wcs to convert RA/Dec to pixel x/y.
46 startPos : `int`
47 Start position to iterate from when creating test DiaObjects
49 Returns
50 -------
51 test_points : `pandas.DataFrame`
52 Catalog of points to test.
53 """
54 ids = np.arange(n_points, dtype=np.int64)
55 points = [wcs.pixelToSky(startPos + src_idx, startPos + src_idx) for src_idx in ids]
56 ra = np.array([point.getRa().asDegrees() for point in points], dtype=float)
57 decl = np.array([point.getDec().asDegrees() for point in points], dtype=float)
59 objects = pandas.DataFrame({
60 "diaObjectId": ids,
61 "ra": ra,
62 "decl": decl
63 })
65 return objects
68class TestDiaForcedSource(unittest.TestCase):
70 def setUp(self):
71 # metadata taken from CFHT data
72 # v695856-e0/v695856-e0-c000-a00.sci_img.fits
73 self.metadata = dafBase.PropertySet()
75 self.metadata.set("SIMPLE", "T")
76 self.metadata.set("BITPIX", -32)
77 self.metadata.set("NAXIS", 2)
78 self.metadata.set("NAXIS1", 1024)
79 self.metadata.set("NAXIS2", 1153)
80 self.metadata.set("RADECSYS", 'FK5')
81 self.metadata.set("EQUINOX", 2000.)
83 self.metadata.setDouble("CRVAL1", 215.604025685476)
84 self.metadata.setDouble("CRVAL2", 53.1595451514076)
85 self.metadata.setDouble("CRPIX1", 1109.99981456774)
86 self.metadata.setDouble("CRPIX2", 560.018167811613)
87 self.metadata.set("CTYPE1", 'RA---SIN')
88 self.metadata.set("CTYPE2", 'DEC--SIN')
90 self.metadata.setDouble("CD1_1", 5.10808596133527E-05)
91 self.metadata.setDouble("CD1_2", 1.85579539217196E-07)
92 self.metadata.setDouble("CD2_2", -5.10281493481982E-05)
93 self.metadata.setDouble("CD2_1", -8.27440751733828E-07)
95 self.wcs = afwGeom.makeSkyWcs(self.metadata)
97 self.calibration = 10000
98 self.calibrationErr = 100
99 self.exposureId = 1234
100 self.exposureTime = 200.
101 self.imageSize = [1024, 1153]
102 self.dateTime = "2014-05-13T17:00:00.000000000"
104 # Make images with one source in them and distinct values and
105 # variance for each image.
106 # Direct Image
107 source_image = afwImage.MaskedImageF(
108 lsst.geom.ExtentI(self.imageSize[0] + 1, self.imageSize[1] + 1))
109 source_image.image[100, 100, afwImage.LOCAL] = 10
110 source_image.getVariance().set(1)
111 bbox = lsst.geom.BoxI(
112 lsst.geom.PointI(1, 1),
113 lsst.geom.ExtentI(self.imageSize[0],
114 self.imageSize[1]))
115 masked_image = afwImage.MaskedImageF(source_image, bbox, afwImage.LOCAL)
116 self.exposure = afwImage.makeExposure(masked_image, self.wcs)
118 detector = DetectorWrapper(
119 id=23, bbox=self.exposure.getBBox()).detector
120 visit = afwImage.VisitInfo(
121 exposureId=self.exposureId,
122 exposureTime=self.exposureTime,
123 date=dafBase.DateTime(self.dateTime,
124 dafBase.DateTime.Timescale.TAI))
125 self.exposure.info.id = self.exposureId
126 self.exposure.setDetector(detector)
127 self.exposure.getInfo().setVisitInfo(visit)
128 self.exposure.setFilterLabel(afwImage.FilterLabel(band='g', physical='g.MP9401'))
129 self.exposure.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr))
131 # Difference Image
132 source_image = afwImage.MaskedImageF(
133 lsst.geom.ExtentI(self.imageSize[0] + 1, self.imageSize[1] + 1))
134 source_image.image[100, 100, afwImage.LOCAL] = 20
135 source_image.getVariance().set(2)
136 bbox = lsst.geom.BoxI(
137 lsst.geom.PointI(1, 1),
138 lsst.geom.ExtentI(self.imageSize[0],
139 self.imageSize[1]))
140 masked_image = afwImage.MaskedImageF(source_image, bbox, afwImage.LOCAL)
141 self.diffim = afwImage.makeExposure(masked_image, self.wcs)
142 self.diffim.info.id = self.exposureId
143 self.diffim.setDetector(detector)
144 self.diffim.getInfo().setVisitInfo(visit)
145 self.diffim.setFilterLabel(afwImage.FilterLabel(band='g', physical='g.MP9401'))
146 self.diffim.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr))
148 self.expIdBits = 16
150 FWHM = 5
151 psf = measAlg.DoubleGaussianPsf(15, 15, FWHM/(2*np.sqrt(2*np.log(2))))
152 self.exposure.setPsf(psf)
153 self.diffim.setPsf(psf)
155 self.testDiaObjects = create_test_dia_objects(5, self.wcs)
156 # Add additional diaObjects that are outside of the above difference
157 # and calexp visit images.
158 objects = [
159 (10000000, self.wcs.pixelToSky(-100000, -100000)), # xy outside
160 (10000001, self.wcs.pixelToSky(100, -100000)), # y outside
161 (10000002, self.wcs.pixelToSky(-100000, 100)), # x outside
162 ]
163 extra = pandas.DataFrame({
164 "diaObjectId": np.array([id for id, point in objects], dtype=np.int64),
165 "ra": [point.getRa().asDegrees() for id, point in objects],
166 "decl": [point.getDec().asDegrees() for id, point in objects]
167 })
168 self.testDiaObjects = self.testDiaObjects.append(extra, ignore_index=True)
169 # Ids of objects that were "updated" during "ap_association"
170 # processing.
171 self.updatedTestIds = np.array([1, 2, 3, 4, 10000001], dtype=np.uint64)
172 # Expecdted number of sources is the number of updated ids plus
173 # any that are within the CCD footprint but are not in the
174 # above list of ids.
175 self.expectedDiaForcedSources = 6
177 self.expected_n_columns = 11
179 def testRun(self):
180 """Test that forced source catalogs are successfully created and have
181 sensible values.
182 """
183 test_objects = self.testDiaObjects.copy()
184 test_objects.set_index("diaObjectId", inplace=True, drop=False)
185 dfs = DiaForcedSourceTask()
186 dia_forced_sources = dfs.run(
187 test_objects, self.updatedTestIds, self.expIdBits, self.exposure, self.diffim)
189 direct_values = [199854.48417094944, 160097.40719241602,
190 82299.17897267535, 27148.604434624354,
191 5746.988388215507]
192 direct_var = [75240.939811168, 75231.42933749466,
193 75218.89495113207, 75214.88248249644,
194 75214.41447602339]
195 diff_values = [399708.9683418989, 320194.81438483205,
196 164598.3579453507, 54297.20886924871,
197 11493.976776431015]
198 diff_var = [106444.28782374493, 106417.39592887461,
199 106381.94840437356, 106370.59980584883,
200 106369.27608815048]
202 # Should be number of test objects minus one as one object is purposely
203 # outside of the ccd area.
204 self.assertEqual(len(dia_forced_sources), self.expectedDiaForcedSources)
205 self.assertEqual(len(dia_forced_sources.columns),
206 self.expected_n_columns)
208 for (diaFS_id, diaFS), dirVal, diffVal, dirVar, diffVar in zip(dia_forced_sources.iterrows(),
209 direct_values,
210 diff_values,
211 direct_var,
212 diff_var):
213 self.assertAlmostEqual(diaFS["psFlux"] / diffVal, 1.)
214 self.assertAlmostEqual(diaFS["psFluxErr"] / diffVar, 1.)
216 self.assertAlmostEqual(diaFS["totFlux"] / dirVal, 1.)
217 self.assertAlmostEqual(diaFS["totFluxErr"] / dirVar, 1.)
219 self.assertEqual(diaFS["ccdVisitId"], self.exposureId)
222class MemoryTester(lsst.utils.tests.MemoryTestCase):
223 pass
226def setup_module(module):
227 lsst.utils.tests.init()
230if __name__ == "__main__": 230 ↛ 231line 230 didn't jump to line 231, because the condition on line 230 was never true
231 lsst.utils.tests.init()
232 unittest.main()