Coverage for tests/testModifiedJulianDate.py : 13%

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
12from lsst.utils import getPackageDir
13from lsst.sims.utils import ModifiedJulianDate, UTCtoUT1Warning
16def setup_module(module):
17 lsst.utils.tests.init()
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 """
28 longMessage = True
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 """
38 file_name = os.path.join(getPackageDir('sims_utils'), 'tests')
39 file_name = os.path.join(file_name, 'testData', 'utc_tai_comparison_data.txt')
41 dtype = np.dtype([('utc', np.float), ('tai', np.float)])
42 data = np.genfromtxt(file_name, dtype=dtype)
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."
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)
57 def test_tt(self):
58 """
59 Verify that Terrestrial Time is TAI + 32.184 seconds
60 as in equation 2.223-6 of
62 Explanatory Supplement to the Astrnomical Almanac
63 ed. Seidelmann, Kenneth P.
64 1992, University Science Books
66 Mostly, this test exists to catch any major API
67 changes in astropy.time
68 """
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)
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
81 Explanatory Supplement to the Astrnomical Almanac
82 ed. Seidelmann, Kenneth P.
83 1992, University Science Books
85 Mostly, this test exists to catch any major API
86 changes in astropy.time
87 """
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)
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.
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 """
110 rng = np.random.RandomState(117)
112 utc_list = rng.random_sample(1000) * 10000.0 + 43000.0
113 for utc in utc_list:
114 mjd = ModifiedJulianDate(UTC=utc)
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
122 self.assertLess(np.abs(dt - mjd.dut1), 1.0e-5,
123 msg='failed on UTC: %.12f' % mjd.UTC)
125 self.assertLess(np.abs(mjd.dut1), 0.9)
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.
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 """
139 rng = np.random.RandomState(117)
141 utc_list = rng.random_sample(1000) * 10000.0 + 63000.0
142 for utc in utc_list:
143 mjd = ModifiedJulianDate(UTC=utc)
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
151 self.assertLess(np.abs(dt - mjd.dut1), 1.0e-5,
152 msg='failed on UTC %.12f' % mjd.UTC)
154 self.assertLess(np.abs(mjd.dut1), 0.9)
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)
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__())
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__())
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__())
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")
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")
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)
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)
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 """
283 rng = np.random.RandomState(88)
284 tol = 10 # decimal place tolerance
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)
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)
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)
331class MemoryTestClass(lsst.utils.tests.MemoryTestCase):
332 pass
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()