예제 #1
0
 def test_zn(self):
     """Test pulse phase calculation, frequency only."""
     ph = np.array([0, 1])
     np.testing.assert_array_almost_equal(z_n(ph), 8)
     ph = np.array([])
     np.testing.assert_array_almost_equal(z_n(ph), 0)
     ph = np.array([0.2, 0.7])
     ph2 = np.array([0, 0.5])
     np.testing.assert_array_almost_equal(z_n(ph), z_n(ph2))
예제 #2
0
 def test_zn(self):
     """Test pulse phase calculation, frequency only."""
     ph = np.array([0, 1])
     np.testing.assert_array_almost_equal(z_n(ph), 8)
     ph = np.array([])
     np.testing.assert_array_almost_equal(z_n(ph), 0)
     ph = np.array([0.2, 0.7])
     ph2 = np.array([0, 0.5])
     np.testing.assert_array_almost_equal(z_n(ph), z_n(ph2))
예제 #3
0
def get_z2_label(phas, prof):
    good = phas < 1
    z2 = z_n(phas[good], n=2, norm=prof[good])
    z2_detlev = z2_n_detection_level(n=2)
    z2_label = r'$Z_2^2 = {:.1f} (90\% det. lev. {:.1f})$'.format(
        z2, z2_detlev)
    return z2_label
예제 #4
0
def pulsar_events_mp(length,
                     period,
                     ctrate,
                     pulsed_fraction,
                     mean_obs,
                     bkg_ctrate,
                     detlev,
                     nbin=128):

    nustar_orb = 5808

    dt = period / 20
    # The total length of the time series should be the number of pointings times the time per orbit.
    # Add one orbit for buffer.
    N_orb = int(round(length / mean_obs, 0))
    tot_len = (N_orb + 1) * nustar_orb

    # The orbital period is 5808s. Every 5808s, a continuous observation with min_obs < length < max_obs begins
    start_t = numpy.multiply(
        numpy.arange(N_orb),
        numpy.random.normal(loc=nustar_orb, scale=60, size=N_orb))
    point_t = numpy.random.uniform(low=mean_obs - 500,
                                   high=mean_obs + 500,
                                   size=N_orb)
    end_t = numpy.add(start_t, point_t)

    times = numpy.arange(dt / 2, tot_len + dt / 2, dt)
    cont_lc = numpy.random.poisson(
        (ctrate *
         (1 + pulsed_fraction * numpy.cos(2 * numpy.pi / period * times)) *
         dt)) + numpy.random.poisson(bkg_ctrate * dt)

    lc = Lightcurve(time=times,
                    counts=cont_lc,
                    gti=numpy.column_stack((start_t, end_t)),
                    dt=dt)
    exposure = numpy.sum(point_t)
    events = EventList()
    events.gti = lc.gti
    events.simulate_times(lc)
    phase = numpy.arange(0, 1, 1 / nbin)
    zsq = z_n(phase,
              n=2,
              norm=fold_events(events.time, 1 / period, nbin=nbin)[1])
    detected = zsq > detlev
    return (detected, exposure)
예제 #5
0
 def test_zn_2(self):
     np.testing.assert_almost_equal(z_n(np.arange(1), n=1, norm=1), 2)
     np.testing.assert_almost_equal(z_n(np.arange(1), n=2, norm=1), 4)
     np.testing.assert_almost_equal(z_n(np.arange(2), n=2, norm=1), 8)
     np.testing.assert_almost_equal(z_n(np.arange(2) + 0.5, n=2, norm=1), 8)
예제 #6
0
 def test_zn_2(self):
     np.testing.assert_almost_equal(z_n(np.arange(1), n=1, norm=1), 2)
     np.testing.assert_almost_equal(z_n(np.arange(1), n=2, norm=1), 4)
     np.testing.assert_almost_equal(z_n(np.arange(2), n=2, norm=1), 8)
     np.testing.assert_almost_equal(z_n(np.arange(2)+0.5, n=2, norm=1), 8)
