예제 #1
0
파일: test_basic.py 프로젝트: MQQ/astropy
 def test_copy(self):
     """Test copy method"""
     t = Time("2000:001", format="yday", scale="tai")
     t_yday = t.yday
     t2 = t.copy()
     assert t.yday == t2.yday
     # This is not allowed publicly, but here we hack the internal time values
     # to show that t and t2 are not sharing references.
     t2._time.jd1 += 100.0
     assert t.yday != t2.yday
     assert t.yday == t_yday  # prove that it did not change
예제 #2
0
def mjd2lst(mjd):
    """
    Converts decimal MJD to LST in decimal degrees

    Args:
        mjd: float

    Returns:
        lst: float (degrees)
    """

    lon = str(mayall.west_lon_deg) + 'd'
    lat = str(mayall.lat_deg) + 'd'

    t = Time(mjd, format='mjd', location=(lon, lat))
    lst_tmp = t.copy()

    #try:
    #    lst_str = str(lst_tmp.sidereal_time('apparent'))
    #except IndexError:
    #    lst_tmp.delta_ut1_utc = -0.1225
    #    lst_str = str(lst_tmp.sidereal_time('apparent'))

    x, y, dut = earthOrientation(mjd)
    lst_tmp.delta_ut1_utc = dut
    lst_str = str(lst_tmp.sidereal_time('apparent'))
    # 23h09m35.9586s
    # 01234567890123
    if lst_str[2] == 'h':
        lst_hr = float(lst_str[0:2])
        lst_mn = float(lst_str[3:5])
        lst_sc = float(lst_str[6:-1])
    else:
        lst_hr = float(lst_str[0:1])
        lst_mn = float(lst_str[2:4])
        lst_sc = float(lst_str[5:-1])
    lst = lst_hr + lst_mn / 60.0 + lst_sc / 3600.0
    lst *= 15.0  # Convert from hours to degrees
    return lst
