示例#1
0
    def __init__(self,
                 events,
                 freq_interval,
                 energy_spec,
                 ref_band=None,
                 bin_time=1,
                 use_pi=False,
                 segment_size=None,
                 events2=None):

        self.events1 = events
        self.events2 = assign_value_if_none(events2, events)
        self.freq_interval = freq_interval
        self.use_pi = use_pi
        self.bin_time = bin_time
        if isinstance(energy_spec, tuple):
            energies = _decode_energy_specification(energy_spec)
        else:
            energies = np.asarray(energy_spec)

        self.energy_intervals = list(zip(energies[0:-1], energies[1:]))

        self.ref_band = np.asarray(assign_value_if_none(ref_band, [0, np.inf]))

        if len(self.ref_band.shape) <= 1:
            self.ref_band = np.asarray([self.ref_band])

        self.segment_size = segment_size
        self.spectrum, self.spectrum_error = self._spectrum_function()
示例#2
0
def lcurve_from_txt(txt_file, outfile=None,
                    noclobber=False, outdir=None,
                    mjdref=None, gti=None):
    """
    Load a lightcurve from a text file.

    Parameters
    ----------
    txt_file : str
        File name of the input light curve in text format. Assumes two columns:
        time, counts. Times are seconds from MJDREF 55197.00076601852 (NuSTAR)
        if not otherwise specified.

    Returns
    -------
    outfile : [str]
        Returned as a list with a single element for consistency with
        `lcurve_from_events`

    Other Parameters
    ----------------
    outfile : str
        Output file name
    noclobber : bool
        If True, do not overwrite existing files
    mjdref : float, default 55197.00076601852
        the MJD time reference
    gti : [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
        Good Time Intervals
    """
    import numpy as np
    if mjdref is None:
        mjdref = np.longdouble('55197.00076601852')

    outfile = assign_value_if_none(outfile, hen_root(txt_file) + '_lc')
    outfile = outfile.replace(HEN_FILE_EXTENSION, '') + HEN_FILE_EXTENSION

    outdir = assign_value_if_none(
        outdir, os.path.dirname(os.path.abspath(txt_file)))

    _, outfile = os.path.split(outfile)
    mkdir_p(outdir)
    outfile = os.path.join(outdir, outfile)

    if noclobber and os.path.exists(outfile):
        warnings.warn('File exists, and noclobber option used. Skipping')
        return [outfile]

    time, counts = np.genfromtxt(txt_file, delimiter=' ', unpack=True)
    time = np.array(time, dtype=np.longdouble)
    counts = np.array(counts, dtype=np.float)

    lc = Lightcurve(time=time, counts=counts, gti=gti,
                    mjdref=mjdref)

    lc.instr = 'EXTERN'

    logging.info('Saving light curve to %s' % outfile)
    save_lcurve(lc, outfile)
    return [outfile]
示例#3
0
    def __getitem__(self, index):
        """
        Return the corresponding count value at the index or a new Lightcurve
        object upon slicing.

        This method adds functionality to retrieve the count value at
        a particular index. This also can be used for slicing and generating
        a new Lightcurve object. GTIs are recalculated based on the new light
        curve segment

        If the slice object is of kind start:stop:step, GTIs are also sliced,
        and rewritten as zip(time - self.dt /2, time + self.dt / 2)

        Parameters
        ----------
        index : int or slice instance
            Index value of the time array or a slice object.

        Examples
        --------
        >>> time = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        >>> count = [11, 22, 33, 44, 55, 66, 77, 88, 99]
        >>> lc = Lightcurve(time, count)
        >>> lc[2]
        33
        >>> lc[:2].counts
        array([11, 22])
        """
        if isinstance(index, int):
            return self.counts[index]
        elif isinstance(index, slice):
            start = assign_value_if_none(index.start, 0)
            stop = assign_value_if_none(index.stop, len(self.counts))
            step = assign_value_if_none(index.step, 1)

            new_counts = self.counts[start:stop:step]
            new_time = self.time[start:stop:step]

            new_gti = [[
                self.time[start] - 0.5 * self.dt,
                self.time[stop - 1] + 0.5 * self.dt
            ]]
            new_gti = np.asarray(new_gti)
            if step > 1:
                new_gt1 = np.array(
                    list(zip(new_time - self.dt / 2, new_time + self.dt / 2)))
                new_gti = cross_two_gtis(new_gti, new_gt1)

            new_gti = cross_two_gtis(self.gti, new_gti)

            return Lightcurve(new_time,
                              new_counts,
                              mjdref=self.mjdref,
                              gti=new_gti,
                              dt=self.dt)
        else:
            raise IndexError("The index must be either an integer or a slice "
                             "object !")
示例#4
0
    def __getitem__(self, index):
        """
        Return the corresponding count value at the index or a new Lightcurve
        object upon slicing.

        This method adds functionality to retrieve the count value at
        a particular index. This also can be used for slicing and generating
        a new Lightcurve object. GTIs are recalculated based on the new light
        curve segment

        If the slice object is of kind start:stop:step, GTIs are also sliced,
        and rewritten as zip(time - self.dt /2, time + self.dt / 2)

        Parameters
        ----------
        index : int or slice instance
            Index value of the time array or a slice object.

        Examples
        --------
        >>> time = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        >>> count = [11, 22, 33, 44, 55, 66, 77, 88, 99]
        >>> lc = Lightcurve(time, count)
        >>> lc[2]
        33
        >>> lc[:2].counts
        array([11, 22])
        """
        if isinstance(index, int):
            return self.counts[index]
        elif isinstance(index, slice):
            start = assign_value_if_none(index.start, 0)
            stop = assign_value_if_none(index.stop, len(self.counts))
            step = assign_value_if_none(index.step, 1)

            new_counts = self.counts[start:stop:step]
            new_time = self.time[start:stop:step]

            new_gti = [[self.time[start] - 0.5 * self.dt,
                        self.time[stop - 1] + 0.5 * self.dt]]
            new_gti = np.asarray(new_gti)
            if step > 1:
                new_gt1 = np.array(list(zip(new_time - self.dt / 2,
                                            new_time + self.dt / 2)))
                new_gti = cross_two_gtis(new_gti, new_gt1)

            new_gti = cross_two_gtis(self.gti, new_gti)

            return Lightcurve(new_time, new_counts, mjdref=self.mjdref,
                              gti=new_gti, dt=self.dt)
        else:
            raise IndexError("The index must be either an integer or a slice "
                             "object !")
示例#5
0
    def _construct_lightcurves(self,
                               channel_band,
                               tstart=None,
                               tstop=None,
                               exclude=True,
                               only_base=False):
        if self.use_pi:
            energies1 = self.events1.pi
            energies2 = self.events2.pi
        else:
            energies2 = self.events2.energy
            energies1 = self.events1.energy

        gti = cross_two_gtis(self.events1.gti, self.events2.gti)

        tstart = assign_value_if_none(tstart, gti[0, 0])
        tstop = assign_value_if_none(tstop, gti[-1, -1])

        good = (energies1 >= channel_band[0]) & (energies1 < channel_band[1])
        base_lc = Lightcurve.make_lightcurve(self.events1.time[good],
                                             self.bin_time,
                                             tstart=tstart,
                                             tseg=tstop - tstart,
                                             gti=gti,
                                             mjdref=self.events1.mjdref)

        if only_base:
            return base_lc

        if exclude:
            ref_intervals = self._decide_ref_intervals(channel_band,
                                                       self.ref_band)
        else:
            ref_intervals = self.ref_band

        ref_lc = Lightcurve(base_lc.time,
                            np.zeros_like(base_lc.counts),
                            gti=base_lc.gti,
                            mjdref=base_lc.mjdref,
                            err_dist='gauss')

        for i in ref_intervals:
            good = (energies2 >= i[0]) & (energies2 < i[1])
            new_lc = Lightcurve.make_lightcurve(self.events2.time[good],
                                                self.bin_time,
                                                tstart=tstart,
                                                tseg=tstop - tstart,
                                                gti=base_lc.gti,
                                                mjdref=self.events2.mjdref)
            ref_lc = ref_lc + new_lc

        ref_lc.err_dist = base_lc.err_dist
        return base_lc, ref_lc
    def _construct_lightcurves(self, channel_band, tstart=None, tstop=None,
                               exclude=True, only_base=False):
        if self.use_pi:
            energies1 = self.events1.pi
            energies2 = self.events2.pi
        else:
            energies2 = self.events2.energy
            energies1 = self.events1.energy

        gti = cross_two_gtis(self.events1.gti, self.events2.gti)

        tstart = assign_value_if_none(tstart, gti[0, 0])
        tstop = assign_value_if_none(tstop, gti[-1, -1])

        good = (energies1 >= channel_band[0]) & (energies1 < channel_band[1])
        base_lc = Lightcurve.make_lightcurve(self.events1.time[good],
                                             self.bin_time,
                                             tstart=tstart,
                                             tseg=tstop - tstart,
                                             gti=gti,
                                             mjdref=self.events1.mjdref)

        if only_base:
            return base_lc

        if exclude:
            ref_intervals = self._decide_ref_intervals(channel_band,
                                                       self.ref_band)
        else:
            ref_intervals = self.ref_band

        ref_lc = Lightcurve(base_lc.time, np.zeros_like(base_lc.counts),
                            gti=base_lc.gti, mjdref=base_lc.mjdref,
                            err_dist='gauss')

        for i in ref_intervals:
            good = (energies2 >= i[0]) & (energies2 < i[1])
            new_lc = Lightcurve.make_lightcurve(self.events2.time[good],
                                                self.bin_time,
                                                tstart=tstart,
                                                tseg=tstop - tstart,
                                                gti=base_lc.gti,
                                                mjdref=self.events2.mjdref)
            ref_lc = ref_lc + new_lc

        ref_lc.err_dist = base_lc.err_dist
        return base_lc, ref_lc
