Coverage for tests/test_map_ap_data.py : 14%

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 os
24import unittest
26from lsst.ap.association import (
27 MapApDataConfig,
28 MapApDataTask,
29 MapDiaSourceConfig,
30 MapDiaSourceTask,
31 UnpackApdbFlags)
32from lsst.afw.cameraGeom.testUtils import DetectorWrapper
33import lsst.afw.table as afwTable
34import lsst.daf.base as dafBase
35import lsst.afw.geom as afwGeom
36import lsst.afw.image as afwImage
37import lsst.afw.image.utils as afwImageUtils
38import lsst.geom as geom
39from lsst.utils import getPackageDir
40import lsst.utils.tests
43def make_input_source_catalog(n_objects, add_flags=False):
44 """Create tests objects to map into apData products.
46 Parameters
47 ----------
48 n_objects: `int`
49 Number of objects to create.
50 """
51 schema = afwTable.SourceTable.makeMinimalSchema()
52 schema.addField("base_NaiveCentroid_x", type="D")
53 schema.addField("base_NaiveCentroid_y", type="D")
54 schema.addField("base_PsfFlux_instFlux", type="D")
55 schema.addField("base_PsfFlux_instFluxErr", type="D")
56 schema.addField("ip_diffim_DipoleFit_separation", type="D")
57 schema.addField("ip_diffim_DipoleFit_orientation", type="D")
58 schema.addField("ip_diffim_DipoleFit_neg_instFlux", type="D")
59 schema.addField("ip_diffim_DipoleFit_neg_instFluxErr", type="D")
60 schema.addField("ip_diffim_DipoleFit_pos_instFlux", type="D")
61 schema.addField("ip_diffim_DipoleFit_pos_instFluxErr", type="D")
62 schema.addField("ip_diffim_forced_PsfFlux_instFlux", type="D")
63 schema.addField("ip_diffim_forced_PsfFlux_instFluxErr", type="D")
64 if add_flags:
65 schema.addField("base_PixelFlags_flag", type="Flag")
66 schema.addField("base_PixelFlags_flag_offimage", type="Flag")
68 objects = afwTable.SourceCatalog(schema)
69 objects.preallocate(n_objects)
70 objects.definePsfFlux("base_PsfFlux")
71 objects.defineCentroid("base_NaiveCentroid")
73 for obj_idx in range(n_objects):
74 obj = objects.addNew()
75 for subSchema in schema:
76 if isinstance(obj.get(subSchema.getKey()), geom.Angle):
77 obj.set(subSchema.getKey(), 1. * geom.degrees)
78 elif subSchema.getField().getName() == "ip_diffim_DipoleFit_neg_instFlux":
79 obj.set(subSchema.getKey(), -1)
80 else:
81 obj.set(subSchema.getKey(), 1)
82 return objects
85class TestAPDataMapperTask(unittest.TestCase):
87 def setUp(self):
88 # CFHT Filters from the camera mapper.
89 afwImageUtils.resetFilters()
90 afwImageUtils.defineFilter('u', lambdaEff=374, alias="u.MP9301")
91 afwImageUtils.defineFilter('g', lambdaEff=487, alias="g.MP9401")
92 afwImageUtils.defineFilter('r', lambdaEff=628, alias="r.MP9601")
93 afwImageUtils.defineFilter('i', lambdaEff=778, alias="i.MP9701")
94 afwImageUtils.defineFilter('z', lambdaEff=1170, alias="z.MP9801")
96 self.metadata = dafBase.PropertySet()
98 self.metadata.set("SIMPLE", "T")
99 self.metadata.set("BITPIX", -32)
100 self.metadata.set("NAXIS", 2)
101 self.metadata.set("NAXIS1", 1024)
102 self.metadata.set("NAXIS2", 1153)
103 self.metadata.set("RADECSYS", 'FK5')
104 self.metadata.set("EQUINOX", 2000.)
106 self.metadata.setDouble("CRVAL1", 215.604025685476)
107 self.metadata.setDouble("CRVAL2", 53.1595451514076)
108 self.metadata.setDouble("CRPIX1", 1109.99981456774)
109 self.metadata.setDouble("CRPIX2", 560.018167811613)
110 self.metadata.set("CTYPE1", 'RA---SIN')
111 self.metadata.set("CTYPE2", 'DEC--SIN')
113 self.metadata.setDouble("CD1_1", 5.10808596133527E-05)
114 self.metadata.setDouble("CD1_2", 1.85579539217196E-07)
115 self.metadata.setDouble("CD2_2", -5.10281493481982E-05)
116 self.metadata.setDouble("CD2_1", -8.27440751733828E-07)
118 self.wcs = afwGeom.makeSkyWcs(self.metadata)
119 self.exposure = afwImage.makeExposure(
120 afwImage.makeMaskedImageFromArrays(np.ones((1024, 1153))),
121 self.wcs)
122 detector = DetectorWrapper(id=23, bbox=self.exposure.getBBox()).detector
123 visit = afwImage.VisitInfo(
124 exposureId=4321,
125 exposureTime=200.,
126 date=dafBase.DateTime(nsecs=1400000000 * 10**9))
127 self.exposure.setDetector(detector)
128 self.exposure.getInfo().setVisitInfo(visit)
129 self.exposure.setFilter(afwImage.Filter('g'))
130 scale = 2
131 scaleErr = 1
132 self.photoCalib = afwImage.PhotoCalib(scale, scaleErr)
133 self.exposure.setPhotoCalib(self.photoCalib)
135 self.inputCatalogNoFlags = make_input_source_catalog(10, False)
136 self.inputCatalog = make_input_source_catalog(10, True)
138 def test_run(self):
139 """Test the generic data product mapper.
140 """
141 outSchema = afwTable.SourceTable.makeMinimalSchema()
142 outSchema.addField("psFlux", type="D")
143 outSchema.addField("psFluxErr", type="D")
145 mapApDConfig = MapApDataConfig()
146 mapApDConfig.copyColumns = {
147 "id": "id",
148 "parent": "parent",
149 "coord_ra": "coord_ra",
150 "coord_dec": "coord_dec",
151 "slot_PsfFlux_instFlux": "psFlux",
152 "slot_PsfFlux_instFluxErr": "psFluxErr"
153 }
155 mapApD = MapApDataTask(inputSchema=self.inputCatalog.schema,
156 outputSchema=outSchema,
157 config=mapApDConfig)
158 outputCatalog = mapApD.run(self.inputCatalog)
160 for inObj, outObj in zip(self.inputCatalog, outputCatalog):
161 for inputName, outputName in mapApDConfig.copyColumns.items():
162 self.assertEqual(inObj[inputName], outObj[outputName])
164 def test_run_dia_source(self):
165 """Test the DiaSource specific data product mapper/calibrator.
166 """
167 mapApDConfig = self._create_map_dia_source_config()
168 mapApD = MapDiaSourceTask(inputSchema=self.inputCatalog.schema,
169 config=mapApDConfig)
170 outputCatalog = mapApD.run(self.inputCatalog, self.exposure)
172 expectedMeanDip = 2.
173 expectedDiffFlux = 0.
174 expectedLength = 0.18379083
176 for inObj, outObj in zip(self.inputCatalog, outputCatalog):
177 self.assertEqual(
178 outObj["ccdVisitId"],
179 self.exposure.getInfo().getVisitInfo().getExposureId())
180 self.assertEqual(
181 outObj["midPointTai"],
182 self.exposure.getInfo().getVisitInfo().getDate().get(
183 system=dafBase.DateTime.MJD))
184 self.assertEqual(
185 outObj["flags"],
186 1 * 2 ** 0 + 1 * 2 ** 1)
187 for inputName, outputName in mapApDConfig.copyColumns.items():
188 if inputName.startswith("slot_PsfFlux"):
189 self._test_calibrated_flux(inObj, outObj)
190 else:
191 self.assertEqual(inObj[inputName], outObj[outputName])
192 self.assertEqual(outObj["dipMeanFlux"], expectedMeanDip)
193 self.assertEqual(outObj["dipFluxDiff"], expectedDiffFlux)
194 self.assertAlmostEqual(outObj["dipLength"], expectedLength)
196 def _create_map_dia_source_config(self):
197 """Create a test config for use in MapDiaSourceTask.
199 Returns
200 -------
201 configurable : `lsst.pex.config.Config`
202 Configurable for use in MapDiaSourceTask.
203 """
204 configurable = MapDiaSourceConfig()
205 configurable.copyColumns = {
206 "id": "id",
207 "parent": "parent",
208 "coord_ra": "coord_ra",
209 "coord_dec": "coord_dec",
210 "slot_PsfFlux_instFlux": "psFlux",
211 "slot_PsfFlux_instFluxErr": "psFluxErr"
212 }
213 configurable.calibrateColumns = ["slot_PsfFlux"]
214 configurable.flagMap = os.path.join(
215 getPackageDir("ap_association"),
216 "tests",
217 "test-flag-map.yaml")
219 return configurable
221 def test_run_dia_source_wrong_flags(self):
222 """Test that the proper errors are thrown when requesting flag columns
223 that are not in the input schema.
224 """
225 mapApDConfig = self._create_map_dia_source_config()
226 with self.assertRaises(KeyError):
227 MapDiaSourceTask(inputSchema=self.inputCatalogNoFlags.schema,
228 config=mapApDConfig)
230 def test_calibrateFluxes(self):
231 """Test that flux calibration works as expected.
232 """
233 outSchema = afwTable.SourceTable.makeMinimalSchema()
234 outSchema.addField("psFlux", type="D")
235 outSchema.addField("psFluxErr", type="D")
237 outputCatalog = afwTable.SourceCatalog(outSchema)
238 outRecord = outputCatalog.addNew()
240 mapApDConfig = self._create_map_dia_source_config()
241 mapApD = MapDiaSourceTask(inputSchema=self.inputCatalog.schema,
242 config=mapApDConfig)
244 mapApD.calibrateFluxes(self.inputCatalog[0],
245 outRecord,
246 self.photoCalib)
247 self._test_calibrated_flux(self.inputCatalog[0], outRecord)
249 def _test_calibrated_flux(self, inputRecord, outputRecord):
250 """Compare calibrated fluxes to expectation from zero point.
252 Parameters
253 ----------
254 inputRecord: `lsst.afw.table.SourceRecord`
255 Input source record with uncalibrated flux values.
256 outputRecord: `lsst.afw.table.SourceRecord`
257 Source record with calibrated fluxes.
258 """
259 expected = self.photoCalib.instFluxToNanojansky(inputRecord["slot_PsfFlux_instFlux"],
260 inputRecord["slot_PsfFlux_instFluxErr"])
261 self.assertAlmostEqual(outputRecord["psFlux"], expected.value)
262 self.assertAlmostEqual(outputRecord["psFluxErr"], expected.error)
264 def test_bit_unpacker(self):
265 """Test that the integer bit packer is functioning correctly.
266 """
267 mapApDConfig = self._create_map_dia_source_config()
268 mapApD = MapDiaSourceTask(inputSchema=self.inputCatalog.schema,
269 config=mapApDConfig)
270 for idx, obj in enumerate(self.inputCatalog):
271 if idx in [1, 3, 5]:
272 obj.set("base_PixelFlags_flag", 0)
273 if idx in [1, 4, 6]:
274 obj.set("base_PixelFlags_flag_offimage", 0)
275 outputCatalog = mapApD.run(self.inputCatalog, self.exposure)
277 unpacker = UnpackApdbFlags(mapApDConfig.flagMap, "DiaSource")
278 flag_values = unpacker.unpack(outputCatalog.get("flags"), "flags")
280 for idx, flag in enumerate(flag_values):
281 if idx in [1, 3, 5]:
282 self.assertFalse(flag['base_PixelFlags_flag'])
283 else:
284 self.assertTrue(flag['base_PixelFlags_flag'])
286 if idx in [1, 4, 6]:
287 self.assertFalse(flag['base_PixelFlags_flag_offimage'])
288 else:
289 self.assertTrue(flag['base_PixelFlags_flag_offimage'])
292class MemoryTester(lsst.utils.tests.MemoryTestCase):
293 pass
296def setup_module(module):
297 lsst.utils.tests.init()
300if __name__ == "__main__": 300 ↛ 301line 300 didn't jump to line 301, because the condition on line 300 was never true
301 lsst.utils.tests.init()
302 unittest.main()