Esempio n. 1
0
    def _make_segment_spectrum(self, lc, segment_size):

        if not isinstance(lc, lightcurve.Lightcurve):
            raise TypeError("lc must be a lightcurve.Lightcurve object")

        if self.gti is None:
            self.gti = lc.gti
        check_gtis(self.gti)

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc.time)

        power_all = []
        nphots_all = []
        for start_ind, end_ind in zip(start_inds, end_inds):
            time = lc.time[start_ind:end_ind]
            counts = lc.counts[start_ind:end_ind]
            counts_err = lc.counts_err[start_ind:end_ind]
            lc_seg = lightcurve.Lightcurve(time,
                                           counts,
                                           err=counts_err,
                                           err_dist=lc.err_dist.lower())
            power_seg = Powerspectrum(lc_seg, norm=self.norm)
            power_all.append(power_seg)
            nphots_all.append(np.sum(lc_seg.counts))

        return power_all, nphots_all
Esempio n. 2
0
    def _make_segment_spectrum(self, lc, segment_size):

        if not isinstance(lc, lightcurve.Lightcurve):
            raise TypeError("lc must be a lightcurve.Lightcurve object")

        if self.gti is None:
            self.gti = lc.gti
        check_gtis(self.gti)

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc.time)

        power_all = []
        nphots_all = []
        for start_ind, end_ind in zip(start_inds, end_inds):
            time = lc.time[start_ind:end_ind]
            counts = lc.counts[start_ind:end_ind]
            counts_err = lc.counts_err[start_ind: end_ind]
            lc_seg = lightcurve.Lightcurve(time, counts, err=counts_err,
                                           err_dist=lc.err_dist.lower())
            power_seg = Powerspectrum(lc_seg, norm=self.norm)
            power_all.append(power_seg)
            nphots_all.append(np.sum(lc_seg.counts))

        return power_all, nphots_all
Esempio n. 3
0
    def _make_segment_spectrum(self, lc1, lc2, segment_size):

        # TODO: need to update this for making cross spectra.
        assert isinstance(lc1, Lightcurve)
        assert isinstance(lc2, Lightcurve)

        if lc1.tseg != lc2.tseg:
            raise ValueError("Lightcurves do not have same tseg.")

        # If dt differs slightly, its propagated error must not be more than
        # 1/100th of the bin
        if not np.isclose(lc1.dt, lc2.dt, rtol=0.01 * lc1.dt / lc1.tseg):
            raise ValueError("Light curves do not have same time binning dt.")

        # In case a small difference exists, ignore it
        lc1.dt = lc2.dt

        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)
            lc1.gti = lc2.gti = self.gti
            lc1._apply_gtis()
            lc2._apply_gtis()

        check_gtis(self.gti)

        cs_all = []
        nphots1_all = []
        nphots2_all = []

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc1.time,
                                    dt=lc1.dt)

        for start_ind, end_ind in zip(start_inds, end_inds):
            time_1 = lc1.time[start_ind:end_ind]
            counts_1 = lc1.counts[start_ind:end_ind]
            counts_1_err = lc1.counts_err[start_ind:end_ind]
            time_2 = lc2.time[start_ind:end_ind]
            counts_2 = lc2.counts[start_ind:end_ind]
            counts_2_err = lc2.counts_err[start_ind:end_ind]
            gti1 = np.array([[time_1[0] - lc1.dt / 2,
                             time_1[-1] + lc1.dt / 2]])
            gti2 = np.array([[time_2[0] - lc2.dt / 2,
                             time_2[-1] + lc2.dt / 2]])
            lc1_seg = Lightcurve(time_1, counts_1, err=counts_1_err,
                                 err_dist=lc1.err_dist,
                                 gti=gti1,
                                 dt=lc1.dt)
            lc2_seg = Lightcurve(time_2, counts_2, err=counts_2_err,
                                 err_dist=lc2.err_dist,
                                 gti=gti2,
                                 dt=lc2.dt)
            cs_seg = Crossspectrum(lc1_seg, lc2_seg, norm=self.norm)
            cs_all.append(cs_seg)
            nphots1_all.append(np.sum(lc1_seg.counts))
            nphots2_all.append(np.sum(lc2_seg.counts))
        return cs_all, nphots1_all, nphots2_all
Esempio n. 4
0
    def _make_segment_spectrum(self, lc1, lc2, segment_size):

        # TODO: need to update this for making cross spectra.
        assert isinstance(lc1, Lightcurve)
        assert isinstance(lc2, Lightcurve)

        if lc1.tseg != lc2.tseg:
            raise ValueError("Lightcurves do not have same tseg.")

        # If dt differs slightly, its propagated error must not be more than
        # 1/100th of the bin
        if not np.isclose(lc1.dt, lc2.dt, rtol=0.01 * lc1.dt / lc1.tseg):
            raise ValueError("Light curves do not have same time binning dt.")

        # In case a small difference exists, ignore it
        lc1.dt = lc2.dt

        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)
            lc1.gti = lc2.gti = self.gti
            lc1._apply_gtis()
            lc2._apply_gtis()

        check_gtis(self.gti)

        cs_all = []
        nphots1_all = []
        nphots2_all = []

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc1.time,
                                    dt=lc1.dt)

        for start_ind, end_ind in zip(start_inds, end_inds):
            time_1 = lc1.time[start_ind:end_ind]
            counts_1 = lc1.counts[start_ind:end_ind]
            counts_1_err = lc1.counts_err[start_ind:end_ind]
            time_2 = lc2.time[start_ind:end_ind]
            counts_2 = lc2.counts[start_ind:end_ind]
            counts_2_err = lc2.counts_err[start_ind:end_ind]
            gti1 = np.array([[time_1[0] - lc1.dt / 2,
                             time_1[-1] + lc1.dt / 2]])
            gti2 = np.array([[time_2[0] - lc2.dt / 2,
                             time_2[-1] + lc2.dt / 2]])
            lc1_seg = Lightcurve(time_1, counts_1, err=counts_1_err,
                                 err_dist=lc1.err_dist,
                                 gti=gti1,
                                 dt=lc1.dt)
            lc2_seg = Lightcurve(time_2, counts_2, err=counts_2_err,
                                 err_dist=lc2.err_dist,
                                 gti=gti2,
                                 dt=lc2.dt)
            cs_seg = Crossspectrum(lc1_seg, lc2_seg, norm=self.norm)
            cs_all.append(cs_seg)
            nphots1_all.append(np.sum(lc1_seg.counts))
            nphots2_all.append(np.sum(lc2_seg.counts))
        return cs_all, nphots1_all, nphots2_all
Esempio n. 5
0
    def _make_crossspectrum(self, lc1, lc2):

        # make sure the inputs work!
        if not isinstance(lc1, lightcurve.Lightcurve):
            raise TypeError("lc1 must be a lightcurve.Lightcurve object")

        if not isinstance(lc2, lightcurve.Lightcurve):
            raise TypeError("lc2 must be a lightcurve.Lightcurve object")

        # Then check that GTIs make sense
        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)

        check_gtis(self.gti)

        if self.gti.shape[0] != 1:
            raise TypeError("Non-averaged Cross Spectra need "
                            "a single Good Time Interval")

        lc1 = lc1.split_by_gti()[0]
        lc2 = lc2.split_by_gti()[0]

        # total number of photons is the sum of the
        # counts in the light curve
        self.nphots1 = np.float64(np.sum(lc1.counts))
        self.nphots2 = np.float64(np.sum(lc2.counts))

        self.meancounts1 = np.mean(lc1.counts)
        self.meancounts2 = np.mean(lc2.counts)

        # the number of data points in the light curve

        if lc1.n != lc2.n:
            raise StingrayError("Light curves do not have same number "
                                "of time bins per segment.")

        if lc1.dt != lc2.dt:
            raise StingrayError("Light curves do not have "
                                "same time binning dt.")

        self.n = lc1.n

        # the frequency resolution
        self.df = 1.0 / lc1.tseg

        # the number of averaged periodograms in the final output
        # This should *always* be 1 here
        self.m = 1

        # make the actual Fourier transform and compute cross spectrum
        self.freq, self.unnorm_power = self._fourier_cross(lc1, lc2)

        # If co-spectrum is desired, normalize here. Otherwise, get raw back
        # with the imaginary part still intact.
        self.power = self._normalize_crossspectrum(self.unnorm_power, lc1.tseg)