示例#7
0
    def __init__(
        self,
        events,
        freq_interval,
        energy_spec,
        ref_band=None,
        bin_time=1,
        use_pi=False,
        segment_size=None,
        events2=None,
        return_complex=False,
    ):
        self.events1 = events
        self.events2 = assign_value_if_none(events2, events)
        self._analyze_inputs()
        # This will be set to True in ComplexCovariance
        self.return_complex = return_complex

        self.freq_interval = freq_interval
        self.use_pi = use_pi
        self.bin_time = bin_time

        if isinstance(energy_spec, tuple):
            energies = _decode_energy_specification(energy_spec)
        else:
            energies = np.asarray(energy_spec)

        self.energy_intervals = list(zip(energies[0:-1], energies[1:]))

        self.ref_band = np.asarray(assign_value_if_none(ref_band, [0, np.inf]))

        if len(self.ref_band.shape) <= 1:
            self.ref_band = np.asarray([self.ref_band])

        self.segment_size = self.delta_nu = None
        if segment_size is not None:
            self.segment_size = segment_size
            self.delta_nu = 1 / self.segment_size

        self._create_empty_spectrum()

        if len(events.time) == 0:
            simon("There are no events in your event list!" +
                  "Can't make a spectrum!")
        else:
            self._spectrum_function()
示例#8
0
def _load_and_prepare_TOAs(mjds, errs_us=None, ephem="DE405"):
    errs_us = assign_value_if_none(errs_us, np.zeros_like(mjds))

    toalist = [None] * len(mjds)
    for i, m in enumerate(mjds):
        toalist[i] = \
            toa.TOA(m, error=errs_us[i], obs='Barycenter', scale='tdb')

    toalist = toa.TOAs(toalist=toalist)
    if 'tdb' not in toalist.table.colnames:
        toalist.compute_TDBs()
    if 'ssb_obs_pos' not in toalist.table.colnames:
        toalist.compute_posvels(ephem, False)
    return toalist
示例#9
0
文件: io.py 项目: swapsha96/HENDRICS
def load_gtis(fits_file, gtistring=None):
    """Load GTI from HDU EVENTS of file fits_file."""
    from astropy.io import fits as pf
    import numpy as np

    gtistring = assign_value_if_none(gtistring, 'GTI')
    logging.info("Loading GTIS from file %s" % fits_file)
    lchdulist = pf.open(fits_file, checksum=True)
    lchdulist.verify('warn')

    gtitable = lchdulist[gtistring].data
    gti_list = np.array(
        [[a, b]
         for a, b in zip(gtitable.field('START'), gtitable.field('STOP'))],
        dtype=np.longdouble)
    lchdulist.close()
    return gti_list
示例#10
0
文件: io.py 项目: swapsha96/HENDRICS
def load_events_and_gtis(fits_file,
                         additional_columns=None,
                         gtistring='GTI,STDGTI',
                         gti_file=None,
                         hduname='EVENTS',
                         column='TIME'):
    """Load event lists and GTIs from one or more files.

    Loads event list from HDU EVENTS of file fits_file, with Good Time
    intervals. Optionally, returns additional columns of data from the same
    HDU of the events.

    Parameters
    ----------
    fits_file : str
    return_limits: bool, optional
        Return the TSTART and TSTOP keyword values
    additional_columns: list of str, optional
        A list of keys corresponding to the additional columns to extract from
        the event HDU (ex.: ['PI', 'X'])

    Returns
    -------
    ev_list : array-like
    gtis: [[gti0_0, gti0_1], [gti1_0, gti1_1], ...]
    additional_data: dict
        A dictionary, where each key is the one specified in additional_colums.
        The data are an array with the values of the specified column in the
        fits file.
    t_start : float
    t_stop : float
    """
    from astropy.io import fits as pf

    gtistring = assign_value_if_none(gtistring, 'GTI,STDGTI')
    lchdulist = pf.open(fits_file)

    # Load data table
    try:
        lctable = lchdulist[hduname].data
    except:  # pragma: no cover
        logging.warning('HDU %s not found. Trying first extension' % hduname)
        lctable = lchdulist[1].data
        hduname = 1

    # Read event list
    ev_list = np.array(lctable.field(column), dtype=np.longdouble)
    detector_id = _get_detector_id(lctable)
    det_number = None if detector_id is None else list(set(detector_id))
    header = lchdulist[1].header
    # Read TIMEZERO keyword and apply it to events
    try:
        timezero = np.longdouble(header['TIMEZERO'])
    except:  # pragma: no cover
        logging.warning("No TIMEZERO in file")
        timezero = np.longdouble(0.)

    try:
        instr = header['INSTRUME']
    except:
        instr = 'unknown'

    ev_list += timezero

    # Read TSTART, TSTOP from header
    try:
        t_start = np.longdouble(header['TSTART'])
        t_stop = np.longdouble(header['TSTOP'])
    except:  # pragma: no cover
        logging.warning("Tstart and Tstop error. using defaults")
        t_start = ev_list[0]
        t_stop = ev_list[-1]

    mjdref = np.longdouble(high_precision_keyword_read(header, 'MJDREF'))

    # Read and handle GTI extension
    accepted_gtistrings = gtistring.split(',')

    if gti_file is None:
        # Select first GTI with accepted name
        try:
            gti_list = \
                _get_gti_from_all_extensions(
                    lchdulist, accepted_gtistrings=accepted_gtistrings,
                    det_numbers=det_number)
        except:  # pragma: no cover
            warnings.warn("No extensions found with a valid name. "
                          "Please check the `accepted_gtistrings` values.")
            gti_list = np.array([[t_start, t_stop]], dtype=np.longdouble)
    else:
        gti_list = load_gtis(gti_file, gtistring)

    if additional_columns is None:
        additional_columns = ['PI']
    if 'PI' not in additional_columns:
        additional_columns.append('PI')

    additional_data = _get_additional_data(lctable, additional_columns)

    lchdulist.close()

    # Sort event list
    order = np.argsort(ev_list)
    ev_list = ev_list[order]

    additional_data = _order_list_of_arrays(additional_data, order)
    pi = additional_data['PI'][order]
    additional_data.pop('PI')

    returns = _empty()

    returns.ev_list = EventList(ev_list, gti=gti_list, pi=pi)

    returns.ev_list.instr = instr
    returns.ev_list.mjdref = mjdref
    returns.ev_list.header = header.tostring()
    returns.additional_data = additional_data
    returns.t_start = t_start
    returns.t_stop = t_stop
    returns.detector_id = detector_id

    return returns
示例#11
0
def treat_event_file(filename,
                     noclobber=False,
                     gti_split=False,
                     min_length=4,
                     gtistring=None):
    """Read data from an event file, with no external GTI information.

    Parameters
    ----------
    filename : str

    Other Parameters
    ----------------
    noclobber: bool
        if a file is present, do not overwrite it
    gtistring: str
        comma-separated set of GTI strings to consider
    gti_split: bool
        split the file in multiple chunks, containing one GTI each
    min_length: float
        minimum length of GTIs accepted (only if gti_split is True)
    """
    gtistring = assign_value_if_none(gtistring, 'GTI,STDGTI')
    logging.info('Opening %s' % filename)

    instr = read_header_key(filename, 'INSTRUME')
    mission = read_header_key(filename, 'TELESCOP')

    data = load_events_and_gtis(filename, gtistring=gtistring)

    events = data.ev_list
    gtis = events.gti
    detector_id = data.detector_id

    if detector_id is not None:
        detectors = list(set(detector_id))
    else:
        detectors = [None]
    outfile_root = \
        hen_root(filename) + '_' + mission.lower() + '_' + instr.lower()

    for d in detectors:
        if d is not None:
            good_det = data.detector_id
            outroot_local = \
                '{0}_det{1:02d}'.format(outfile_root, d)

        else:
            good_det = np.ones_like(events.time, dtype=bool)
            outroot_local = outfile_root

        outfile = outroot_local + '_ev' + HEN_FILE_EXTENSION
        if noclobber and os.path.exists(outfile) and (not gti_split):
            warnings.warn(
                '{0} exists, and noclobber option used. Skipping'.format(
                    outfile))
            return

        if gti_split:
            for ig, g in enumerate(gtis):
                length = g[1] - g[0]
                if length < min_length:
                    print("GTI shorter than {} s; skipping".format(min_length))
                    continue

                outfile_local = \
                    '{0}_gti{1}_ev'.format(outroot_local,
                                           ig) + HEN_FILE_EXTENSION

                if noclobber and os.path.exists(outfile_local):
                    warnings.warn('{0} exists, '.format(outfile_local) +
                                  'and noclobber option used. Skipping')
                    return
                good = np.logical_and(events.time >= g[0], events.time < g[1])
                all_good = good_det & good
                events_filt = EventList(events.time[all_good],
                                        pi=events.pi[all_good],
                                        gti=np.array([g], dtype=np.longdouble),
                                        mjdref=events.mjdref)
                events_filt.instr = events.instr
                events_filt.header = events.header
                save_events(events_filt, outfile_local)
            pass
        else:
            events_filt = EventList(events.time[good_det],
                                    pi=events.pi[good_det],
                                    gti=events.gti,
                                    mjdref=events.mjdref)
            events_filt.instr = events.instr
            events_filt.header = events.header

            save_events(events_filt, outfile)
