Hide keyboard shortcuts

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 jointcal. 

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 

23import os 

24 

25from astropy import units as u 

26import numpy as np 

27 

28from lsst.daf.butler import Butler 

29import lsst.geom 

30import lsst.pex.config 

31import lsst.utils 

32import lsst.pex.exceptions 

33 

34import jointcalTestBase 

35 

36 

37# for MemoryTestCase 

38def setup_module(module): 

39 lsst.utils.tests.init() 

40 

41 

42class JointcalTestHSC(jointcalTestBase.JointcalTestBase, lsst.utils.tests.TestCase): 

43 

44 @classmethod 

45 def setUpClass(cls): 

46 try: 

47 cls.data_dir = lsst.utils.getPackageDir('testdata_jointcal') 

48 except LookupError: 

49 raise unittest.SkipTest("testdata_jointcal not setup") 

50 try: 

51 lsst.utils.getPackageDir('obs_subaru') 

52 except LookupError: 

53 raise unittest.SkipTest("obs_subaru not setup") 

54 

55 def setUp(self): 

56 # See Readme for an explanation of these empirical values. 

57 self.dist_rms_absolute = 21e-3*u.arcsecond 

58 self.dist_rms_relative = 7e-3*u.arcsecond 

59 

60 do_plot = False 

61 

62 # center of the hsc validation_data catalog 

63 center = lsst.geom.SpherePoint(337.710899, +0.807006, lsst.geom.degrees) 

64 radius = 0.5*lsst.geom.degrees 

65 

66 input_dir = os.path.join(self.data_dir, 'hsc') 

67 all_visits = [34648, 34690, 34714, 34674, 34670, 36140, 35892, 36192, 36260, 36236] 

68 

69 where = "instrument='HSC' and tract=9697 and skymap='hsc_rings_v1'" 

70 

71 self.setUp_base(center, radius, 

72 input_dir=input_dir, 

73 all_visits=all_visits, 

74 do_plot=do_plot, 

75 where=where) 

76 

77 test_config = os.path.join(lsst.utils.getPackageDir('jointcal'), 'tests/config/hsc-config.py') 

78 self.configfiles.append(test_config) 

79 

80 def test_jointcalTask_2_visits_simple(self): 

81 self.config = lsst.jointcal.jointcal.JointcalConfig() 

82 self.config.astrometryModel = "simple" 

83 self.config.photometryModel = "simpleFlux" 

84 

85 # See Readme for an explanation of these empirical values. 

86 pa1 = 0.016 

87 metrics = {'astrometry_collected_refStars': 568, 

88 'photometry_collected_refStars': 6485, 

89 'astrometry_prepared_refStars': 137, 

90 'photometry_prepared_refStars': 1609, 

91 'astrometry_matched_fittedStars': 2070, 

92 'photometry_matched_fittedStars': 2070, 

93 'astrometry_prepared_fittedStars': 989, 

94 'photometry_prepared_fittedStars': 1731, 

95 'astrometry_prepared_ccdImages': 6, 

96 'photometry_prepared_ccdImages': 6, 

97 'astrometry_final_chi2': 835.473, 

98 'astrometry_final_ndof': 1918, 

99 'photometry_final_chi2': 4997.62, 

100 'photometry_final_ndof': 2188 

101 } 

102 self._testJointcalTask(2, self.dist_rms_relative, self.dist_rms_absolute, pa1, metrics=metrics) 

103 

104 def test_jointcalTask_2_visits_simple_gen3(self): 

105 """Test gen3 butler jointcal.""" 

106 configOptions = {"astrometryModel": "simple", "photometryModel": "simpleFlux"} 

107 where = f" and visit in ({self.all_visits[0]},{self.all_visits[1]})" 

108 