예제 #3
0
class TestManipulation:
    """Manipulation of Time objects, ensuring attributes are done correctly."""
    def setup(self):
        mjd = np.arange(50000, 50010)
        frac = np.arange(0., 0.999, 0.2)
        if use_masked_data:
            frac = np.ma.array(frac)
            frac[1] = np.ma.masked
        self.t0 = Time(mjd[:, np.newaxis] + frac, format='mjd', scale='utc')
        self.t1 = Time(mjd[:, np.newaxis] + frac,
                       format='mjd',
                       scale='utc',
                       location=('45d', '50d'))
        self.t2 = Time(mjd[:, np.newaxis] + frac,
                       format='mjd',
                       scale='utc',
                       location=(np.arange(len(frac)), np.arange(len(frac))))
        # Note: location is along last axis only.
        self.t2 = Time(mjd[:, np.newaxis] + frac,
                       format='mjd',
                       scale='utc',
                       location=(np.arange(len(frac)), np.arange(len(frac))))

    def test_ravel(self, masked):
        t0_ravel = self.t0.ravel()
        assert t0_ravel.shape == (self.t0.size, )
        assert np.all(t0_ravel.jd1 == self.t0.jd1.ravel())
        assert np.may_share_memory(t0_ravel.jd1, self.t0.jd1)
        assert t0_ravel.location is None
        t1_ravel = self.t1.ravel()
        assert t1_ravel.shape == (self.t1.size, )
        assert np.all(t1_ravel.jd1 == self.t1.jd1.ravel())
        assert np.may_share_memory(t1_ravel.jd1, self.t1.jd1)
        assert t1_ravel.location is self.t1.location
        t2_ravel = self.t2.ravel()
        assert t2_ravel.shape == (self.t2.size, )
        assert np.all(t2_ravel.jd1 == self.t2.jd1.ravel())
        assert np.may_share_memory(t2_ravel.jd1, self.t2.jd1)
        assert t2_ravel.location.shape == t2_ravel.shape
        # Broadcasting and ravelling cannot be done without a copy.
        assert not np.may_share_memory(t2_ravel.location, self.t2.location)

    def test_flatten(self, masked):
        t0_flatten = self.t0.flatten()
        assert t0_flatten.shape == (self.t0.size, )
        assert t0_flatten.location is None
        # Flatten always makes a copy.
        assert not np.may_share_memory(t0_flatten.jd1, self.t0.jd1)
        t1_flatten = self.t1.flatten()
        assert t1_flatten.shape == (self.t1.size, )
        assert not np.may_share_memory(t1_flatten.jd1, self.t1.jd1)
        assert t1_flatten.location is not self.t1.location
        assert t1_flatten.location == self.t1.location
        t2_flatten = self.t2.flatten()
        assert t2_flatten.shape == (self.t2.size, )
        assert not np.may_share_memory(t2_flatten.jd1, self.t2.jd1)
        assert t2_flatten.location.shape == t2_flatten.shape
        assert not np.may_share_memory(t2_flatten.location, self.t2.location)

    def test_transpose(self, masked):
        t0_transpose = self.t0.transpose()
        assert t0_transpose.shape == (5, 10)
        assert np.all(t0_transpose.jd1 == self.t0.jd1.transpose())
        assert np.may_share_memory(t0_transpose.jd1, self.t0.jd1)
        assert t0_transpose.location is None
        t1_transpose = self.t1.transpose()
        assert t1_transpose.shape == (5, 10)
        assert np.all(t1_transpose.jd1 == self.t1.jd1.transpose())
        assert np.may_share_memory(t1_transpose.jd1, self.t1.jd1)
        assert t1_transpose.location is self.t1.location
        t2_transpose = self.t2.transpose()
        assert t2_transpose.shape == (5, 10)
        assert np.all(t2_transpose.jd1 == self.t2.jd1.transpose())
        assert np.may_share_memory(t2_transpose.jd1, self.t2.jd1)
        assert t2_transpose.location.shape == t2_transpose.shape
        assert np.may_share_memory(t2_transpose.location, self.t2.location)
        # Only one check on T, since it just calls transpose anyway.
        t2_T = self.t2.T
        assert t2_T.shape == (5, 10)
        assert np.all(t2_T.jd1 == self.t2.jd1.T)
        assert np.may_share_memory(t2_T.jd1, self.t2.jd1)
        assert t2_T.location.shape == t2_T.location.shape
        assert np.may_share_memory(t2_T.location, self.t2.location)

    def test_diagonal(self, masked):
        t0_diagonal = self.t0.diagonal()
        assert t0_diagonal.shape == (5, )
        assert np.all(t0_diagonal.jd1 == self.t0.jd1.diagonal())
        assert t0_diagonal.location is None
        assert np.may_share_memory(t0_diagonal.jd1, self.t0.jd1)
        t1_diagonal = self.t1.diagonal()
        assert t1_diagonal.shape == (5, )
        assert np.all(t1_diagonal.jd1 == self.t1.jd1.diagonal())
        assert t1_diagonal.location is self.t1.location
        assert np.may_share_memory(t1_diagonal.jd1, self.t1.jd1)
        t2_diagonal = self.t2.diagonal()
        assert t2_diagonal.shape == (5, )
        assert np.all(t2_diagonal.jd1 == self.t2.jd1.diagonal())
        assert t2_diagonal.location.shape == t2_diagonal.shape
        assert np.may_share_memory(t2_diagonal.jd1, self.t2.jd1)
        assert np.may_share_memory(t2_diagonal.location, self.t2.location)

    def test_swapaxes(self, masked):
        t0_swapaxes = self.t0.swapaxes(0, 1)
        assert t0_swapaxes.shape == (5, 10)
        assert np.all(t0_swapaxes.jd1 == self.t0.jd1.swapaxes(0, 1))
        assert np.may_share_memory(t0_swapaxes.jd1, self.t0.jd1)
        assert t0_swapaxes.location is None
        t1_swapaxes = self.t1.swapaxes(0, 1)
        assert t1_swapaxes.shape == (5, 10)
        assert np.all(t1_swapaxes.jd1 == self.t1.jd1.swapaxes(0, 1))
        assert np.may_share_memory(t1_swapaxes.jd1, self.t1.jd1)
        assert t1_swapaxes.location is self.t1.location
        t2_swapaxes = self.t2.swapaxes(0, 1)
        assert t2_swapaxes.shape == (5, 10)
        assert np.all(t2_swapaxes.jd1 == self.t2.jd1.swapaxes(0, 1))
        assert np.may_share_memory(t2_swapaxes.jd1, self.t2.jd1)
        assert t2_swapaxes.location.shape == t2_swapaxes.shape
        assert np.may_share_memory(t2_swapaxes.location, self.t2.location)

    def test_reshape(self, masked):
        t0_reshape = self.t0.reshape(5, 2, 5)
        assert t0_reshape.shape == (5, 2, 5)
        assert np.all(t0_reshape.jd1 == self.t0._time.jd1.reshape(5, 2, 5))
        assert np.all(t0_reshape.jd2 == self.t0._time.jd2.reshape(5, 2, 5))
        assert np.may_share_memory(t0_reshape.jd1, self.t0.jd1)
        assert np.may_share_memory(t0_reshape.jd2, self.t0.jd2)
        assert t0_reshape.location is None
        t1_reshape = self.t1.reshape(2, 5, 5)
        assert t1_reshape.shape == (2, 5, 5)
        assert np.all(t1_reshape.jd1 == self.t1.jd1.reshape(2, 5, 5))
        assert np.may_share_memory(t1_reshape.jd1, self.t1.jd1)
        assert t1_reshape.location is self.t1.location
        # For reshape(5, 2, 5), the location array can remain the same.
        t2_reshape = self.t2.reshape(5, 2, 5)
        assert t2_reshape.shape == (5, 2, 5)
        assert np.all(t2_reshape.jd1 == self.t2.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t2_reshape.jd1, self.t2.jd1)
        assert t2_reshape.location.shape == t2_reshape.shape
        assert np.may_share_memory(t2_reshape.location, self.t2.location)
        # But for reshape(5, 5, 2), location has to be broadcast and copied.
        t2_reshape2 = self.t2.reshape(5, 5, 2)
        assert t2_reshape2.shape == (5, 5, 2)
        assert np.all(t2_reshape2.jd1 == self.t2.jd1.reshape(5, 5, 2))
        assert np.may_share_memory(t2_reshape2.jd1, self.t2.jd1)
        assert t2_reshape2.location.shape == t2_reshape2.shape
        assert not np.may_share_memory(t2_reshape2.location, self.t2.location)
        t2_reshape_t = self.t2.reshape(10, 5).T
        assert t2_reshape_t.shape == (5, 10)
        assert np.may_share_memory(t2_reshape_t.jd1, self.t2.jd1)
        assert t2_reshape_t.location.shape == t2_reshape_t.shape
        assert np.may_share_memory(t2_reshape_t.location, self.t2.location)
        # Finally, reshape in a way that cannot be a view.
        t2_reshape_t_reshape = t2_reshape_t.reshape(10, 5)
        assert t2_reshape_t_reshape.shape == (10, 5)
        assert not np.may_share_memory(t2_reshape_t_reshape.jd1, self.t2.jd1)
        assert (
            t2_reshape_t_reshape.location.shape == t2_reshape_t_reshape.shape)
        assert not np.may_share_memory(t2_reshape_t_reshape.location,
                                       t2_reshape_t.location)

    def test_shape_setting(self, masked):
        t0_reshape = self.t0.copy()
        mjd = t0_reshape.mjd  # Creates a cache of the mjd attribute
        t0_reshape.shape = (5, 2, 5)
        assert t0_reshape.shape == (5, 2, 5)
        assert mjd.shape != t0_reshape.mjd.shape  # Cache got cleared
        assert np.all(t0_reshape.jd1 == self.t0._time.jd1.reshape(5, 2, 5))
        assert np.all(t0_reshape.jd2 == self.t0._time.jd2.reshape(5, 2, 5))
        assert t0_reshape.location is None
        # But if the shape doesn't work, one should get an error.
        t0_reshape_t = t0_reshape.T
        with pytest.raises(AttributeError):
            t0_reshape_t.shape = (10, 5)
        # check no shape was changed.
        assert t0_reshape_t.shape == t0_reshape.T.shape
        assert t0_reshape_t.jd1.shape == t0_reshape.T.shape
        assert t0_reshape_t.jd2.shape == t0_reshape.T.shape
        t1_reshape = self.t1.copy()
        t1_reshape.shape = (2, 5, 5)
        assert t1_reshape.shape == (2, 5, 5)
        assert np.all(t1_reshape.jd1 == self.t1.jd1.reshape(2, 5, 5))
        # location is a single element, so its shape should not change.
        assert t1_reshape.location.shape == ()
        # For reshape(5, 2, 5), the location array can remain the same.
        # Note that we need to work directly on self.t2 here, since any
        # copy would cause location to have the full shape.
        self.t2.shape = (5, 2, 5)
        assert self.t2.shape == (5, 2, 5)
        assert self.t2.jd1.shape == (5, 2, 5)
        assert self.t2.jd2.shape == (5, 2, 5)
        assert self.t2.location.shape == (5, 2, 5)
        assert self.t2.location.strides == (0, 0, 24)
        # But for reshape(50), location would need to be copied, so this
        # should fail.
        oldshape = self.t2.shape
        with pytest.raises(AttributeError):
            self.t2.shape = (50, )
        # check no shape was changed.
        assert self.t2.jd1.shape == oldshape
        assert self.t2.jd2.shape == oldshape
        assert self.t2.location.shape == oldshape
        # reset t2 to its original.
        self.setup()

    def test_squeeze(self, masked):
        t0_squeeze = self.t0.reshape(5, 1, 2, 1, 5).squeeze()
        assert t0_squeeze.shape == (5, 2, 5)
        assert np.all(t0_squeeze.jd1 == self.t0.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t0_squeeze.jd1, self.t0.jd1)
        assert t0_squeeze.location is None
        t1_squeeze = self.t1.reshape(1, 5, 1, 2, 5).squeeze()
        assert t1_squeeze.shape == (5, 2, 5)
        assert np.all(t1_squeeze.jd1 == self.t1.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t1_squeeze.jd1, self.t1.jd1)
        assert t1_squeeze.location is self.t1.location
        t2_squeeze = self.t2.reshape(1, 1, 5, 2, 5, 1, 1).squeeze()
        assert t2_squeeze.shape == (5, 2, 5)
        assert np.all(t2_squeeze.jd1 == self.t2.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t2_squeeze.jd1, self.t2.jd1)
        assert t2_squeeze.location.shape == t2_squeeze.shape
        assert np.may_share_memory(t2_squeeze.location, self.t2.location)

    def test_add_dimension(self, masked):
        t0_adddim = self.t0[:, np.newaxis, :]
        assert t0_adddim.shape == (10, 1, 5)
        assert np.all(t0_adddim.jd1 == self.t0.jd1[:, np.newaxis, :])
        assert np.may_share_memory(t0_adddim.jd1, self.t0.jd1)
        assert t0_adddim.location is None
        t1_adddim = self.t1[:, :, np.newaxis]
        assert t1_adddim.shape == (10, 5, 1)
        assert np.all(t1_adddim.jd1 == self.t1.jd1[:, :, np.newaxis])
        assert np.may_share_memory(t1_adddim.jd1, self.t1.jd1)
        assert t1_adddim.location is self.t1.location
        t2_adddim = self.t2[:, :, np.newaxis]
        assert t2_adddim.shape == (10, 5, 1)
        assert np.all(t2_adddim.jd1 == self.t2.jd1[:, :, np.newaxis])
        assert np.may_share_memory(t2_adddim.jd1, self.t2.jd1)
        assert t2_adddim.location.shape == t2_adddim.shape
        assert np.may_share_memory(t2_adddim.location, self.t2.location)

    def test_take(self, masked):
        t0_take = self.t0.take((5, 2))
        assert t0_take.shape == (2, )
        assert np.all(t0_take.jd1 == self.t0._time.jd1.take((5, 2)))
        assert t0_take.location is None
        t1_take = self.t1.take((2, 4), axis=1)
        assert t1_take.shape == (10, 2)
        assert np.all(t1_take.jd1 == self.t1.jd1.take((2, 4), axis=1))
        assert t1_take.location is self.t1.location
        t2_take = self.t2.take((1, 3, 7), axis=0)
        assert t2_take.shape == (3, 5)
        assert np.all(t2_take.jd1 == self.t2.jd1.take((1, 3, 7), axis=0))
        assert t2_take.location.shape == t2_take.shape
        t2_take2 = self.t2.take((5, 15))
        assert t2_take2.shape == (2, )
        assert np.all(t2_take2.jd1 == self.t2.jd1.take((5, 15)))
        assert t2_take2.location.shape == t2_take2.shape

    def test_broadcast(self, masked):
        """Test using a callable method."""
        t0_broadcast = self.t0._apply(np.broadcast_to, shape=(3, 10, 5))
        assert t0_broadcast.shape == (3, 10, 5)
        assert np.all(t0_broadcast.jd1 == self.t0.jd1)
        assert np.may_share_memory(t0_broadcast.jd1, self.t0.jd1)
        assert t0_broadcast.location is None
        t1_broadcast = self.t1._apply(np.broadcast_to, shape=(3, 10, 5))
        assert t1_broadcast.shape == (3, 10, 5)
        assert np.all(t1_broadcast.jd1 == self.t1.jd1)
        assert np.may_share_memory(t1_broadcast.jd1, self.t1.jd1)
        assert t1_broadcast.location is self.t1.location
        t2_broadcast = self.t2._apply(np.broadcast_to, shape=(3, 10, 5))
        assert t2_broadcast.shape == (3, 10, 5)
        assert np.all(t2_broadcast.jd1 == self.t2.jd1)
        assert np.may_share_memory(t2_broadcast.jd1, self.t2.jd1)
        assert t2_broadcast.location.shape == t2_broadcast.shape
        assert np.may_share_memory(t2_broadcast.location, self.t2.location)