示例#12
0
def lcurve_from_fits(fits_file, gtistring='GTI',
                     timecolumn='TIME', ratecolumn=None, ratehdu=1,
                     fracexp_limit=0.9, outfile=None,
                     noclobber=False, outdir=None):
    """
    Load a lightcurve from a fits file and save it in HENDRICS format.

    .. note ::
        FITS light curve handling is still under testing.
        Absolute times might be incorrect depending on the light curve format.

    Parameters
    ----------
    fits_file : str
        File name of the input light curve in FITS format

    Returns
    -------
    outfile : [str]
        Returned as a list with a single element for consistency with
        `lcurve_from_events`

    Other Parameters
    ----------------
    gtistring : str
        Name of the GTI extension in the FITS file
    timecolumn : str
        Name of the column containing times in the FITS file
    ratecolumn : str
        Name of the column containing rates in the FITS file
    ratehdu : str or int
        Name or index of the FITS extension containing the light curve
    fracexp_limit : float
        Minimum exposure fraction allowed
    outfile : str
        Output file name
    noclobber : bool
        If True, do not overwrite existing files
    """
    logging.warning(
        """WARNING! FITS light curve handling is still under testing.
        Absolute times might be incorrect.""")
    # TODO:
    # treat consistently TDB, UTC, TAI, etc. This requires some documentation
    # reading. For now, we assume TDB
    from astropy.io import fits as pf
    from astropy.time import Time
    import numpy as np
    from .base import create_gti_from_condition

    outfile = assign_value_if_none(outfile, hen_root(fits_file) + '_lc')
    outfile = outfile.replace(HEN_FILE_EXTENSION, '') + HEN_FILE_EXTENSION
    outdir = assign_value_if_none(
        outdir, os.path.dirname(os.path.abspath(fits_file)))

    _, outfile = os.path.split(outfile)
    mkdir_p(outdir)
    outfile = os.path.join(outdir, outfile)

    if noclobber and os.path.exists(outfile):
        warnings.warn('File exists, and noclobber option used. Skipping')
        return [outfile]

    lchdulist = pf.open(fits_file)
    lctable = lchdulist[ratehdu].data

    # Units of header keywords
    tunit = lchdulist[ratehdu].header['TIMEUNIT']

    try:
        mjdref = high_precision_keyword_read(lchdulist[ratehdu].header,
                                             'MJDREF')
        mjdref = Time(mjdref, scale='tdb', format='mjd')
    except:
        mjdref = None

    try:
        instr = lchdulist[ratehdu].header['INSTRUME']
    except:
        instr = 'EXTERN'

    # ----------------------------------------------------------------
    # Trying to comply with all different formats of fits light curves.
    # It's a madness...
    try:
        tstart = high_precision_keyword_read(lchdulist[ratehdu].header,
                                             'TSTART')
        tstop = high_precision_keyword_read(lchdulist[ratehdu].header,
                                            'TSTOP')
    except:
        raise(Exception('TSTART and TSTOP need to be specified'))

    # For nulccorr lcs this whould work

    timezero = high_precision_keyword_read(lchdulist[ratehdu].header,
                                           'TIMEZERO')
    # Sometimes timezero is "from tstart", sometimes it's an absolute time.
    # This tries to detect which case is this, and always consider it
    # referred to tstart
    timezero = assign_value_if_none(timezero, 0)

    # for lcurve light curves this should instead work
    if tunit == 'd':
        # TODO:
        # Check this. For now, I assume TD (JD - 2440000.5).
        # This is likely wrong
        timezero = Time(2440000.5 + timezero, scale='tdb', format='jd')
        tstart = Time(2440000.5 + tstart, scale='tdb', format='jd')
        tstop = Time(2440000.5 + tstop, scale='tdb', format='jd')
        # if None, use NuSTAR defaulf MJDREF
        mjdref = assign_value_if_none(
            mjdref, Time(np.longdouble('55197.00076601852'), scale='tdb',
                         format='mjd'))

        timezero = (timezero - mjdref).to('s').value
        tstart = (tstart - mjdref).to('s').value
        tstop = (tstop - mjdref).to('s').value

    if timezero > tstart:
        timezero -= tstart

    time = np.array(lctable.field(timecolumn), dtype=np.longdouble)
    if time[-1] < tstart:
        time += timezero + tstart
    else:
        time += timezero

    try:
        dt = high_precision_keyword_read(lchdulist[ratehdu].header,
                                         'TIMEDEL')
        if tunit == 'd':
            dt *= 86400
    except:
        warnings.warn('Assuming that TIMEDEL is the difference between the'
                      ' first two times of the light curve')
        dt = time[1] - time[0]

    # ----------------------------------------------------------------
    ratecolumn = assign_value_if_none(
        ratecolumn,
        _look_for_array_in_array(['RATE', 'RATE1', 'COUNTS'], lctable.names))

    rate = np.array(lctable.field(ratecolumn), dtype=np.float)

    try:
        rate_e = np.array(lctable.field('ERROR'), dtype=np.longdouble)
    except:
        rate_e = np.zeros_like(rate)

    if 'RATE' in ratecolumn:
        rate *= dt
        rate_e *= dt

    try:
        fracexp = np.array(lctable.field('FRACEXP'), dtype=np.longdouble)
    except:
        fracexp = np.ones_like(rate)

    good_intervals = (rate == rate) * (fracexp >= fracexp_limit) * \
        (fracexp <= 1)

    rate[good_intervals] /= fracexp[good_intervals]
    rate_e[good_intervals] /= fracexp[good_intervals]

    rate[np.logical_not(good_intervals)] = 0

    try:
        gtitable = lchdulist[gtistring].data
        gti_list = np.array([[a, b]
                             for a, b in zip(gtitable.field('START'),
                                             gtitable.field('STOP'))],
                            dtype=np.longdouble)
    except:
        gti_list = create_gti_from_condition(time, good_intervals)

    lchdulist.close()

    lc = Lightcurve(time=time, counts=rate, err=rate_e, gti=gti_list,
                    mjdref=mjdref.mjd)

    lc.instr = instr
    lc.header = lchdulist[ratehdu].header.tostring()

    logging.info('Saving light curve to %s' % outfile)
    save_lcurve(lc, outfile)
    return [outfile]