109 metrics = {'astrometry_collected_refStars': 568, 

110 'photometry_collected_refStars': 6485, 

111 'astrometry_prepared_refStars': 137, 

112 'photometry_prepared_refStars': 1609, 

113 'astrometry_matched_fittedStars': 2070, 

114 'photometry_matched_fittedStars': 2070, 

115 'astrometry_prepared_fittedStars': 989, 

116 'photometry_prepared_fittedStars': 1731, 

117 'astrometry_prepared_ccdImages': 6, 

118 'photometry_prepared_ccdImages': 6, 

119 'astrometry_final_chi2': 835.473, 

120 'astrometry_final_ndof': 1918, 

121 'photometry_final_chi2': 4997.62, 

122 'photometry_final_ndof': 2188 

123 } 

124 self._runGen3Jointcal("lsst.obs.subaru.HyperSuprimeCam", "HSC", whereSuffix=where, 

125 configOptions=configOptions, metrics=metrics) 

126 # TODO DM-28863: this does not currently test anything other than the code 

127 # running without raising and that it writes non-empty output. 

128 butler = Butler(self.repo, collections=['HSC/testdata/jointcal']) 

129 

130 def check_output(visit, detectors): 

131 """Check that there is something for each detector, and only 

132 entries for the correct detectors.""" 

133 dataId = {'visit': visit, 'instrument': 'HSC', 'tract': 9697} 

134 

135 catalog = butler.get('jointcalPhotoCalibCatalog', dataId) 

136 for record in catalog: 

137 self.assertIsInstance(record.getPhotoCalib(), lsst.afw.image.PhotoCalib, 

138 msg=f"visit {visit}: {record}") 

139 np.testing.assert_array_equal(catalog['id'], detectors) 

140 

141 catalog = butler.get('jointcalSkyWcsCatalog', dataId) 

142 for record in catalog: 

143 self.assertIsInstance(record.getWcs(), lsst.afw.geom.SkyWcs, 

144 msg=f"visit {visit}: {record}") 

145 np.testing.assert_array_equal(catalog['id'], detectors) 

146 

147 check_output(34648, [51, 59, 67]) 

148 check_output(34690, [48, 56, 64]) 

149 

150 def test_jointcalTask_ri_visits_2_bands_simple_gen3_dm32207(self): 

151 """Test gen3 butler jointcal putting 2 bands in same repo.""" 

152 configOptions = {"astrometryModel": "simple", "photometryModel": "simpleFlux"} 

153 where = (f" and visit in ({self.all_visits[0]},{self.all_visits[1]}," 

154 f"{self.all_visits[5]},{self.all_visits[6]})") 

155 

156 self._runGen3Jointcal("lsst.obs.subaru.HyperSuprimeCam", "HSC", whereSuffix=where, 

157 configOptions=configOptions, metrics=None, nJobs=2) 

158 

159 def test_jointcalTask_2_visits_simple_astrometry_no_photometry_gen3(self): 

160 """Test gen3 butler jointcal, no photometry.""" 

161 configOptions = {"astrometryModel": "simple", "doPhotometry": False} 

162 where = f" and visit in ({self.all_visits[0]},{self.all_visits[1]})" 

163 

164 metrics = {'astrometry_collected_refStars': 568, 

165 'astrometry_prepared_refStars': 137, 

166 'astrometry_matched_fittedStars': 2070, 

167 'astrometry_prepared_fittedStars': 989, 

168 'astrometry_prepared_ccdImages': 6, 

169 'astrometry_final_chi2': 835.473, 

170 'astrometry_final_ndof': 1918, 

171 } 

172 self._runGen3Jointcal("lsst.obs.subaru.HyperSuprimeCam", "HSC", whereSuffix=where, 

173 configOptions=configOptions, metrics=metrics) 

174 # TODO DM-28863: this does not currently test anything other than the code 

175 # running without raising and that it writes non-empty output. 

176 butler = Butler(self.repo, collections=['HSC/testdata/jointcal']) 

177 

178 def check_output(visit, detectors): 

179 """Check that there is something for each detector, and only 

180 entries for the correct detectors.""" 