Esempio n. 6
0
    def _make_crossspectrum(self, lc1, lc2):

        ## make sure the inputs work!
        if not isinstance(lc1, lightcurve.Lightcurve):
            raise TypeError("lc1 must be a lightcurve.Lightcurve object")

        if not isinstance(lc2, lightcurve.Lightcurve):
            raise TypeError("lc2 must be a lightcurve.Lightcurve object")

        # Then check that GTIs make sense
        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)

        check_gtis(self.gti)

        if self.gti.shape[0] != 1:
            raise TypeError("Non-averaged Cross Spectra need "
                            "a single Good Time Interval")

        lc1 = lc1.split_by_gti()[0]
        lc2 = lc2.split_by_gti()[0]

        ## total number of photons is the sum of the
        ## counts in the light curve
        self.nphots1 = np.float64(np.sum(lc1.counts))
        self.nphots2 = np.float64(np.sum(lc2.counts))

        self.meancounts1 = np.mean(lc1.counts)
        self.meancounts2 = np.mean(lc2.counts)

        ## the number of data points in the light curve

        if lc1.counts.shape[0] != lc2.counts.shape[0]:
            raise StingrayError("Light curves do not have same number "
                                "of time bins per segment.")

        if lc1.dt != lc2.dt:
            raise StingrayError("Light curves do not have "
                                "same time binning dt.")

        self.n = lc1.counts.shape[0]

        ## the frequency resolution
        self.df = 1.0/lc1.tseg

        ## the number of averaged periodograms in the final output
        ## This should *always* be 1 here
        self.m = 1

        ## make the actual Fourier transform and compute cross spectrum
        self.freq, self.unnorm_power = self._fourier_cross(lc1, lc2)

        ## If co-spectrum is desired, normalize here. Otherwise, get raw back
        ## with the imaginary part still intact.
        self.power = self._normalize_crossspectrum(self.unnorm_power, lc1.tseg)
Esempio n. 7
0
    def _make_segment_spectrum(self, lc, segment_size):
        """
        Split the light curves into segments of size ``segment_size``, and calculate a power spectrum for
        each.

        Parameters
        ----------
        lc  : :class:`stingray.Lightcurve` objects\
            The input light curve

        segment_size : ``numpy.float``
            Size of each light curve segment to use for averaging.

        Returns
        -------
        power_all : list of :class:`Powerspectrum` objects
            A list of power spectra calculated independently from each light curve segment

        nphots_all : ``numpy.ndarray``
            List containing the number of photons for all segments calculated from ``lc``
        """
        if not isinstance(lc, lightcurve.Lightcurve):
            raise TypeError("lc must be a lightcurve.Lightcurve object")

        if self.gti is None:
            self.gti = lc.gti
        else:
            if not np.all(lc.gti == self.gti):
                self.gti = np.vstack([self.gti, lc.gti])

        check_gtis(self.gti)

        start_inds, end_inds = \
            bin_intervals_from_gtis(lc.gti, segment_size, lc.time, dt=lc.dt)

        power_all = []
        nphots_all = []
        for start_ind, end_ind in zip(start_inds, end_inds):
            time = lc.time[start_ind:end_ind]
            counts = lc.counts[start_ind:end_ind]
            counts_err = lc.counts_err[start_ind:end_ind]
            lc_seg = lightcurve.Lightcurve(time,
                                           counts,
                                           err=counts_err,
                                           err_dist=lc.err_dist.lower(),
                                           skip_checks=True,
                                           dt=lc.dt)
            power_seg = Powerspectrum(lc_seg, norm=self.norm)
            power_all.append(power_seg)
            nphots_all.append(np.sum(lc_seg.counts))

        return power_all, nphots_all
Esempio n. 8
0
    def _apply_gtis(self):
        """Apply GTIs to a light curve after modification."""
        check_gtis(self.gti)

        good = create_gti_mask(self.time, self.gti)

        self.time = self.time[good]
        self.counts = self.counts[good]
        self.counts_err = self.counts_err[good]
        self.countrate = self.countrate[good]
        self.countrate_err = self.countrate_err[good]

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]
Esempio n. 9
0
    def _make_segment_spectrum(self, lc1, lc2, segment_size):

        # TODO: need to update this for making cross spectra.
        assert isinstance(lc1, Lightcurve)
        assert isinstance(lc2, Lightcurve)

        if lc1.dt != lc2.dt:
            raise ValueError("Light curves do not have same time binning dt.")

        if lc1.tseg != lc2.tseg:
            raise ValueError("Lightcurves do not have same tseg.")

        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)

        check_gtis(self.gti)

        cs_all = []
        nphots1_all = []
        nphots2_all = []

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc1.time)

        for start_ind, end_ind in zip(start_inds, end_inds):
            time_1 = lc1.time[start_ind:end_ind]
            counts_1 = lc1.counts[start_ind:end_ind]
            counts_1_err = lc1.counts_err[start_ind:end_ind]
            time_2 = lc2.time[start_ind:end_ind]
            counts_2 = lc2.counts[start_ind:end_ind]
            counts_2_err = lc2.counts_err[start_ind:end_ind]
            lc1_seg = Lightcurve(time_1,
                                 counts_1,
                                 err=counts_1_err,
                                 err_dist=lc1.err_dist)
            lc2_seg = Lightcurve(time_2,
                                 counts_2,
                                 err=counts_2_err,
                                 err_dist=lc2.err_dist)
            cs_seg = Crossspectrum(lc1_seg, lc2_seg, norm=self.norm)
            cs_all.append(cs_seg)
            nphots1_all.append(np.sum(lc1_seg.counts))
            nphots2_all.append(np.sum(lc2_seg.counts))

        return cs_all, nphots1_all, nphots2_all
Esempio n. 10
0
    def _make_segment_spectrum(self, lc, segment_size):
        """
        Split the light curves into segments of size ``segment_size``, and calculate a power spectrum for
        each.

        Parameters
        ----------
        lc  : :class:`stingray.Lightcurve` objects\
            The input light curve

        segment_size : ``numpy.float``
            Size of each light curve segment to use for averaging.

        Returns
        -------
        power_all : list of :class:`Powerspectrum` objects
            A list of power spectra calculated independently from each light curve segment

        nphots_all : ``numpy.ndarray``
            List containing the number of photons for all segments calculated from ``lc``
        """
        if not isinstance(lc, lightcurve.Lightcurve):
            raise TypeError("lc must be a lightcurve.Lightcurve object")

        if self.gti is None:
            self.gti = lc.gti
        check_gtis(self.gti)

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc.time, dt=lc.dt)

        power_all = []
        nphots_all = []
        for start_ind, end_ind in zip(start_inds, end_inds):
            time = lc.time[start_ind:end_ind]
            counts = lc.counts[start_ind:end_ind]
            counts_err = lc.counts_err[start_ind: end_ind]
            lc_seg = lightcurve.Lightcurve(time, counts, err=counts_err,
                                           err_dist=lc.err_dist.lower())
            power_seg = Powerspectrum(lc_seg, norm=self.norm)
            power_all.append(power_seg)
            nphots_all.append(np.sum(lc_seg.counts))

        return power_all, nphots_all