示例#13
0
def lcurve_from_events(f, safe_interval=0,
                       pi_interval=None,
                       e_interval=None,
                       min_length=0,
                       gti_split=False,
                       ignore_gtis=False,
                       bintime=1.,
                       outdir=None,
                       outfile=None,
                       noclobber=False):
    """Bin an event list in a light curve.

    Parameters
    ----------
    f : str
        Input event file name
    bintime : float
        The bin time of the output light curve

    Returns
    -------
    outfiles : list
        List of output light curves

    Other Parameters
    ----------------
    safe_interval : float or [float, float]
        Seconds to filter out at the start and end of each GTI. If single
        float, these safe windows are equal, otherwise the two numbers refer
        to the start and end of the GTI respectively
    pi_interval : [int, int]
        PI channel interval to select. Default None, meaning that all PI
        channels are used
    e_interval : [float, float]
        Energy interval to select (only works if event list is calibrated with
        `calibrate`). Default None
    min_length : float
        GTIs below this length will be filtered out
    gti_split : bool
        If True, create one light curve for each good time interval
    ignore_gtis : bool
        Ignore good time intervals, and get a single light curve that includes
        possible gaps
    outdir : str
        Output directory
    outfile : str
        Output file
    noclobber : bool
        If True, do not overwrite existing files

    """
    logging.info("Loading file %s..." % f)
    evdata = load_events(f)
    logging.info("Done.")

    if bintime < 0:
        bintime = 2 ** (bintime)
    bintime = np.longdouble(bintime)

    tag = ''

    gtis = evdata.gti
    tstart = np.min(gtis)
    tstop = np.max(gtis)
    events = evdata.time
    if hasattr(evdata, 'instr') and evdata.instr is not None:
        instr = evdata.instr
    else:
        instr = "unknown"

    if ignore_gtis:
        gtis = np.array([[tstart, tstop]])
        evdata.gtis = gtis

    total_lc = evdata.to_lc(100)
    total_lc.instr = instr

    # Then, apply filters
    if pi_interval is not None and np.all(np.array(pi_interval) > 0):
        pis = evdata.pi
        good = np.logical_and(pis > pi_interval[0],
                              pis <= pi_interval[1])
        events = events[good]
        tag = '_PI%g-%g' % (pi_interval[0], pi_interval[1])
    elif e_interval is not None and np.all(np.array(e_interval) > 0):
        if not hasattr(evdata, 'energy') or evdata.energy is None:
            raise \
                ValueError("No energy information is present in the file." +
                           " Did you run HENcalibrate?")
        es = evdata.energy
        good = np.logical_and(es > e_interval[0],
                              es <= e_interval[1])
        events = events[good]
        tag = '_E%g-%g' % (e_interval[0], e_interval[1])
    else:
        pass

    if tag != "":
        save_lcurve(total_lc, hen_root(f) + '_std_lc' + HEN_FILE_EXTENSION)

    # Assign default value if None
    outfile = assign_value_if_none(outfile,  hen_root(f) + tag + '_lc')

    # Take out extension from name, if present, then give extension. This
    # avoids multiple extensions
    outfile = outfile.replace(HEN_FILE_EXTENSION, '') + HEN_FILE_EXTENSION
    outdir = assign_value_if_none(
        outdir, os.path.dirname(os.path.abspath(f)))

    _, outfile = os.path.split(outfile)
    mkdir_p(outdir)
    outfile = os.path.join(outdir, outfile)

    if noclobber and os.path.exists(outfile):
        warnings.warn('File exists, and noclobber option used. Skipping')
        return [outfile]

    lc = Lightcurve.make_lightcurve(events, bintime, tstart=tstart,
                                    tseg=tstop-tstart, mjdref=evdata.mjdref)

    lc.instr = instr

    lc = filter_lc_gtis(lc, safe_interval=safe_interval,
                        delete=False,
                        min_length=min_length)

    if len(lc.gti) == 0:
        warnings.warn(
            "No GTIs above min_length ({0}s) found.".format(min_length))
        return

    if gti_split:
        lcs = lc.split_by_gti()
        outfiles = []

        for ib, l0 in enumerate(lcs):
            local_tag = tag + '_gti%d' % ib
            outf = hen_root(outfile) + local_tag + '_lc' + HEN_FILE_EXTENSION
            if noclobber and os.path.exists(outf):
                warnings.warn(
                    'File exists, and noclobber option used. Skipping')
                outfiles.append(outf)
            l0.instr = lc.instr
            save_lcurve(l0, outf)
            outfiles.append(outf)
    else:
        logging.info('Saving light curve to %s' % outfile)
        save_lcurve(lc, outfile)
        outfiles = [outfile]

    # For consistency in return value
    return outfiles
示例#14
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.")
示例#15
0
 def test_assign_value_if_none(self):
     assert utils.assign_value_if_none(None, 2) == 2
     assert utils.assign_value_if_none(1, 2) == 1
示例#16
0
    def _construct_lightcurves(self,
                               channel_band,
                               tstart=None,
                               tstop=None,
                               exclude=True,
                               only_base=False):
        """
        Construct light curves from event data, for each band of interest.

        Parameters
        ----------
        channel_band : iterable of type ``[elow, ehigh]``
            The lower/upper limits of the energies to be contained in the band
            of interest

        tstart : float, optional, default ``None``
            A common start time (if start of observation is different from
            the first recorded event)

        tstop : float, optional, default ``None``
            A common stop time (if start of observation is different from
            the first recorded event)

        exclude : bool, optional, default ``True``
            if ``True``, exclude the band of interest from the reference band

        only_base : bool, optional, default ``False``
            if ``True``, only return the light curve of the channel of interest, not
            that of the reference band

        Returns
        -------
        base_lc : :class:`Lightcurve` object
            The light curve of the channels of interest

        ref_lc : :class:`Lightcurve` object (only returned if ``only_base`` is ``False``)
            The reference light curve for comparison with ``base_lc``
        """
        if self.use_pi:
            energies1 = self.events1.pi
            energies2 = self.events2.pi
        else:
            energies2 = self.events2.energy
            energies1 = self.events1.energy

        gti = cross_two_gtis(self.events1.gti, self.events2.gti)

        tstart = assign_value_if_none(tstart, gti[0, 0])
        tstop = assign_value_if_none(tstop, gti[-1, -1])

        good = (energies1 >= channel_band[0]) & (energies1 < channel_band[1])
        base_lc = Lightcurve.make_lightcurve(
            self.events1.time[good],
            self.bin_time,
            tstart=tstart,
            tseg=tstop - tstart,
            gti=gti,
            mjdref=self.events1.mjdref,
        )

        if only_base:
            return base_lc

        if exclude:
            ref_intervals = get_non_overlapping_ref_band(
                channel_band, self.ref_band)
        else:
            ref_intervals = self.ref_band

        ref_lc = Lightcurve(
            base_lc.time,
            np.zeros_like(base_lc.counts),
            gti=base_lc.gti,
            mjdref=base_lc.mjdref,
            dt=base_lc.dt,
            err_dist=base_lc.err_dist,
            skip_checks=True,
        )

        for i in ref_intervals:
            good = (energies2 >= i[0]) & (energies2 < i[1])
            new_lc = Lightcurve.make_lightcurve(
                self.events2.time[good],
                self.bin_time,
                tstart=tstart,
                tseg=tstop - tstart,
                gti=base_lc.gti,
                mjdref=self.events2.mjdref,
            )
            ref_lc = ref_lc + new_lc

        ref_lc.err_dist = base_lc.err_dist
        return base_lc, ref_lc