예제 #7
0
def efold_search_AandB(events_A,
                       events_B,
                       f_min,
                       f_max,
                       f_steps,
                       fdots=None,
                       time_intervals=None,
                       nbin=32,
                       pi_min=35,
                       pi_max=260,
                       return_peak=False,
                       z_n=2):
    # Scan over frequency and do epoch folding.

    A_mask = np.sqrt(
        np.square(events_A.x - events_A.centroid[0]) +
        np.square(events_A.y - events_A.centroid[1])) <= events_A.radius
    B_mask = np.sqrt(
        np.square(events_B.x - events_B.centroid[0]) +
        np.square(events_B.y - events_B.centroid[1])) <= events_B.radius

    temp_time = np.concatenate([events_A.time[A_mask], events_B.time[B_mask]])
    sorted_arg = np.argsort(temp_time)
    temp_time = temp_time[sorted_arg]
    temp_pi = np.concatenate([events_A.pi[A_mask],
                              events_B.pi[B_mask]])[sorted_arg]

    joined_ev = EventList_ext(time=temp_time,
                              gti=sting_gti.cross_two_gtis(
                                  events_A.gti, events_B.gti),
                              pi=temp_pi)
    ref_time = joined_ev.time[0]
    f_arr = np.linspace(f_min, f_max, num=f_steps)

    # if fdots:
    #     fgrid, fdgrid, z_stats = z_n_search(joined_ev.time, f_arr, nharm=z_n, nbin=nbin, gti=joined_ev.gti, fdots=fdots, segment_size=1e6)
    # else:
    #     fgrid, z_stats = z_n_search(joined_ev.time, f_arr, nharm=z_n, nbin=nbin, gti=joined_ev.gti, fdots=fdots, segment_size=1e6)

    pi_mask = ((joined_ev.pi > pi_min) * (joined_ev.pi < pi_max)).astype(bool)
    # The times to actually fold into a profile
    fold_times = joined_ev.time[pi_mask] - ref_time
    z_stats = []
    if fdots is not None:
        f_grid, fd_grid = np.meshgrid(f_arr, fdots)
        z_stats = np.zeros(f_grid.shape)
        for x in tqdm(range(f_steps)):
            for y in range(len(fdots)):
                # The phase of each folded event
                fold_phases = plsr.pulse_phase(fold_times,
                                               *[f_grid[y, x], fd_grid[y, x]])
                z_stats[y, x] = plsr.z_n(fold_phases, n=z_n)

        z_prob = stats.z2_n_logprobability(z_stats,
                                           ntrial=(f_steps * len(fdots)),
                                           n=z_n)

        if return_peak:
            max_yx = np.unravel_index(np.argmax(z_stats, axis=None),
                                      z_stats.shape)
            phase_bins, profile, profile_err, _ = \
                joined_ev.fold_events(*[f_grid[max_yx], fd_grid[max_yx]], time_intervals = time_intervals, \
                                        nbin = nbin, ref_time = ref_time, region_filter=False, pi_min=pi_min, pi_max=pi_max, weight_pos=False, z_n=z_n)

            return f_grid, fd_grid, z_prob, z_stats, phase_bins, profile, profile_err

        else:
            return f_grid, fd_grid, z_prob, z_stats

    else:
        for f in tqdm(f_arr):
            # The phase of each folded event
            fold_phases = plsr.pulse_phase(fold_times, f)

            z_stat = plsr.z_n(fold_phases, n=z_n)

            # _, _, _, z_stat = \
            #     joined_ev.fold_events(f, time_intervals = time_intervals, \
            #                             nbin = nbin, ref_time = joined_ev.time[0], region_filter=False, pi_min=pi_min, pi_max=pi_max, weight_pos=False, z_n=z_n)

            z_stats.append(z_stat)

        z_stats = np.array(z_stats)
        z_prob = stats.z2_n_logprobability(z_stats, ntrial=len(f_arr), n=z_n)

        if return_peak:
            phase_bins, profile, profile_err, _ = \
                joined_ev.fold_events(f_arr[np.argmax(z_stats)], time_intervals = time_intervals, \
                                        nbin = nbin, ref_time = ref_time, region_filter=False, pi_min=pi_min, pi_max=pi_max, weight_pos=False, z_n=z_n)

            return f_arr, z_prob, z_stats, phase_bins, profile, profile_err

        else:
            return f_arr, z_prob, z_stats