Esempio n. 11
0
    def test_check_gtis_shape(self):
        with pytest.raises(TypeError):
            check_gtis([0, 1])

        with pytest.raises(TypeError):
            check_gtis([[0, 1], [0]])

        with pytest.raises(TypeError):
            check_gtis([[0, 1], [[0], [3]]])

        with pytest.raises(TypeError):
            check_gtis([[0, 1, 4], [0, 3, 4]])
Esempio n. 12
0
    def _apply_gtis(self):
        """
        Apply GTIs to a light curve. Filters the ``time``, ``counts``, ``countrate``, ``counts_err`` and
        ``countrate_err`` arrays for all bins that fall into Good Time Intervals and recalculates mean
        count(rate) and the number of bins.
        """
        check_gtis(self.gti)

        good = create_gti_mask(self.time, self.gti, dt=self.dt)

        self.time = self.time[good]
        self.counts = self.counts[good]

        self.counts_err = self.counts_err[good]
        self.countrate = self.countrate[good]
        self.countrate_err = self.countrate_err[good]

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]
Esempio n. 13
0
    def _apply_gtis(self):
        """
        Apply GTIs to a light curve. Filters the ``time``, ``counts``, ``countrate``, ``counts_err`` and
        ``countrate_err`` arrays for all bins that fall into Good Time Intervals and recalculates mean
        count(rate) and the number of bins.
        """
        check_gtis(self.gti)

        good = create_gti_mask(self.time, self.gti, dt=self.dt)

        self.time = self.time[good]
        self.counts = self.counts[good]

        self.counts_err = self.counts_err[good]
        self.countrate = self.countrate[good]
        self.countrate_err = self.countrate_err[good]

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]
Esempio n. 14
0
    def _make_segment_spectrum(self, lc1, lc2, segment_size):

        # TODO: need to update this for making cross spectra.
        assert isinstance(lc1, lightcurve.Lightcurve)
        assert isinstance(lc2, lightcurve.Lightcurve)

        if lc1.dt != lc2.dt:
            raise ValueError("Light curves do not have same time binning dt.")

        if lc1.tseg != lc2.tseg:
            raise ValueError("Lightcurves do not have same tseg.")

        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)

        check_gtis(self.gti)

        cs_all = []
        nphots1_all = []
        nphots2_all = []

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc1.time)

        for start_ind, end_ind in zip(start_inds, end_inds):
            time_1 = lc1.time[start_ind:end_ind]
            counts_1 = lc1.counts[start_ind:end_ind]
            time_2 = lc2.time[start_ind:end_ind]
            counts_2 = lc2.counts[start_ind:end_ind]
            lc1_seg = lightcurve.Lightcurve(time_1, counts_1)
            lc2_seg = lightcurve.Lightcurve(time_2, counts_2)
            cs_seg = Crossspectrum(lc1_seg, lc2_seg, norm=self.norm)
            cs_all.append(cs_seg)
            nphots1_all.append(np.sum(lc1_seg.counts))
            nphots2_all.append(np.sum(lc2_seg.counts))

        return cs_all, nphots1_all, nphots2_all
Esempio n. 15
0
    def __init__(self, time, counts, err=None, input_counts=True,
                 gti=None, err_dist='poisson', mjdref=0, dt=None):
        """
        Make a light curve object from an array of time stamps and an
        array of counts.

        Parameters
        ----------
        time: iterable
            A list or array of time stamps for a light curve

        counts: iterable, optional, default None
            A list or array of the counts in each bin corresponding to the
            bins defined in `time` (note: use `input_counts=False` to
            input the count range, i.e. counts/second, otherwise use
            counts/bin).

        err: iterable, optional, default None:
            A list or array of the uncertainties in each bin corresponding to
            the bins defined in `time` (note: use `input_counts=False` to
            input the count rage, i.e. counts/second, otherwise use
            counts/bin). If None, we assume the data is poisson distributed
            and calculate the error from the average of the lower and upper 
            1-sigma confidence intervals for the Poissonian distribution with 
            mean equal to `counts`.

        input_counts: bool, optional, default True
            If True, the code assumes that the input data in 'counts'
            is in units of counts/bin. If False, it assumes the data
            in 'counts' is in counts/second.

        gti: 2-d float array, default None
            [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
            Good Time Intervals. They are *not* applied to the data by default.
            They will be used by other methods to have an indication of the
            "safe" time intervals to use during analysis.

        err_dist: str, optional, default=None
            Statistic of the Lightcurve, it is used to calculate the
            uncertainties and other statistical values apropriately.
            Default makes no assumptions and keep errors equal to zero.

        mjdref: float
            MJD reference (useful in most high-energy mission data)


        Attributes
        ----------
        time: numpy.ndarray
            The array of midpoints of time bins.

        bin_lo:
            The array of lower time stamp of time bins.

        bin_hi:
            The array of higher time stamp of time bins.

        counts: numpy.ndarray
            The counts per bin corresponding to the bins in `time`.

        counts_err: numpy.ndarray
            The uncertainties corresponding to `counts`

        countrate: numpy.ndarray
            The counts per second in each of the bins defined in `time`.

        countrate_err: numpy.ndarray
            The uncertainties corresponding to `countrate`

        meanrate: float
            The mean count rate of the light curve.

        meancounts: float
            The mean counts of the light curve.

        n: int
            The number of data points in the light curve.

        dt: float
            The time resolution of the light curve.

        mjdref: float
            MJD reference date (tstart / 86400 gives the date in MJD at the
            start of the observation)

        tseg: float
            The total duration of the light curve.

        tstart: float
            The start time of the light curve.

        gti: 2-d float array
            [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
            Good Time Intervals. They indicate the "safe" time intervals
            to be used during the analysis of the light curve.

        err_dist: string
            Statistic of the Lightcurve, it is used to calculate the
            uncertainties and other statistical values apropriately.
            It propagates to Spectrum classes.

        """

        if not np.all(np.isfinite(time)):
            raise ValueError("There are inf or NaN values in "
                             "your time array!")

        if not np.all(np.isfinite(counts)):
            raise ValueError("There are inf or NaN values in "
                             "your counts array!")

        if len(time) != len(counts):

            raise StingrayError("time and counts array are not "
                                "of the same length!")

        if len(time) <= 1:
            raise StingrayError("A single or no data points can not create "
                                "a lightcurve!")

        if err is not None:
            if not np.all(np.isfinite(err)):
                raise ValueError("There are inf or NaN values in "
                                 "your err array")
        else:
            if err_dist.lower() not in valid_statistics:
                # err_dist set can be increased with other statistics
                raise StingrayError("Statistic not recognized."
                                    "Please select one of these: ",
                                    "{}".format(valid_statistics))
            if err_dist.lower() == 'poisson':
                # Instead of the simple square root, we use confidence
                # intervals (should be valid for low fluxes too)
                err_low, err_high = poisson_conf_interval(np.asarray(counts),
                    interval='frequentist-confidence', sigma=1)
                # calculate approximately symmetric uncertainties
                err_low -= np.asarray(counts)
                err_high -= np.asarray(counts)
                err = (np.absolute(err_low) + np.absolute(err_high))/2.0
                # other estimators can be implemented for other statistics
            else:
                simon("Stingray only uses poisson err_dist at the moment, "
                      "We are setting your errors to zero. "
                      "Sorry for the inconvenience.")
                err = np.zeros_like(counts)

        self.mjdref = mjdref
        self.time = np.asarray(time)
        if dt is None:
            self.dt = np.median(self.time[1:] - self.time[:-1])
        else:
            self.dt = dt

        self.bin_lo = self.time - 0.5 * self.dt
        self.bin_hi = self.time + 0.5 * self.dt

        self.err_dist = err_dist

        self.tstart = self.time[0] - 0.5*self.dt
        self.tseg = self.time[-1] - self.time[0] + self.dt

        self.gti = \
            np.asarray(assign_value_if_none(gti,
                                            [[self.tstart,
                                              self.tstart + self.tseg]]))
        check_gtis(self.gti)

        good = create_gti_mask(self.time, self.gti)

        self.time = self.time[good]
        if input_counts:
            self.counts = np.asarray(counts)[good]
            self.countrate = self.counts / self.dt
            self.counts_err = np.asarray(err)[good]
            self.countrate_err = np.asarray(err)[good] / self.dt
        else:
            self.countrate = np.asarray(counts)[good]
            self.counts = self.countrate * self.dt
            self.counts_err = np.asarray(err)[good] * self.dt
            self.countrate_err = np.asarray(err)[good]

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]

        # Issue a warning if the input time iterable isn't regularly spaced,
        # i.e. the bin sizes aren't equal throughout.
        dt_array = np.diff(self.time)
        if not (np.allclose(dt_array, np.repeat(self.dt, dt_array.shape[0]))):
            simon("Bin sizes in input time array aren't equal throughout! "
                  "This could cause problems with Fourier transforms. "
                  "Please make the input time evenly sampled.")
