Coverage for tests/test_catalogMatch.py: 29%

101 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-09-16 01:43 -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/>. 

21 

22import unittest 

23 

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 

34 

35 

36class MockSourceTableRef: 

37 """Replicate functionality of `DeferredDatasetHandle`""" 

38 

39 def __init__(self, source_table, ref=None, dataId=None): 

40 self.source_table = source_table 

41 self.ref = ref 

42 self.dataId = dataId 

43 

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() 

60 

61 

62class MockDataId: 

63 """Replicate functionality of `DeferredDatasetHandle.dataId`""" 

64 

65 def __init__(self, region): 

66 self.region = region 

67 

68 datasetDimensions = DimensionUniverse().extract(["htm7"]) 

69 datasetType = DatasetType("gaia_dr2_20200414", datasetDimensions, StorageClass("SimpleCatalog")) 

70 self.ref = DatasetRef(datasetType, {"htm7": "mockRefCat"}) 

71 

72 

73class TestCatalogMatch(unittest.TestCase): 

74 """Test CatalogMatchTask""" 

75 

76 def setUp(self): 

77 self.task = CatalogMatchTask() 

78 self.task.config.extraColumns.append("sourceId") 

79 

80 self.skymap = self._make_skymap() 

81 self.tract = 9813 

82 

83 tract = self.skymap.generateTract(self.tract) 

84 self.tractPoly = tract.getOuterSkyPolygon() 

85 self.tractBbox = self.tractPoly.getBoundingBox() 

86 

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 ) 

97 

98 refDataId, deferredRefCat = self._make_refCat(starIds, starRas, starDecs, self.tractPoly) 

99 

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) 

105 

106 self.objectTable = self._make_objectCat(starIds, starRas, starDecs) 

107 

108 def _make_skymap(self): 

109 """Make a testing skymap. 

110 

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) 

122 

123 def _make_refCat(self, starIds, starRas, starDecs, poly): 

124 """Make a mock `deferredDatasetReference` and 

125 `DeferredDatasetHandle.dataId for a reference catalog. 

126 

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 

137 

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 

161 

162 def _make_objectCat(self, starIds, starRas, starDecs): 

163 """Make a `pd.DataFrame` catalog with the columns needed for the 

164 object selector. 

165 

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 

176 

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 } 

192 

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 

226 

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) 

236 

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) 

242 

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 ) 

248 

249 

250class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase): 

251 pass 

252 

253 

254def setup_module(module): 

255 lsst.utils.tests.init() 

256 

257 

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()