예제 #4
0
    def __init__(self, data=None, *, time_bin_start=None, time_bin_end=None,
                 time_bin_size=None, n_bins=None, **kwargs):

        super().__init__(data=data, **kwargs)

        # For some operations, an empty time series needs to be created, then
        # columns added one by one. We should check that when columns are added
        # manually, time is added first and is of the right type.
        if (data is None and time_bin_start is None and time_bin_end is None and
                time_bin_size is None and n_bins is None):
            self._required_columns_relax = True
            return

        # First if time_bin_start and time_bin_end have been given in the table data, we
        # should extract them and treat them as if they had been passed as
        # keyword arguments.

        if 'time_bin_start' in self.colnames:
            if time_bin_start is None:
                time_bin_start = self.columns['time_bin_start']
            else:
                raise TypeError("'time_bin_start' has been given both in the table "
                                "and as a keyword argument")

        if 'time_bin_size' in self.colnames:
            if time_bin_size is None:
                time_bin_size = self.columns['time_bin_size']
            else:
                raise TypeError("'time_bin_size' has been given both in the table "
                                "and as a keyword argument")

        if time_bin_start is None:
            raise TypeError("'time_bin_start' has not been specified")

        if time_bin_end is None and time_bin_size is None:
            raise TypeError("Either 'time_bin_size' or 'time_bin_end' should be specified")

        if not isinstance(time_bin_start, (Time, TimeDelta)):
            time_bin_start = Time(time_bin_start)

        if time_bin_end is not None and not isinstance(time_bin_end, (Time, TimeDelta)):
            time_bin_end = Time(time_bin_end)

        if time_bin_size is not None and not isinstance(time_bin_size, (Quantity, TimeDelta)):
            raise TypeError("'time_bin_size' should be a Quantity or a TimeDelta")

        if isinstance(time_bin_size, TimeDelta):
            time_bin_size = time_bin_size.sec * u.s

        if time_bin_start.isscalar:

            # We interpret this as meaning that this is the start of the
            # first bin and that the bins are contiguous. In this case,
            # we require time_bin_size to be specified.

            if time_bin_size is None:
                raise TypeError("'time_bin_start' is scalar, so 'time_bin_size' is required")

            if time_bin_size.isscalar:
                if data is not None:
                    if n_bins is not None:
                        if n_bins != len(self):
                            raise TypeError("'n_bins' has been given and it is not the "
                                            "same length as the input data.")
                    else:
                        n_bins = len(self)

                time_bin_size = np.repeat(time_bin_size, n_bins)

            time_delta = np.cumsum(time_bin_size)
            time_bin_end = time_bin_start + time_delta

            # Now shift the array so that the first entry is 0
            time_delta = np.roll(time_delta, 1)
            time_delta[0] = 0. * u.s

            # Make time_bin_start into an array
            time_bin_start = time_bin_start + time_delta

        else:

            if len(self.colnames) > 0 and len(time_bin_start) != len(self):
                raise ValueError("Length of 'time_bin_start' ({}) should match "
                                 "table length ({})".format(len(time_bin_start), len(self)))

            if time_bin_end is not None:
                if time_bin_end.isscalar:
                    times = time_bin_start.copy()
                    times[:-1] = times[1:]
                    times[-1] = time_bin_end
                    time_bin_end = times
                time_bin_size = (time_bin_end - time_bin_start).sec * u.s

        if time_bin_size.isscalar:
            time_bin_size = np.repeat(time_bin_size, len(self))

        with self._delay_required_column_checks():

            if 'time_bin_start' in self.colnames:
                self.remove_column('time_bin_start')

            if 'time_bin_size' in self.colnames:
                self.remove_column('time_bin_size')

            self.add_column(time_bin_start, index=0, name='time_bin_start')
            self.add_index('time_bin_start')
            self.add_column(time_bin_size, index=1, name='time_bin_size')