Esempio n. 16
0
    def __init__(self, time, counts, input_counts=True, gti=None):
        """
        Make a light curve object from an array of time stamps and an
        array of counts.

        Parameters
        ----------
        time: iterable
            A list or array of time stamps for a light curve

        counts: iterable, optional, default None
            A list or array of the counts in each bin corresponding to the
            bins defined in `time` (note: **not** the count rate, i.e.
            counts/second, but the counts/bin).

        input_counts: bool, optional, default True
            If True, the code assumes that the input data in 'counts'
            is in units of counts/bin. If False, it assumes the data
            in 'counts' is in counts/second.

        gti: 2-d float array, default None
            [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
            Good Time Intervals. They are *not* applied to the data by default.
            They will be used by other methods to have an indication of the
            "safe" time intervals to use during analysis.

        Attributes
        ----------
        time: numpy.ndarray
            The array of midpoints of time bins.

        bin_lo:
            The array of lower time stamp of time bins.

        bin_hi:
            The array of higher time stamp of time bins.

        counts: numpy.ndarray
            The counts per bin corresponding to the bins in `time`.

        countrate: numpy.ndarray
            The counts per second in each of the bins defined in `time`.

        meanrate: float
            The mean count rate of the light curve.
            
        meancounts: float
            The mean counts of the light curve.

        n: int
            The number of data points in the light curve.

        dt: float
            The time resolution of the light curve.

        tseg: float
            The total duration of the light curve.

        tstart: float
            The start time of the light curve.

        gti: 2-d float array
            [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
            Good Time Intervals. They indicate the "safe" time intervals
            to be used during the analysis of the light curve.

        """
        if not np.all(np.isfinite(time)):
            raise ValueError("There are inf or NaN values in "
                             "your time array!")

        if not np.all(np.isfinite(counts)):
            raise ValueError("There are inf or NaN values in "
                             "your counts array!")

        if len(time) != len(counts):

            raise StingrayError("time and counts array are not "
                                "of the same length!")

        if len(time) <= 1:
            raise StingrayError("A single or no data points can not create "
                                "a lightcurve!")

        self.time = np.asarray(time)
        self.dt = time[1] - time[0]

        self.bin_lo = self.time - 0.5 * self.dt
        self.bin_hi = self.time + 0.5 * self.dt

        if input_counts:
            self.counts = np.asarray(counts)
            self.countrate = self.counts / self.dt
        else:
            self.countrate = np.asarray(counts)
            self.counts = self.countrate * self.dt

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]

        # Issue a warning if the input time iterable isn't regularly spaced,
        # i.e. the bin sizes aren't equal throughout.
        dt_array = np.diff(self.time)
        if not (np.allclose(dt_array, np.repeat(self.dt, dt_array.shape[0]))):
            simon("Bin sizes in input time array aren't equal throughout! "
                  "This could cause problems with Fourier transforms. "
                  "Please make the input time evenly sampled.")

        self.tseg = self.time[-1] - self.time[0] + self.dt
        self.tstart = self.time[0] - 0.5 * self.dt
        self.gti = \
            np.asarray(assign_value_if_none(gti,
                                            [[self.tstart,
                                              self.tstart + self.tseg]]))
        check_gtis(self.gti)
Esempio n. 17
0
    def _make_segment_spectrum(self, lc1, lc2, segment_size):
        """
        Split the light curves into segments of size ``segment_size``, and calculate a cross spectrum for
        each.

        Parameters
        ----------
        lc1, lc2 : :class:`stingray.Lightcurve` objects
            Two light curves used for computing the cross spectrum.

        segment_size : ``numpy.float``
            Size of each light curve segment to use for averaging.

        Returns
        -------
        cs_all : list of :class:`Crossspectrum`` objects
            A list of cross spectra calculated independently from each light curve segment

        nphots1_all, nphots2_all : ``numpy.ndarray` for each of ``lc1`` and ``lc2``
            Two lists containing the number of photons for all segments calculated from ``lc1`` and ``lc2``.

        """

        # TODO: need to update this for making cross spectra.
        assert isinstance(lc1, Lightcurve)
        assert isinstance(lc2, Lightcurve)

        if lc1.tseg != lc2.tseg:
            simon("Lightcurves do not have same tseg. This means that the data"
                  "from the two channels are not completely in sync. This "
                  "might or might not be an issue. Keep an eye on it.")

        # If dt differs slightly, its propagated error must not be more than
        # 1/100th of the bin
        if not np.isclose(lc1.dt, lc2.dt, rtol=0.01 * lc1.dt / lc1.tseg):
            raise ValueError("Light curves do not have same time binning dt.")

        # In case a small difference exists, ignore it
        lc1.dt = lc2.dt

        gti = cross_two_gtis(lc1.gti, lc2.gti)
        lc1.apply_gtis()
        lc2.apply_gtis()
        if self.gti is None:
            self.gti = gti
        else:
            if not np.all(self.gti == gti):
                self.gti = np.vstack([self.gti, gti])

        check_gtis(self.gti)

        cs_all = []
        nphots1_all = []
        nphots2_all = []


        start_inds, end_inds = \
            bin_intervals_from_gtis(gti, segment_size, lc1.time,
                                    dt=lc1.dt)
        simon("Errorbars on cross spectra are not thoroughly tested. "
              "Please report any inconsistencies.")
        for start_ind, end_ind in zip(start_inds, end_inds):
            time_1 = lc1.time[start_ind:end_ind]
            counts_1 = lc1.counts[start_ind:end_ind]
            counts_1_err = lc1.counts_err[start_ind:end_ind]
            time_2 = lc2.time[start_ind:end_ind]
            counts_2 = lc2.counts[start_ind:end_ind]
            counts_2_err = lc2.counts_err[start_ind:end_ind]
            gti1 = np.array([[time_1[0] - lc1.dt / 2,
                              time_1[-1] + lc1.dt / 2]])
            gti2 = np.array([[time_2[0] - lc2.dt / 2,
                              time_2[-1] + lc2.dt / 2]])
            lc1_seg = Lightcurve(time_1, counts_1, err=counts_1_err,
                                 err_dist=lc1.err_dist,
                                 gti=gti1,
                                 dt=lc1.dt, skip_checks=True)
            lc2_seg = Lightcurve(time_2, counts_2, err=counts_2_err,
                                 err_dist=lc2.err_dist,
                                 gti=gti2,
                                 dt=lc2.dt, skip_checks=True)
            with warnings.catch_warnings(record=True) as w:
                cs_seg = Crossspectrum(lc1_seg, lc2_seg, norm=self.norm, power_type=self.power_type)

            cs_all.append(cs_seg)
            nphots1_all.append(np.sum(lc1_seg.counts))
            nphots2_all.append(np.sum(lc2_seg.counts))

        return cs_all, nphots1_all, nphots2_all
