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

1from __future__ import with_statement 

2from __future__ import division 

3from builtins import zip 

4import astropy 

5import unittest 

6import warnings 

7import numpy as np 

8import os 

9import copy 

10import lsst.utils.tests 

11 

12from lsst.utils import getPackageDir 

13from lsst.sims.utils import ModifiedJulianDate, UTCtoUT1Warning 

14 

15 

16def setup_module(module): 

17 lsst.utils.tests.init() 

18 

19 

20class MjdTest(unittest.TestCase): 

21 """ 

22 This unit test TestCase will just verify that the contents 

23 of ModifiedJulianDate agree with results generated 'by hand'. 

24 The 'by hand' transformations will have been tested by 

25 testTimeTransformations.py 

26 """ 

27 

28 longMessage = True 

29 

30 def test_tai_from_utc(self): 

31 """ 

32 Load a table of UTC vs. TAI (as JD) generated directly 

33 with ERFA. Verify our ModifiedJulianDate wrapper against 

34 this data. This is mostly so that we can catch any major 

35 API changes in astropy. 

36 """ 

37 

38 file_name = os.path.join(getPackageDir('sims_utils'), 'tests') 

39 file_name = os.path.join(file_name, 'testData', 'utc_tai_comparison_data.txt') 

40 

41 dtype = np.dtype([('utc', np.float), ('tai', np.float)]) 

42 data = np.genfromtxt(file_name, dtype=dtype) 

43 

44 msg = "\n\nIt is possible you are using an out-of-date astropy.\n" + \ 

45 "Try running 'conda update astropy' and restarting the build." 

46 

47 for uu, tt in zip(data['utc']-2400000.5, data['tai']-2400000.5): 

48 mjd = ModifiedJulianDate(UTC=uu) 

49 dd_sec = np.abs(mjd.TAI-tt)*86400.0 

50 self.assertLess(dd_sec, 5.0e-5, msg=msg) 

51 self.assertAlmostEqual(mjd.UTC, uu, 15, msg=msg) 

52 mjd = ModifiedJulianDate(TAI=tt) 

53 dd_sec = np.abs(mjd.UTC-uu)*86400.0 

54 self.assertLess(dd_sec, 5.0e-5, msg=msg) 

55 self.assertAlmostEqual(mjd.TAI, tt, 15, msg=msg) 

56 

57 def test_tt(self): 

58 """ 

59 Verify that Terrestrial Time is TAI + 32.184 seconds 

60 as in equation 2.223-6 of 

61 

62 Explanatory Supplement to the Astrnomical Almanac 

63 ed. Seidelmann, Kenneth P. 

64 1992, University Science Books 

65 

66 Mostly, this test exists to catch any major API 

67 changes in astropy.time 

68 """ 

69 

70 rng = np.random.RandomState(115) 

71 tai_list = rng.random_sample(1000)*7000.0+50000.0 

72 for tai in tai_list: 

73 mjd = ModifiedJulianDate(TAI=tai) 

74 self.assertAlmostEqual(mjd.TT, tai + 32.184 / 86400.0, 15) 

75 

76 def test_tdb(self): 

77 """ 

78 Verify that TDB is within a few tens of microseconds of the value given 

79 by the approximation given by equation 2.222-1 of 

80 

81 Explanatory Supplement to the Astrnomical Almanac 

82 ed. Seidelmann, Kenneth P. 

83 1992, University Science Books 

84 

85 Mostly, this test exists to catch any major API 

86 changes in astropy.time 

87 """ 

88 

89 rng = np.random.RandomState(117) 

90 tai_list = rng.random_sample(1000)*10000.0 + 46000.0 

91 for tai in tai_list: 

92 mjd = ModifiedJulianDate(TAI=tai) 

93 g = np.radians(357.53 + 0.9856003 * (np.round(tai - 51544.5))) 

94 tdb_test = mjd.TT + (0.001658 * np.sin(g) + 0.000014 * np.sin(2.0*g)) / 86400.0 

95 dt = np.abs(tdb_test-mjd.TDB) * 8.64 * 1.0e10 # convert to microseconds 

96 self.assertLess(dt, 50) 

97 

98 def test_dut1(self): 