예제 #5
0
파일: binned.py 프로젝트: Cadair/astropy
    def __init__(self, data=None, *, time_bin_start=None, time_bin_end=None,
                 time_bin_size=None, n_bins=None, **kwargs):

        super().__init__(data=data, **kwargs)

        # For some operations, an empty time series needs to be created, then
        # columns added one by one. We should check that when columns are added
        # manually, time is added first and is of the right type.
        if (data is None and time_bin_start is None and time_bin_end is None and
                time_bin_size is None and n_bins is None):
            self._required_columns_relax = True
            return

        # First if time_bin_start and time_bin_end have been given in the table data, we
        # should extract them and treat them as if they had been passed as
        # keyword arguments.

        if 'time_bin_start' in self.colnames:
            if time_bin_start is None:
                time_bin_start = self.columns['time_bin_start']
            else:
                raise TypeError("'time_bin_start' has been given both in the table "
                                "and as a keyword argument")

        if 'time_bin_size' in self.colnames:
            if time_bin_size is None:
                time_bin_size = self.columns['time_bin_size']
            else:
                raise TypeError("'time_bin_size' has been given both in the table "
                                "and as a keyword argument")

        if time_bin_start is None:
            raise TypeError("'time_bin_start' has not been specified")

        if time_bin_end is None and time_bin_size is None:
            raise TypeError("Either 'time_bin_size' or 'time_bin_end' should be specified")

        if not isinstance(time_bin_start, Time):
            time_bin_start = Time(time_bin_start)

        if time_bin_end is not None and not isinstance(time_bin_end, Time):
            time_bin_end = Time(time_bin_end)

        if time_bin_size is not None and not isinstance(time_bin_size, (Quantity, TimeDelta)):
            raise TypeError("'time_bin_size' should be a Quantity or a TimeDelta")

        if isinstance(time_bin_size, TimeDelta):
            time_bin_size = time_bin_size.sec * u.s

        if time_bin_start.isscalar:

            # We interpret this as meaning that this is the start of the
            # first bin and that the bins are contiguous. In this case,
            # we require time_bin_size to be specified.

            if time_bin_size is None:
                raise TypeError("'time_bin_start' is scalar, so 'time_bin_size' is required")

            if time_bin_size.isscalar:
                if data is not None:
                    if n_bins is not None:
                        if n_bins != len(self):
                            raise TypeError("'n_bins' has been given and it is not the "
                                            "same length as the input data.")
                    else:
                        n_bins = len(self)

                time_bin_size = np.repeat(time_bin_size, n_bins)

            time_delta = np.cumsum(time_bin_size)
            time_bin_end = time_bin_start + time_delta

            # Now shift the array so that the first entry is 0
            time_delta = np.roll(time_delta, 1)
            time_delta[0] = 0. * u.s

            # Make time_bin_start into an array
            time_bin_start = time_bin_start + time_delta

        else:

            if len(self.colnames) > 0 and len(time_bin_start) != len(self):
                raise ValueError("Length of 'time_bin_start' ({0}) should match "
                                 "table length ({1})".format(len(time_bin_start), len(self)))

            if time_bin_end is not None:
                if time_bin_end.isscalar:
                    times = time_bin_start.copy()
                    times[:-1] = times[1:]
                    times[-1] = time_bin_end
                    time_bin_end = times
                time_bin_size = (time_bin_end - time_bin_start).sec * u.s

        if time_bin_size.isscalar:
            time_bin_size = np.repeat(time_bin_size, len(self))

        with self._delay_required_column_checks():

            if 'time_bin_start' in self.colnames:
                self.remove_column('time_bin_start')

            if 'time_bin_size' in self.colnames:
                self.remove_column('time_bin_size')

            self.add_column(time_bin_start, index=0, name='time_bin_start')
            self.add_index('time_bin_start')
            self.add_column(time_bin_size, index=1, name='time_bin_size')
