Coverage for tests/test_catalogMatch.py: 24%
101 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-20 03:04 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-20 03:04 -0700
1# This file is part of analysis_tools.
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 unittest
24import astropy.units as u
25import lsst.afw.table as afwTable
26import lsst.geom
27import lsst.skymap
28import numpy as np
29import pandas as pd
30from lsst.analysis.tools.tasks import CatalogMatchTask
31from lsst.daf.base import PropertyList
32from lsst.daf.butler import DatasetRef, DatasetType, DimensionUniverse, StorageClass
33from lsst.meas.algorithms import ReferenceObjectLoader
36class MockSourceTableRef:
37 """Replicate functionality of `DeferredDatasetHandle`"""
39 def __init__(self, source_table, ref=None, dataId=None):
40 self.source_table = source_table
41 self.ref = ref
42 self.dataId = dataId
44 def get(self, parameters={}, **kwargs):
45 """Retrieve the specified dataset using the API of the Gen3 Butler.
46 Parameters
47 ----------
48 parameters : `dict`, optional
49 Parameter dictionary. Supported key is ``columns``.
50 Returns
51 -------
52 dataframe : `pandas.DataFrame`
53 dataframe, cut to the specified columns.
54 """
55 if "columns" in parameters:
56 _columns = parameters["columns"]
57 return self.source_table[_columns]
58 else:
59 return self.source_table.copy()
62class MockDataId:
63 """Replicate functionality of `DeferredDatasetHandle.dataId`"""
65 def __init__(self, region):
66 self.region = region
68 datasetDimensions = DimensionUniverse().extract(["htm7"])
69 datasetType = DatasetType("gaia_dr2_20200414", datasetDimensions, StorageClass("SimpleCatalog"))
70 self.ref = DatasetRef(datasetType, {"htm7": "mockRefCat"})
73class TestCatalogMatch(unittest.TestCase):
74 """Test CatalogMatchTask"""
76 def setUp(self):
77 self.task = CatalogMatchTask()
78 self.task.config.extraColumns.append("sourceId")
80 self.skymap = self._make_skymap()
81 self.tract = 9813
83 tract = self.skymap.generateTract(self.tract)
84 self.tractPoly = tract.getOuterSkyPolygon()
85 self.tractBbox = self.tractPoly.getBoundingBox()
87 self.nStars = 1000
88 starIds = np.arange(self.nStars)
89 starRas = (
90 np.random.random(self.nStars) * self.tractBbox.getWidth().asDegrees()
91 + self.tractBbox.getLon().getA().asDegrees()
92 )
93 starDecs = (
94 np.random.random(self.nStars) * self.tractBbox.getHeight().asDegrees()
95 + self.tractBbox.getLat().getA().asDegrees()
96 )
98 refDataId, deferredRefCat = self._make_refCat(starIds, starRas, starDecs, self.tractPoly)
100 self.task.refObjLoader = ReferenceObjectLoader(
101 dataIds=[refDataId], refCats=[deferredRefCat], name="gaia_dr2_20200414"
102 )
103 self.task.refObjLoader.config.anyFilterMapsToThis = "phot_g_mean"
104 self.task.setRefCat(self.skymap, self.tract)
106 self.objectTable = self._make_objectCat(starIds, starRas, starDecs)
108 def _make_skymap(self):
109 """Make a testing skymap.
111 Returns
112 -------
113 `lsst.skymap.ringsSkyMap.RingsSkyMap`
114 Skymap that mimics the "hsc_rings_v1" skymap
115 """
116 skymap_config = lsst.skymap.ringsSkyMap.RingsSkyMapConfig()
117 skymap_config.numRings = 120
118 skymap_config.projection = "TAN"
119 skymap_config.tractOverlap = 1.0 / 60
120 skymap_config.pixelScale = 0.168
121 return lsst.skymap.ringsSkyMap.RingsSkyMap(skymap_config)
123 def _make_refCat(self, starIds, starRas, starDecs, poly):
124 """Make a mock `deferredDatasetReference` and
125 `DeferredDatasetHandle.dataId for a reference catalog.
127 Parameters
128 ----------
129 starIds : `np.ndarray` of `int`
130 Source ids for the simulated stars
131 starRas : `np.ndarray` of `float`
132 RAs of the simulated stars
133 starDecs : `np.ndarray` of `float`
134 Decs of the simulated stars
135 poly : `lsst.sphgeom._sphgeom.ConvexPolygon`
136 Bounding polygon containing the simulated stars
138 Returns
139 -------
140 refDataId : MockDataId
141 Object that replicates the functionality of a dataId
142 deferredRefCat : MockSourceTableRef
143 Object that replicates the functionality of a `DeferredDatasetRef`
144 """
145 refSchema = afwTable.SimpleTable.makeMinimalSchema()
146 idKey = refSchema.addField("sourceId", type="I")
147 fluxKey = refSchema.addField("phot_g_mean_flux", units="nJy", type=np.float64)
148 refCat = afwTable.SimpleCatalog(refSchema)
149 ref_md = PropertyList()
150 ref_md.set("REFCAT_FORMAT_VERSION", 1)
151 refCat.table.setMetadata(ref_md)
152 for i in range(len(starIds)):
153 record = refCat.addNew()
154 record.set(idKey, starIds[i])
155 record.setRa(lsst.geom.Angle(starRas[i], lsst.geom.degrees))
156 record.setDec(lsst.geom.Angle(starDecs[i], lsst.geom.degrees))
157 record.set(fluxKey, 1)
158 refDataId = MockDataId(poly)
159 deferredRefCat = MockSourceTableRef(refCat, ref=refDataId.ref)
160 return refDataId, deferredRefCat
162 def _make_objectCat(self, starIds, starRas, starDecs):
163 """Make a `pd.DataFrame` catalog with the columns needed for the
164 object selector.
166 Parameters
167 ----------
168 starIds : `np.ndarray` of `int`
169 Source ids for the simulated stars
170 starRas : `np.ndarray` of `float`
171 RAs of the simulated stars
172 starDecs : `np.ndarray` of `float`
173 Decs of the simulated stars
174 poly : `lsst.sphgeom._sphgeom.ConvexPolygon`
175 Bounding polygon containing the simulated stars
177 Returns
178 -------
179 sourceCat : `pd.DataFrame`
180 Catalog containing the simulated stars
181 """
182 x = np.random.random(self.nStars) * 4000
183 y = np.random.random(self.nStars) * 4000
184 radecErr = 1.0 / (3600 * 10) # Let random scatter be about 1/10 arcsecond
185 sourceDict = {
186 "sourceId": starIds,
187 "coord_ra": starRas + np.random.randn(self.nStars) * radecErr,
188 "coord_dec": starDecs + np.random.randn(self.nStars) * radecErr,
189 "x": x,
190 "y": y,
191 }
193 for key in [
194 "r_psfFlux_flag",
195 "y_extendedness_flag",
196 "i_pixelFlags_saturatedCenter",
197 "r_extendedness_flag",
198 "y_extendedness",
199 "g_extendedness_flag",
200 "z_extendedness",
201 "i_extendedness",
202 "z_pixelFlags_saturatedCenter",
203 "i_psfFlux_flag",
204 "r_pixelFlags_saturatedCenter",
205 "xy_flag",
206 "r_extendedness",
207 "y_pixelFlags_saturatedCenter",
208 "i_extendedness_flag",
209 "patch",
210 "g_psfFlux_flag",
211 "y_psfFlux_flag",
212 "z_psfFlux_flag",
213 "g_pixelFlags_saturatedCenter",
214 "z_extendedness_flag",
215 "g_extendedness",
216 ]:
217 sourceDict[key] = 0
218 for key in ["detect_isPatchInner", "detect_isDeblendedSource"]:
219 sourceDict[key] = 1
220 for key in ["i_psfFlux", "g_psfFlux", "r_psfFlux", "y_psfFlux", "z_psfFlux"]:
221 sourceDict[key] = 1000
222 for key in ["z_psfFluxErr", "i_psfFluxErr", "r_psfFluxErr", "g_psfFluxErr", "y_psfFluxErr"]:
223 sourceDict[key] = 1
224 sourceCat = pd.DataFrame(sourceDict)
225 return sourceCat
227 def test_setRefCat(self):
228 """Test whether the objects in the reference catalog are in the
229 expected footprint and that we get as many as expected
230 """
231 coord_ra = (self.task.refCat["coord_ra"].to_numpy() * u.degree).to(u.radian).value
232 coord_dec = (self.task.refCat["coord_dec"].to_numpy() * u.degree).to(u.radian).value
233 inFootprint = self.tractBbox.contains(coord_ra, coord_dec)
234 self.assertTrue(inFootprint.all())
235 self.assertEqual(len(self.task.refCat), self.nStars)
237 def test_run(self):
238 """Test whether `CatalogMatchTask` correctly associates the target and
239 reference catalog.
240 """
241 output = self.task.run(self.objectTable)
243 self.assertEqual(len(output.matchedCatalog), self.nStars)
244 self.assertListEqual(
245 output.matchedCatalog["sourceId_target"].to_list(),
246 output.matchedCatalog["sourceId_ref"].to_list(),
247 )
250class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
251 pass
254def setup_module(module):
255 lsst.utils.tests.init()
258if __name__ == "__main__": 258 ↛ 259line 258 didn't jump to line 259, because the condition on line 258 was never true
259 lsst.utils.tests.init()
260 unittest.main()