181 dataId = {'visit': visit, 'instrument': 'HSC', 'tract': 9697} 

182 

183 catalog = butler.get('jointcalSkyWcsCatalog', dataId) 

184 for record in catalog: 

185 self.assertIsInstance(record.getWcs(), lsst.afw.geom.SkyWcs, 

186 msg=f"visit {visit}: {record}") 

187 np.testing.assert_array_equal(catalog['id'], detectors) 

188 

189 check_output(34648, [51, 59, 67]) 

190 check_output(34690, [48, 56, 64]) 

191 

192 def test_jointcalTask_2_visits_simple_photometry_no_astrometry_gen3(self): 

193 """Test gen3 butler jointcal, no astrometry.""" 

194 configOptions = {"doAstrometry": False, "photometryModel": "simpleFlux"} 

195 where = f" and visit in ({self.all_visits[0]},{self.all_visits[1]})" 

196 

197 metrics = {'photometry_collected_refStars': 6485, 

198 'photometry_prepared_refStars': 1609, 

199 'photometry_matched_fittedStars': 2070, 

200 'photometry_prepared_fittedStars': 1731, 

201 'photometry_prepared_ccdImages': 6, 

202 'photometry_final_chi2': 4997.62, 

203 'photometry_final_ndof': 2188 

204 } 

205 self._runGen3Jointcal("lsst.obs.subaru.HyperSuprimeCam", "HSC", whereSuffix=where, 

206 configOptions=configOptions, metrics=metrics) 

207 # TODO DM-28863: this does not currently test anything other than the code 

208 # running without raising and that it writes non-empty output. 

209 butler = Butler(self.repo, collections=['HSC/testdata/jointcal']) 

210 

211 def check_output(visit, detectors): 

212 """Check that there is something for each detector, and only 

213 entries for the correct detectors.""" 

214 dataId = {'visit': visit, 'instrument': 'HSC', 'tract': 9697} 

215 

216 catalog = butler.get('jointcalPhotoCalibCatalog', dataId) 

217 for record in catalog: 

218 self.assertIsInstance(record.getPhotoCalib(), lsst.afw.image.PhotoCalib, 

219 msg=f"visit {visit}: {record}") 

220 np.testing.assert_array_equal(catalog['id'], detectors) 

221 

222 check_output(34648, [51, 59, 67]) 

223 check_output(34690, [48, 56, 64]) 

224 

225 def test_jointcalTask_10_visits_simple_astrometry_no_photometry(self): 

226 """Test all 10 visits with different filters. 

227 Testing photometry doesn't make sense for this currently. 

228 """ 

229 

230 self.config = lsst.jointcal.jointcal.JointcalConfig() 

231 self.config.astrometryModel = "simple" 

232 self.config.doPhotometry = False 

233 self.jointcalStatistics.do_photometry = False 

234 

235 # See Readme for an explanation of these empirical values. 

236 dist_rms_absolute = 23e-3*u.arcsecond 

237 dist_rms_relative = 13e-3*u.arcsecond 

238 pa1 = None 

239 metrics = {'astrometry_collected_refStars': 1316, 

240 'astrometry_prepared_refStars': 318, 

241 'astrometry_matched_fittedStars': 5860, 

242 'astrometry_prepared_fittedStars': 3568, 

243 'astrometry_prepared_ccdImages': 30, 

244 'astrometry_final_chi2': 10225.31, 

245 'astrometry_final_ndof': 18576, 

246 } 

247 self._testJointcalTask(10, dist_rms_relative, dist_rms_absolute, pa1, metrics=metrics) 

248 

249 def setup_jointcalTask_2_visits_simplePhotometry(self): 

250 """Set default values for the simplePhotometry tests, and make it so 

251 the differences between each test and the defaults are more obvious. 

252 """ 

253 self.config = lsst.jointcal.jointcal.JointcalConfig() 

254 self.config.photometryModel = "simpleFlux" 

255 self.config.doAstrometry = False 