예제 #6
0
class TestManipulation():
    """Manipulation of Time objects, ensuring attributes are done correctly."""

    def setup(self):
        mjd = np.arange(50000, 50010)
        frac = np.arange(0., 0.999, 0.2)
        if use_masked_data:
            frac = np.ma.array(frac)
            frac[1] = np.ma.masked
        self.t0 = Time(mjd[:, np.newaxis] + frac, format='mjd', scale='utc')
        self.t1 = Time(mjd[:, np.newaxis] + frac, format='mjd', scale='utc',
                       location=('45d', '50d'))
        self.t2 = Time(mjd[:, np.newaxis] + frac, format='mjd', scale='utc',
                       location=(np.arange(len(frac)), np.arange(len(frac))))
        # Note: location is along last axis only.
        self.t2 = Time(mjd[:, np.newaxis] + frac, format='mjd', scale='utc',
                       location=(np.arange(len(frac)), np.arange(len(frac))))

    def test_ravel(self, masked):
        t0_ravel = self.t0.ravel()
        assert t0_ravel.shape == (self.t0.size,)
        assert np.all(t0_ravel.jd1 == self.t0.jd1.ravel())
        assert np.may_share_memory(t0_ravel.jd1, self.t0.jd1)
        assert t0_ravel.location is None
        t1_ravel = self.t1.ravel()
        assert t1_ravel.shape == (self.t1.size,)
        assert np.all(t1_ravel.jd1 == self.t1.jd1.ravel())
        assert np.may_share_memory(t1_ravel.jd1, self.t1.jd1)
        assert t1_ravel.location is self.t1.location
        t2_ravel = self.t2.ravel()
        assert t2_ravel.shape == (self.t2.size,)
        assert np.all(t2_ravel.jd1 == self.t2.jd1.ravel())
        assert np.may_share_memory(t2_ravel.jd1, self.t2.jd1)
        assert t2_ravel.location.shape == t2_ravel.shape
        # Broadcasting and ravelling cannot be done without a copy.
        assert not np.may_share_memory(t2_ravel.location, self.t2.location)

    def test_flatten(self, masked):
        t0_flatten = self.t0.flatten()
        assert t0_flatten.shape == (self.t0.size,)
        assert t0_flatten.location is None
        # Flatten always makes a copy.
        assert not np.may_share_memory(t0_flatten.jd1, self.t0.jd1)
        t1_flatten = self.t1.flatten()
        assert t1_flatten.shape == (self.t1.size,)
        assert not np.may_share_memory(t1_flatten.jd1, self.t1.jd1)
        assert t1_flatten.location is not self.t1.location
        assert t1_flatten.location == self.t1.location
        t2_flatten = self.t2.flatten()
        assert t2_flatten.shape == (self.t2.size,)
        assert not np.may_share_memory(t2_flatten.jd1, self.t2.jd1)
        assert t2_flatten.location.shape == t2_flatten.shape
        assert not np.may_share_memory(t2_flatten.location, self.t2.location)

    def test_transpose(self, masked):
        t0_transpose = self.t0.transpose()
        assert t0_transpose.shape == (5, 10)
        assert np.all(t0_transpose.jd1 == self.t0.jd1.transpose())
        assert np.may_share_memory(t0_transpose.jd1, self.t0.jd1)
        assert t0_transpose.location is None
        t1_transpose = self.t1.transpose()
        assert t1_transpose.shape == (5, 10)
        assert np.all(t1_transpose.jd1 == self.t1.jd1.transpose())
        assert np.may_share_memory(t1_transpose.jd1, self.t1.jd1)
        assert t1_transpose.location is self.t1.location
        t2_transpose = self.t2.transpose()
        assert t2_transpose.shape == (5, 10)
        assert np.all(t2_transpose.jd1 == self.t2.jd1.transpose())
        assert np.may_share_memory(t2_transpose.jd1, self.t2.jd1)
        assert t2_transpose.location.shape == t2_transpose.shape
        assert np.may_share_memory(t2_transpose.location, self.t2.location)
        # Only one check on T, since it just calls transpose anyway.
        t2_T = self.t2.T
        assert t2_T.shape == (5, 10)
        assert np.all(t2_T.jd1 == self.t2.jd1.T)
        assert np.may_share_memory(t2_T.jd1, self.t2.jd1)
        assert t2_T.location.shape == t2_T.location.shape
        assert np.may_share_memory(t2_T.location, self.t2.location)

    def test_diagonal(self, masked):
        t0_diagonal = self.t0.diagonal()
        assert t0_diagonal.shape == (5,)
        assert np.all(t0_diagonal.jd1 == self.t0.jd1.diagonal())
        assert t0_diagonal.location is None
        assert np.may_share_memory(t0_diagonal.jd1, self.t0.jd1)
        t1_diagonal = self.t1.diagonal()
        assert t1_diagonal.shape == (5,)
        assert np.all(t1_diagonal.jd1 == self.t1.jd1.diagonal())
        assert t1_diagonal.location is self.t1.location
        assert np.may_share_memory(t1_diagonal.jd1, self.t1.jd1)
        t2_diagonal = self.t2.diagonal()
        assert t2_diagonal.shape == (5,)
        assert np.all(t2_diagonal.jd1 == self.t2.jd1.diagonal())
        assert t2_diagonal.location.shape == t2_diagonal.shape
        assert np.may_share_memory(t2_diagonal.jd1, self.t2.jd1)
        assert np.may_share_memory(t2_diagonal.location, self.t2.location)

    def test_swapaxes(self, masked):
        t0_swapaxes = self.t0.swapaxes(0, 1)
        assert t0_swapaxes.shape == (5, 10)
        assert np.all(t0_swapaxes.jd1 == self.t0.jd1.swapaxes(0, 1))
        assert np.may_share_memory(t0_swapaxes.jd1, self.t0.jd1)
        assert t0_swapaxes.location is None
        t1_swapaxes = self.t1.swapaxes(0, 1)
        assert t1_swapaxes.shape == (5, 10)
        assert np.all(t1_swapaxes.jd1 == self.t1.jd1.swapaxes(0, 1))
        assert np.may_share_memory(t1_swapaxes.jd1, self.t1.jd1)
        assert t1_swapaxes.location is self.t1.location
        t2_swapaxes = self.t2.swapaxes(0, 1)
        assert t2_swapaxes.shape == (5, 10)
        assert np.all(t2_swapaxes.jd1 == self.t2.jd1.swapaxes(0, 1))
        assert np.may_share_memory(t2_swapaxes.jd1, self.t2.jd1)
        assert t2_swapaxes.location.shape == t2_swapaxes.shape
        assert np.may_share_memory(t2_swapaxes.location, self.t2.location)

    def test_reshape(self, masked):
        t0_reshape = self.t0.reshape(5, 2, 5)
        assert t0_reshape.shape == (5, 2, 5)
        assert np.all(t0_reshape.jd1 == self.t0._time.jd1.reshape(5, 2, 5))
        assert np.all(t0_reshape.jd2 == self.t0._time.jd2.reshape(5, 2, 5))
        assert np.may_share_memory(t0_reshape.jd1, self.t0.jd1)
        assert np.may_share_memory(t0_reshape.jd2, self.t0.jd2)
        assert t0_reshape.location is None
        t1_reshape = self.t1.reshape(2, 5, 5)
        assert t1_reshape.shape == (2, 5, 5)
        assert np.all(t1_reshape.jd1 == self.t1.jd1.reshape(2, 5, 5))
        assert np.may_share_memory(t1_reshape.jd1, self.t1.jd1)
        assert t1_reshape.location is self.t1.location
        # For reshape(5, 2, 5), the location array can remain the same.
        t2_reshape = self.t2.reshape(5, 2, 5)
        assert t2_reshape.shape == (5, 2, 5)
        assert np.all(t2_reshape.jd1 == self.t2.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t2_reshape.jd1, self.t2.jd1)
        assert t2_reshape.location.shape == t2_reshape.shape
        assert np.may_share_memory(t2_reshape.location, self.t2.location)
        # But for reshape(5, 5, 2), location has to be broadcast and copied.
        t2_reshape2 = self.t2.reshape(5, 5, 2)
        assert t2_reshape2.shape == (5, 5, 2)
        assert np.all(t2_reshape2.jd1 == self.t2.jd1.reshape(5, 5, 2))
        assert np.may_share_memory(t2_reshape2.jd1, self.t2.jd1)
        assert t2_reshape2.location.shape == t2_reshape2.shape
        assert not np.may_share_memory(t2_reshape2.location, self.t2.location)
        t2_reshape_t = self.t2.reshape(10, 5).T
        assert t2_reshape_t.shape == (5, 10)
        assert np.may_share_memory(t2_reshape_t.jd1, self.t2.jd1)
        assert t2_reshape_t.location.shape == t2_reshape_t.shape
        assert np.may_share_memory(t2_reshape_t.location, self.t2.location)
        # Finally, reshape in a way that cannot be a view.
        t2_reshape_t_reshape = t2_reshape_t.reshape(10, 5)
        assert t2_reshape_t_reshape.shape == (10, 5)
        assert not np.may_share_memory(t2_reshape_t_reshape.jd1, self.t2.jd1)
        assert (t2_reshape_t_reshape.location.shape ==
                t2_reshape_t_reshape.shape)
        assert not np.may_share_memory(t2_reshape_t_reshape.location,
                                       t2_reshape_t.location)

    def test_shape_setting(self, masked):
        t0_reshape = self.t0.copy()
        mjd = t0_reshape.mjd  # Creates a cache of the mjd attribute
        t0_reshape.shape = (5, 2, 5)
        assert t0_reshape.shape == (5, 2, 5)
        assert mjd.shape != t0_reshape.mjd.shape  # Cache got cleared
        assert np.all(t0_reshape.jd1 == self.t0._time.jd1.reshape(5, 2, 5))
        assert np.all(t0_reshape.jd2 == self.t0._time.jd2.reshape(5, 2, 5))
        assert t0_reshape.location is None
        # But if the shape doesn't work, one should get an error.
        t0_reshape_t = t0_reshape.T
        with pytest.raises(AttributeError):
            t0_reshape_t.shape = (10, 5)
        # check no shape was changed.
        assert t0_reshape_t.shape == t0_reshape.T.shape
        assert t0_reshape_t.jd1.shape == t0_reshape.T.shape
        assert t0_reshape_t.jd2.shape == t0_reshape.T.shape
        t1_reshape = self.t1.copy()
        t1_reshape.shape = (2, 5, 5)
        assert t1_reshape.shape == (2, 5, 5)
        assert np.all(t1_reshape.jd1 == self.t1.jd1.reshape(2, 5, 5))
        # location is a single element, so its shape should not change.
        assert t1_reshape.location.shape == ()
        # For reshape(5, 2, 5), the location array can remain the same.
        # Note that we need to work directly on self.t2 here, since any
        # copy would cause location to have the full shape.
        self.t2.shape = (5, 2, 5)
        assert self.t2.shape == (5, 2, 5)
        assert self.t2.jd1.shape == (5, 2, 5)
        assert self.t2.jd2.shape == (5, 2, 5)
        assert self.t2.location.shape == (5, 2, 5)
        assert self.t2.location.strides == (0, 0, 24)
        # But for reshape(50), location would need to be copied, so this
        # should fail.
        oldshape = self.t2.shape
        with pytest.raises(AttributeError):
            self.t2.shape = (50,)
        # check no shape was changed.
        assert self.t2.jd1.shape == oldshape
        assert self.t2.jd2.shape == oldshape
        assert self.t2.location.shape == oldshape
        # reset t2 to its original.
        self.setup()

    def test_squeeze(self, masked):
        t0_squeeze = self.t0.reshape(5, 1, 2, 1, 5).squeeze()
        assert t0_squeeze.shape == (5, 2, 5)
        assert np.all(t0_squeeze.jd1 == self.t0.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t0_squeeze.jd1, self.t0.jd1)
        assert t0_squeeze.location is None
        t1_squeeze = self.t1.reshape(1, 5, 1, 2, 5).squeeze()
        assert t1_squeeze.shape == (5, 2, 5)
        assert np.all(t1_squeeze.jd1 == self.t1.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t1_squeeze.jd1, self.t1.jd1)
        assert t1_squeeze.location is self.t1.location
        t2_squeeze = self.t2.reshape(1, 1, 5, 2, 5, 1, 1).squeeze()
        assert t2_squeeze.shape == (5, 2, 5)
        assert np.all(t2_squeeze.jd1 == self.t2.jd1.reshape(5, 2, 5))
        assert np.may_share_memory(t2_squeeze.jd1, self.t2.jd1)
        assert t2_squeeze.location.shape == t2_squeeze.shape
        assert np.may_share_memory(t2_squeeze.location, self.t2.location)

    def test_add_dimension(self, masked):
        t0_adddim = self.t0[:, np.newaxis, :]
        assert t0_adddim.shape == (10, 1, 5)
        assert np.all(t0_adddim.jd1 == self.t0.jd1[:, np.newaxis, :])
        assert np.may_share_memory(t0_adddim.jd1, self.t0.jd1)
        assert t0_adddim.location is None
        t1_adddim = self.t1[:, :, np.newaxis]
        assert t1_adddim.shape == (10, 5, 1)
        assert np.all(t1_adddim.jd1 == self.t1.jd1[:, :, np.newaxis])
        assert np.may_share_memory(t1_adddim.jd1, self.t1.jd1)
        assert t1_adddim.location is self.t1.location
        t2_adddim = self.t2[:, :, np.newaxis]
        assert t2_adddim.shape == (10, 5, 1)
        assert np.all(t2_adddim.jd1 == self.t2.jd1[:, :, np.newaxis])
        assert np.may_share_memory(t2_adddim.jd1, self.t2.jd1)
        assert t2_adddim.location.shape == t2_adddim.shape
        assert np.may_share_memory(t2_adddim.location, self.t2.location)

    def test_take(self, masked):
        t0_take = self.t0.take((5, 2))
        assert t0_take.shape == (2,)
        assert np.all(t0_take.jd1 == self.t0._time.jd1.take((5, 2)))
        assert t0_take.location is None
        t1_take = self.t1.take((2, 4), axis=1)
        assert t1_take.shape == (10, 2)
        assert np.all(t1_take.jd1 == self.t1.jd1.take((2, 4), axis=1))
        assert t1_take.location is self.t1.location
        t2_take = self.t2.take((1, 3, 7), axis=0)
        assert t2_take.shape == (3, 5)
        assert np.all(t2_take.jd1 == self.t2.jd1.take((1, 3, 7), axis=0))
        assert t2_take.location.shape == t2_take.shape
        t2_take2 = self.t2.take((5, 15))
        assert t2_take2.shape == (2,)
        assert np.all(t2_take2.jd1 == self.t2.jd1.take((5, 15)))
        assert t2_take2.location.shape == t2_take2.shape

    def test_broadcast(self, masked):
        """Test using a callable method."""
        t0_broadcast = self.t0._apply(np.broadcast_to, shape=(3, 10, 5))
        assert t0_broadcast.shape == (3, 10, 5)
        assert np.all(t0_broadcast.jd1 == self.t0.jd1)
        assert np.may_share_memory(t0_broadcast.jd1, self.t0.jd1)
        assert t0_broadcast.location is None
        t1_broadcast = self.t1._apply(np.broadcast_to, shape=(3, 10, 5))
        assert t1_broadcast.shape == (3, 10, 5)
        assert np.all(t1_broadcast.jd1 == self.t1.jd1)
        assert np.may_share_memory(t1_broadcast.jd1, self.t1.jd1)
        assert t1_broadcast.location is self.t1.location
        t2_broadcast = self.t2._apply(np.broadcast_to, shape=(3, 10, 5))
        assert t2_broadcast.shape == (3, 10, 5)
        assert np.all(t2_broadcast.jd1 == self.t2.jd1)
        assert np.may_share_memory(t2_broadcast.jd1, self.t2.jd1)
        assert t2_broadcast.location.shape == t2_broadcast.shape
        assert np.may_share_memory(t2_broadcast.location, self.t2.location)
    freq = np.linspace(550, 750, fh.shape[1])