Esempio n. 18
0
    def _make_crossspectrum(self, lc1, lc2):
        """
        Auxiliary method computing the normalized cross spectrum from two
        light curves. This includes checking for the presence of and
        applying Good Time Intervals, computing the unnormalized Fourier
        cross-amplitude, and then renormalizing using the required
        normalization. Also computes an uncertainty estimate on the cross
        spectral powers.

        Parameters
        ----------
        lc1, lc2 : :class:`stingray.Lightcurve` objects
            Two light curves used for computing the cross spectrum.

        """
        # make sure the inputs work!
        if not isinstance(lc1, Lightcurve):
            raise TypeError("lc1 must be a lightcurve.Lightcurve object")

        if not isinstance(lc2, Lightcurve):
            raise TypeError("lc2 must be a lightcurve.Lightcurve object")

        if self.lc2.mjdref != self.lc1.mjdref:
            raise ValueError("MJDref is different in the two light curves")

        # Then check that GTIs make sense
        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)

        check_gtis(self.gti)

        if self.gti.shape[0] != 1:
            raise TypeError("Non-averaged Cross Spectra need "
                            "a single Good Time Interval")

        lc1 = lc1.split_by_gti()[0]
        lc2 = lc2.split_by_gti()[0]

        # total number of photons is the sum of the
        # counts in the light curve
        self.nphots1 = np.float64(np.sum(lc1.counts))
        self.nphots2 = np.float64(np.sum(lc2.counts))

        self.meancounts1 = lc1.meancounts
        self.meancounts2 = lc2.meancounts

        # the number of data points in the light curve

        if lc1.n != lc2.n:
            raise StingrayError("Light curves do not have same number "
                                "of time bins per segment.")

        # If dt differs slightly, its propagated error must not be more than
        # 1/100th of the bin
        if not np.isclose(lc1.dt, lc2.dt, rtol=0.01 * lc1.dt / lc1.tseg):
            raise StingrayError("Light curves do not have same time binning "
                                "dt.")

        # In case a small difference exists, ignore it
        lc1.dt = lc2.dt

        self.n = lc1.n

        # the frequency resolution
        self.df = 1.0 / lc1.tseg

        # the number of averaged periodograms in the final output
        # This should *always* be 1 here
        self.m = 1

        # make the actual Fourier transform and compute cross spectrum
        self.freq, self.unnorm_power = self._fourier_cross(lc1, lc2)

        # If co-spectrum is desired, normalize here. Otherwise, get raw back
        # with the imaginary part still intact.
        self.power = self._normalize_crossspectrum(self.unnorm_power, lc1.tseg)

        if lc1.err_dist.lower() != lc2.err_dist.lower():
            simon("Your lightcurves have different statistics."
                  "The errors in the Crossspectrum will be incorrect.")
        elif lc1.err_dist.lower() != "poisson":
            simon("Looks like your lightcurve statistic is not poisson."
                  "The errors in the Powerspectrum will be incorrect.")

        if self.__class__.__name__ in ['Powerspectrum',
                                       'AveragedPowerspectrum']:
            self.power_err = self.power / np.sqrt(self.m)
        elif self.__class__.__name__ in ['Crossspectrum',
                                         'AveragedCrossspectrum']:
            # This is clearly a wild approximation.
            simon("Errorbars on cross spectra are not thoroughly tested. "
                  "Please report any inconsistencies.")
            unnorm_power_err = np.sqrt(2) / np.sqrt(self.m)  # Leahy-like
            unnorm_power_err /= (2 / np.sqrt(self.nphots1 * self.nphots2))
            unnorm_power_err += np.zeros_like(self.power)

            self.power_err = \
                self._normalize_crossspectrum(unnorm_power_err, lc1.tseg)
        else:
            self.power_err = np.zeros(len(self.power))
Esempio n. 19
0
    def _make_segment_spectrum(self, lc, segment_size, silent=False):
        """
        Split the light curves into segments of size ``segment_size``, and
        calculate a power spectrum for each.

        Parameters
        ----------
        lc  : :class:`stingray.Lightcurve` objects\
            The input light curve

        segment_size : ``numpy.float``
            Size of each light curve segment to use for averaging.

        Other parameters
        ----------------
        silent : bool, default False
            Suppress progress bars

        Returns
        -------
        power_all : list of :class:`Powerspectrum` objects
            A list of power spectra calculated independently from each light curve segment

        nphots_all : ``numpy.ndarray``
            List containing the number of photons for all segments calculated from ``lc``
        """
        if not isinstance(lc, Lightcurve):
            raise TypeError("lc must be a Lightcurve object")

        current_gtis = lc.gti

        if self.gti is None:
            self.gti = lc.gti
        else:
            if not np.allclose(lc.gti, self.gti):
                self.gti = np.vstack([self.gti, lc.gti])

        check_gtis(self.gti)

        start_inds, end_inds = \
            bin_intervals_from_gtis(current_gtis, segment_size, lc.time, dt=lc.dt)

        power_all = []
        nphots_all = []

        local_show_progress = show_progress
        if not self.show_progress or silent:
            def local_show_progress(a): return a

        for start_ind, end_ind in \
                local_show_progress(zip(start_inds, end_inds)):
            time = lc.time[start_ind:end_ind]
            counts = lc.counts[start_ind:end_ind]
            counts_err = lc.counts_err[start_ind: end_ind]

            if np.sum(counts) == 0:
                warnings.warn(
                    "No counts in interval {}--{}s".format(time[0], time[-1]))
                continue

            lc_seg = Lightcurve(time, counts, err=counts_err,
                                err_dist=lc.err_dist.lower(),
                                skip_checks=True, dt=lc.dt)

            power_seg = Powerspectrum(lc_seg, norm=self.norm)
            power_all.append(power_seg)
            nphots_all.append(np.sum(lc_seg.counts))

        return power_all, nphots_all
