Coverage for tests / test_loadReferenceCatalog.py: 23%

140 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-17 09:21 +0000

1import unittest 

2import copy 

3 

4import astropy.units as u 

5 

6import lsst.utils.tests 

7import lsst.afw.geom 

8import lsst.pipe.base as pipeBase 

9from lsst.meas.algorithms import (convertReferenceCatalog, 

10 getRefFluxField, 

11 ReferenceObjectLoader) 

12from lsst.pipe.tasks.loadReferenceCatalog import LoadReferenceCatalogConfig, LoadReferenceCatalogTask 

13from lsst.pipe.tasks.colorterms import Colorterm, ColortermDict, ColortermLibrary 

14 

15 

16synthTerms = ColortermLibrary(data={ 

17 "synth*": ColortermDict(data={ 

18 "filter1": Colorterm(primary="ref1", secondary="ref2", c0=0.0, c1=0.01), 

19 "filter2": Colorterm(primary="ref2", secondary="ref3", c0=0.0, c1=-0.01), 

20 }) 

21}) 

22 

23 

24_synthFlux = 100.0 

25_synthCenter = lsst.geom.SpherePoint(30, -30, lsst.geom.degrees) 

26 

27 

28def setup_module(module): 

29 lsst.utils.tests.init() 

30 

31 

32class TrivialLoader(ReferenceObjectLoader): 

33 """Minimal subclass of ReferenceObjectLoader""" 

34 def make_synthetic_refcat(self, center, flux): 

35 """Make a synthetic reference catalog.""" 

36 filters = ["ref1", "ref2", "ref3"] 

37 schema = convertReferenceCatalog._makeSchema(filters) 

38 schema.addField('pm_ra', 'D') 

39 schema.addField('pm_dec', 'D') 

40 

41 catalog = lsst.afw.table.SimpleCatalog(schema) 

42 record = catalog.addNew() 

43 record.setCoord(center) 

44 record[filters[0] + '_flux'] = flux 

45 record[filters[0] + '_fluxErr'] = flux*0.1 

46 record[filters[1] + '_flux'] = flux*10 

47 record[filters[1] + '_fluxErr'] = flux*10*0.1 

48 record[filters[2] + '_flux'] = flux*100 

49 record[filters[2] + '_fluxErr'] = flux*100*0.1 

50 record['pm_ra'] = 0.0 

51 record['pm_dec'] = 0.0 

52 

53 return catalog 

54 

55 def loadSkyCircle(self, ctrCoord, radius, filterName, **kwargs): 

56 refCat = self.make_synthetic_refcat(_synthCenter, _synthFlux) 

57 fluxField = getRefFluxField(schema=refCat.schema, filterName=filterName) 

58 return pipeBase.Struct( 

59 refCat=self.make_synthetic_refcat(_synthCenter, _synthFlux), 

60 fluxField=fluxField 

61 ) 

62 

63 def loadPixelBox(self, bbox, wcs, referenceFilter, **kwargs): 

64 return self.loadSkyCircle(None, None, referenceFilter) 

65 

66 def loadSchema(self, filterName): 

67 refCat = self.make_synthetic_refcat(_synthCenter, _synthFlux) 

68 fluxField = getRefFluxField(schema=refCat.schema, filterName=filterName) 

69 return pipeBase.Struct( 

70 schema=refCat.schema, 

71 fluxField=fluxField 

72 ) 

73 

74 

75class LoadReferenceCatalogTestCase(lsst.utils.tests.TestCase): 

76 @classmethod 

77 def setUpClass(cls): 

78 cls.config = LoadReferenceCatalogConfig() 

79 cls.config.refObjLoader.filterMap = {"filter1": "ref1", 

80 "filter2": "ref2"} 

81 cls.config.colorterms = synthTerms 

82 cls.config.referenceSelector.doSignalToNoise = True 

83 cls.config.referenceSelector.signalToNoise.fluxField = 'ref1_flux' 

84 cls.config.referenceSelector.signalToNoise.errField = 'ref1_fluxErr' 

85 cls.config.referenceSelector.signalToNoise.minimum = 20.0 

86 

87 cls.config.doApplyColorTerms = False 

88 cls.config.doReferenceSelection = False 

89 

90 cls.synthMag1 = (_synthFlux*u.nanojansky).to(u.ABmag).value 