示例#17
0
    def __init__(self,
                 ev_times,
                 freq,
                 nph=128,
                 nt=128,
                 test=False,
                 fdot=0,
                 fddot=0,
                 mjdref=None,
                 pepoch=None,
                 gti=None,
                 label="phaseogram",
                 norm=None,
                 position=None,
                 object=None,
                 plot_only=False,
                 time_corr=None,
                 **kwargs):
        """Init BasePhaseogram class.

        Parameters
        ----------
        ev_times : array-like
            Event times
        freq : float
            Frequency of pulsation

        Other parameters
        ----------------
        nph : int
            Number of phase bins in the profile
        nt : int
            Number of time bins in the profile
        pepoch : float, default None
            Epoch of timing solution, in the same units as ev_times
        mjdref : float, default None
            Reference MJD
        fdot : float
            First frequency derivative
        fddot : float
            Second frequency derivative
        label : str
            Label for windows
        norm : str
            Normalization
        position : `astropy.Skycoord` object
            Position of the pulsar
        object : str
            Name of the pulsar
        **kwargs : keyword args
            additional arguments to pass to `self._construct_widgets`
        """

        self.fdot = fdot
        self.fddot = fddot
        self.nt = nt
        self.nph = nph
        self.mjdref = mjdref
        self.gti = gti
        self.label = label
        self.test = test

        self.pepoch = assign_value_if_none(pepoch, ev_times[0])
        self.time_corr = \
            assign_value_if_none(time_corr, np.zeros_like(ev_times))
        self.ev_times = ev_times
        self.freq = freq
        self.norm = norm
        self.position = position
        self.object = object
        self.timing_model_string = ""

        self.time_corr_fun = interp1d(self.ev_times,
                                      self.time_corr,
                                      bounds_error=False,
                                      fill_value="extrapolate")
        self.time_corr_mjd_fun = interp1d(self.ev_times / 86400 + mjdref,
                                          self.time_corr / 86400,
                                          bounds_error=False,
                                          fill_value="extrapolate")

        self.fig = plt.figure(label, figsize=plt.figaspect(1.2))
        from matplotlib.gridspec import GridSpec
        gs = GridSpec(2, 2, width_ratios=[15, 1], height_ratios=[2, 3])
        plt.subplots_adjust(left=0.25, bottom=0.30)
        ax = plt.subplot(gs[1, 0])
        self.profax = plt.subplot(gs[0, 0], sharex=ax)
        self.profax.set_xticks([])
        colorbax = plt.subplot(gs[1, 1])

        corrected_times = self.ev_times - self._delay_fun(self.ev_times)
        self.unnorm_phaseogr, phases, times, additional_info = \
            normalized_phaseogram(None, corrected_times, freq,
                                  return_plot=True, nph=nph, nt=nt, fdot=fdot,
                                  fddot=fddot, plot=False, pepoch=pepoch)

        self.phaseogr, phases, times, additional_info = \
            normalized_phaseogram(self.norm, corrected_times, freq,
                                  return_plot=True, nph=nph, nt=nt, fdot=fdot,
                                  fddot=fddot, plot=False, pepoch=pepoch)

        self.phases, self.times = phases, times
        self.pcolor = ax.pcolormesh(phases,
                                    times,
                                    self.phaseogr.T,
                                    cmap=DEFAULT_COLORMAP)
        self.colorbar = plt.colorbar(self.pcolor, cax=colorbax)
        ax.set_xlabel('Phase')
        ax.set_ylabel('Time')
        # plt.colorbar()
        self.lines = []
        self.line_phases = np.arange(-2, 3, 0.5)
        for ph0 in self.line_phases:
            newline, = ax.plot(np.zeros_like(times) + ph0,
                               times,
                               zorder=10,
                               lw=2,
                               color='w')
            self.lines.append(newline)

        ax.set_xlim([0, 2])

        axcolor = '#ff8888'
        self.slider_axes = []

        def newax_fn(*args, **kwargs):
            try:
                ax = plt.axes(*args, facecolor=axcolor)
            except AttributeError:
                # MPL < 2
                ax = plt.axes(*args, axis_bgcolor=axcolor)
            return ax

        self.slider_axes.append(
            newax_fn([0.25, 0.1, 0.5, 0.03], facecolor=axcolor))
        self.slider_axes.append(
            newax_fn([0.25, 0.15, 0.5, 0.03], facecolor=axcolor))
        self.slider_axes.append(
            newax_fn([0.25, 0.2, 0.5, 0.03], facecolor=axcolor))

        self._construct_widgets(**kwargs)

        self.closeax = plt.axes([0.15, 0.020, 0.15, 0.04])
        self.button_close = Button(self.closeax,
                                   'Quit',
                                   color=axcolor,
                                   hovercolor='0.8')

        self.recalcax = plt.axes([0.3, 0.020, 0.15, 0.04])
        self.button_recalc = Button(self.recalcax,
                                    'Recalculate',
                                    color=axcolor,
                                    hovercolor='0.975')

        self.resetax = plt.axes([0.45, 0.020, 0.15, 0.04])
        self.button_reset = Button(self.resetax,
                                   'Reset',
                                   color=axcolor,
                                   hovercolor='0.975')

        self.zoominax = plt.axes([0.6, 0.020, 0.1, 0.04])
        self.button_zoomin = Button(self.zoominax,
                                    '+Zoom',
                                    color=axcolor,
                                    hovercolor='0.975')

        self.zoomoutax = plt.axes([0.7, 0.020, 0.1, 0.04])
        self.button_zoomout = Button(self.zoomoutax,
                                     '-Zoom',
                                     color=axcolor,
                                     hovercolor='0.975')

        self.toaax = plt.axes([0.8, 0.020, 0.1, 0.04])
        self.button_toa = Button(self.toaax,
                                 'TOA',
                                 color=axcolor,
                                 hovercolor='0.975')

        self.button_reset.on_clicked(self.reset)
        self.button_zoomin.on_clicked(self.zoom_in)
        self.button_zoomout.on_clicked(self.zoom_out)
        self.button_toa.on_clicked(self.toa)
        self.button_recalc.on_clicked(self.recalculate)
        self.button_close.on_clicked(self.quit)
        #self.profax = plt.axes([0.25, 0.75, 0.5, 0.2])

        prof = np.sum(np.nan_to_num(self.unnorm_phaseogr), axis=1)
        nbin = len(prof)
        phas = np.linspace(0, 2, nbin + 1)[:-1]
        self.profile_fixed, = \
            self.profax.plot(phas, prof, drawstyle='steps-mid', color='grey')
        self.profile, = \
            self.profax.plot(phas, prof, drawstyle='steps-mid', color='k')
        mean = np.mean(prof)
        low, high = \
            poisson_conf_interval(mean,
                                  interval='frequentist-confidence', sigma=2)
        self.profax.fill_between(phas, low, high, alpha=0.5)
        z2_label = get_z2_label(phas, prof)
        self.proftext = self.profax.text(0.1,
                                         0.8,
                                         z2_label,
                                         transform=self.profax.transAxes)
        if not test and not plot_only:
            plt.show()
        if plot_only:
            plt.savefig(self.label + '_{:.10f}Hz.png'.format(self.freq))
示例#18
0
def main(args=None):
    """Main function called by the `HENfake` command line script."""
    import argparse
    description = (
        'Create an event file in FITS format from an event list, or simulating'
        ' it. If input event list is not specified, generates the events '
        'randomly')
    parser = argparse.ArgumentParser(description=description)

    parser.add_argument("-e",
                        "--event-list",
                        type=str,
                        default=None,
                        help="File containint event list")
    parser.add_argument("-l",
                        "--lc",
                        type=str,
                        default=None,
                        help="File containing light curve")
    parser.add_argument("-c",
                        "--ctrate",
                        type=float,
                        default=None,
                        help="Count rate for simulated events")
    parser.add_argument("-o",
                        "--outname",
                        type=str,
                        default='events.evt',
                        help="Output file name")
    parser.add_argument("-i",
                        "--instrument",
                        type=str,
                        default='FPMA',
                        help="Instrument name")
    parser.add_argument("-m",
                        "--mission",
                        type=str,
                        default='NUSTAR',
                        help="Mission name")
    parser.add_argument("--tstart",
                        type=float,
                        default=None,
                        help="Start time of the observation (s from MJDREF)")
    parser.add_argument("--tstop",
                        type=float,
                        default=None,
                        help="End time of the observation (s from MJDREF)")
    parser.add_argument("--mjdref",
                        type=float,
                        default=55197.00076601852,
                        help="Reference MJD")
    parser.add_argument("--deadtime",
                        type=float,
                        default=None,
                        nargs='+',
                        help="Dead time magnitude. Can be specified as a "
                        "single number, or two. In this last case, the "
                        "second value is used as sigma of the dead time "
                        "distribution")

    parser.add_argument("--loglevel",
                        help=("use given logging level (one between INFO, "
                              "WARNING, ERROR, CRITICAL, DEBUG; "
                              "default:WARNING)"),
                        default='WARNING',
                        type=str)
    parser.add_argument("--debug",
                        help="use DEBUG logging level",
                        default=False,
                        action='store_true')

    args = parser.parse_args(args)

    if args.debug:
        args.loglevel = 'DEBUG'

    numeric_level = getattr(logging, args.loglevel.upper(), None)
    logging.basicConfig(filename='HENfake.log',
                        level=numeric_level,
                        filemode='w')

    additional_columns = {}
    livetime = None
    if args.lc is None and args.ctrate is None and args.event_list is not None:
        event_list = _read_event_list(args.event_list)
    elif args.lc is not None or args.ctrate is not None:
        event_list = EventList()
        if args.lc is not None:
            lc = _read_light_curve(args.lc)
        elif args.ctrate is not None:
            tstart = assign_value_if_none(args.tstart, 0)
            tstop = assign_value_if_none(args.tstop, 1025)
            t = np.arange(tstart, tstop)
            lc = Lightcurve(time=t, counts=args.ctrate + np.zeros_like(t))
        event_list.simulate_times(lc)
        nevents = len(event_list.time)
        event_list.pi = np.zeros(nevents, dtype=int)
        print('{} events generated'.format(nevents))
    else:
        event_list = None

    if args.deadtime is not None and event_list is not None:
        deadtime = args.deadtime[0]
        deadtime_sigma = None
        if len(args.deadtime) > 1:
            deadtime_sigma = args.deadtime[1]
        print(deadtime, deadtime_sigma)
        event_list, info = filter_for_deadtime(event_list,
                                               deadtime,
                                               dt_sigma=deadtime_sigma,
                                               return_all=True)
        print('{} events after filter'.format(len(event_list.time)))

        prior = np.zeros_like(event_list.time)

        prior[1:] = np.diff(event_list.time) - info.deadtime[:-1]

        additional_columns["PRIOR"] = {"data": prior, "format": "D"}
        additional_columns["KIND"] = {"data": info.is_event, "format": "L"}
        livetime = np.sum(prior)

    generate_fake_fits_observation(event_list=event_list,
                                   filename=args.outname,
                                   instr=args.instrument,
                                   mission=args.mission,
                                   tstart=args.tstart,
                                   tstop=args.tstop,
                                   mjdref=args.mjdref,
                                   livetime=livetime,
                                   additional_columns=additional_columns)