Esempio n. 20
0
    def __init__(self, time, counts, err=None, input_counts=True,
                 gti=None, err_dist='poisson', mjdref=0, dt=None):

        if not np.all(np.isfinite(time)):
            raise ValueError("There are inf or NaN values in "
                             "your time array!")

        if not np.all(np.isfinite(counts)):
            raise ValueError("There are inf or NaN values in "
                             "your counts array!")

        if len(time) != len(counts):

            raise StingrayError("time and counts array are not "
                                "of the same length!")

        if len(time) <= 1:
            raise StingrayError("A single or no data points can not create "
                                "a lightcurve!")

        if err is not None:
            if not np.all(np.isfinite(err)):
                raise ValueError("There are inf or NaN values in "
                                 "your err array")
        else:
            if err_dist.lower() not in valid_statistics:
                # err_dist set can be increased with other statistics
                raise StingrayError("Statistic not recognized."
                                    "Please select one of these: ",
                                    "{}".format(valid_statistics))
            if err_dist.lower() == 'poisson':
                # Instead of the simple square root, we use confidence
                # intervals (should be valid for low fluxes too)
                err = poisson_symmetrical_errors(counts)
            else:
                simon("Stingray only uses poisson err_dist at the moment, "
                      "We are setting your errors to zero. "
                      "Sorry for the inconvenience.")
                err = np.zeros_like(counts)

        self.mjdref = mjdref
        self.time = np.asarray(time)
        dt_array = np.diff(np.sort(self.time))
        dt_array_unsorted = np.diff(self.time)
        unsorted = np.any(dt_array_unsorted < 0)

        if dt is None:
            if unsorted:
                logging.warning("The light curve is unordered! This may cause "
                                "unexpected behaviour in some methods! Use "
                                "sort() to order the light curve in time and "
                                "check that the time resolution `dt` is "
                                "calculated correctly!")

            self.dt = np.median(dt_array)
        else:
            self.dt = dt

        self.bin_lo = self.time - 0.5 * self.dt
        self.bin_hi = self.time + 0.5 * self.dt

        self.err_dist = err_dist

        if unsorted:
            self.tstart = np.min(self.time) - 0.5 * self.dt
            self.tseg = np.max(self.time) - np.min(self.time) + self.dt
        else:
            self.tstart = self.time[0] - 0.5 * self.dt
            self.tseg = self.time[-1] - self.time[0] + self.dt

        self.gti = \
            np.asarray(assign_value_if_none(gti,
                                            [[self.tstart,
                                              self.tstart + self.tseg]]))

        check_gtis(self.gti)

        good = create_gti_mask(self.time, self.gti, dt=self.dt)

        self.time = self.time[good]

        if input_counts:
            self.counts = np.asarray(counts)[good]
            self.countrate = self.counts / self.dt
            self.counts_err = np.asarray(err)[good]
            self.countrate_err = np.asarray(err)[good] / self.dt
        else:
            self.countrate = np.asarray(counts)[good]
            self.counts = self.countrate * self.dt
            self.counts_err = np.asarray(err)[good] * self.dt
            self.countrate_err = np.asarray(err)[good]

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]

        # Issue a warning if the input time iterable isn't regularly spaced,
        # i.e. the bin sizes aren't equal throughout.
        dt_array = []
        for g in self.gti:
            mask = create_gti_mask(self.time, [g], dt=self.dt)
            t = self.time[mask]
            dt_array.extend(np.diff(t))
        dt_array = np.asarray(dt_array)

        if not (np.allclose(dt_array, np.repeat(self.dt, dt_array.shape[0]))):
            simon("Bin sizes in input time array aren't equal throughout! "
                  "This could cause problems with Fourier transforms. "
                  "Please make the input time evenly sampled.")
Esempio n. 21
0
 def test_check_gti_fails_empty(self):
     with pytest.raises(ValueError) as excinfo:
         check_gtis([])
     assert 'Empty' in str(excinfo.value)
Esempio n. 22
0
    def test_check_gtis_values(self):
        with pytest.raises(ValueError):
            check_gtis([[0, 2], [1, 3]])

        with pytest.raises(ValueError):
            check_gtis([[1, 0]])
Esempio n. 23
0
    def _make_crossspectrum(self, lc1, lc2):

        # make sure the inputs work!
        if not isinstance(lc1, Lightcurve):
            raise TypeError("lc1 must be a lightcurve.Lightcurve object")

        if not isinstance(lc2, Lightcurve):
            raise TypeError("lc2 must be a lightcurve.Lightcurve object")

        if self.lc2.mjdref != self.lc1.mjdref:
            raise ValueError("MJDref is different in the two light curves")

        # Then check that GTIs make sense
        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)

        check_gtis(self.gti)

        if self.gti.shape[0] != 1:
            raise TypeError("Non-averaged Cross Spectra need "
                            "a single Good Time Interval")

        lc1 = lc1.split_by_gti()[0]
        lc2 = lc2.split_by_gti()[0]

        # total number of photons is the sum of the
        # counts in the light curve
        self.nphots1 = np.float64(np.sum(lc1.counts))
        self.nphots2 = np.float64(np.sum(lc2.counts))

        self.meancounts1 = lc1.meancounts
        self.meancounts2 = lc2.meancounts

        # the number of data points in the light curve

        if lc1.n != lc2.n:
            raise StingrayError("Light curves do not have same number "
                                "of time bins per segment.")

        # If dt differs slightly, its propagated error must not be more than
        # 1/100th of the bin
        if not np.isclose(lc1.dt, lc2.dt, rtol=0.01 * lc1.dt / lc1.tseg):
            raise StingrayError("Light curves do not have same time binning "
                                "dt.")

        # In case a small difference exists, ignore it
        lc1.dt = lc2.dt

        self.n = lc1.n

        # the frequency resolution
        self.df = 1.0 / lc1.tseg

        # the number of averaged periodograms in the final output
        # This should *always* be 1 here
        self.m = 1

        # make the actual Fourier transform and compute cross spectrum
        self.freq, self.unnorm_power = self._fourier_cross(lc1, lc2)

        # If co-spectrum is desired, normalize here. Otherwise, get raw back
        # with the imaginary part still intact.
        self.power = self._normalize_crossspectrum(self.unnorm_power, lc1.tseg)

        if lc1.err_dist.lower() != lc2.err_dist.lower():
            simon("Your lightcurves have different statistics."
                  "The errors in the Crossspectrum will be incorrect.")
        elif lc1.err_dist.lower() != "poisson":
            simon("Looks like your lightcurve statistic is not poisson."
                  "The errors in the Powerspectrum will be incorrect.")

        if self.__class__.__name__ in ['Powerspectrum',
                                       'AveragedPowerspectrum']:
            self.power_err = self.power / np.sqrt(self.m)
        elif self.__class__.__name__ in ['Crossspectrum',
                                         'AveragedCrossspectrum']:
            # This is clearly a wild approximation.
            simon("Errorbars on cross spectra are not thoroughly tested. "
                  "Please report any inconsistencies.")
            unnorm_power_err = np.sqrt(2) / np.sqrt(self.m)  # Leahy-like
            unnorm_power_err /= (2 / np.sqrt(self.nphots1 * self.nphots2))
            unnorm_power_err += np.zeros_like(self.power)

            self.power_err = \
                self._normalize_crossspectrum(unnorm_power_err, lc1.tseg)
        else:
            self.power_err = np.zeros(len(self.power))
