Coverage for tests/test_catalogMatch.py: 24%
104 statements
« prev ^ index » next coverage.py v6.5.0, created at 2023-04-01 03:11 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2023-04-01 03:11 -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 CatalogMatchConfig, 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 config = CatalogMatchConfig()
78 config.bands = ["g", "r", "i", "z", "y"]
79 self.task = CatalogMatchTask(config=config)
80 self.task.config.extraColumns.append("sourceId")
82 self.rng = np.random.default_rng(12345)
84 self.skymap = self._make_skymap()
85 self.tract = 9813
87 tract = self.skymap.generateTract(self.tract)
88 self.tractPoly = tract.getOuterSkyPolygon()
89 self.tractBbox = self.tractPoly.getBoundingBox()
91 self.nStars = 1000
92 starIds = np.arange(self.nStars)
93 starRas = (
94 self.rng.random(self.nStars) * self.tractBbox.getWidth().asDegrees()
95 + self.tractBbox.getLon().getA().asDegrees()
96 )
97 starDecs = (
98 self.rng.random(self.nStars) * self.tractBbox.getHeight().asDegrees()
99 + self.tractBbox.getLat().getA().asDegrees()
100 )
102 refDataId, deferredRefCat = self._make_refCat(starIds, starRas, starDecs, self.tractPoly)
104 self.task.refObjLoader = ReferenceObjectLoader(
105 dataIds=[refDataId], refCats=[deferredRefCat], name="gaia_dr2_20200414"
106 )
107 self.task.refObjLoader.config.anyFilterMapsToThis = "phot_g_mean"
108 self.task.setRefCat(self.skymap, self.tract)
110 self.objectTable = self._make_objectCat(starIds, starRas, starDecs)
112 def _make_skymap(self):
113 """Make a testing skymap.
115 Returns
116 -------
117 `lsst.skymap.ringsSkyMap.RingsSkyMap`
118 Skymap that mimics the "hsc_rings_v1" skymap
119 """
120 skymap_config = lsst.skymap.ringsSkyMap.RingsSkyMapConfig()
121 skymap_config.numRings = 120
122 skymap_config.projection = "TAN"
123 skymap_config.tractOverlap = 1.0 / 60
124 skymap_config.pixelScale = 0.168
125 return lsst.skymap.ringsSkyMap.RingsSkyMap(skymap_config)
127 def _make_refCat(self, starIds, starRas, starDecs, poly):
128 """Make a mock `deferredDatasetReference` and
129 `DeferredDatasetHandle.dataId for a reference catalog.
131 Parameters
132 ----------
133 starIds : `np.ndarray` of `int`
134 Source ids for the simulated stars
135 starRas : `np.ndarray` of `float`
136 RAs of the simulated stars
137 starDecs : `np.ndarray` of `float`
138 Decs of the simulated stars
139 poly : `lsst.sphgeom._sphgeom.ConvexPolygon`
140 Bounding polygon containing the simulated stars
142 Returns
143 -------
144 refDataId : MockDataId
145 Object that replicates the functionality of a dataId
146 deferredRefCat : MockSourceTableRef
147 Object that replicates the functionality of a `DeferredDatasetRef`
148 """
149 refSchema = afwTable.SimpleTable.makeMinimalSchema()
150 idKey = refSchema.addField("sourceId", type="I")
151 fluxKey = refSchema.addField("phot_g_mean_flux", units="nJy", type=np.float64)
152 refCat = afwTable.SimpleCatalog(refSchema)
153 ref_md = PropertyList()
154 ref_md.set("REFCAT_FORMAT_VERSION", 1)
155 refCat.table.setMetadata(ref_md)
156 for i in range(len(starIds)):
157 record = refCat.addNew()
158 record.set(idKey, starIds[i])
159 record.setRa(lsst.geom.Angle(starRas[i], lsst.geom.degrees))
160 record.setDec(lsst.geom.Angle(starDecs[i], lsst.geom.degrees))
161 record.set(fluxKey, 1)
162 refDataId = MockDataId(poly)
163 deferredRefCat = MockSourceTableRef(refCat, ref=refDataId.ref)
164 return refDataId, deferredRefCat
166 def _make_objectCat(self, starIds, starRas, starDecs):
167 """Make a `pd.DataFrame` catalog with the columns needed for the
168 object selector.
170 Parameters
171 ----------
172 starIds : `np.ndarray` of `int`
173 Source ids for the simulated stars
174 starRas : `np.ndarray` of `float`
175 RAs of the simulated stars
176 starDecs : `np.ndarray` of `float`
177 Decs of the simulated stars
178 poly : `lsst.sphgeom._sphgeom.ConvexPolygon`
179 Bounding polygon containing the simulated stars
181 Returns
182 -------
183 sourceCat : `pd.DataFrame`
184 Catalog containing the simulated stars
185 """
186 x = self.rng.random(self.nStars) * 4000
187 y = self.rng.random(self.nStars) * 4000
188 radecErr = 1.0 / (3600 * 10) # Let random scatter be about 1/10 arcsecond
189 sourceDict = {
190 "sourceId": starIds,
191 "coord_ra": starRas + self.rng.standard_normal(self.nStars) * radecErr,
192 "coord_dec": starDecs + self.rng.standard_normal(self.nStars) * radecErr,
193 "x": x,
194 "y": y,
195 }
197 for key in [
198 "r_psfFlux_flag",
199 "y_extendedness_flag",
200 "i_pixelFlags_saturatedCenter",
201 "r_extendedness_flag",
202 "y_extendedness",
203 "g_extendedness_flag",
204 "z_extendedness",
205 "i_extendedness",
206 "z_pixelFlags_saturatedCenter",
207 "i_psfFlux_flag",
208 "r_pixelFlags_saturatedCenter",
209 "xy_flag",
210 "r_extendedness",
211 "y_pixelFlags_saturatedCenter",
212 "i_extendedness_flag",
213 "patch",
214 "g_psfFlux_flag",
215 "y_psfFlux_flag",
216 "z_psfFlux_flag",
217 "g_pixelFlags_saturatedCenter",
218 "z_extendedness_flag",
219 "g_extendedness",
220 ]:
221 sourceDict[key] = 0
222 for key in ["detect_isPatchInner", "detect_isDeblendedSource"]:
223 sourceDict[key] = 1
224 for key in ["i_psfFlux", "g_psfFlux", "r_psfFlux", "y_psfFlux", "z_psfFlux"]:
225 sourceDict[key] = 1000
226 for key in ["z_psfFluxErr", "i_psfFluxErr", "r_psfFluxErr", "g_psfFluxErr", "y_psfFluxErr"]:
227 sourceDict[key] = 1
228 sourceCat = pd.DataFrame(sourceDict)
229 return sourceCat
231 def test_setRefCat(self):
232 """Test whether the objects in the reference catalog are in the
233 expected footprint and that we get as many as expected
234 """
235 coord_ra = (self.task.refCat["coord_ra"].to_numpy() * u.degree).to(u.radian).value
236 coord_dec = (self.task.refCat["coord_dec"].to_numpy() * u.degree).to(u.radian).value
237 inFootprint = self.tractBbox.contains(coord_ra, coord_dec)
238 self.assertTrue(inFootprint.all())
239 self.assertEqual(len(self.task.refCat), self.nStars)
241 def test_run(self):
242 """Test whether `CatalogMatchTask` correctly associates the target and
243 reference catalog.
244 """
245 output = self.task.run(self.objectTable)
247 self.assertEqual(len(output.matchedCatalog), self.nStars)
248 self.assertListEqual(
249 output.matchedCatalog["sourceId_target"].to_list(),
250 output.matchedCatalog["sourceId_ref"].to_list(),
251 )
254class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
255 pass
258def setup_module(module):
259 lsst.utils.tests.init()
262if __name__ == "__main__": 262 ↛ 263line 262 didn't jump to line 263, because the condition on line 262 was never true
263 lsst.utils.tests.init()
264 unittest.main()