256 self.jointcalStatistics.do_astrometry = False 

257 

258 # See Readme for an explanation of these empirical values. 

259 pa1 = 0.016 

260 metrics = {'photometry_collected_refStars': 6485, 

261 'photometry_prepared_refStars': 1609, 

262 'photometry_matched_fittedStars': 2070, 

263 'photometry_prepared_fittedStars': 1731, 

264 'photometry_prepared_ccdImages': 6, 

265 'photometry_final_chi2': 4997.62, 

266 'photometry_final_ndof': 2188 

267 } 

268 return pa1, metrics 

269 

270 def test_jointcalTask_2_visits_simpleFlux(self): 

271 pa1, metrics = self.setup_jointcalTask_2_visits_simplePhotometry() 

272 self._testJointcalTask(2, None, None, pa1, metrics=metrics) 

273 

274 def test_jointcalTask_2_visits_simpleMagnitude(self): 

275 pa1, metrics = self.setup_jointcalTask_2_visits_simplePhotometry() 

276 self.config.photometryModel = "simpleMagnitude" 

277 metrics['photometry_final_chi2'] = 5236.91 

278 metrics['photometry_final_ndof'] = 2200 

279 

280 self._testJointcalTask(2, None, None, pa1, metrics=metrics) 

281 

282 def test_jointcalTask_2_visits_simpleMagnitude_colorterms(self): 

283 """Test that colorterms are applied and change the fit.""" 

284 pa1, metrics = self.setup_jointcalTask_2_visits_simplePhotometry() 

285 self.config.photometryModel = "simpleMagnitude" 

286 test_config = os.path.join(lsst.utils.getPackageDir('jointcal'), 

287 'tests/config/hsc-colorterms-config.py') 

288 self.configfiles.append(test_config) 

289 

290 # slightly fewer refstars because they each need the specific filters required by the colorterms 

291 metrics['photometry_collected_refStars'] = 6478 

292 # Final chi2 should be different, but I don't have an a-priori reason 

293 # to expect it to be larger or smaller. 

294 metrics['photometry_final_chi2'] = 5181.25 

295 metrics['photometry_final_ndof'] = 2197 

296 

297 self._testJointcalTask(2, None, None, pa1, metrics=metrics) 

298 

299 def test_jointcalTask_2_visits_simpleMagnitude_colorterms_no_library(self): 

300 """Fail Config validation if the color term library isn't defined.""" 

301 pa1, metrics = self.setup_jointcalTask_2_visits_simplePhotometry() 

302 test_config = os.path.join(lsst.utils.getPackageDir('jointcal'), 

303 'tests/config/hsc-colorterms_no_library-config.py') 

304 self.configfiles.append(test_config) 

305 

306 with self.assertRaises(lsst.pex.config.FieldValidationError): 

307 self._testJointcalTask(2, None, None, pa1) 

308 

309 def test_JointcalTask_2_visits_simple_astrometry_no_photometry(self): 

310 """Test turning off fitting photometry.""" 

311 metrics = {'astrometry_collected_refStars': 568, 

312 'astrometry_prepared_refStars': 137, 

313 'astrometry_matched_fittedStars': 2070, 

314 'astrometry_prepared_fittedStars': 989, 

315 'astrometry_prepared_ccdImages': 6, 

316 'astrometry_final_chi2': 835.473, 

317 'astrometry_final_ndof': 1918, 

318 } 

319 self.config = lsst.jointcal.jointcal.JointcalConfig() 

320 self.config.astrometryModel = "simple" 

321 self.config.doPhotometry = False 

322 self.jointcalStatistics.do_photometry = False 

323 

324 data_refs = self._testJointcalTask(2, self.dist_rms_relative, self.dist_rms_absolute, 

325 None, metrics=metrics) 

326 

327 for data_ref in data_refs: 

328 with self.assertRaises(lsst.daf.persistence.butlerExceptions.NoResults): 

329 data_ref.get('jointcal_photoCalib') 