예제 #8
0
    def fold_events(self,
                    *frequency_derivatives,
                    time_intervals=None,
                    pi_min=35,
                    pi_max=1909,
                    region_filter=False,
                    centroid=None,
                    radius=None,
                    ref_time=None,
                    nbin=64,
                    weights=1,
                    gtis=None,
                    expocorr=False,
                    weight_pos=False,
                    z_n=2):

        # Epoch folding without livetime correction.
        # Includes region and energy filtering, position weighting, and custom weighting.

        if region_filter or weight_pos:
            if centroid == None:
                centroid = self.centroid
            if radius == None:
                radius = self.radius
        if time_intervals == None:
            time_intervals = [[self.time[0], self.time[-1]]]
        if ref_time == None:
            ref_time = self.time[0]
        if gtis == None:
            gtis = self.gti

        time_mask = np.zeros(np.shape(self.time))
        if np.shape(time_intervals)[-1] != 2:
            print('The array of time intervals has the wrong shape')
            return None
        for interval in time_intervals:
            start_time, end_time = interval
            if (start_time < np.min(self.time)):
                print('Invalid start time')
                return None
            elif (end_time > np.max(self.time)):
                print('Invalid end time')
                return None
            time_mask = time_mask + ((self.time >= start_time) *
                                     (self.time <= end_time))
        time_mask = time_mask.astype(bool)
        pi_mask = ((self.pi > pi_min) * (self.pi < pi_max)).astype(bool)

        reg_mask = np.ones(np.shape(self.time)).astype(bool)
        p_weights = 1.0
        if region_filter:
            # if weight_pos:
            # print('Region filtering overrides position weighting.')
            reg_mask = (np.sqrt(
                np.square(self.x - centroid[0]) +
                np.square(self.y - centroid[1])) < radius).astype(bool)
        elif weight_pos:
            #             print('Make sure you have called set_xy_weights')
            p_weights = self.xy_weights[time_mask * pi_mask * reg_mask]


#             print([g.x_mean, g.y_mean, g.amplitude, g.x_stddev, g.y_stddev])

# The times to actually fold into a profile
        fold_times = self.time[time_mask * pi_mask * reg_mask]
        # The phase of each folded event
        fold_phases = plsr.pulse_phase(fold_times, *frequency_derivatives)

        phase_bins, profile, profile_err = plsr.fold_events(fold_times, *frequency_derivatives, ref_time=ref_time, \
                                                           nbin=nbin, weights=weights * p_weights, gtis=gtis, expocorr=expocorr)

        z_stat = plsr.z_n(fold_phases, n=z_n, norm=weights * p_weights)

        return phase_bins, profile, profile_err, z_stat