Esempio n. 24
0
    def __init__(self, time, counts, err=None, input_counts=True,
                 gti=None, err_dist='poisson', mjdref=0, dt=None):

        if not np.all(np.isfinite(time)):
            raise ValueError("There are inf or NaN values in "
                             "your time array!")

        if not np.all(np.isfinite(counts)):
            raise ValueError("There are inf or NaN values in "
                             "your counts array!")

        if len(time) != len(counts):

            raise StingrayError("time and counts array are not "
                                "of the same length!")

        if len(time) <= 1:
            raise StingrayError("A single or no data points can not create "
                                "a lightcurve!")

        if err is not None:
            if not np.all(np.isfinite(err)):
                raise ValueError("There are inf or NaN values in "
                                 "your err array")
        else:
            if err_dist.lower() not in valid_statistics:
                # err_dist set can be increased with other statistics
                raise StingrayError("Statistic not recognized."
                                    "Please select one of these: ",
                                    "{}".format(valid_statistics))
            if err_dist.lower() == 'poisson':
                # Instead of the simple square root, we use confidence
                # intervals (should be valid for low fluxes too)
                err = poisson_symmetrical_errors(counts)
            else:
                simon("Stingray only uses poisson err_dist at the moment, "
                      "We are setting your errors to zero. "
                      "Sorry for the inconvenience.")
                err = np.zeros_like(counts)

        self.mjdref = mjdref
        self.time = np.asarray(time)
        dt_array = np.diff(np.sort(self.time))
        dt_array_unsorted = np.diff(self.time)
        unsorted = np.any(dt_array_unsorted < 0)

        if dt is None:
            if unsorted:
                logging.warning("The light curve is unordered! This may cause "
                                "unexpected behaviour in some methods! Use "
                                "sort() to order the light curve in time and "
                                "check that the time resolution `dt` is "
                                "calculated correctly!")

            self.dt = np.median(dt_array)
        else:
            self.dt = dt

        self.bin_lo = self.time - 0.5 * self.dt
        self.bin_hi = self.time + 0.5 * self.dt

        self.err_dist = err_dist

        if unsorted:
            self.tstart = np.min(self.time) - 0.5 * self.dt
            self.tseg = np.max(self.time) - np.min(self.time) + self.dt
        else:
            self.tstart = self.time[0] - 0.5 * self.dt
            self.tseg = self.time[-1] - self.time[0] + self.dt

        self.gti = \
            np.asarray(assign_value_if_none(gti,
                                            [[self.tstart,
                                              self.tstart + self.tseg]]))

        check_gtis(self.gti)

        good = create_gti_mask(self.time, self.gti, dt=self.dt)

        self.time = self.time[good]

        if input_counts:
            self.counts = np.asarray(counts)[good]
            self.countrate = self.counts / self.dt
            self.counts_err = np.asarray(err)[good]
            self.countrate_err = np.asarray(err)[good] / self.dt
        else:
            self.countrate = np.asarray(counts)[good]
            self.counts = self.countrate * self.dt
            self.counts_err = np.asarray(err)[good] * self.dt
            self.countrate_err = np.asarray(err)[good]

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]

        # Issue a warning if the input time iterable isn't regularly spaced,
        # i.e. the bin sizes aren't equal throughout.
        dt_array = []
        for g in self.gti:
            mask = create_gti_mask(self.time, [g], dt=self.dt)
            t = self.time[mask]
            dt_array.extend(np.diff(t))
        dt_array = np.asarray(dt_array)

        if not (np.allclose(dt_array, np.repeat(self.dt, dt_array.shape[0]))):
            simon("Bin sizes in input time array aren't equal throughout! "
                  "This could cause problems with Fourier transforms. "
                  "Please make the input time evenly sampled.")
Esempio n. 25
0
    def _make_multitaper_periodogram(self, lc, NW=4, adaptive=False,
                                     jackknife=True, low_bias=True,
                                     lombscargle=False):
        """Compute the normalized multitaper spectral estimate.

        This includes checking for the presence of and applying Good Time Intervals,
        computing the a nitime inspired normalized power spectrum, unnormalizing it,
        and then renormalizing it using the required normalization.

        Parameters
        ----------
        lc : :class:`stingray.Lightcurve` objects
            Two light curves used for computing the cross spectrum.

        NW: float, optional, default ``4``
            The normalized half-bandwidth of the data tapers, indicating a
            multiple of the fundamental frequency of the DFT (Fs/N).
        Common choices are n/2, for n >= 4.

        adaptive: boolean, optional, default ``False``
            Use an adaptive weighting routine to combine the PSD estimates of
            different tapers.

        jackknife: boolean, optional, default ``True``
            Use the jackknife method to make an estimate of the PSD variance
            at each point.

        low_bias: boolean, optional, default ``True``
            Rather than use 2NW tapers, only use the tapers that have better than
            90% spectral concentration within the bandwidth (still using
            a maximum of 2NW tapers)
        """

        if not isinstance(lc, Lightcurve):
            raise TypeError("lc must be a lightcurve.Lightcurve object")

        if self.gti is None:
            self.gti = cross_two_gtis(lc.gti, lc.gti)

        check_gtis(self.gti)

        if self.gti.shape[0] != 1:
            raise TypeError("Non-averaged Spectra need "
                            "a single Good Time Interval")

        lc = lc.split_by_gti()[0]

        self.meancounts = lc.meancounts
        self.nphots = np.float64(np.sum(lc.counts))

        self.err_dist = 'poisson'
        if lc.err_dist == 'poisson':
            self.var = lc.meancounts
        else:
            self.var = np.mean(lc.counts_err) ** 2
            self.err_dist = 'gauss'

        self.dt = lc.dt
        self.n = lc.n

        # the frequency resolution
        self.df = 1.0 / lc.tseg

        # the number of averaged periodograms in the final output
        # This should *always* be 1 here
        self.m = 1

        if lombscargle:
            self.freq, self.multitaper_norm_power = \
                self._fourier_multitaper_lomb_scargle(lc, NW=NW,
                                                      low_bias=low_bias)

            self.unnorm_power = self.multitaper_norm_power * lc.n * 2

        else:

            self.freq, self.multitaper_norm_power = \
                self._fourier_multitaper(lc, NW=NW, adaptive=adaptive,
                                         jackknife=jackknife, low_bias=low_bias)

            self.unnorm_power = self.multitaper_norm_power * lc.n / lc.dt

        self.power = \
            self._normalize_multitaper(self.unnorm_power, lc.tseg)

        if lc.err_dist.lower() != "poisson":
            simon("Looks like your lightcurve statistic is not poisson."
                  "The errors in the Powerspectrum will be incorrect.")

        self.power_err = self.power / np.sqrt(self.m)
Esempio n. 26
0
    def _make_crossspectrum(self, lc1, lc2):

        # make sure the inputs work!
        if not isinstance(lc1, Lightcurve):
            raise TypeError("lc1 must be a lightcurve.Lightcurve object")

        if not isinstance(lc2, Lightcurve):
            raise TypeError("lc2 must be a lightcurve.Lightcurve object")

        # Then check that GTIs make sense
        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)

        check_gtis(self.gti)

        if self.gti.shape[0] != 1:
            raise TypeError("Non-averaged Cross Spectra need "
                            "a single Good Time Interval")

        lc1 = lc1.split_by_gti()[0]
        lc2 = lc2.split_by_gti()[0]

        # total number of photons is the sum of the
        # counts in the light curve
        self.nphots1 = np.float64(np.sum(lc1.counts))
        self.nphots2 = np.float64(np.sum(lc2.counts))

        self.meancounts1 = lc1.meancounts
        self.meancounts2 = lc2.meancounts

        # the number of data points in the light curve

        if lc1.n != lc2.n:
            raise StingrayError("Light curves do not have same number "
                                "of time bins per segment.")

        if lc1.dt != lc2.dt:
            raise StingrayError("Light curves do not have "
                                "same time binning dt.")

        self.n = lc1.n

        # the frequency resolution
        self.df = 1.0 / lc1.tseg

        # the number of averaged periodograms in the final output
        # This should *always* be 1 here
        self.m = 1

        # make the actual Fourier transform and compute cross spectrum
        self.freq, self.unnorm_power = self._fourier_cross(lc1, lc2)

        # If co-spectrum is desired, normalize here. Otherwise, get raw back
        # with the imaginary part still intact.
        self.power = self._normalize_crossspectrum(self.unnorm_power, lc1.tseg)

        if lc1.err_dist.lower() != lc2.err_dist.lower():
            simon("Your lightcurves have different statistics."
                  "The errors in the Crossspectrum will be incorrect.")
        elif lc1.err_dist.lower() != "poisson":
            simon("Looks like your lightcurve statistic is not poisson."
                  "The errors in the Powerspectrum will be incorrect.")

        if self.__class__.__name__ in [
                'Powerspectrum', 'AveragedPowerspectrum'
        ]:
            self.power_err = self.power / np.sqrt(self.m)
        elif self.__class__.__name__ in [
                'Crossspectrum', 'AveragedCrossspectrum'
        ]:
            # This is clearly a wild approximation.
            simon("Errorbars on cross spectra are not thoroughly tested. "
                  "Please report any inconsistencies.")
            unnorm_power_err = np.sqrt(2) / np.sqrt(self.m)  # Leahy-like
            unnorm_power_err /= (2 / np.sqrt(self.nphots1 * self.nphots2))
            unnorm_power_err += np.zeros_like(self.power)

            self.power_err = \
                self._normalize_crossspectrum(unnorm_power_err, lc1.tseg)
        else:
            self.power_err = np.zeros(len(self.power))