示例#19
0
def generate_fake_fits_observation(event_list=None,
                                   filename=None,
                                   instr='FPMA',
                                   gti=None,
                                   tstart=None,
                                   tstop=None,
                                   mission='NUSTAR',
                                   mjdref=55197.00076601852,
                                   livetime=None,
                                   additional_columns={}):
    """Generate fake NuSTAR data.

    Takes an event list (as a list of floats)
    All inputs are None by default, and can be set during the call.

    Parameters
    ----------
    event_list : list-like
        :class:`stingray.events.Eventlist` object. If left None, 1000
        random events will be generated, for a total length of 1025 s or the
        difference between tstop and tstart.
    filename : str
        Output file name

    Returns
    -------
    hdulist : FITS hdu list
        FITS hdu list of the output file

    Other Parameters
    ----------------
    mjdref : float
        Reference MJD. Default is 55197.00076601852 (NuSTAR)
    pi : list-like
        The PI channel of each event
    tstart : float
        Start of the observation (s from mjdref)
    tstop : float
        End of the observation (s from mjdref)
    instr : str
        Name of the instrument. Default is 'FPMA'
    livetime : float
        Total livetime. Default is tstop - tstart
    """
    from astropy.io import fits
    import numpy.random as ra

    if event_list is None:
        tstart = assign_value_if_none(tstart, 8e+7)
        tstop = assign_value_if_none(tstop, tstart + 1025)
        ev_list = sorted(ra.uniform(tstart, tstop, 1000))
    else:
        ev_list = event_list.time

    if hasattr(event_list, 'pi'):
        pi = event_list.pi
    else:
        pi = ra.randint(0, 1024, len(ev_list))

    tstart = assign_value_if_none(tstart, np.floor(ev_list[0]))
    tstop = assign_value_if_none(tstop, np.ceil(ev_list[-1]))
    gti = assign_value_if_none(gti, np.array([[tstart, tstop]]))
    filename = assign_value_if_none(filename, 'events.evt')
    livetime = assign_value_if_none(livetime, tstop - tstart)

    if livetime > tstop - tstart:
        raise ValueError('Livetime must be equal or smaller than '
                         'tstop - tstart')

    # Create primary header
    prihdr = fits.Header()
    prihdr['OBSERVER'] = 'Edwige Bubble'
    prihdr['TELESCOP'] = (mission, 'Telescope (mission) name')
    prihdr['INSTRUME'] = (instr, 'Instrument name')
    prihdu = fits.PrimaryHDU(header=prihdr)

    # Write events to table
    col1 = fits.Column(name='TIME', format='1D', array=ev_list)
    col2 = fits.Column(name='PI', format='1J', array=pi)

    allcols = [col1, col2]

    if mission.lower().strip() == 'xmm':
        ccdnr = np.zeros(len(ev_list)) + 1
        ccdnr[1] = 2  # Make it less trivial
        ccdnr[10] = 7
        allcols.append(fits.Column(name='CCDNR', format='1J', array=ccdnr))

    for c in additional_columns.keys():
        col = fits.Column(name=c,
                          array=additional_columns[c]["data"],
                          format=additional_columns[c]["format"])
        allcols.append(col)

    cols = fits.ColDefs(allcols)
    tbhdu = fits.BinTableHDU.from_columns(cols)
    tbhdu.name = 'EVENTS'

    # ---- Fake lots of information ----
    tbheader = tbhdu.header
    tbheader['OBSERVER'] = 'Edwige Bubble'
    tbheader['COMMENT'] = ("FITS (Flexible Image Transport System) format is"
                           " defined in 'Astronomy and Astrophysics', volume"
                           " 376, page 359; bibcode: 2001A&A...376..359H")
    tbheader['TELESCOP'] = (mission, 'Telescope (mission) name')
    tbheader['INSTRUME'] = (instr, 'Instrument name')
    tbheader['OBS_ID'] = ('00000000001', 'Observation ID')
    tbheader['TARG_ID'] = (0, 'Target ID')
    tbheader['OBJECT'] = ('Fake X-1', 'Name of observed object')
    tbheader['RA_OBJ'] = (0.0, '[deg] R.A. Object')
    tbheader['DEC_OBJ'] = (0.0, '[deg] Dec Object')
    tbheader['RA_NOM'] = (0.0,
                          'Right Ascension used for barycenter corrections')
    tbheader['DEC_NOM'] = (0.0, 'Declination used for barycenter corrections')
    tbheader['RA_PNT'] = (0.0, '[deg] RA pointing')
    tbheader['DEC_PNT'] = (0.0, '[deg] Dec pointing')
    tbheader['PA_PNT'] = (0.0, '[deg] Position angle (roll)')
    tbheader['EQUINOX'] = (2.000E+03, 'Equinox of celestial coord system')
    tbheader['RADECSYS'] = ('FK5', 'Coordinate Reference System')
    tbheader['TASSIGN'] = ('SATELLITE', 'Time assigned by onboard clock')
    tbheader['TIMESYS'] = ('TDB', 'All times in this file are TDB')
    tbheader['MJDREFI'] = (int(mjdref),
                           'TDB time reference; Modified Julian Day (int)')
    tbheader['MJDREFF'] = (mjdref - int(mjdref),
                           'TDB time reference; Modified Julian Day (frac)')
    tbheader['TIMEREF'] = ('SOLARSYSTEM',
                           'Times are pathlength-corrected to barycenter')
    tbheader['CLOCKAPP'] = (False, 'TRUE if timestamps corrected by gnd sware')
    tbheader['COMMENT'] = ("MJDREFI+MJDREFF = epoch of Jan 1, 2010, in TT "
                           "time system.")
    tbheader['TIMEUNIT'] = ('s', 'unit for time keywords')
    tbheader['TSTART'] = (tstart,
                          'Elapsed seconds since MJDREF at start of file')
    tbheader['TSTOP'] = (tstop, 'Elapsed seconds since MJDREF at end of file')
    tbheader['LIVETIME'] = (livetime, 'On-source time')
    tbheader['TIMEZERO'] = (0.000000E+00, 'Time Zero')
    tbheader['COMMENT'] = ("Generated with HENDRICS by {0}".format(
        os.getenv('USER')))

    # ---- END Fake lots of information ----

    # Fake GTIs

    start = gti[:, 0]
    stop = gti[:, 1]

    col1 = fits.Column(name='START', format='1D', array=start)
    col2 = fits.Column(name='STOP', format='1D', array=stop)
    allcols = [col1, col2]
    cols = fits.ColDefs(allcols)
    gtinames = ['GTI']
    if mission.lower().strip() == 'xmm':
        gtinames = ['STDGTI01', 'STDGTI02', 'STDGTI07']

    all_new_hdus = [prihdu, tbhdu]
    for name in gtinames:
        gtihdu = fits.BinTableHDU.from_columns(cols)
        gtihdu.name = name
        all_new_hdus.append(gtihdu)

    thdulist = fits.HDUList(all_new_hdus)

    thdulist.writeto(filename, clobber=True)
    return thdulist
    def __init__(self, events, freq_interval, energy_spec, ref_band=None,
                 bin_time=1, use_pi=False, segment_size=None, events2=None):

        """Base variability-energy spectrum.

        This class is only a base for the various variability spectra, and it's
        not to be instantiated by itself.

        Parameters
        ----------
        events : stingray.events.EventList object
            event list
        freq_interval : [f0, f1], floats
            the frequency range over which calculating the variability quantity
        energy_spec : list or tuple (emin, emax, N, type)
            if a list is specified, this is interpreted as a list of bin edges;
            if a tuple is provided, this will encode the minimum and maximum
            energies, the number of intervals, and "lin" or "log".

        Other Parameters
        ----------------
        ref_band : [emin, emax], floats; default None
            minimum and maximum energy of the reference band. If None, the
            full band is used.
        use_pi : boolean, default False
            Use channel instead of energy
        events2 : stingray.events.EventList object
            event list for the second channel, if not the same. Useful if the
            reference band has to be taken from another detector.

        Attributes
        ----------
        events1 : array-like
            list of events used to produce the spectrum
        events2 : array-like
            if the spectrum requires it, second list of events
        freq_interval : array-like
            interval of frequencies used to calculate the spectrum
        energy_intervals : [[e00, e01], [e10, e11], ...]
            energy intervals used for the spectrum
        spectrum : array-like
            the spectral values, corresponding to each energy interval
        spectrum_error : array-like
            the errorbars corresponding to spectrum

        """
        self.events1 = events
        self.events2 = assign_value_if_none(events2, events)
        self.freq_interval = freq_interval
        self.use_pi = use_pi
        self.bin_time = bin_time
        if isinstance(energy_spec, tuple):
            energies = _decode_energy_specification(energy_spec)
        else:
            energies = np.asarray(energy_spec)

        self.energy_intervals = list(zip(energies[0: -1], energies[1:]))

        self.ref_band = np.asarray(assign_value_if_none(ref_band,
                                                        [0, np.inf]))

        if len(self.ref_band.shape) <= 1:
            self.ref_band = np.asarray([self.ref_band])

        self.segment_size = segment_size
        self.spectrum, self.spectrum_error = self._spectrum_function()