99 """ 

100 Test that UT1 is within 0.9 seconds of UTC and that dut1 is equal 

101 to UT1-UTC to within a microsecond. 

102 

103 (Because calculating UT1-UTC requires loading a lookup 

104 table, we will just do this somewhat gross unit test to 

105 make sure that the astropy.time API doesn't change out 

106 from under us in some weird way... for instance, returning 

107 dut in units of days rather than seconds, etc.) 

108 """ 

109 

110 rng = np.random.RandomState(117) 

111 

112 utc_list = rng.random_sample(1000) * 10000.0 + 43000.0 

113 for utc in utc_list: 

114 mjd = ModifiedJulianDate(UTC=utc) 

115 

116 # first, test the self-consistency of ModifiedJulianData.dut1 

117 # and ModifiedJulianData.UT1-ModifiedJulianData.UTC 

118 # 

119 # this only works for days on which a leap second is not applied 

120 dt = (mjd.UT1-mjd.UTC) * 86400.0 

121 

122 self.assertLess(np.abs(dt - mjd.dut1), 1.0e-5, 

123 msg='failed on UTC: %.12f' % mjd.UTC) 

124 

125 self.assertLess(np.abs(mjd.dut1), 0.9) 

126 

127 def test_dut1_future(self): 

128 """ 

129 Test that UT1 is within 0.9 seconds of UTC and that dut1 is equal 

130 to UT1-UTC to within a microsecond. Consider times far in the future. 

131 

132 (Because calculating UT1-UTC requires loading a lookup 

133 table, we will just do this somewhat gross unit test to 

134 make sure that the astropy.time API doesn't change out 

135 from under us in some weird way... for instance, returning 

136 dut in units of days rather than seconds, etc.) 

137 """ 

138 

139 rng = np.random.RandomState(117) 

140 

141 utc_list = rng.random_sample(1000) * 10000.0 + 63000.0 

142 for utc in utc_list: 

143 mjd = ModifiedJulianDate(UTC=utc) 

144 

145 # first, test the self-consistency of ModifiedJulianData.dut1 

146 # and ModifiedJulianData.UT1-ModifiedJulianData.UTC 

147 # 

148 # this only works for days on which a leap second is not applied 

149 dt = (mjd.UT1-mjd.UTC) * 86400.0 

150 

151 self.assertLess(np.abs(dt - mjd.dut1), 1.0e-5, 

152 msg='failed on UTC %.12f' % mjd.UTC) 

153 

154 self.assertLess(np.abs(mjd.dut1), 0.9) 

155 

156 def test_eq(self): 

157 mjd1 = ModifiedJulianDate(TAI=43000.0) 

158 mjd2 = ModifiedJulianDate(TAI=43000.0) 

159 self.assertEqual(mjd1, mjd2) 

160 self.assertTrue(mjd1 == mjd2) 

161 self.assertFalse(mjd1 != mjd2) 

162 mjd3 = ModifiedJulianDate(TAI=43000.01) 

163 self.assertNotEqual(mjd1, mjd3) 

164 self.assertFalse(mjd1 == mjd3) 

165 self.assertTrue(mjd1 != mjd3) 

166 

167 def test_deepcopy(self): 

168 # make sure that deepcopy() creates identical 

169 # ModifiedJulianDates with different memory addresses 

170 mjd1 = ModifiedJulianDate(TAI=43590.0) 

171 mjd1.dut1 

172 deep_mjd2 = copy.deepcopy(mjd1) 

173 self.assertEqual(mjd1, deep_mjd2) 

174 self.assertNotEqual(mjd1.__repr__(), deep_mjd2.__repr__()) 

175 self.assertEqual(mjd1.TAI, deep_mjd2.TAI) 

176 self.assertEqual(mjd1.dut1, deep_mjd2.dut1) 

177 equiv_mjd2 = mjd1 

178 self.assertEqual(mjd1, equiv_mjd2) 

179 self.assertEqual(mjd1.__repr__(), equiv_mjd2.__repr__()) 

180 

181 mjd1 = ModifiedJulianDate(UTC=43590.0) 

182 mjd1.dut1 

183 deep_mjd2 = copy.deepcopy(mjd1) 

184 self.assertEqual(mjd1, deep_mjd2) 

185 self.assertEqual(mjd1.UTC, deep_mjd2.UTC) 

186 self.assertEqual(mjd1.dut1, deep_mjd2.dut1) 

187 self.assertNotEqual(mjd1.__repr__(), deep_mjd2.__repr__()) 