Esempio n. 27
0
    def _make_segment_spectrum(self, lc1, lc2, segment_size):
        """
        Split the light curves into segments of size ``segment_size``, and calculate a cross spectrum for
        each.

        Parameters
        ----------
        lc1, lc2 : :class:`stingray.Lightcurve` objects
            Two light curves used for computing the cross spectrum.

        segment_size : ``numpy.float``
            Size of each light curve segment to use for averaging.

        Returns
        -------
        cs_all : list of :class:`Crossspectrum`` objects
            A list of cross spectra calculated independently from each light curve segment

        nphots1_all, nphots2_all : ``numpy.ndarray` for each of ``lc1`` and ``lc2``
            Two lists containing the number of photons for all segments calculated from ``lc1`` and ``lc2``.

        """

        # TODO: need to update this for making cross spectra.
        assert isinstance(lc1, Lightcurve)
        assert isinstance(lc2, Lightcurve)

        if lc1.tseg != lc2.tseg:
            raise ValueError("Lightcurves do not have same tseg.")

        # If dt differs slightly, its propagated error must not be more than
        # 1/100th of the bin
        if not np.isclose(lc1.dt, lc2.dt, rtol=0.01 * lc1.dt / lc1.tseg):
            raise ValueError("Light curves do not have same time binning dt.")

        # In case a small difference exists, ignore it
        lc1.dt = lc2.dt

        if self.gti is None:
            self.gti = cross_two_gtis(lc1.gti, lc2.gti)
            lc1.gti = lc2.gti = self.gti
            lc1._apply_gtis()
            lc2._apply_gtis()

        check_gtis(self.gti)

        cs_all = []
        nphots1_all = []
        nphots2_all = []

        start_inds, end_inds = \
            bin_intervals_from_gtis(self.gti, segment_size, lc1.time,
                                    dt=lc1.dt)

        for start_ind, end_ind in zip(start_inds, end_inds):
            time_1 = lc1.time[start_ind:end_ind]
            counts_1 = lc1.counts[start_ind:end_ind]
            counts_1_err = lc1.counts_err[start_ind:end_ind]
            time_2 = lc2.time[start_ind:end_ind]
            counts_2 = lc2.counts[start_ind:end_ind]
            counts_2_err = lc2.counts_err[start_ind:end_ind]
            gti1 = np.array([[time_1[0] - lc1.dt / 2,
                              time_1[-1] + lc1.dt / 2]])
            gti2 = np.array([[time_2[0] - lc2.dt / 2,
                              time_2[-1] + lc2.dt / 2]])
            lc1_seg = Lightcurve(time_1, counts_1, err=counts_1_err,
                                 err_dist=lc1.err_dist,
                                 gti=gti1,
                                 dt=lc1.dt)
            lc2_seg = Lightcurve(time_2, counts_2, err=counts_2_err,
                                 err_dist=lc2.err_dist,
                                 gti=gti2,
                                 dt=lc2.dt)
            cs_seg = Crossspectrum(lc1_seg, lc2_seg, norm=self.norm, power_type=self.power_type)
            cs_all.append(cs_seg)
            nphots1_all.append(np.sum(lc1_seg.counts))
            nphots2_all.append(np.sum(lc2_seg.counts))

        return cs_all, nphots1_all, nphots2_all
Esempio n. 28
0
    def __init__(self, time, counts, input_counts=True, gti=None):
        """
        Make a light curve object from an array of time stamps and an
        array of counts.

        Parameters
        ----------
        time: iterable
            A list or array of time stamps for a light curve

        counts: iterable, optional, default None
            A list or array of the counts in each bin corresponding to the
            bins defined in `time` (note: **not** the count rate, i.e.
            counts/second, but the counts/bin).

        input_counts: bool, optional, default True
            If True, the code assumes that the input data in 'counts'
            is in units of counts/bin. If False, it assumes the data
            in 'counts' is in counts/second.

        gti: 2-d float array, default None
            [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
            Good Time Intervals. They are *not* applied to the data by default.
            They will be used by other methods to have an indication of the
            "safe" time intervals to use during analysis.

        Attributes
        ----------
        time: numpy.ndarray
            The array of midpoints of time bins.

        counts: numpy.ndarray
            The counts per bin corresponding to the bins in `time`.

        countrate: numpy.ndarray
            The counts per second in each of the bins defined in `time`.

        meanrate: float
            The mean count rate of the light curve.
            
        meancounts: float
            The mean counts of the light curve.

        n: int
            The number of data points in the light curve.

        dt: float
            The time resolution of the light curve.

        tseg: float
            The total duration of the light curve.

        tstart: float
            The start time of the light curve.

        gti: 2-d float array
            [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
            Good Time Intervals. They indicate the "safe" time intervals
            to be used during the analysis of the light curve.

        """
        if not np.all(np.isfinite(time)):
            raise ValueError("There are inf or NaN values in "
                             "your time array!")

        if not np.all(np.isfinite(counts)):
            raise ValueError("There are inf or NaN values in "
                             "your counts array!")

        if len(time) != len(counts):

            raise StingrayError("time are counts array are not "
                                "of the same length!")

        if len(time) <= 1:
            raise StingrayError("A single or no data points can not create "
                                "a lightcurve!")

        self.time = np.asarray(time)
        self.dt = time[1] - time[0]

        if input_counts:
            self.counts = np.asarray(counts)
            self.countrate = self.counts / self.dt
        else:
            self.countrate = np.asarray(counts)
            self.counts = self.countrate * self.dt

        self.meanrate = np.mean(self.countrate)
        self.meancounts = np.mean(self.counts)
        self.n = self.counts.shape[0]

        # Issue a warning if the input time iterable isn't regularly spaced,
        # i.e. the bin sizes aren't equal throughout.
        dt_array = np.diff(self.time)
        if not (np.allclose(dt_array, np.repeat(self.dt, dt_array.shape[0]))):
            simon("Bin sizes in input time array aren't equal throughout! "
                  "This could cause problems with Fourier transforms. "
                  "Please make the input time evenly sampled.")

        self.tseg = self.time[-1] - self.time[0] + self.dt
        self.tstart = self.time[0] - 0.5*self.dt
        self.gti = \
            np.asarray(assign_value_if_none(gti,
                                            [[self.tstart,
                                              self.tstart + self.tseg]]))
        check_gtis(self.gti)