91 cls.synthMag2 = ((_synthFlux*10)*u.nanojansky).to(u.ABmag).value 

92 cls.synthMag3 = ((_synthFlux*100)*u.nanojansky).to(u.ABmag).value 

93 

94 cls.synthMag1Corr = cls.synthMag1 + 0.01*(cls.synthMag1 - cls.synthMag2) 

95 cls.synthMag2Corr = cls.synthMag2 - 0.01*(cls.synthMag2 - cls.synthMag3) 

96 

97 cls.trivialLoader = TrivialLoader(dataIds=[], 

98 refCats=[], 

99 name="synthCam", 

100 config=cls.config.refObjLoader) 

101 

102 def testGetReferenceCatalogCircle(self): 

103 """Get a reference catalog skycircle.""" 

104 config = copy.copy(self.config) 

105 config.freeze() 

106 

107 loaderTask = LoadReferenceCatalogTask(config=config, dataIds=[], refCats=[], name="synthCam") 

108 # Monkey-patch our testing trivial loader to bypass the butler 

109 loaderTask.refObjLoader = self.trivialLoader 

110 

111 cat = loaderTask.getSkyCircleCatalog(_synthCenter, 

112 1.0*lsst.geom.degrees, 

113 ['filter1', 'filter2']) 

114 

115 self.assertAlmostEqual(cat['ra'], _synthCenter.getRa().asDegrees()) 

116 self.assertAlmostEqual(cat['dec'], _synthCenter.getDec().asDegrees()) 

117 self.assertFloatsAlmostEqual(cat['refMag'][0, 0], self.synthMag1, rtol=1e-7) 

118 self.assertFloatsAlmostEqual(cat['refMag'][0, 1], self.synthMag2, rtol=1e-7) 

119 

120 def testGetReferenceCatalogBox(self): 

121 """Get a reference catalog box.""" 

122 config = copy.copy(self.config) 

123 config.freeze() 

124 

125 loaderTask = LoadReferenceCatalogTask(config=config, dataIds=[], refCats=[], name="synthCam") 

126 # Monkey-patch our testing trivial loader to bypass the butler 

127 loaderTask.refObjLoader = self.trivialLoader 

128 

129 bbox = lsst.geom.Box2I(corner=lsst.geom.Point2I(0, 0), 

130 dimensions=lsst.geom.Extent2I(100, 100)) 

131 crpix = lsst.geom.Point2D(50, 50) 

132 crval = _synthCenter 

133 cdMatrix = lsst.afw.geom.makeCdMatrix(scale=1.0*lsst.geom.arcseconds) 

134 wcs = lsst.afw.geom.makeSkyWcs(crpix, crval, cdMatrix) 

135 

136 cat = loaderTask.getPixelBoxCatalog(bbox, 

137 wcs, 

138 ['filter1', 'filter2']) 

139 

140 self.assertAlmostEqual(cat['ra'], _synthCenter.getRa().asDegrees()) 

141 self.assertAlmostEqual(cat['dec'], _synthCenter.getDec().asDegrees()) 

142 self.assertFloatsAlmostEqual(cat['refMag'][0, 0], self.synthMag1, rtol=1e-7) 

143 self.assertFloatsAlmostEqual(cat['refMag'][0, 1], self.synthMag2, rtol=1e-7) 

144 

145 def testGetReferenceCatalogCircleColorterms(self): 

146 """Get a reference catalog circle, with color terms applied.""" 

147 config = copy.copy(self.config) 

148 config.doApplyColorTerms = True 

149 config.freeze() 

150 

151 loaderTask = LoadReferenceCatalogTask(config=config, dataIds=[], refCats=[], name="synthCam") 

152 # Monkey-patch our testing trivial loader to bypass the butler 

153 loaderTask.refObjLoader = self.trivialLoader 

154 

155 cat = loaderTask.getSkyCircleCatalog(_synthCenter, 

156 1.0*lsst.geom.degrees, 

157 ['filter1', 'filter2']) 

158 

159 self.assertAlmostEqual(cat['ra'], _synthCenter.getRa().asDegrees()) 

160 self.assertAlmostEqual(cat['dec'], _synthCenter.getDec().asDegrees()) 

161 self.assertFloatsAlmostEqual(cat['refMag'][0, 0], self.synthMag1Corr, rtol=1e-7) 