示例#21
0
    def __init__(self,
                 ev_times,
                 freq,
                 nph=128,
                 nt=128,
                 test=False,
                 pepoch=None,
                 fdot=0,
                 fddot=0,
                 **kwargs):

        self.fdot = fdot
        self.fddot = fddot
        self.nt = nt
        self.nph = nph

        self.pepoch = assign_value_if_none(pepoch, ev_times[0])
        self.ev_times = ev_times
        self.freq = freq

        self.fig, ax = plt.subplots()
        plt.subplots_adjust(left=0.25, bottom=0.30)

        corrected_times = self.ev_times - self._delay_fun(self.ev_times)
        self.phaseogr, phases, times, additional_info = \
            phaseogram(corrected_times, freq, return_plot=True, nph=nph, nt=nt,
                       fdot=fdot, fddot=fddot, plot=False, pepoch=pepoch)
        self.phases, self.times = phases, times

        self.pcolor = plt.pcolormesh(phases,
                                     times,
                                     self.phaseogr.T,
                                     cmap='magma')
        plt.xlabel('Phase')
        plt.ylabel('Time')
        plt.colorbar()
        self.lines = []
        self.line_phases = np.arange(-2, 3, 0.5)
        for ph0 in self.line_phases:
            newline, = plt.plot(np.zeros_like(times) + ph0,
                                times,
                                zorder=10,
                                lw=2,
                                color='w')
            self.lines.append(newline)

        plt.xlim([0, 2])

        axcolor = '#ff8888'
        self.slider_axes = []
        self.slider_axes.append(
            plt.axes([0.25, 0.1, 0.5, 0.03], facecolor=axcolor))
        self.slider_axes.append(
            plt.axes([0.25, 0.15, 0.5, 0.03], facecolor=axcolor))
        self.slider_axes.append(
            plt.axes([0.25, 0.2, 0.5, 0.03], facecolor=axcolor))

        self._construct_widgets(**kwargs)

        self.closeax = plt.axes([0.15, 0.020, 0.15, 0.04])
        self.button_close = Button(self.closeax,
                                   'Quit',
                                   color=axcolor,
                                   hovercolor='0.8')

        self.recalcax = plt.axes([0.3, 0.020, 0.15, 0.04])
        self.button_recalc = Button(self.recalcax,
                                    'Recalculate',
                                    color=axcolor,
                                    hovercolor='0.975')

        self.resetax = plt.axes([0.45, 0.020, 0.15, 0.04])
        self.button_reset = Button(self.resetax,
                                   'Reset',
                                   color=axcolor,
                                   hovercolor='0.975')

        self.zoominax = plt.axes([0.6, 0.020, 0.15, 0.04])
        self.button_zoomin = Button(self.zoominax,
                                    'Zoom in',
                                    color=axcolor,
                                    hovercolor='0.975')

        self.zoomoutax = plt.axes([0.75, 0.020, 0.15, 0.04])
        self.button_zoomout = Button(self.zoomoutax,
                                     'Zoom out',
                                     color=axcolor,
                                     hovercolor='0.975')

        self.button_reset.on_clicked(self.reset)
        self.button_zoomin.on_clicked(self.zoom_in)
        self.button_zoomout.on_clicked(self.zoom_out)
        self.button_recalc.on_clicked(self.recalculate)
        self.button_close.on_clicked(self.quit)

        if not test:
            plt.show()
示例#22
0
def get_TOAs_from_events(events, folding_length, *frequency_derivatives,
                         **kwargs):
    """Get TOAs of pulsation.

    Parameters
    ----------
    events : array-like
        event arrival times
    folding_length : float
        length of sub-intervals to fold
    *frequency_derivatives : floats
        pulse frequency, first derivative, second derivative, etc.

    Other parameters
    ----------------
    pepoch : float, default None
        Epoch of timing solution, in the same units as ev_times. If none, the
        first event time is used.
    mjdref : float, default None
        Reference MJD
    template : array-like, default None
        The pulse template
    nbin : int, default 16
        The number of bins in the profile (overridden by the dimension of the
        template)
    timfile : str, default 'out.tim'
        file to save the TOAs to (if PINT is installed)
    gti: [[g0_0, g0_1], [g1_0, g1_1], ...]
         Good time intervals. Defaults to None
    quick: bool
         If True, use a quicker fitting algorithms for TOAs. Defaults to False
    position: `astropy.SkyCoord` object
         Position of the object

    Returns
    -------
    toas : array-like
        list of times of arrival. If ``mjdref`` is specified, they are
        expressed as MJDs, otherwise in MET
    toa_err : array-like
        errorbars on TOAs, in the same units as TOAs.
    """
    import matplotlib.pyplot as plt
    template = kwargs['template'] if 'template' in kwargs else None
    mjdref = kwargs['mjdref'] if 'mjdref' in kwargs else None
    nbin = kwargs['nbin'] if 'nbin' in kwargs else 16
    pepoch = kwargs['pepoch'] if 'pepoch' in kwargs else None
    timfile = kwargs['timfile'] if 'timfile' in kwargs else 'out.tim'
    gti = kwargs['gti'] if 'gti' in kwargs else None
    label = kwargs['label'] if 'label' in kwargs else None
    quick = kwargs['quick'] if 'quick' in kwargs else False
    position = kwargs['position'] if 'position' in kwargs else None

    pepoch = assign_value_if_none(pepoch, events[0])
    gti = assign_value_if_none(gti, [[events[0], events[-1]]])
    # run exposure correction only if there are less than 1000 pulsations
    # in the interval
    length = gti.max() - gti.min()
    expocorr = folding_length < (1000 / frequency_derivatives[0])

    if template is not None:
        nbin = len(template)
        additional_phase = np.argmax(template) / nbin
    else:
        phase, profile, profile_err = \
            fold_events(copy.deepcopy(events), *frequency_derivatives,
                        ref_time=pepoch, gtis=copy.deepcopy(gti),
                        expocorr=expocorr, nbin=nbin)
        fit_pars_save, _, _ = \
            fit_profile_with_sinusoids(profile, profile_err, nperiods=1,
                                       baseline=True)
        template = std_fold_fit_func(fit_pars_save, phase)
        fig = plt.figure()
        plt.plot(phase, profile, drawstyle='steps-mid')
        plt.plot(phase, template, drawstyle='steps-mid')
        plt.savefig(timfile.replace('.tim', '') + '.png')
        plt.close(fig)
        # start template from highest bin!
        # template = np.roll(template, -np.argmax(template))
        template *= folding_length / length
        template_fine = std_fold_fit_func(fit_pars_save,
                                          np.arange(0, 1, 0.001))
        additional_phase = np.argmax(template_fine) / len(template_fine)

    starts = np.arange(gti[0, 0], gti[-1, 1], folding_length)

    toas = []
    toa_errs = []
    for start in show_progress(starts):
        stop = start + folding_length
        good = (events >= start) & (events < stop)
        events_tofold = events[good]
        if len(events_tofold) < nbin:
            continue
        gtis_tofold = \
            copy.deepcopy(gti[(gti[:, 0] < stop) & (gti[:, 1] > start)])
        gtis_tofold[0, 0] = start
        gtis_tofold[-1, 1] = stop

        local_f = frequency_derivatives[0]
        for i_f, f in enumerate(frequency_derivatives[1:]):
            local_f += 1 / np.math.factorial(i_f + 1) * (start -
                                                         pepoch)**(i_f + 1) * f

        fder = copy.deepcopy(list(frequency_derivatives))
        fder[0] = local_f
        phase, profile, profile_err = \
            fold_events(events_tofold, *fder,
                        ref_time=start, gtis=gtis_tofold,
                        expocorr=expocorr, nbin=nbin)

        # BAD!BAD!BAD!
        # [[Pay attention to time reference here.
        # We are folding wrt pepoch, and calculating TOAs wrt start]]

        toa, toaerr = \
            get_TOA(profile, 1/frequency_derivatives[0], start,
                    template=template, additional_phase=additional_phase,
                    quick=quick, debug=True)
        toas.append(toa)
        toa_errs.append(toaerr)

    toas, toa_errs = np.array(toas), np.array(toa_errs)

    if mjdref is not None:
        toas = toas / 86400 + mjdref
        toa_errs = toa_errs * 1e6
        if HAS_PINT:
            label = assign_value_if_none(label, 'hendrics')
            toa_list = _load_and_prepare_TOAs(toas, errs_us=toa_errs)
            # workaround until PR #368 is accepted in pint
            toa_list.table['clkcorr'] = 0
            toa_list.write_TOA_file(timfile, name=label, format='Tempo2')

        print('TOA(MJD)  TOAerr(us)')
    else:
        print('TOA(MET)  TOAerr(us)')

    for t, e in zip(toas, toa_errs):
        print(t, e)

    return toas, toa_errs
