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.MP9401'))
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)
195 # Mapper should always emit standardized filters
196 self.assertEqual(outObj["filterName"], 'g')
198 def _create_map_dia_source_config(self):
199 """Create a test config for use in MapDiaSourceTask.
201 Returns
202 -------
203 configurable : `lsst.pex.config.Config`
204 Configurable for use in MapDiaSourceTask.
205 """
206 configurable = MapDiaSourceConfig()
207 configurable.copyColumns = {
208 "id": "id",
209 "parent": "parent",
210 "coord_ra": "coord_ra",
211 "coord_dec": "coord_dec",
212 "slot_PsfFlux_instFlux": "psFlux",
213 "slot_PsfFlux_instFluxErr": "psFluxErr"
214 }
215 configurable.calibrateColumns = ["slot_PsfFlux"]
216 configurable.flagMap = os.path.join(
217 getPackageDir("ap_association"),
218 "tests",
219 "test-flag-map.yaml")
221 return configurable
223 def test_run_dia_source_wrong_flags(self):
224 """Test that the proper errors are thrown when requesting flag columns
225 that are not in the input schema.
226 """
227 mapApDConfig = self._create_map_dia_source_config()
228 with self.assertRaises(KeyError):
229 MapDiaSourceTask(inputSchema=self.inputCatalogNoFlags.schema,
230 config=mapApDConfig)
232 def test_calibrateFluxes(self):
233 """Test that flux calibration works as expected.
234 """
235 outSchema = afwTable.SourceTable.makeMinimalSchema()
236 outSchema.addField("psFlux", type="D")
237 outSchema.addField("psFluxErr", type="D")
239 outputCatalog = afwTable.SourceCatalog(outSchema)
240 outRecord = outputCatalog.addNew()
242 mapApDConfig = self._create_map_dia_source_config()
243 mapApD = MapDiaSourceTask(inputSchema=self.inputCatalog.schema,
244 config=mapApDConfig)
246 mapApD.calibrateFluxes(self.inputCatalog[0],
247 outRecord,
248 self.photoCalib)
249 self._test_calibrated_flux(self.inputCatalog[0], outRecord)
251 def _test_calibrated_flux(self, inputRecord, outputRecord):
252 """Compare calibrated fluxes to expectation from zero point.
254 Parameters
255 ----------
256 inputRecord: `lsst.afw.table.SourceRecord`
257 Input source record with uncalibrated flux values.
258 outputRecord: `lsst.afw.table.SourceRecord`
259 Source record with calibrated fluxes.
260 """
261 expected = self.photoCalib.instFluxToNanojansky(inputRecord["slot_PsfFlux_instFlux"],
262 inputRecord["slot_PsfFlux_instFluxErr"])
263 self.assertAlmostEqual(outputRecord["psFlux"], expected.value)
264 self.assertAlmostEqual(outputRecord["psFluxErr"], expected.error)
266 def test_bit_unpacker(self):
267 """Test that the integer bit packer is functioning correctly.
268 """
269 mapApDConfig = self._create_map_dia_source_config()
270 mapApD = MapDiaSourceTask(inputSchema=self.inputCatalog.schema,
271 config=mapApDConfig)
272 for idx, obj in enumerate(self.inputCatalog):
273 if idx in [1, 3, 5]:
274 obj.set("base_PixelFlags_flag", 0)
275 if idx in [1, 4, 6]:
276 obj.set("base_PixelFlags_flag_offimage", 0)
277 outputCatalog = mapApD.run(self.inputCatalog, self.exposure)
279 unpacker = UnpackApdbFlags(mapApDConfig.flagMap, "DiaSource")
280 flag_values = unpacker.unpack(outputCatalog.get("flags"), "flags")
282 for idx, flag in enumerate(flag_values):
283 if idx in [1, 3, 5]:
284 self.assertFalse(flag['base_PixelFlags_flag'])
285 else:
286 self.assertTrue(flag['base_PixelFlags_flag'])
288 if idx in [1, 4, 6]:
289 self.assertFalse(flag['base_PixelFlags_flag_offimage'])
290 else:
291 self.assertTrue(flag['base_PixelFlags_flag_offimage'])
294class MemoryTester(lsst.utils.tests.MemoryTestCase):
295 pass
298def setup_module(module):
299 lsst.utils.tests.init()
302if __name__ == "__main__": 302 ↛ 303line 302 didn't jump to line 303, because the condition on line 302 was never true
303 lsst.utils.tests.init()
304 unittest.main()