Switch to keeping only one whole number in a Time
Instead of splitting every time scale into two floats, let’s keep only a single master `whole` number and then a series of fractions, each that when combined with the whole gives the time in a particular scale. This saves memory, keeps the attribute list smaller, is conceptually simpler, and avoids the problem I just encountered with wanting a high precision two-float version of `ut1` — `ut1_1` or `ut11` would look confusing to others reading the code, and given that the UT1 timescale at least includes a number, folks reading `tt1` and `tt2` might have thought those were different timescales instead of simply two parts of a single number. So I will be using `whole` and `fraction` consistently in the code from now on.
This commit is contained in:
parent
c2c32455a8
commit
1f8e66a42f
|
@ -69,8 +69,11 @@ def main():
|
|||
def reduce_precision(t):
|
||||
# The NOVAS library uses only 64-bit precision for Julian dates.
|
||||
# Some of these tests are so sensitive they can see the difference!
|
||||
t.tdb1 = t.tdb1 + t.tdb2
|
||||
t.tdb2 = 0.0
|
||||
# So we need to collapse the Julian dates back into single floats.
|
||||
delta = t.tdb - t.tt
|
||||
t.whole = t.tdb
|
||||
t.tt_fraction = delta
|
||||
t.tdb_fraction = 0.0
|
||||
|
||||
""")
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ class ChebyshevPosition(SPICESegment):
|
|||
segment = self.spk_segment
|
||||
try:
|
||||
position, velocity = segment.compute_and_differentiate(
|
||||
t.tdb1, t.tdb2)
|
||||
t.whole, t.tdb_fraction)
|
||||
except OutOfRangeError as e:
|
||||
start_time = t.ts.tdb(jd=segment.start_jd)
|
||||
end_time = t.ts.tdb(jd=segment.end_jd)
|
||||
|
@ -226,7 +226,7 @@ class ChebyshevPosition(SPICESegment):
|
|||
|
||||
class ChebyshevPositionVelocity(SPICESegment):
|
||||
def _at(self, t):
|
||||
pv = self.spk_segment.compute(t.tdb1, t.tdb2)
|
||||
pv = self.spk_segment.compute(t.whole, t.tdb_fraction)
|
||||
return pv[:3] / AU_KM, pv[3:] * DAY_S / AU_KM, None, None
|
||||
|
||||
|
||||
|
|
|
@ -35,8 +35,11 @@ def earth():
|
|||
def reduce_precision(t):
|
||||
# The NOVAS library uses only 64-bit precision for Julian dates.
|
||||
# Some of these tests are so sensitive they can see the difference!
|
||||
t.tdb1 = t.tdb1 + t.tdb2
|
||||
t.tdb2 = 0.0
|
||||
# So we need to collapse the Julian dates back into single floats.
|
||||
delta = t.tdb - t.tt
|
||||
t.whole = t.tdb
|
||||
t.tt_fraction = delta
|
||||
t.tdb_fraction = 0.0
|
||||
|
||||
def test_calendar_date_0():
|
||||
compare(timelib.calendar_date(2440423.345833333), array((1969, 7, 20.345833333209157)), 0.0)
|
||||
|
|
|
@ -221,9 +221,7 @@ class Timescale(object):
|
|||
_to_array(hour), _to_array(minute), _to_array(second),
|
||||
)
|
||||
tdb = _to_array(tdb)
|
||||
tt = tdb - tdb_minus_tt(tdb) / DAY_S
|
||||
t = Time(self, tt)
|
||||
t.tdb1, t.tdb2 = tdb, 0.0
|
||||
t = Time(self, tdb, - tdb_minus_tt(tdb) / DAY_S)
|
||||
return t
|
||||
|
||||
def tdb_jd(self, jd):
|
||||
|
@ -237,9 +235,7 @@ class Timescale(object):
|
|||
|
||||
"""
|
||||
tdb = _to_array(jd)
|
||||
tt = tdb - tdb_minus_tt(tdb) / DAY_S
|
||||
t = Time(self, tt)
|
||||
t.tdb1, t.tdb2 = tdb, 0.0
|
||||
t = Time(self, tdb, - tdb_minus_tt(tdb) / DAY_S)
|
||||
return t
|
||||
|
||||
def ut1(self, year=None, month=1, day=1, hour=0, minute=0, second=0.0,
|
||||
|
@ -315,11 +311,10 @@ class Time(object):
|
|||
psi_correction = 0.0
|
||||
eps_correction = 0.0
|
||||
|
||||
def __init__(self, ts, tt, tt2=0.0):
|
||||
def __init__(self, ts, tt, tt_fraction=0.0):
|
||||
self.ts = ts
|
||||
self.tt1, fraction = divmod(tt, 1.0)
|
||||
self.tt2 = fraction + tt2
|
||||
self.tdb1 = self.tt1
|
||||
self.whole, fraction = divmod(tt, 1.0)
|
||||
self.tt_fraction = fraction + tt_fraction
|
||||
self.shape = getattr(tt, 'shape', ())
|
||||
|
||||
def __len__(self):
|
||||
|
@ -339,8 +334,8 @@ class Time(object):
|
|||
# TODO: also copy cached matrices?
|
||||
# TODO: raise non-IndexError exception if this Time is not an array;
|
||||
# otherwise, a `for` loop over it will not raise an error.
|
||||
t = Time(self.ts, self.tt1[index], self.tt2[index])
|
||||
for name in 'tai', 'tdb1', 'tdb2', 'ut1', 'delta_t':
|
||||
t = Time(self.ts, self.whole[index], self.tt_fraction[index])
|
||||
for name in 'tai', 'tdb_fraction', 'ut1', 'delta_t':
|
||||
value = getattr(self, name, None)
|
||||
if value is not None:
|
||||
if getattr(value, 'shape', None):
|
||||
|
@ -569,8 +564,9 @@ class Time(object):
|
|||
i = searchsorted(ts._leap_reverse_dates, tai, 'right')
|
||||
j = tai - ts.leap_offsets[i] / DAY_S
|
||||
|
||||
whole1, fraction = divmod(self.tt1, 1.0)
|
||||
whole2, fraction = divmod(offset - tt_minus_tai + fraction + self.tt2
|
||||
whole1, fraction = divmod(self.whole, 1.0)
|
||||
whole2, fraction = divmod(offset - tt_minus_tai
|
||||
+ fraction + self.tt_fraction
|
||||
- ts.leap_offsets[i] / DAY_S + 0.5, 1.0)
|
||||
whole = (whole1 + whole2).astype(int)
|
||||
|
||||
|
@ -650,9 +646,9 @@ class Time(object):
|
|||
return array(utc) if self.shape else utc
|
||||
|
||||
@reify
|
||||
def tdb2(self):
|
||||
tt2 = self.tt2
|
||||
return tt2 + tdb_minus_tt(self.tt1 + tt2) / DAY_S
|
||||
def tdb_fraction(self):
|
||||
fraction = self.tt_fraction
|
||||
return fraction + tdb_minus_tt(self.whole + fraction) / DAY_S
|
||||
|
||||
@reify
|
||||
def ut1(self):
|
||||
|
@ -665,6 +661,7 @@ class Time(object):
|
|||
|
||||
@reify
|
||||
def dut1(self):
|
||||
# TODO: add test, and then streamline this computation.
|
||||
return (self.tt - self._utc_float()) * DAY_S - self.delta_t
|
||||
|
||||
@reify
|
||||
|
@ -687,11 +684,11 @@ class Time(object):
|
|||
|
||||
@property
|
||||
def tt(self):
|
||||
return self.tt1 + self.tt2
|
||||
return self.whole + self.tt_fraction
|
||||
|
||||
@property
|
||||
def tdb(self):
|
||||
return self.tdb1 + self.tdb2
|
||||
return self.whole + self.tdb_fraction
|
||||
|
||||
# Various dunders.
|
||||
|
||||
|
|
Loading…
Reference in New Issue