162 self.assertFloatsAlmostEqual(cat['refMag'][0, 1], self.synthMag2Corr, rtol=1e-7) 

163 

164 def testGetReferenceCatalogCircleSelection(self): 

165 """Get a reference catalog circle, apply selection.""" 

166 config = copy.copy(self.config) 

167 config.doReferenceSelection = True 

168 config.freeze() 

169 

170 loaderTask = LoadReferenceCatalogTask(config=config, dataIds=[], refCats=[], name="synthCam") 

171 # Monkey-patch our testing trivial loader to bypass the butler 

172 loaderTask.refObjLoader = self.trivialLoader 

173 

174 cat = loaderTask.getSkyCircleCatalog(_synthCenter, 

175 1.0*lsst.geom.degrees, 

176 ['filter1', 'filter2']) 

177 

178 # The selection removed all the objects. 

179 self.assertEqual(len(cat), 0) 

180 

181 def testGetReferenceCatalogCircleSingleFilter(self): 

182 """Get a reference catalog circle, single filter.""" 

183 config = copy.copy(self.config) 

184 config.freeze() 

185 

186 loaderTask = LoadReferenceCatalogTask(config=config, dataIds=[], refCats=[], name="synthCam") 

187 # Monkey-patch our testing trivial loader to bypass the butler 

188 loaderTask.refObjLoader = self.trivialLoader 

189 

190 cat = loaderTask.getSkyCircleCatalog(_synthCenter, 

191 1.0*lsst.geom.degrees, 

192 ['filter1']) 

193 

194 self.assertAlmostEqual(cat['ra'], _synthCenter.getRa().asDegrees()) 

195 self.assertAlmostEqual(cat['dec'], _synthCenter.getDec().asDegrees()) 

196 self.assertFloatsAlmostEqual(cat['refMag'][0, 0], self.synthMag1, rtol=1e-7) 

197 

198 def testGetReferenceCatalogAnyFilter(self): 

199 """Get a reference catalog circle, using anyFilterMapsToThis.""" 

200 config = LoadReferenceCatalogConfig() 

201 config.refObjLoader.anyFilterMapsToThis = 'ref1' 

202 

203 config.doApplyColorTerms = False 

204 config.doReferenceSelection = False 

205 config.freeze() 

206 

207 loaderTask = LoadReferenceCatalogTask(config=config, dataIds=[], refCats=[], name="synthCam") 

208 # Monkey-patch our testing trivial loader to bypass the butler 

209 loaderTask.refObjLoader = self.trivialLoader 

210 

211 cat = loaderTask.getSkyCircleCatalog(_synthCenter, 

212 1.0*lsst.geom.degrees, 

213 ['filter1', 'filter2']) 

214 

215 self.assertFloatsAlmostEqual(cat['refMag'][0, 0], self.synthMag1, rtol=1e-7) 

216 self.assertFloatsAlmostEqual(cat['refMag'][0, 1], self.synthMag1, rtol=1e-7) 

217 

218 def testGetReferenceCatalogRequirePm(self): 

219 """Get a reference catalog circle, requiring proper motion.""" 

220 config = copy.copy(self.config) 

221 config.refObjLoader.requireProperMotion = True 

222 config.freeze() 

223 

224 loaderTask = LoadReferenceCatalogTask(config=config, dataIds=[], refCats=[], name="synthCam") 

225 # Monkey-patch our testing trivial loader to bypass the butler 

226 trivialLoader2 = TrivialLoader(dataIds=[], refCats=[], name="synthCam", config=config.refObjLoader) 

227 loaderTask.refObjLoader = trivialLoader2 

228 

229 cat = loaderTask.getSkyCircleCatalog(_synthCenter, 

230 1.0*lsst.geom.degrees, 

231 ['filter1']) 

232 

233 self.assertAlmostEqual(cat['ra'], _synthCenter.getRa().asDegrees()) 

234 self.assertAlmostEqual(cat['dec'], _synthCenter.getDec().asDegrees()) 

235 self.assertFloatsAlmostEqual(cat['refMag'][0, 0], self.synthMag1, rtol=1e-7) 

236 

237 

238class MemoryTester(lsst.utils.tests.MemoryTestCase): 

239 pass 

240 

241 

242if __name__ == "__main__": 242 ↛ 243line 242 didn't jump to line 243 because the condition on line 242 was never true

243 lsst.utils.tests.init() 

244 unittest.main()