188 equiv_mjd2 = mjd1 

189 self.assertEqual(mjd1, equiv_mjd2) 

190 self.assertEqual(mjd1.__repr__(), equiv_mjd2.__repr__()) 

191 

192 # make sure that deepcopy() still works, even if you have called 

193 # all of the original ModifiedJulianDate's properties 

194 mjd1 = ModifiedJulianDate(TAI=42590.0) 

195 mjd1.UTC 

196 mjd1.dut1 

197 mjd1.UT1 

198 mjd1.TT 

199 mjd1.TDB 

200 mjd2 = copy.deepcopy(mjd1) 

201 self.assertEqual(mjd1.TAI, mjd2.TAI) 

202 self.assertEqual(mjd1.UTC, mjd2.UTC) 

203 self.assertEqual(mjd1.dut1, mjd2.dut1) 

204 self.assertEqual(mjd1.UT1, mjd2.UT1) 

205 self.assertEqual(mjd1.TT, mjd2.TT) 

206 self.assertEqual(mjd1.TDB, mjd2.TDB) 

207 self.assertEqual(mjd1, mjd2) 

208 self.assertNotEqual(mjd1.__repr__(), mjd2.__repr__()) 

209 

210 @unittest.skipIf(astropy.__version__ >= '1.2', 

211 "astropy 1.2 handles cases of dates too far in the future " 

212 "on its own in a graceful manner. Our warning classes are not needed") 

213 def test_warnings(self): 

214 """ 

215 Test that warnings raised when trying to interpolate UT1-UTC 

216 for UTC too far in the future are of the type UTCtoUT1Warning 

217 """ 

218 with warnings.catch_warnings(record=True) as w_list: 

219 mjd = ModifiedJulianDate(1000000.0) 

220 # clear the warning registry, in case a previous test raised the warnings 

221 # we are looking for 

222 if '__warningregistry__' in mjd._warn_utc_out_of_bounds.__globals__: 

223 mjd._warn_utc_out_of_bounds.__globals__['__warningregistry__'].clear() 

224 warnings.simplefilter("always") 

225 # Trigger a warning. 

226 # Note that this may also trigger astropy warnings, 

227 # depending on the order in which tests are run. 

228 mjd.UT1 

229 expected_MJD_warnings = 1 

230 MJD_warnings = 0 

231 for w in w_list: 

232 # Count the number of warnings and test we can filter by category. 

233 if w.category == UTCtoUT1Warning: 

234 MJD_warnings += 1 

235 # Test that the string "ModifiedJulianDate.UT1" actually showed up in the message. 

236 # This indicates what method the warning occured from (UT1 vs dut). 

237 self.assertIn("ModifiedJulianDate.UT1", str(w.message)) 

238 self.assertEqual(expected_MJD_warnings, MJD_warnings, msg="UT1 did not emit a UTCtoUT1Warning") 

239 

240 expected_MJD_warnings = 1 

241 MJD_warnings = 0 

242 with warnings.catch_warnings(record=True) as w_list: 

243 warnings.simplefilter('always') 

244 mjd = ModifiedJulianDate(1000000.0) 

245 mjd.dut1 

246 for w in w_list: 

247 if w.category == UTCtoUT1Warning: 

248 MJD_warnings += 1 

249 self.assertIn("ModifiedJulianDate.dut1", str(w.message)) 

250 self.assertEqual(expected_MJD_warnings, MJD_warnings, msg="dut1 did not emit a UTCtoUT1Warning") 

251 

252 def test_force_values(self): 

253 """ 

254 Test that we can force the properties of a ModifiedJulianDate to have 

255 specific values 

256 """ 

257 tt = ModifiedJulianDate(TAI=59580.0) 

258 values = np.arange(6) 

259 tt._force_values(values) 

260 self.assertEqual(tt.TAI, 0.0) 

261 self.assertEqual(tt.UTC, 1.0) 

262 self.assertEqual(tt.TT, 2.0) 

263 self.assertEqual(tt.TDB, 3.0) 

264 self.assertEqual(tt.UT1, 4.0) 

265 self.assertEqual(tt.dut1, 5.0) 

266 

267 tt = ModifiedJulianDate(UTC=59580.0) 

268 values = 2.0*np.arange(6) 

269 tt._force_values(values) 

