You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			212 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			212 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Python
		
	
"""Epoch module."""
 | 
						|
 | 
						|
import functools
 | 
						|
import operator
 | 
						|
import math
 | 
						|
import datetime as DT
 | 
						|
 | 
						|
from matplotlib import _api
 | 
						|
from matplotlib.dates import date2num
 | 
						|
 | 
						|
 | 
						|
class Epoch:
 | 
						|
    # Frame conversion offsets in seconds
 | 
						|
    # t(TO) = t(FROM) + allowed[ FROM ][ TO ]
 | 
						|
    allowed = {
 | 
						|
        "ET": {
 | 
						|
            "UTC": +64.1839,
 | 
						|
            },
 | 
						|
        "UTC": {
 | 
						|
            "ET": -64.1839,
 | 
						|
            },
 | 
						|
        }
 | 
						|
 | 
						|
    def __init__(self, frame, sec=None, jd=None, daynum=None, dt=None):
 | 
						|
        """
 | 
						|
        Create a new Epoch object.
 | 
						|
 | 
						|
        Build an epoch 1 of 2 ways:
 | 
						|
 | 
						|
        Using seconds past a Julian date:
 | 
						|
        #   Epoch('ET', sec=1e8, jd=2451545)
 | 
						|
 | 
						|
        or using a matplotlib day number
 | 
						|
        #   Epoch('ET', daynum=730119.5)
 | 
						|
 | 
						|
        = ERROR CONDITIONS
 | 
						|
        - If the input units are not in the allowed list, an error is thrown.
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - frame     The frame of the epoch.  Must be 'ET' or 'UTC'
 | 
						|
        - sec        The number of seconds past the input JD.
 | 
						|
        - jd         The Julian date of the epoch.
 | 
						|
        - daynum    The matplotlib day number of the epoch.
 | 
						|
        - dt         A python datetime instance.
 | 
						|
        """
 | 
						|
        if ((sec is None and jd is not None) or
 | 
						|
                (sec is not None and jd is None) or
 | 
						|
                (daynum is not None and
 | 
						|
                 (sec is not None or jd is not None)) or
 | 
						|
                (daynum is None and dt is None and
 | 
						|
                 (sec is None or jd is None)) or
 | 
						|
                (daynum is not None and dt is not None) or
 | 
						|
                (dt is not None and (sec is not None or jd is not None)) or
 | 
						|
                ((dt is not None) and not isinstance(dt, DT.datetime))):
 | 
						|
            raise ValueError(
 | 
						|
                "Invalid inputs.  Must enter sec and jd together, "
 | 
						|
                "daynum by itself, or dt (must be a python datetime).\n"
 | 
						|
                "Sec = %s\n"
 | 
						|
                "JD  = %s\n"
 | 
						|
                "dnum= %s\n"
 | 
						|
                "dt  = %s" % (sec, jd, daynum, dt))
 | 
						|
 | 
						|
        _api.check_in_list(self.allowed, frame=frame)
 | 
						|
        self._frame = frame
 | 
						|
 | 
						|
        if dt is not None:
 | 
						|
            daynum = date2num(dt)
 | 
						|
 | 
						|
        if daynum is not None:
 | 
						|
            # 1-JAN-0001 in JD = 1721425.5
 | 
						|
            jd = float(daynum) + 1721425.5
 | 
						|
            self._jd = math.floor(jd)
 | 
						|
            self._seconds = (jd - self._jd) * 86400.0
 | 
						|
 | 
						|
        else:
 | 
						|
            self._seconds = float(sec)
 | 
						|
            self._jd = float(jd)
 | 
						|
 | 
						|
            # Resolve seconds down to [ 0, 86400)
 | 
						|
            deltaDays = math.floor(self._seconds / 86400)
 | 
						|
            self._jd += deltaDays
 | 
						|
            self._seconds -= deltaDays * 86400.0
 | 
						|
 | 
						|
    def convert(self, frame):
 | 
						|
        if self._frame == frame:
 | 
						|
            return self
 | 
						|
 | 
						|
        offset = self.allowed[self._frame][frame]
 | 
						|
 | 
						|
        return Epoch(frame, self._seconds + offset, self._jd)
 | 
						|
 | 
						|
    def frame(self):
 | 
						|
        return self._frame
 | 
						|
 | 
						|
    def julianDate(self, frame):
 | 
						|
        t = self
 | 
						|
        if frame != self._frame:
 | 
						|
            t = self.convert(frame)
 | 
						|
 | 
						|
        return t._jd + t._seconds / 86400.0
 | 
						|
 | 
						|
    def secondsPast(self, frame, jd):
 | 
						|
        t = self
 | 
						|
        if frame != self._frame:
 | 
						|
            t = self.convert(frame)
 | 
						|
 | 
						|
        delta = t._jd - jd
 | 
						|
        return t._seconds + delta * 86400
 | 
						|
 | 
						|
    def _cmp(self, op, rhs):
 | 
						|
        """Compare Epochs *self* and *rhs* using operator *op*."""
 | 
						|
        t = self
 | 
						|
        if self._frame != rhs._frame:
 | 
						|
            t = self.convert(rhs._frame)
 | 
						|
        if t._jd != rhs._jd:
 | 
						|
            return op(t._jd, rhs._jd)
 | 
						|
        return op(t._seconds, rhs._seconds)
 | 
						|
 | 
						|
    __eq__ = functools.partialmethod(_cmp, operator.eq)
 | 
						|
    __ne__ = functools.partialmethod(_cmp, operator.ne)
 | 
						|
    __lt__ = functools.partialmethod(_cmp, operator.lt)
 | 
						|
    __le__ = functools.partialmethod(_cmp, operator.le)
 | 
						|
    __gt__ = functools.partialmethod(_cmp, operator.gt)
 | 
						|
    __ge__ = functools.partialmethod(_cmp, operator.ge)
 | 
						|
 | 
						|
    def __add__(self, rhs):
 | 
						|
        """
 | 
						|
        Add a duration to an Epoch.
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - rhs     The Epoch to subtract.
 | 
						|
 | 
						|
        = RETURN VALUE
 | 
						|
        - Returns the difference of ourselves and the input Epoch.
 | 
						|
        """
 | 
						|
        t = self
 | 
						|
        if self._frame != rhs.frame():
 | 
						|
            t = self.convert(rhs._frame)
 | 
						|
 | 
						|
        sec = t._seconds + rhs.seconds()
 | 
						|
 | 
						|
        return Epoch(t._frame, sec, t._jd)
 | 
						|
 | 
						|
    def __sub__(self, rhs):
 | 
						|
        """
 | 
						|
        Subtract two Epoch's or a Duration from an Epoch.
 | 
						|
 | 
						|
        Valid:
 | 
						|
        Duration = Epoch - Epoch
 | 
						|
        Epoch = Epoch - Duration
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - rhs     The Epoch to subtract.
 | 
						|
 | 
						|
        = RETURN VALUE
 | 
						|
        - Returns either the duration between to Epoch's or the a new
 | 
						|
          Epoch that is the result of subtracting a duration from an epoch.
 | 
						|
        """
 | 
						|
        # Delay-load due to circular dependencies.
 | 
						|
        import matplotlib.testing.jpl_units as U
 | 
						|
 | 
						|
        # Handle Epoch - Duration
 | 
						|
        if isinstance(rhs, U.Duration):
 | 
						|
            return self + -rhs
 | 
						|
 | 
						|
        t = self
 | 
						|
        if self._frame != rhs._frame:
 | 
						|
            t = self.convert(rhs._frame)
 | 
						|
 | 
						|
        days = t._jd - rhs._jd
 | 
						|
        sec = t._seconds - rhs._seconds
 | 
						|
 | 
						|
        return U.Duration(rhs._frame, days*86400 + sec)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        """Print the Epoch."""
 | 
						|
        return f"{self.julianDate(self._frame):22.15e} {self._frame}"
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        """Print the Epoch."""
 | 
						|
        return str(self)
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def range(start, stop, step):
 | 
						|
        """
 | 
						|
        Generate a range of Epoch objects.
 | 
						|
 | 
						|
        Similar to the Python range() method.  Returns the range [
 | 
						|
        start, stop) at the requested step.  Each element will be a
 | 
						|
        Epoch object.
 | 
						|
 | 
						|
        = INPUT VARIABLES
 | 
						|
        - start     The starting value of the range.
 | 
						|
        - stop      The stop value of the range.
 | 
						|
        - step      Step to use.
 | 
						|
 | 
						|
        = RETURN VALUE
 | 
						|
        - Returns a list containing the requested Epoch values.
 | 
						|
        """
 | 
						|
        elems = []
 | 
						|
 | 
						|
        i = 0
 | 
						|
        while True:
 | 
						|
            d = start + i * step
 | 
						|
            if d >= stop:
 | 
						|
                break
 | 
						|
 | 
						|
            elems.append(d)
 | 
						|
            i += 1
 | 
						|
 | 
						|
        return elems
 |