def test_pulse_phase1(self): """Test pulse phase calculation, frequency only.""" times = np.arange(0, 4, 0.5) ph = pulse_phase(times, 1, ph0=0, to_1=False) np.testing.assert_array_almost_equal(ph, times)
def run_folding(file, freq, fdot=0, fddot=0, nbin=16, nebin=16, tref=None, test=False, emin=0, emax=1e32, norm='to1', smooth_window=None, deorbit_par=None, **opts): from matplotlib.gridspec import GridSpec import matplotlib.pyplot as plt file_label = '' ev = load_events(file) if deorbit_par is not None: events = deorbit_events(ev, deorbit_par) times = ev.time gtis = ev.gti plot_energy = True if hasattr(ev, 'energy') and ev.energy is not None: energy = ev.energy elabel = 'Energy' elif hasattr(ev, 'pi') and ev.pi is not None: energy = ev.pi elabel = 'PI' else: energy = np.ones_like(times) elabel = '' plot_energy = False if tref is None: tref = times[0] good = (energy > emin) & (energy < emax) times = times[good] energy = energy[good] phases = pulse_phase(times - tref, freq, fdot, fddot, to_1=True) binx = np.linspace(0, 1, nbin + 1) if plot_energy: biny = np.percentile(energy, np.linspace(0, 100, nebin + 1)) biny[0] = emin biny[-1] = emax profile, _ = np.histogram(phases, bins=binx) if smooth_window is None: smooth_window = np.min([len(profile), np.max([len(profile) // 10, 5])]) smooth_window = _check_odd(smooth_window) smoothed_profile = savgol_filter(profile, window_length=smooth_window, polyorder=2, mode='wrap') profile = np.concatenate((profile, profile)) smooth = np.concatenate((smoothed_profile, smoothed_profile)) if plot_energy: histen, _ = np.histogram(energy, bins=biny) hist2d, _, _ = np.histogram2d(phases.astype(np.float64), energy, bins=(binx, biny)) binx = np.concatenate((binx[:-1], binx + 1)) meanbins = (binx[:-1] + binx[1:]) / 2 if plot_energy: hist2d = np.vstack((hist2d, hist2d)) hist2d_save = np.copy(hist2d) X, Y = np.meshgrid(binx, biny) if norm == 'ratios': hist2d /= smooth[:, np.newaxis] hist2d *= histen[np.newaxis, :] file_label = '_ratios' else: hist2d /= histen[np.newaxis, :] factor = np.max(hist2d, axis=0)[np.newaxis, :] hist2d /= factor file_label = '_to1' plt.figure() if plot_energy: gs = GridSpec(2, 2, height_ratios=(1, 3)) ax0 = plt.subplot(gs[0, 0]) ax1 = plt.subplot(gs[1, 0], sharex=ax0) ax2 = plt.subplot(gs[1, 1], sharex=ax0) ax3 = plt.subplot(gs[0, 1]) else: ax0 = plt.subplot() # Plot pulse profile max = np.max(smooth) min = np.min(smooth) ax0.plot(meanbins, profile, drawstyle='steps-mid', color='white', zorder=2) ax0.plot(meanbins, smooth, drawstyle='steps-mid', label='Smooth profile ' '(P.F. = {:.1f}%)'.format(100 * (max - min) / max), color='k', zorder=3) err_low, err_high = \ poisson_conf_interval(smooth, interval='frequentist-confidence', sigma=3) try: ax0.fill_between(meanbins, err_low, err_high, color='grey', zorder=1, alpha=0.5, label='3-sigma confidence', step='mid') except AttributeError: # MPL < 2 ax0.fill_between(meanbins, err_low, err_high, color='grey', zorder=1, alpha=0.5, label='3-sigma confidence') ax0.axhline(max, lw=1, color='k') ax0.axhline(min, lw=1, color='k') mean = np.mean(profile) ax0.fill_between(meanbins, mean - np.sqrt(mean), mean + np.sqrt(mean), alpha=0.5) ax0.axhline(mean, ls='--') ax0.legend() ax0.set_ylim([0, None]) if plot_energy: ax1.pcolormesh(X, Y, hist2d.T) ax1.semilogy() ax1.set_xlabel('Phase') ax1.set_ylabel(elabel) ax1.set_xlim([0, 2]) pfs = [] errs = [] meannrgs = (biny[:-1] + biny[1:]) / 2 for i, prof in enumerate(hist2d_save.T): smooth = savgol_filter(prof, window_length=smooth_window, polyorder=2, mode='wrap') max = np.max(smooth) min = np.min(smooth) pf = 100 * (max - min) / max ax2.plot(meanbins, prof, drawstyle='steps-mid', label='{}={:.2f}-{:.2f}'.format(elabel, biny[i], biny[i + 1], pf)) std = np.max(prof - smooth) ax2.set_xlabel('Phase') ax2.set_ylabel('Counts') pfs.append(pf) errs.append(std / max) if len(meannrgs) < 6: ax2.legend() ax2.set_xlim([0, 2]) ax3.errorbar(meannrgs, pfs, fmt='o', yerr=errs, xerr=(biny[1:] - biny[:-1]) / 2) ax3.semilogx() ax3.set_xlabel('Energy') ax3.set_ylabel('Pulsed fraction') plt.savefig('Energyprofile' + file_label + '.png') if not test: # pragma:no cover plt.show()
def test_pulse_phase3(self): """Test pulse phase calculation, fddot only.""" times = np.arange(0, 4, 0.5) ph = pulse_phase(times, 0, 0, 1, ph0=0, to_1=False) np.testing.assert_array_almost_equal(ph, 1/6 * times ** 3)
def test_pulse_phase3(self): """Test pulse phase calculation, fddot only.""" times = np.arange(0, 4, 0.5) ph = pulse_phase(times, 0, 0, 1, ph0=0, to_1=False) np.testing.assert_array_almost_equal(ph, 1 / 6 * times**3)
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
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
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
def phase_tag(ev_list, parameter_info, gtis=None, mjdref=0, nbin=10, ref_to_max=False, pepoch=None, expocorr=True, pulse_ref_time=None, plot=True, test=False): """Phase-tag events in a FITS file with a given ephemeris. Parameters ---------- ev_list : float Event times parameter_info : str or array of floats If a string, this is a pulsar parameter file that PINT is able to understand. Otherwise, this is a list of frequency derivatives [F0, F1, F2, ...] Other parameters ---------------- gtis : [[g0_0, g0_1], [g1_0, g1_1], ...] Good time intervals nbin : int Number of nbin in the pulsed profile ref_to_max : bool Automatically refer the TOAs to the maximum of the profile pepoch : float, default None Reference epoch for the timing solution. If None, this is the start of the observation. pulse_ref_time : float Reference time for the pulse. This overrides ref_to_max plot : bool Plot diagnostics expocorr : bool Use exposure correction when calculating the profile """ # ---- in MJD ---- if gtis is None: gtis = np.array([[ev_list[0], ev_list[-1]]]) ev_mjd = ev_list / 86400 + mjdref gtis_mjd = gtis / 86400 + mjdref pepoch = _assign_value_if_none(pepoch, gtis_mjd[0, 0]) # ------ Orbital DEMODULATION -------------------- if is_string(parameter_info): raise NotImplementedError('This part is not yet implemented. Please ' 'use single frequencies and pepoch as ' 'documented') else: frequency_derivatives = parameter_info times = (ev_mjd - pepoch) * 86400 f = frequency_derivatives[0] phase = pulse_phase(times, *frequency_derivatives, to_1=False) gti_phases = pulse_phase((gtis_mjd - pepoch) * 86400, *frequency_derivatives, to_1=False) # ------- now apply period derivatives ------ print("Calculating phases...", end='') ref_phase = 0 ref_time = 0 if pulse_ref_time is not None: ref_time = (pulse_ref_time - pepoch) * 86400 ref_phase = ref_time * f elif ref_to_max: phase_to1 = phase - np.floor(phase) raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gtis=gti_phases) profile = raw_profile / exposure profile_err = np.sqrt(raw_profile) / exposure sinpars, bu, bu = fit_profile(profile, profile_err, nperiods=2, baseline=True, debug=test) fine_phases = np.linspace(0, 2, 1000 * 2) fitted_profile = std_fold_fit_func(sinpars, fine_phases) maxp = np.argmax(fitted_profile) ref_phase = fine_phases[maxp] if test: # pragma: no cover # No tests with a pulsed profile yet ref_phase = bins[np.argmax(raw_profile)] ref_time = ref_phase / f phase -= ref_phase gti_phases -= ref_phase phase_to1 = phase - np.floor(phase) raw_profile, bins = np.histogram(phase_to1, bins=np.linspace(0, 1, nbin + 1)) exposure = phase_exposure(gti_phases[0, 0], gti_phases[-1, 1], 1, nbin=nbin, gtis=gti_phases) if np.any(np.logical_or(exposure != exposure, exposure == 0)): warnings.warn('Exposure has NaNs or zeros. Profile is not normalized') expocorr = False if not expocorr: exposure = np.ones_like(raw_profile) profile = raw_profile / exposure profile = np.append(profile, profile) exposure = np.append(exposure, exposure) profile_err = np.sqrt(profile) phs = (bins[1:] + bins[:-1]) / 2 phs = np.append(phs, phs + 1) fig = None if plot: fig = plt.figure() plt.errorbar(phs, profile / exposure, yerr=profile_err / exposure, fmt='none') plt.plot(phs, profile / exposure, 'k-', drawstyle='steps-mid') plt.xlabel("Phase") plt.ylabel("Counts") for i in range(20): plt.axvline(i * 0.1, ls='--', color='b') if not test: # pragma: no cover plt.show() # ------ WRITE RESULTS BACK TO FITS -------------- results = type('results', (object, ), {}) results.ev_list = ev_list results.phase = phase results.frequency_derivatives = frequency_derivatives results.ref_time = ref_time results.figure = fig results.plot_phase = phs results.plot_profile = profile / exposure results.plot_profile_err = profile_err / exposure return results
plt.axhline(y=prob3,lw=0.5,alpha=0.5) plt.axhline(y=prob4,lw=0.5,alpha=0.5) plt.axhline(y=prob5,lw=0.5,alpha=0.5) plt.show() """ nphase = 20 ##### using foldAt phases = foldAt(x, pb, T0=0) ##### using phase mod 1 phase_mod = (1 / pb * x) % 1 #or shift by -0.7*pb ##### using stingray.pulse.pulsar phase_stingray = pulse_phase(x, [1 / pb]) #,ph0=1-0.7) expocorr = Lv2_phase.phase_exposure(times[0] - times[0], times[-1] - times[0], period=pb, nbin=nphase, gtis=gtis_conform) ################################################################################ ##### Testing the 3 different routines for calculating phase phase_bins = np.linspace(0, 1, nphase + 1) profile, bin_edges, binnumber = stats.binned_statistic(phases, y, statistic='mean',
def run_folding(file, freq, fdot=0, fddot=0, nbin=16, nebin=16, tref=0, test=False, emin=0, emax=1e32, norm='to1', smooth_window=None, **opts): file_label = '' ev = load_events(file) times = ev.time gtis = ev.gti plot_energy = True if hasattr(ev, 'energy') and ev.energy is not None: energy = ev.energy elabel = 'Energy' elif hasattr(ev, 'pi') and ev.pi is not None: energy = ev.pi elabel = 'PI' else: energy = np.ones_like(times) elabel = '' plot_energy = False good = (energy > emin) & (energy < emax) times = times[good] energy = energy[good] phases = pulse_phase(times - tref, freq, fdot, fddot, to_1=True) binx = np.linspace(0, 1, nbin + 1) if plot_energy: biny = np.percentile(energy, np.linspace(0, 100, nebin + 1)) biny[0] = emin biny[-1] = emax profile, _ = np.histogram(phases, bins=binx) if smooth_window is None: smooth_window = np.min([len(profile), np.max([len(profile) // 10, 5])]) smooth_window = _check_odd(smooth_window) smoothed_profile = savgol_filter(profile, window_length=smooth_window, polyorder=2, mode='wrap') profile = np.concatenate((profile, profile)) smooth = np.concatenate((smoothed_profile, smoothed_profile)) if plot_energy: histen, _ = np.histogram(energy, bins=biny) hist2d, _, _ = np.histogram2d(phases.astype(np.float64), energy, bins=(binx, biny)) binx = np.concatenate((binx[:-1], binx + 1)) meanbins = (binx[:-1] + binx[1:])/2 if plot_energy: hist2d = np.vstack((hist2d, hist2d)) X, Y = np.meshgrid(binx, biny) if norm == 'ratios': hist2d /= smooth[:, np.newaxis] hist2d *= histen[np.newaxis, :] file_label = '_ratios' else: hist2d /= histen[np.newaxis, :] factor = np.max(hist2d, axis=0)[np.newaxis, :] hist2d /= factor file_label = '_to1' plt.figure() if plot_energy: gs = GridSpec(2, 1, height_ratios=(1, 3)) ax0 = plt.subplot(gs[0]) ax1 = plt.subplot(gs[1], sharex=ax0) else: ax0 = plt.subplot() # Plot pulse profile max = np.max(smooth) min = np.min(smooth) ax0.plot(meanbins, profile, drawstyle='steps-mid', color='grey') ax0.plot(meanbins, smooth, drawstyle='steps-mid', label='Smooth profile ' '(P.F. = {:.1f}%)'.format(100 * (max - min) / max), color='k') ax0.axhline(max, lw=1, color='k') ax0.axhline(min, lw=1, color='k') mean = np.mean(profile) ax0.fill_between(meanbins, mean - np.sqrt(mean), mean + np.sqrt(mean)) ax0.axhline(mean, ls='--') ax0.legend() if plot_energy: ax1.pcolormesh(X, Y, hist2d.T) ax1.semilogy() ax1.set_xlabel('Phase') ax1.set_ylabel(elabel) plt.savefig('Energyprofile' + file_label + '.png') if not test: # pragma:no cover plt.show()