예제 #9
0
    def fold_events_ltcorr(self, *frequency_derivatives, time_intervals= None, pi_min=35, pi_max=1909, \
                           region_filter=False, centroid = None, radius=None, ref_time=None, nbin = 64, weights  = 1, gtis = None, expocorr=False, weight_pos=False):
        # Do Epoch folding to look for pulsations while also correction for livetime variations. This is important for high count rates and high pulse fractions.
        # Includes region and energy filtering, position weighting, and custom weighting.

        if centroid == None:
            centroid = self.centroid
        if radius == None:
            radius = self.radius
        if time_intervals == None:
            time_intervals = [[self.time[0], self.time[-1]]]
        if ref_time == None:
            ref_time = self.time[0]
        if gtis == None:
            gtis = self.gti

        time_mask = np.zeros(np.shape(self.time))
        if np.shape(time_intervals)[-1] != 2:
            print('The array of time intervals has the wrong shape')
            return None
        for interval in time_intervals:
            start_time, end_time = interval
            if (start_time < np.min(self.time)):
                print('Invalid start time')
                return None
            elif (end_time > np.max(self.time)):
                print('Invalid end time')
                return None
            time_mask = time_mask + ((self.time >= start_time) *
                                     (self.time <= end_time))
        time_mask = time_mask.astype(bool)
        pi_mask = ((self.pi > pi_min) * (self.pi < pi_max)).astype(bool)

        reg_mask = np.ones(np.shape(self.time)).astype(bool)
        p_weights = 1.0
        if region_filter:
            if weight_pos:
                print('Region filtering overrides position weighting.')
            reg_mask = (np.sqrt(
                np.square(self.x - centroid[0]) +
                np.square(self.y - centroid[1])) < radius).astype(bool)
        elif weight_pos:
            #             print('Make sure you have called set_xy_weights')
            p_weights = self.xy_weights[time_mask * pi_mask * reg_mask]
#             print([g.x_mean, g.y_mean, g.amplitude, g.x_stddev, g.y_stddev])

# The times to actually fold into a profile
        fold_times = self.time[time_mask * pi_mask * reg_mask]
        # The phase of each folded event
        fold_phases = plsr.pulse_phase(fold_times, *frequency_derivatives)

        # We should use PRIOR from every event though
        temp_times = self.time[time_mask]
        temp_prior = self.prior[time_mask]
        temp_phases = plsr.pulse_phase(temp_times, *frequency_derivatives)

        #         print(frequency_derivatives)
        p_derivs = plsr.p_to_f(*frequency_derivatives)
        p_t = np.zeros(np.shape(temp_times))
        # Taylor expand P(t)
        for i in range(len(p_derivs)):
            p_t = p_t + (p_derivs[i] * np.power(temp_times - ref_time, i) /
                         scipy.special.factorial(i, exact=True))

        phase_bins, profile, profile_err = plsr.fold_events(fold_times, *frequency_derivatives, ref_time=ref_time, \
                                                           nbin=nbin, weights=weights * p_weights, gtis=gtis, expocorr=expocorr)
        livetime_profile = np.zeros(np.shape(profile))

        # During which phase bin did PRIOR start counting before each event?
        start_bins = np.floor(nbin * (temp_phases - (temp_prior / p_t)))
        # What phase bin is each event at?
        end_bins = np.floor(nbin * temp_phases)

        # Add 1 to every phase bin for which PRIOR was active.
        for i in range(len(start_bins)):
            start = start_bins[i]
            end = end_bins[i]
            #             print(start)
            # If PRIOR started counting in a previous cycle, add 1 to each full cycle and to the partial cycles
            if start < 0:
                for j in range(int(np.floor(np.abs(start) / nbin))):
                    livetime_profile = livetime_profile + 1
                livetime_profile[int(start %
                                     nbin):] = livetime_profile[int(start %
                                                                    nbin):] + 1
                livetime_profile[:int(end)] = livetime_profile[:int(end)] + 1

            # Else, just add 1 to the portion of this cycle during which PRIOR was counting
            else:
                livetime_profile[int(start):int(
                    end)] = livetime_profile[int(start):int(end)] + 1

        # livetime corresponding to the phase bin for each photon
        fold_lts = np.array(
            [livetime_profile[int(b)] for b in np.floor(nbin * fold_phases)])

        z_stat = plsr.z_n(fold_phases,
                          n=2,
                          norm=weights * p_weights * np.max(livetime_profile) /
                          fold_lts)
        #         livetime_profile = livetime_profile/np.max(livetime_profile)

        return phase_bins, profile, profile_err, livetime_profile, z_stat