# Make a reorganized array
# First column is time, second frequency and third phase
start = Time(date + start_time)
end = start + dt * fh.shape[0]
total_t = (end - start).to(u.s)
print("Length of time chunk:", (end - start).to(u.s))
total_tbins = np.int((total_t / subint).value) + 1
folded = np.zeros(shape=(total_tbins, fh.shape[1], n_phase))
counts = np.zeros(shape=(total_tbins, fh.shape[1], n_phase))
print("Shape of output is:", folded.shape)

# Set values for current time, current time bin and time array
start = Time(date + start_time)
t = start.copy()
time = []
current_time_bin = Time(date + start_time, precision=-1)
current_time_bin = Time(current_time_bin.__str__())
time.append(current_time_bin)
t_bin = 0
p0 = psr_polyco(t).value

# Loop through each data point
for i in range(fh.shape[0]):
    p = psr_polyco(t).value
    # Calculate which index
    if t >= current_time_bin + subint:
        t_bin += 1
        current_time_bin += subint
        time.append(current_time_bin)
예제 #8
0
class DateTime(object):
    # The Python API requires the enums are class attributes of DateTime
    JD = DateSystem.JD
    MJD = DateSystem.MJD
    EPOCH = DateSystem.EPOCH
    TAI = Timescale.TAI
    UTC = Timescale.UTC
    TT = Timescale.TT
    _EPOCH_INTEGER_LEAP = 63072000
    DEBUG = False

    @classmethod
    def now(self):
        t = Time.now()
        t.precision = 9
        return DateTime(t)

    @classmethod
    def _import_date_system(cls, system):
        """
        Determine the date system. Return argument if it is already
        a DateSystem enum, create one if we are given an integer (which
        can happen via C++). We have no way to enforce that python users
        specify arguments with proper enums.
        """
        if isinstance(system, DateSystem):
            return system
        sys_lut = {0: DateSystem.JD, 1: DateSystem.MJD, 2: DateSystem.EPOCH}
        if system in sys_lut:
            return sys_lut[system]
        raise ValueError("Supplied date systen value ({}) is not valid".format(system))

    @classmethod
    def _import_scale(cls, scale):
        """
        Determine the time scale. Return argument if it is already
        a Timescale enum, create one if we are given an integer (which
        can happen via C++). We have no way to enforce that python users
        specify arguments with proper enums.
        """
        if isinstance(scale, Timescale):
            return scale
        scale_lut = {0: Timescale.TAI, 1: Timescale.UTC, 2: Timescale.TT}
        if scale in scale_lut:
            return scale_lut[scale]
        raise ValueError("Supplied scale value ({}) is not valid".format(scale))

    @classmethod
    def _scale_to_astropy(cls, scale):
        """
        Convert a Timescale enum to the equivalent astropy string.
        """
        if not isinstance(scale, Timescale):
            raise ValueError("Supplied timescale is not a Timescale enum")
        return scale.name.lower()

    @classmethod
    def _system_to_astropy(cls, system):
        """
        Convert a DateSystem enum to the equivalent astropy string.
        """
        if not isinstance(system, DateSystem):
            raise ValueError("Supplied system is not a DateSystem enum")
        if system in (DateSystem.MJD, DateSystem.JD):
            sysstr = system.name.lower()
        elif system is DateSystem.EPOCH:
            sysstr = "jyear"
        else:
            raise ValueError("Supplied system enum is not recognized: {}".format(system))
        return sysstr

    def _in_timescale(self, scale):
        if scale is Timescale.UTC:
            t = self._internal.utc
        elif scale is Timescale.TAI:
            t = self._internal.tai
        elif scale is Timescale.TT:
            t = self._internal.tt
        else:
            raise ValueError("Unexpected time scale provided: {}".format(scale))
        return t

    def _in_format(self, t, system):
        if system is DateSystem.MJD:
            f = t.mjd
        elif system is DateSystem.JD:
            f = t.jd
        elif system is DateSystem.EPOCH:
            f = t.jyear
        else:
            raise ValueError("Unexpected data system provided: {}".format(system))
        return f

    # Python2 does not let us use (*arg, system=X, scale=Y) argument style
    def __init__(self, *args, **kwargs):
        """
        Position arguments:
        nsecs: (int) nanoseconds since epoch (uses scale)
        date: (double) date in system (uses system and scale)
        year, month, day, hr, min, sec (uses scale)
        iso8601: (string) ISO string format in UTC only

        Optional arguments:
        system: Defaults to DateSystem.MJD
        scale: Defaults to Timescale.TAI

        Can also take an Astropy Time object, which will be copied.

        If no arguments are supplied the constructor will assume 0 nanoseconds.
        """
        if self.DEBUG:
            print("Entering DateTime constructor with {} arguments".format(len(args)))
            print("Args", args)
        if len(args):
            if isinstance(args[0], Time):
                self._internal = args[0].copy(format="mjd")
                return
        else:
            # Assume 0 nanoseconds if no arguments at al
            args = [0]

        # Support scale= and also explicit system+scale arguments
        if len(args) == 2 or len(args) == 7:
            # Just have a scale
            args = list(args)
            kwargs["scale"] = self._import_scale(args.pop())
        elif len(args) == 3 or len(args) == 8:
            args = list(args)
            kwargs["scale"] = self._import_scale(args.pop())
            kwargs["system"] = self._import_date_system(args.pop())

        if "system" not in kwargs:
            kwargs["system"] = DateSystem.MJD
        if "scale" not in kwargs:
            kwargs["scale"] = Timescale.TAI

        # We are going to work out the three arguments for the astropy Time constructor
        format = "isot"
        scale = self._scale_to_astropy(kwargs["scale"])
        time_arg = None
        fraction = None
        if self.DEBUG:
            print("Arg:", args[0], "Scale=", scale)
        if len(args) == 1:
            # in current compatibility scheme have to look for string vs float vs int types
            if isinstance(args[0], basestring):
                time_arg = args[0]
                scale = "utc"
                # daf_base supports a compact string form that is not supported
                # directly by Astropy: YYYYMMDDTHHMMSSZ, optional with decimal fraction
                # we have to translate it before it hits astropy
                matcher = re.compile(r"(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(\.\d+)?Z")
                matched = matcher.search(time_arg)
                if matched:
                    parts = matched.groups()
                    time_arg = "{0}-{1}-{2}T{3}:{4}:{5}".format(*parts[0:6])
                    if parts[6] is not None:
                        time_arg += parts[6]
            elif isinstance(args[0], long) or isinstance(args[0], int):
                # Astropy does not have a nanosec representation
                # for now we risk losing precision
                # "unix" does not work properly for leap days (the extra second is spread out over the day)
                # so we have to work out the TAI delta and specify
                # TAI epoch seconds

                # Fractions of seconds will be tracked separately as Astropy does not handle
                # nanosecond integers natively.

                nsecs = args[0]
                fraction = int(str(abs(nsecs))[-9:])
                fracpositive = False if nsecs < 0 else True
                time_arg = int(nsecs / 1e9)
                if kwargs["scale"] is Timescale.TAI:
                    format = "taiunix"
                elif kwargs["scale"] is Timescale.UTC:
                    format = "taiunix"
                    ttmp = Time(time_arg, format="unix", scale="utc")
                    deltat = ttmp.taiunix - ttmp.unix
                    # Massive hack here: since "unix" seconds are not real seconds
                    # on leap days we have to force deltat to be an integer. This
                    # is broken before 1972. Need to obtain actual TAI-UTC offset from astropy.time.
                    if time_arg > DateTime._EPOCH_INTEGER_LEAP:
                        deltat = int(deltat + 0.5)
                    time_arg += deltat
                elif kwargs["scale"] is Timescale.TT:
                    format = "ttunix"
                else:
                    raise ValueError("Unsupported timescale argument")

            elif isinstance(args[0], float):
                format = self._system_to_astropy(kwargs["system"])
                time_arg = args[0]
            else:
                raise ValueError("Can not work out what first argument is for DateTime: {}".format(args[0]))
        elif len(args) == 6:
            # Put content into an ISO 8601 string and use that
            time_arg = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format(*args)
            format = "isot"
        else:
            raise ValueError("Unexpected number of arguments in DateTime constructor")
        if self.DEBUG:
            print("Time Arg: {0!r}".format(time_arg))
        self._internal = Time(time_arg, format=format, scale=scale, precision=9)

        # Handle fractional nanoseconds. Experiment with two approaches. For
        # positive fractions we reparse an ISO format date. For negative
        # fractions we use a TimeDelta object.
        if fraction is not None and fraction != 0:
            t = self._internal
            if fracpositive:
                t.precision = 0
                isostring = "{}.{:09d}".format(t.isot, fraction)
                if self.DEBUG:
                    print("Adjusting fractional seconds as string: {}", isostring)
                self._internal = Time(isostring, format="isot", scale=scale, precision=9)
            else:
                secs = float("0.{:09d}".format(fraction))
                ts = scale if scale != "utc" else "tai"
                td = TimeDelta(secs, format="sec", scale=ts)
                if self.DEBUG:
                    print("Adjusting fractional seconds negative: {}", td)
                self._internal -= td

        if self.DEBUG:
            print("Internal: ", repr(self._internal.copy(format="isot").utc))
            print("Internal: ", repr(self._internal.copy(format="isot").tai))
            print("Internal: ", repr(self._internal.copy(format="isot").tt))
            print("Internal: ", repr(self._internal.copy(format="mjd")))
            print("Internal: ", repr(self._internal.copy(format="unix")))
            print("Internal: ", repr(self._internal.copy(format="taiunix")))
            print("Internal: ", repr(self._internal.copy(format="utcunix")))
        return

    def copy(self):
        """
        Return an independent copy of the DateTime object.
        """
        # Technically DateTime is immutable so a copy could be the same
        # object.
        return self.__class__(self._internal)

    def nsecs(self, *args):
        """
        Return the nanosecs in epoch.

        Follow the LSST convention where TAI is simply the actual number
        of elapsed seconds since epoch but UTC does not include leap seconds
        in the count.

        TT not yet supported
        """
        if self.DEBUG:
            print("Entering nsecs() method:", args)
        if len(args) and args[0] is Timescale.TT:
            raise ValueError("nsecs() does not yet support TT timescale")

        if len(args):
            scale = self._import_scale(args[0])
        else:
            scale = Timescale.TAI

        # Asking for the unix epoch numbers in nanosecond precision
        # is prone to error. So we get the integer part and then
        # request the fractional second by stringifying and relying on
        # astropy time internals to handle precision.
        t = self._internal.copy(format="mjd")

        if scale is Timescale.TAI:
            integer = int(t.taiunix)
        elif scale is Timescale.UTC:
            integer = int(t.unix)
        else:
            raise ValueError("Unexpected timescale in nsecs call")

        # We always ask for the ISO form in TAI after 1972 as we are solely interested
        # in the fractional seconds and the offset is an integer. Prior to 1972 we use
        # UTC and hope for the best.
        t.precision = 9
        if t.unix > DateTime._EPOCH_INTEGER_LEAP:
            iso = t.tai.isot
        else:
            iso = t.utc.isot
        if self.DEBUG:
            print("NSECS String:", iso, " >> ", integer, ".", iso[20:29])
        return long(str(integer) + iso[20:29] + "L")

    def get(self, *args):
        """
        Return floating point representation of time.
        Optional positional arguments:
        system
        scale

        system must be present for scale to be specified.
        """
        scale = Timescale.TAI
        system = DateSystem.MJD
        if len(args) == 2:
            scale = self._import_scale(args[1])
        if len(args):
            system = self._import_date_system(args[0])

        # First get a Time object in the right timescale
        t = self._in_timescale(scale)

        # Now we need to format it properly based on the system
        return self._in_format(t, system)

    def mjd(self, *args):
        """
        Return MJD of supplied time scale. scale defaults to TAI.
        """
        scale = Timescale.TAI
        if len(args):
            scale = args[0]

        t = self._in_timescale(scale)
        return t.mjd

    def __eq__(self, rhs):
        if not hasattr(rhs, "nsecs"):
            return False
        return self.nsecs() == rhs.nsecs()

    def __ne__(self, rhs):
        return self._internal != rhs._internal

    def __str__(self):
        t = self._internal.copy(format="isot").utc
        t.precision = 9
        iso = t.isot
        # daf_base seems to want the Z added if we have a UTC time
        if t.scale == "utc":
            iso = iso + "Z"
        return iso

    def __repr__(self):
        # We report with TAI nanoseconds
        return "{}({})".format(self.__class__.__name__, self.nsecs(Timescale.TAI))

    def toString(self):
        return str(self)

    def toPython(self, timescale=None):
        """Convert a DateTime to Python's datetime

        @param timescale  Timescale for resultant datetime
        """
        import datetime

        nsecs = self.nsecs(timescale) if timescale is not None else self.nsecs()
        return datetime.datetime.utcfromtimestamp(nsecs / 10 ** 9)