330 

331 def test_jointcalTask_2_visits_simple_astrometry_no_photometry_match_cut_10(self): 

332 """A larger matching radius will result in more associated fittedStars, 

333 and a somewhat worse final fit because stars that should not have been 

334 associated, were. 

335 """ 

336 self.config = lsst.jointcal.jointcal.JointcalConfig() 

337 self.config.astrometryModel = "simple" 

338 self.config.matchCut = 10.0 # TODO: once DM-6885 is fixed, we need to put `*lsst.geom.arcseconds` 

339 self.config.doPhotometry = False 

340 self.jointcalStatistics.do_photometry = False 

341 

342 # Slightly larger absolute astrometry RMS because of the larger matching radius 

343 dist_rms_absolute = 23e-3*u.arcsecond 

344 metrics = {'astrometry_collected_refStars': 568, 

345 'astrometry_prepared_refStars': 211, 

346 'astrometry_matched_fittedStars': 2070, 

347 'astrometry_prepared_fittedStars': 1042, 

348 'astrometry_prepared_ccdImages': 6, 

349 'astrometry_final_chi2': 819.608, 

350 'astrometry_final_ndof': 1872, 

351 } 

352 pa1 = None 

353 self._testJointcalTask(2, self.dist_rms_relative, dist_rms_absolute, pa1, metrics=metrics) 

354 

355 def test_jointcalTask_3_visits_simple_astrometry_no_photometry(self): 

356 """3 visit, default config to compare with min_measurements_3 test.""" 

357 self.config = lsst.jointcal.jointcal.JointcalConfig() 

358 self.config.astrometryModel = "simple" 

359 self.config.minMeasurements = 2 

360 self.config.doPhotometry = False 

361 self.jointcalStatistics.do_photometry = False 

362 

363 # More visits and slightly worse relative and absolute rms. 

364 dist_rms_relative = 8.3e-3*u.arcsecond 

365 dist_rms_absolute = 24e-3*u.arcsecond 

366 metrics = {'astrometry_collected_refStars': 1038, 

367 'astrometry_prepared_refStars': 209, 

368 'astrometry_matched_fittedStars': 3199, 

369 'astrometry_prepared_fittedStars': 1282, 

370 'astrometry_prepared_ccdImages': 9, 

371 'astrometry_final_chi2': 1221.63, 

372 'astrometry_final_ndof': 2892, 

373 } 

374 pa1 = None 

375 self._testJointcalTask(3, dist_rms_relative, dist_rms_absolute, pa1, metrics=metrics) 

376 

377 def test_jointcalTask_3_visits_simple_astrometry_no_photometry_min_measurements_3(self): 

378 """Raising min_measurements to 3 will reduce the number of selected 

379 fitted stars (and thus the chisq and Ndof), but should not change the 

380 other values.""" 

381 self.config = lsst.jointcal.jointcal.JointcalConfig() 

382 self.config.minMeasurements = 3 

383 self.config.astrometryModel = "simple" 

384 self.config.doPhotometry = False 

385 self.jointcalStatistics.do_photometry = False 

386 

387 # More visits and slightly worse relative and absolute rms. 

388 dist_rms_relative = 11e-3*u.arcsecond 

389 dist_rms_absolute = 24e-3*u.arcsecond 

390 metrics = {'astrometry_collected_refStars': 1038, 

391 'astrometry_prepared_refStars': 209, 

392 'astrometry_matched_fittedStars': 3199, 

393 'astrometry_prepared_fittedStars': 432, 

394 'astrometry_prepared_ccdImages': 9, 

395 'astrometry_final_chi2': 567.433, 

396 'astrometry_final_ndof': 1286, 

397 } 

398 pa1 = None 

399 self._testJointcalTask(3, dist_rms_relative, dist_rms_absolute, pa1, metrics=metrics) 

400 

401 

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

403 pass 

404 

405 

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

407 lsst.utils.tests.init() 

408 unittest.main()