示例#23
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.")
示例#24
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)
示例#25
0
def treat_event_file(filename,
                     noclobber=False,
                     gti_split=False,
                     min_length=4,
                     gtistring=None,
                     length_split=None):
    """Read data from an event file, with no external GTI information.

    Parameters
    ----------
    filename : str

    Other Parameters
    ----------------
    noclobber: bool
        if a file is present, do not overwrite it
    gtistring: str
        comma-separated set of GTI strings to consider
    gti_split: bool
        split the file in multiple chunks, containing one GTI each
    length_split: float, default None
        split the file in multiple chunks, with approximately this length
    min_length: float
        minimum length of GTIs accepted (only if gti_split is True or
        length_split is not None)
    """
    gtistring = assign_value_if_none(gtistring, 'GTI,STDGTI')
    logging.info('Opening %s' % filename)

    instr = read_header_key(filename, 'INSTRUME')
    mission = read_header_key(filename, 'TELESCOP')

    data = load_events_and_gtis(filename, gtistring=gtistring)

    events = data.ev_list
    gtis = events.gti
    detector_id = data.detector_id

    if detector_id is not None:
        detectors = np.array(list(set(detector_id)))
    else:
        detectors = [None]
    outfile_root = \
        hen_root(filename) + '_' + mission.lower() + '_' + instr.lower()

    for d in detectors:
        if d is not None:
            good_det = d == data.detector_id
            outroot_local = \
                '{0}_det{1:02d}'.format(outfile_root, d)

        else:
            good_det = np.ones_like(events.time, dtype=bool)
            outroot_local = outfile_root

        outfile = outroot_local + '_ev' + HEN_FILE_EXTENSION
        if noclobber and os.path.exists(outfile) and (not (gti_split
                                                           or length_split)):
            warnings.warn(
                '{0} exists and using noclobber. Skipping'.format(outfile))
            return

        if gti_split or (length_split is not None):
            lengths = np.array([g1 - g0 for (g0, g1) in gtis])
            gtis = gtis[lengths >= min_length]

            if length_split:
                gti0 = np.arange(gtis[0, 0], gtis[-1, 1], length_split)
                gti1 = gti0 + length_split
                gti_chunks = np.array([[g0, g1]
                                       for (g0, g1) in zip(gti0, gti1)])
                label = 'chunk'
            else:
                gti_chunks = gtis
                label = 'gti'

            for ig, g in enumerate(gti_chunks):
                outfile_local = \
                    '{0}_{1}{2:03d}_ev'.format(outroot_local, label,
                                           ig) + HEN_FILE_EXTENSION

                good_gtis = cross_two_gtis([g], gtis)
                if noclobber and os.path.exists(outfile_local):
                    warnings.warn('{0} exists, '.format(outfile_local) +
                                  'and noclobber option used. Skipping')
                    return
                good = np.logical_and(events.time >= g[0], events.time < g[1])
                all_good = good_det & good
                if len(events.time[all_good]) < 1:
                    continue
                events_filt = EventList(events.time[all_good],
                                        pi=events.pi[all_good],
                                        gti=good_gtis,
                                        mjdref=events.mjdref)
                events_filt.instr = events.instr
                events_filt.header = events.header
                save_events(events_filt, outfile_local)
            pass
        else:
            events_filt = EventList(events.time[good_det],
                                    pi=events.pi[good_det],
                                    gti=events.gti,
                                    mjdref=events.mjdref)
            events_filt.instr = events.instr
            events_filt.header = events.header

            save_events(events_filt, outfile)
示例#26
0
 def test_assign_value_if_none(self):
     assert utils.assign_value_if_none(None, 2) == 2
     assert utils.assign_value_if_none(1, 2) == 1
示例#27
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)
示例#28
0
def join_lightcurves(lcfilelist, outfile='out_lc' + HEN_FILE_EXTENSION):
    """Join light curves from different files.

    Light curves from different instruments are put in different channels.

    Parameters
    ----------
    lcfilelist :
    outfile :

    See Also
    --------
        scrunch_lightcurves : Create a single light curve from input light
                                 curves.

    """
    lcdatas = []

    for lfc in lcfilelist:
        logging.info("Loading file %s..." % lfc)
        lcdata = load_lcurve(lfc)
        logging.info("Done.")
        lcdatas.append(lcdata)
        del lcdata

    # --------------- Check consistency of data --------------
    lcdts = [lcdata.dt for lcdata in lcdatas]
    # Find unique elements. If multiple bin times are used, throw an exception
    lcdts = list(set(lcdts))
    assert len(lcdts) == 1, 'Light curves must have same dt for scrunching'

    instrs = [lcdata.instr for lcdata in lcdatas if hasattr(lcdata, 'instr')]

    # Find unique elements. A lightcurve will be produced for each instrument
    instrs = list(set(instrs))
    if instrs == []:
        instrs = ['unknown']

    outlcs = {}
    for instr in instrs:
        outlcs[instr] = None
    # -------------------------------------------------------

    for lcdata in lcdatas:
        instr = assign_value_if_none(lcdata.instr, 'unknown')
        if outlcs[instr] is None:
            outlcs[instr] = lcdata
        else:
            outlcs[instr] = outlcs[instr].join(lcdata)

    if outfile is not None:
        for instr in instrs:
            if len(instrs) == 1:
                tag = ""
            else:
                tag = instr
            logging.info('Saving joined light curve to %s' % outfile)

            dname, fname = os.path.split(outfile)
            save_lcurve(outlcs[instr], os.path.join(dname, tag + fname))

    return outlcs
示例#29
0
文件: io.py 项目: swapsha96/HENDRICS
def save_as_qdp(arrays, errors=None, filename="out.qdp", mode='w'):
    """Save arrays in a QDP file.

    Saves an array of variables, and possibly their errors, to a QDP file.

    Parameters
    ----------
    arrays: [array1, array2]
        List of variables. All variables must be arrays and of the same length.
    errors: [array1, array2]
        List of errors. The order has to be the same of arrays; the value can
        be:
        - None if no error is assigned
        - an array of same length of variable for symmetric errors
        - an array of len-2 lists for non-symmetric errors (e.g.
        [[errm1, errp1], [errm2, errp2], [errm3, errp3], ...])

    Other parameters
    ----------------
    mode : str
        the file access mode, to be passed to the open() function. Can be 'w'
        or 'a'
     """
    import numpy as np
    errors = assign_value_if_none(errors, [None for i in arrays])

    data_to_write = []
    list_of_errs = []
    for ia, ar in enumerate(arrays):
        data_to_write.append(ar)
        if errors[ia] is None:
            continue
        shape = np.shape(errors[ia])
        assert shape[0] == len(ar), \
            'Errors and arrays must have same length'
        if len(shape) == 1:
            list_of_errs.append([ia, 'S'])
            data_to_write.append(errors[ia])
        elif shape[1] == 2:
            list_of_errs.append([ia, 'T'])
            mine = [k[0] for k in errors[ia]]
            maxe = [k[1] for k in errors[ia]]
            data_to_write.append(mine)
            data_to_write.append(maxe)

    print_header = True
    if os.path.exists(filename) and mode == 'a':
        print_header = False
    outfile = open(filename, mode)
    if print_header:
        for l in list_of_errs:
            i, kind = l
            print('READ %s' % kind + 'ERR %d' % (i + 1), file=outfile)

    length = len(data_to_write[0])
    for i in range(length):
        for idw, d in enumerate(data_to_write):
            print(d[i], file=outfile, end=" ")
        print("", file=outfile)

    outfile.close()
示例#30
0
    def __init__(self,
                 events,
                 freq_interval,
                 energy_spec,
                 ref_band=None,
                 bin_time=1,
                 use_pi=False,
                 segment_size=None,
                 events2=None):
        """Base variability-energy spectrum.

        This class is only a base for the various variability spectra, and it's
        not to be instantiated by itself.

        Parameters
        ----------
        events : stingray.events.EventList object
            event list
        freq_interval : [f0, f1], floats
            the frequency range over which calculating the variability quantity
        energy_spec : list or tuple (emin, emax, N, type)
            if a list is specified, this is interpreted as a list of bin edges;
            if a tuple is provided, this will encode the minimum and maximum
            energies, the number of intervals, and "lin" or "log".

        Other Parameters
        ----------------
        ref_band : [emin, emax], floats; default None
            minimum and maximum energy of the reference band. If None, the
            full band is used.
        use_pi : boolean, default False
            Use channel instead of energy
        events2 : stingray.events.EventList object
            event list for the second channel, if not the same. Useful if the
            reference band has to be taken from another detector.
            
        Attributes
        ----------
        events1 : array-like
            list of events used to produce the spectrum
        events2 : array-like
            if the spectrum requires it, second list of events
        freq_interval : array-like
            interval of frequencies used to calculate the spectrum
        energy_intervals : [[e00, e01], [e10, e11], ...]
            energy intervals used for the spectrum
        spectrum : array-like
            the spectral values, corresponding to each energy interval
        spectrum_error : array-like
            the errorbars corresponding to spectrum
        
        """
        self.events1 = events
        self.events2 = assign_value_if_none(events2, events)
        self.freq_interval = freq_interval
        self.use_pi = use_pi
        self.bin_time = bin_time
        if isinstance(energy_spec, tuple):
            energies = _decode_energy_specification(energy_spec)
        else:
            energies = np.asarray(energy_spec)

        self.energy_intervals = list(zip(energies[0:-1], energies[1:]))

        self.ref_band = np.asarray(assign_value_if_none(ref_band, [0, np.inf]))

        if len(self.ref_band.shape) <= 1:
            self.ref_band = np.asarray([self.ref_band])

        self.segment_size = segment_size
        self.spectrum, self.spectrum_error = self._spectrum_function()
示例#31
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.")