Coverage for tests/test_diaForcedSource.py : 17%

Hot-keys 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.setDetector(detector)
126 self.exposure.getInfo().setVisitInfo(visit)
127 self.exposure.setFilterLabel(afwImage.FilterLabel(band='g', physical='g.MP9401'))
128 self.exposure.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr))
130 # Difference Image
131 source_image = afwImage.MaskedImageF(
132 lsst.geom.ExtentI(self.imageSize[0] + 1, self.imageSize[1] + 1))
133 source_image.image[100, 100, afwImage.LOCAL] = 20
134 source_image.getVariance().set(2)
135 bbox = lsst.geom.BoxI(
136 lsst.geom.PointI(1, 1),
137 lsst.geom.ExtentI(self.imageSize[0],
138 self.imageSize[1]))
139 masked_image = afwImage.MaskedImageF(source_image, bbox, afwImage.LOCAL)
140 self.diffim = afwImage.makeExposure(masked_image, self.wcs)
141 self.diffim.setDetector(detector)
142 self.diffim.getInfo().setVisitInfo(visit)
143 self.diffim.setFilterLabel(afwImage.FilterLabel(band='g', physical='g.MP9401'))
144 self.diffim.setPhotoCalib(afwImage.PhotoCalib(self.calibration, self.calibrationErr))
146 self.expIdBits = 16
148 FWHM = 5
149 psf = measAlg.DoubleGaussianPsf(15, 15, FWHM/(2*np.sqrt(2*np.log(2))))
150 self.exposure.setPsf(psf)
151 self.diffim.setPsf(psf)
153 self.testDiaObjects = create_test_dia_objects(5, self.wcs)
154 # Add additional diaObjects that are outside of the above difference
155 # and calexp visit images.
156 objects = [
157 (10000000, self.wcs.pixelToSky(-100000, -100000)), # xy outside
158 (10000001, self.wcs.pixelToSky(100, -100000)), # y outside
159 (10000002, self.wcs.pixelToSky(-100000, 100)), # x outside
160 ]
161 extra = pandas.DataFrame({
162 "diaObjectId": np.array([id for id, point in objects], dtype=np.int64),
163 "ra": [point.getRa().asDegrees() for id, point in objects],
164 "decl": [point.getDec().asDegrees() for id, point in objects]
165 })
166 self.testDiaObjects = self.testDiaObjects.append(extra, ignore_index=True)
167 # Ids of objects that were "updated" during "ap_association"
168 # processing.
169 self.updatedTestIds = np.array([1, 2, 3, 4, 10000001], dtype=np.uint64)
170 # Expecdted number of sources is the number of updated ids plus
171 # any that are within the CCD footprint but are not in the
172 # above list of ids.
173 self.expectedDiaForcedSources = 6
175 self.expected_n_columns = 11
177 def testRun(self):
178 """Test that forced source catalogs are successfully created and have
179 sensible values.
180 """
181 test_objects = self.testDiaObjects.copy()
182 test_objects.set_index("diaObjectId", inplace=True, drop=False)
183 dfs = DiaForcedSourceTask()
184 dia_forced_sources = dfs.run(
185 test_objects, self.updatedTestIds, self.expIdBits, self.exposure, self.diffim)
187 direct_values = [199854.48417094944, 160097.40719241602,
188 82299.17897267535, 27148.604434624354,
189 5746.988388215507]
190 direct_var = [75240.939811168, 75231.42933749466,
191 75218.89495113207, 75214.88248249644,
192 75214.41447602339]
193 diff_values = [399708.9683418989, 320194.81438483205,
194 164598.3579453507, 54297.20886924871,
195 11493.976776431015]
196 diff_var = [106444.28782374493, 106417.39592887461,
197 106381.94840437356, 106370.59980584883,
198 106369.27608815048]
200 # Should be number of test objects minus one as one object is purposely
201 # outside of the ccd area.
202 self.assertEqual(len(dia_forced_sources), self.expectedDiaForcedSources)
203 self.assertEqual(len(dia_forced_sources.columns),
204 self.expected_n_columns)
206 for (diaFS_id, diaFS), dirVal, diffVal, dirVar, diffVar in zip(dia_forced_sources.iterrows(),
207 direct_values,
208 diff_values,
209 direct_var,
210 diff_var):
211 self.assertAlmostEqual(diaFS["psFlux"] / diffVal, 1.)
212 self.assertAlmostEqual(diaFS["psFluxErr"] / diffVar, 1.)
214 self.assertAlmostEqual(diaFS["totFlux"] / dirVal, 1.)
215 self.assertAlmostEqual(diaFS["totFluxErr"] / dirVar, 1.)
217 self.assertEqual(diaFS["ccdVisitId"], self.exposureId)
220class MemoryTester(lsst.utils.tests.MemoryTestCase):
221 pass
224def setup_module(module):
225 lsst.utils.tests.init()
228if __name__ == "__main__": 228 ↛ 229line 228 didn't jump to line 229, because the condition on line 228 was never true
229 lsst.utils.tests.init()
230 unittest.main()