270 self.assertEqual(tt.TAI, 0.0) 

271 self.assertEqual(tt.UTC, 2.0) 

272 self.assertEqual(tt.TT, 4.0) 

273 self.assertEqual(tt.TDB, 6.0) 

274 self.assertEqual(tt.UT1, 8.0) 

275 self.assertEqual(tt.dut1, 10.0) 

276 

277 def test_list(self): 

278 """ 

279 Test that ModifiedJulianDate.get_list() gets results that are consistent 

280 with creating a list of ModifiedJulianDates by hand. 

281 """ 

282 

283 rng = np.random.RandomState(88) 

284 tol = 10 # decimal place tolerance 

285 

286 tai_list = 40000.0 + 10000.0 * rng.random_sample(20) 

287 tai_list = np.append(tai_list, 59580.0 + 10000.0 * rng.random_sample(20)) 

288 mjd_list = ModifiedJulianDate.get_list(TAI=tai_list) 

289 for tai, mjd in zip(tai_list, mjd_list): 

290 msg = "Offending TAI: %f" % tai 

291 control = ModifiedJulianDate(TAI=tai) 

292 self.assertAlmostEqual(mjd.TAI, tai, 11, msg=msg) 

293 self.assertAlmostEqual(mjd.TAI, control.TAI, tol, msg=msg) 

294 self.assertAlmostEqual(mjd.UTC, control.UTC, tol, msg=msg) 

295 self.assertAlmostEqual(mjd.UT1, control.UT1, tol, msg=msg) 

296 self.assertAlmostEqual(mjd.TT, control.TT, tol, msg=msg) 

297 self.assertAlmostEqual(mjd.TDB, control.TDB, tol, msg=msg) 

298 self.assertAlmostEqual(mjd.dut1, control.dut1, tol, msg=msg) 

299 

300 utc_list = 40000.0 + 10000.0 * rng.random_sample(20) 

301 utc_list = np.append(utc_list, 59580.0 + 10000.0 * rng.random_sample(20)) 

302 mjd_list = ModifiedJulianDate.get_list(UTC=utc_list) 

303 for utc, mjd in zip(utc_list, mjd_list): 

304 msg = "Offending UTC: %f" % utc 

305 control = ModifiedJulianDate(UTC=utc) 

306 self.assertAlmostEqual(mjd.UTC, utc, tol, msg=msg) 

307 self.assertAlmostEqual(mjd.TAI, control.TAI, tol, msg=msg) 

308 self.assertAlmostEqual(mjd.UTC, control.UTC, tol, msg=msg) 

309 self.assertAlmostEqual(mjd.UT1, control.UT1, tol, msg=msg) 

310 self.assertAlmostEqual(mjd.TT, control.TT, tol, msg=msg) 

311 self.assertAlmostEqual(mjd.TDB, control.TDB, tol, msg=msg) 

312 self.assertAlmostEqual(mjd.dut1, control.dut1, tol, msg=msg) 

313 

314 # Now test the case where we only have dates in the future (this 

315 # is an edge case since good_dexes in ModifiedJulianDate._get_ut1_from_utc 

316 # will have len = 0 

317 tai_list = 60000.0 + 10000.0 * rng.random_sample(20) 

318 mjd_list = ModifiedJulianDate.get_list(TAI=tai_list) 

319 for tai, mjd in zip(tai_list, mjd_list): 

320 msg = "Offending TAI: %f" % tai 

321 control = ModifiedJulianDate(TAI=tai) 

322 self.assertAlmostEqual(mjd.TAI, tai, 11, msg=msg) 

323 self.assertAlmostEqual(mjd.TAI, control.TAI, tol, msg=msg) 

324 self.assertAlmostEqual(mjd.UTC, control.UTC, tol, msg=msg) 

325 self.assertAlmostEqual(mjd.UT1, control.UT1, tol, msg=msg) 

326 self.assertAlmostEqual(mjd.TT, control.TT, tol, msg=msg) 

327 self.assertAlmostEqual(mjd.TDB, control.TDB, tol, msg=msg) 

328 self.assertAlmostEqual(mjd.dut1, control.dut1, tol, msg=msg) 

329 

330 

331class MemoryTestClass(lsst.utils.tests.MemoryTestCase): 

332 pass 

333 

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

335 lsst.utils.tests.init() 

336 unittest.main()