예제 #9
0
    def __init__(self, data=None, start_time=None, end_time=None,
                 bin_size=None, n_bins=None, **kwargs):

        super().__init__(data=data, **kwargs)

        # FIXME: this is because for some operations, an empty time series needs
        # to be created, then columns added one by one. We should check that
        # when columns are added manually, time is added first and is of the
        # right type.
        if (data is None and start_time is None and end_time is None and
                bin_size is None and n_bins is None):
            self._required_columns = ['start_time', 'bin_size']
            return

        # First if start_time and end_time have been given in the table data, we
        # should extract them and treat them as if they had been passed as
        # keyword arguments.

        if 'start_time' in self.colnames:
            if start_time is None:
                start_time = self.columns['start_time']
                self.remove_column('start_time')
            else:
                raise TypeError("'start_time' has been given both in the table "
                                "and as a keyword argument")

        if 'bin_size' in self.colnames:
            if bin_size is None:
                bin_size = self.columns['bin_size']
                self.remove_column('bin_size')
            else:
                raise TypeError("'bin_size' has been given both in the table "
                                "and as a keyword argument")

        if start_time is None:
            raise TypeError("'start_time' has not been specified")

        if end_time is None and bin_size is None:
            raise TypeError("Either 'bin_size' or 'end_time' should be specified")

        if not isinstance(start_time, Time):
            start_time = Time(start_time)

        if end_time is not None and not isinstance(end_time, Time):
            end_time = Time(end_time)

        if bin_size is not None and not isinstance(bin_size, (Quantity, TimeDelta)):
            raise TypeError("'bin_size' should be a Quantity or a TimeDelta")

        if isinstance(bin_size, TimeDelta):
            bin_size = bin_size.sec * u.s

        if start_time.isscalar:

            # We interpret this as meaning that this is the start of the
            # first bin and that the bins are contiguous. In this case,
            # we require bin_size to be specified.

            if bin_size is None:
                raise TypeError("'start_time' is scalar, so 'bin_size' is required")

            if bin_size.isscalar:

                if data is not None:
                    # TODO: raise error if also passed explicily and inconsistent
                    n_bins = len(self)

                bin_size = np.repeat(bin_size, n_bins)

            time_delta = np.cumsum(bin_size)
            end_time = start_time + time_delta

            # Now shift the array so that the first entry is 0
            time_delta = np.roll(time_delta, 1)
            time_delta[0] = 0. * u.s

            # Make start_time into an array
            start_time = start_time + time_delta

        else:

            if len(self.colnames) > 0 and len(start_time) != len(self):
                raise ValueError("Length of 'start_time' ({0}) should match "
                                 "table length ({1})".format(len(start_time), len(self)))

            if end_time is not None:
                if end_time.isscalar:
                    times = start_time.copy()
                    times[:-1] = times[1:]
                    times[-1] = end_time
                    end_time = times
                bin_size = (end_time - start_time).sec * u.s
            elif bin_size is None:
                raise TypeError("Either 'bin_size' or 'end_time' should be specified")

        self.add_column(start_time, index=0, name='start_time')
        self.add_index('start_time')

        if bin_size.isscalar:
            bin_size = np.repeat(bin_size, len(self))

        self.add_column(bin_size, index=1, name='bin_size')