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
26from lsst.afw.cameraGeom.testUtils import DetectorWrapper
27import lsst.afw.geom as afwGeom
28import lsst.afw.image as afwImage
29import lsst.afw.table as afwTable
30import lsst.daf.base as dafBase
31import lsst.meas.algorithms as measAlg
32from lsst.ap.association import \
33 DiaForcedSourceTask, \
34 make_dia_object_schema
35import lsst.utils.tests
38def create_test_dia_objects(n_points, wcs, startPos=100):
39 """Create dummy DIASources or DIAObjects for use in our tests.
41 Parameters
42 ----------
43 n_points : `int`
44 Number of DiaObject test points to create.
45 wcs : `lsst.afw.geom.SkyWcs`
46 Wcs to convert RA/Dec to pixel x/y.
47 startPos : `int`
48 Start position to iterate from when creating test DiaObjects
50 Returns
51 -------
52 test_points : `lsst.afw.table.SourceCatalog`
53 Catalog of points to test.
54 """
55 objects = afwTable.SourceCatalog(make_dia_object_schema())
57 for src_idx in range(n_points):
58 src = objects.addNew()
59 src['id'] = src_idx
60 src.setCoord(wcs.pixelToSky(startPos + src_idx,
61 startPos + src_idx))
63 return objects
66class TestDiaForcedSource(unittest.TestCase):
68 def setUp(self):
69 # metadata taken from CFHT data
70 # v695856-e0/v695856-e0-c000-a00.sci_img.fits
71 self.metadata = dafBase.PropertySet()
73 self.metadata.set("SIMPLE", "T")
74 self.metadata.set("BITPIX", -32)
75 self.metadata.set("NAXIS", 2)
76 self.metadata.set("NAXIS1", 1024)
77 self.metadata.set("NAXIS2", 1153)
78 self.metadata.set("RADECSYS", 'FK5')
79 self.metadata.set("EQUINOX", 2000.)
81 self.metadata.setDouble("CRVAL1", 215.604025685476)
82 self.metadata.setDouble("CRVAL2", 53.1595451514076)
83 self.metadata.setDouble("CRPIX1", 1109.99981456774)
84 self.metadata.setDouble("CRPIX2", 560.018167811613)
85 self.metadata.set("CTYPE1", 'RA---SIN')
86 self.metadata.set("CTYPE2", 'DEC--SIN')
88 self.metadata.setDouble("CD1_1", 5.10808596133527E-05)
89 self.metadata.setDouble("CD1_2", 1.85579539217196E-07)
90 self.metadata.setDouble("CD2_2", -5.10281493481982E-05)
91 self.metadata.setDouble("CD2_1", -8.27440751733828E-07)
93 self.wcs = afwGeom.makeSkyWcs(self.metadata)
95 self.calibration = 10000
96 self.calibrationErr = 100
97 self.exposureId = 1234
98 self.exposureTime = 200.
99 self.imageSize = [1024, 1153]
100 self.dateTime = "2014-05-13T17:00:00.000000000"
102 # Make images with one source in them and distinct values and
103 # variance for each image.
104 # Direct Image
105 source_image = afwImage.MaskedImageF(
106 lsst.geom.ExtentI(self.imageSize[0] + 1, self.imageSize[1] + 1))
107 source_image.image[100, 100, afwImage.LOCAL] = 10
108 source_image.getVariance().set(1)
109 bbox = lsst.geom.BoxI(
110 lsst.geom.PointI(1, 1),
111 lsst.geom.ExtentI(self.imageSize[0],
112 self.imageSize[1]))
113 masked_image = afwImage.MaskedImageF(source_image, bbox, afwImage.LOCAL)
114 self.exposure = afwImage.makeExposure(masked_image, self.wcs)
116 detector = DetectorWrapper(
117 id=23, bbox=self.exposure.getBBox()).detector
118 visit = afwImage.VisitInfo(
119 exposureId=self.exposureId,
120 exposureTime=self.exposureTime,
121 date=dafBase.DateTime(self.dateTime,
122 dafBase.DateTime.Timescale.TAI))
123 self.exposure.setDetector(detector)
124 self.exposure.getInfo().setVisitInfo(visit)
125 self.exposure.setFilterLabel(afwImage.FilterLabel(band='g', physical='g.MP9401'))
126 self.exposure.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr))
128 # Difference Image
129 source_image = afwImage.MaskedImageF(
130 lsst.geom.ExtentI(self.imageSize[0] + 1, self.imageSize[1] + 1))
131 source_image.image[100, 100, afwImage.LOCAL] = 20
132 source_image.getVariance().set(2)
133 bbox = lsst.geom.BoxI(
134 lsst.geom.PointI(1, 1),
135 lsst.geom.ExtentI(self.imageSize[0],
136 self.imageSize[1]))
137 masked_image = afwImage.MaskedImageF(source_image, bbox, afwImage.LOCAL)
138 self.diffim = afwImage.makeExposure(masked_image, self.wcs)
139 self.diffim.setDetector(detector)
140 self.diffim.getInfo().setVisitInfo(visit)
141 self.diffim.setFilterLabel(afwImage.FilterLabel(band='g', physical='g.MP9401'))
142 self.diffim.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr))
144 self.expIdBits = 16
146 FWHM = 5
147 psf = measAlg.DoubleGaussianPsf(15, 15, FWHM/(2*np.sqrt(2*np.log(2))))
148 self.exposure.setPsf(psf)
149 self.diffim.setPsf(psf)
151 self.testDiaObjects = create_test_dia_objects(5, self.wcs)
152 # Add additional diaObjects that are outside of the above difference
153 # and calexp visit images.
154 # xy outside
155 src = self.testDiaObjects.addNew()
156 src['id'] = 10000000
157 src.setCoord(self.wcs.pixelToSky(-100000,
158 -100000))
159 # y outside
160 src = self.testDiaObjects.addNew()
161 src['id'] = 10000001
162 src.setCoord(self.wcs.pixelToSky(100,
163 -100000))
164 # x outside
165 src = self.testDiaObjects.addNew()
166 src['id'] = 10000002
167 src.setCoord(self.wcs.pixelToSky(-100000,
168 100))
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._convert_to_pandas(self.testDiaObjects)
184 test_objects.rename(columns={"id": "diaObjectId"},
185 inplace=True)
186 test_objects.set_index("diaObjectId", inplace=True, drop=False)
187 dfs = DiaForcedSourceTask()
188 dia_forced_sources = dfs.run(
189 test_objects, self.updatedTestIds, self.expIdBits, self.exposure, self.diffim)
191 direct_values = [199854.48417094944, 160097.40719241602,
192 82299.17897267535, 27148.604434624354,
193 5746.988388215507]
194 direct_var = [75240.939811168, 75231.42933749466,
195 75218.89495113207, 75214.88248249644,
196 75214.41447602339]
197 diff_values = [399708.9683418989, 320194.81438483205,
198 164598.3579453507, 54297.20886924871,
199 11493.976776431015]
200 diff_var = [106444.28782374493, 106417.39592887461,
201 106381.94840437356, 106370.59980584883,
202 106369.27608815048]
204 # Should be number of test objects minus one as one object is purposely
205 # outside of the ccd area.
206 self.assertEqual(len(dia_forced_sources), self.expectedDiaForcedSources)
207 self.assertEqual(len(dia_forced_sources.columns),
208 self.expected_n_columns)
210 for (diaFS_id, diaFS), testObj, dirVal, diffVal, dirVar, diffVar in zip(dia_forced_sources.iterrows(),
211 self.testDiaObjects,
212 direct_values,
213 diff_values,
214 direct_var,
215 diff_var):
216 self.assertAlmostEqual(diaFS["psFlux"] / diffVal, 1.)
217 self.assertAlmostEqual(diaFS["psFluxErr"] / diffVar, 1.)
219 self.assertAlmostEqual(diaFS["totFlux"] / dirVal, 1.)
220 self.assertAlmostEqual(diaFS["totFluxErr"] / dirVar, 1.)
222 self.assertEqual(diaFS["ccdVisitId"], self.exposureId)
224 def _convert_to_pandas(self, dia_objects):
225 """Convert input afw table to pandas.
227 Parameters
228 ----------
229 dia_objects : `lsst.afw.table.SourceCatalog`
230 Catalog to convert
232 Returns
233 -------
234 output_catalog : `pandas.DataFrame`
235 Converted catalog
236 """
237 output_catalog = dia_objects.asAstropy().to_pandas()
238 output_catalog.rename(columns={"id": "diaObjectId",
239 "coord_ra": "ra",
240 "coord_dec": "decl"},
241 inplace=True)
243 output_catalog.loc[:, "ra"] = np.degrees(output_catalog["ra"])
244 output_catalog.loc[:, "decl"] = np.degrees(output_catalog["decl"])
246 return output_catalog
249class MemoryTester(lsst.utils.tests.MemoryTestCase):
250 pass
253def setup_module(module):
254 lsst.utils.tests.init()
257if __name__ == "__main__": 257 ↛ 258line 257 didn't jump to line 258, because the condition on line 257 was never true
258 lsst.utils.tests.init()
259 unittest.main()