def setup_class(cls): tstart = 0.0 tend = 1.0 dt = 0.0001 time = np.arange(tstart + 0.5 * dt, tend + 0.5 * dt, dt) mean_count_rate = 100.0 mean_counts = mean_count_rate * dt poisson_counts = np.random.poisson(mean_counts, size=time.shape[0]) cls.lc = Lightcurve(time, counts=poisson_counts, dt=dt, gti=[[tstart, tend]])
def test_leahy_correct_for_multiple(self): n = 100 lc_all = [] for i in range(n): time = np.arange(0.0, 10.0, 10. / 100000) counts = np.random.poisson(1000, size=time.shape[0]) lc = Lightcurve(time, counts) lc_all.append(lc) ps = AveragedPowerspectrum(lc_all, 10.0, norm="leahy") assert np.isclose(np.mean(ps.power), 2.0, atol=1e-3, rtol=1e-3) assert np.isclose(np.std(ps.power), 2.0 / np.sqrt(n), atol=0.1, rtol=0.1)
def test_io_with_hdf5(self): lc = Lightcurve(self.times, self.counts) lc.write('lc.hdf5', format_='hdf5') if _H5PY_INSTALLED: data = lc.read('lc.hdf5', format_='hdf5') assert np.all(data['time'] == self.times) assert np.all(data['counts'] == self.counts) assert np.all(data['gti'] == self.gti) os.remove('lc.hdf5') else: lc.read('lc.pickle', format_='pickle') assert np.all(lc.time == self.times) assert np.all(lc.counts == self.counts) assert np.all(lc.gti == self.gti) os.remove('lc.pickle')
def correct_lightcurve(lc_file, uf_file, outname=None, expo_limit=1e-7): """Apply exposure correction to light curve. Parameters ---------- lc_file : str The light curve file, in HENDRICS format uf_file : str The unfiltered event file, in FITS format Returns ------- outdata : str Output data structure Other Parameters ---------------- outname : str Output file name """ outname = _assign_value_if_none( outname, hen_root(lc_file) + "_lccorr" + HEN_FILE_EXTENSION) ftype, contents = get_file_type(lc_file) time = contents.time lc = contents.counts dt = contents.dt gti = contents.gti expo = get_exposure_from_uf(time, uf_file, dt=dt, gti=gti) newlc = np.array(lc / expo * dt, dtype=np.float64) newlc[expo < expo_limit] = 0 newlc_err = np.array(contents.counts_err / expo * dt, dtype=np.float64) newlc_err[expo < expo_limit] = 0 lcurve = Lightcurve(time, newlc, err=newlc_err, gti=gti, err_dist ='gauss', mjdref=contents.mjdref) lcurve.expo = expo save_lcurve(lcurve, outname) return outname
def test_sort(self): _times = [1, 2, 3, 4] _counts = [40, 10, 20, 5] lc = Lightcurve(_times, _counts, mjdref=57000) mjdref = lc.mjdref lc.sort() assert np.all(lc.counts == np.array([5, 10, 20, 40])) assert np.all(lc.time == np.array([4, 2, 3, 1])) assert lc.mjdref == mjdref lc.sort(reverse=True) assert np.all(lc.counts == np.array([40, 20, 10, 5])) assert np.all(lc.time == np.array([1, 3, 2, 4])) assert lc.mjdref == mjdref
def test_sort_counts(self): _times = [1, 2, 3, 4] _counts = [40, 10, 20, 5] lc = Lightcurve(_times, _counts, mjdref=57000) mjdref = lc.mjdref lc_new = lc.sort_counts() assert np.allclose(lc_new.counts, np.array([5, 10, 20, 40])) assert np.allclose(lc_new.time, np.array([4, 2, 3, 1])) assert lc_new.mjdref == mjdref lc_new = lc.sort_counts(reverse=True) assert np.allclose(lc_new.counts, np.array([40, 20, 10, 5])) assert np.allclose(lc_new.time, np.array([1, 3, 2, 4])) assert lc_new.mjdref == mjdref
def test_fractional_rms_in_frac_norm_is_consistent_averaged(self): time = np.arange(0, 400, 1) + 0.5 poisson_counts = np.random.poisson(100.0, size=time.shape[0]) lc = Lightcurve(time, counts=poisson_counts, dt=1, gti=[[0, 400]]) ps = AveragedPowerspectrum(lc=lc, norm="leahy", segment_size=100) rms_ps_l, rms_err_l = ps.compute_rms(min_freq=ps.freq[1], max_freq=ps.freq[-1], white_noise_offset=0) ps = AveragedPowerspectrum(lc=lc, norm="frac", segment_size=100) rms_ps, rms_err = ps.compute_rms(min_freq=ps.freq[1], max_freq=ps.freq[-1], white_noise_offset=0) assert np.allclose(rms_ps, rms_ps_l, atol=0.01) assert np.allclose(rms_err, rms_err_l, atol=0.01)
def test_timeseries_roundtrip(self): """Test that io methods raise Key Error when wrong format is provided. """ N = len(self.times) lc = Lightcurve(self.times, self.counts, mission="BUBU", instr="BABA", mjdref=53467.) ts = lc.to_astropy_timeseries() new_lc = lc.from_astropy_timeseries(ts) for attr in ['time', 'gti', 'counts']: assert np.allclose(getattr(lc, attr), getattr(new_lc, attr)) for attr in ['mission', 'instr', 'mjdref']: assert getattr(lc, attr) == getattr(new_lc, attr)
def _make_reference_bands_from_lightcurves(self, bounds=None): ''' Helper class to construct reference bands for all light curves in ``band_interest``, assuming the data is given to the class :class:`Covariancespectrum` as a (set of) lightcurve(s). Generally sums up all other light curves within ``bounds`` that are *not* the band of interest. Parameters ---------- bounds : iterable The energy bounds to use for the reference band. Must be of type ``(elow, ehigh)``. Returns ------- lc_all: list of :class:`stingray.Lightcurve` objects. The list of :class:`stingray.Lightcurve` objects containing all reference bands, between the values given in ``bounds``. ''' if not bounds: bounds_idx = [0, len(self.band_interest)] else: low_bound = self.band_interest.searchsorted(bounds[0]) high_bound = self.band_interest.searchsorted(bounds[1]) bounds_idx = [low_bound, high_bound] lc_all = [] for i, b in enumerate(self.band_interest): # initialize empty counts array counts = np.zeros_like(self.lcs[0].counts) for j in range(bounds_idx[0], bounds_idx[1], 1): if i == j: continue else: counts += self.lcs[j].counts # make a combined light curve lc = Lightcurve(self.lcs[0].time, counts, skip_checks=True) # add to list of reference light curves lc_all.append(lc) return lc_all
def _simulate_model_string(self, model_str, params): """ For generating a light curve from a pre-defined model Parameters ---------- model_str : string name of the pre-defined model params : list or dictionary parameters of the pre-defined model Returns ------- lightCurve : `LightCurve` object """ # Frequencies at which the PSD is to be computed # (only positive frequencies, since the signal is real) nbins = self.red_noise * self.N simfreq = np.fft.rfftfreq(nbins, d=self.dt)[1:] if model_str in dir(models): if isinstance(params, dict): model = eval('models.' + model_str + '(**params)') # Compute PSD from model simpsd = model(simfreq) elif isinstance(params, list): simpsd = eval('models.' + model_str + '(simfreq, params)') else: raise ValueError('Params should be list or dictionary!') fac = np.sqrt(simpsd) pos_real = self.random_state.normal(size=nbins // 2) * fac pos_imag = self.random_state.normal(size=nbins // 2) * fac long_lc = self._find_inverse(pos_real, pos_imag) lc = Lightcurve(self.time, self._extract_and_scale(long_lc), err=np.zeros_like(self.time) + np.sqrt(self.mean), err_dist='gauss', dt=self.dt) return lc else: raise ValueError('Model is not defined!')
def test_timelag(self): dt = 0.1 simulator = Simulator(dt, 10000, rms=0.2, mean=1000) test_lc1 = simulator.simulate(2) test_lc2 = Lightcurve(test_lc1.time, np.array(np.roll(test_lc1.counts, 2)), err_dist=test_lc1.err_dist, dt=dt) with warnings.catch_warnings(record=True) as w: cs = AveragedCrossspectrum(test_lc1, test_lc2, segment_size=5, norm="none") time_lag, time_lag_err = cs.time_lag() assert np.all(np.abs(time_lag[:6] - 0.1) < 3 * time_lag_err[:6])
def test_timelag(self): from ..simulator.simulator import Simulator dt = 0.1 simulator = Simulator(dt, 10000, rms=0.8, mean=1000) test_lc1 = simulator.simulate(2) test_lc2 = Lightcurve(test_lc1.time, np.array(np.roll(test_lc1.counts, 2)), err_dist=test_lc1.err_dist, dt=dt) cs = AveragedCrossspectrum(test_lc1, test_lc2, segment_size=5, norm="none") time_lag, time_lag_err = cs.time_lag() assert np.all(np.abs(time_lag[:6] - 0.1) < 3 * time_lag_err[:6])
def _simulate_model(self, model): """ For generating a light curve from a pre-defined model Parameters ---------- model : astropy.modeling.Model derived function the pre-defined model (library-based, available in astropy.modeling.models or custom-defined) Returns ------- lightCurve : :class:`stingray.lightcurve.LightCurve` object """ # Frequencies at which the PSD is to be computed # (only positive frequencies, since the signal is real) nbins = self.red_noise * self.N simfreq = np.fft.rfftfreq(nbins, d=self.dt)[1:] # Compute PSD from model simpsd = model(simfreq) if self.nphot == 0: nphot = 1.0 else: nphot = self.nphot self.std = np.sqrt( (nphot / (self.N**2.)) * (np.sum(simpsd[:-1]) + 0.5 * simpsd[-1])) fac = np.sqrt(simpsd) * nphot / 4.0 pos_real = self.random_state.normal(size=nbins // 2) * fac pos_imag = self.random_state.normal(size=nbins // 2) * fac long_lc = self._find_inverse(pos_real, pos_imag) lc = Lightcurve(self.time, self._extract_and_scale(long_lc), err=np.zeros_like(self.time) + np.sqrt(self.mean), err_dist='gauss', dt=self.dt, skip_checks=True) return lc
def _simulate_power_law(self, B): """ Generate LightCurve from a power law spectrum. Parameters ---------- B : int Defines the shape of power law spectrum. Returns ------- lightCurve : array-like """ # Define frequencies at which to compute PSD w = np.fft.rfftfreq(self.red_noise * self.N, d=self.dt)[1:] # Draw two set of 'N' guassian distributed numbers a1 = self.random_state.normal(size=len(w)) a2 = self.random_state.normal(size=len(w)) psd = np.power((1 / w), B) if self.nphot == 0: nphot = 1.0 else: nphot = self.nphot self.std = np.sqrt( (nphot / (self.N**2.)) * (np.sum(psd[:-1]) + 0.5 * psd[-1])) # Multiply by (1/w)^B to get real and imaginary parts real = a1 * np.sqrt(psd * nphot / 4) imaginary = a2 * np.sqrt(psd * nphot / 4) # Obtain time series long_lc = self._find_inverse(real, imaginary) lc = Lightcurve(self.time, self._extract_and_scale(long_lc), err=np.zeros_like(self.time) + np.sqrt(self.mean), err_dist='gauss', dt=self.dt, skip_checks=True) return lc
def test_sort(self): _times = [2, 1, 3, 4] _counts = [40, 10, 20, 5] _counts_err = [4, 1, 2, 0.5] lc = Lightcurve(_times, _counts, err=_counts_err, mjdref=57000) mjdref = lc.mjdref lc_new = lc.sort() assert np.all(lc_new.counts_err == np.array([1, 4, 2, 0.5])) assert np.all(lc_new.counts == np.array([10, 40, 20, 5])) assert np.all(lc_new.time == np.array([1, 2, 3, 4])) assert lc_new.mjdref == mjdref lc_new = lc.sort(reverse=True) assert np.all(lc_new.counts == np.array([5, 20, 40, 10])) assert np.all(lc_new.time == np.array([4, 3, 2, 1])) assert lc_new.mjdref == mjdref
def _simulate_power_spectrum(self, s): """ Generate a light curve from user-provided spectrum. Parameters ---------- s : array-like power spectrum Returns ------- lightCurve : `LightCurve` object """ # Cast spectrum as numpy array s = np.array(s) if self.nphot == 0: nphot = 1.0 else: nphot = self.nphot self.std = np.sqrt( (nphot / (self.N**2.)) * (np.sum(s[:-1]) + 0.5 * s[-1])) self.red_noise = 1 # Draw two set of 'N' guassian distributed numbers a1 = self.random_state.normal(size=len(s)) a2 = self.random_state.normal(size=len(s)) real = a1 * nphot * np.sqrt(s) / 4.0 imaginary = a2 * nphot * np.sqrt(s) / 4.0 lc = self._find_inverse(real, imaginary) lc = Lightcurve(self.time, self._extract_and_scale(lc), err=np.zeros_like(self.time) + np.sqrt(self.mean), err_dist='gauss', dt=self.dt, skip_checks=True) return lc
def _simulate_impulse_response(self, s, h, mode='same'): """ Generate LightCurve from impulse response. To get accurate results, binning intervals (dt) of variability signal 's' and impulse response 'h' must be equal. Parameters ---------- s : array-like Underlying variability signal h : array-like Impulse response mode : str mode can be 'same', 'filtered, or 'full'. 'same' indicates that the length of output light curve is same as that of input signal. 'filtered' means that length of output light curve is len(s) - lag_delay 'full' indicates that the length of output light curve is len(s) + len(h) -1 Returns ------- lightCurve : :class:`stingray.lightcurve.LightCurve` object """ lc = signal.fftconvolve(s, h) if mode == 'same': lc = lc[:-(len(h) - 1)] elif mode == 'filtered': lc = lc[(len(h) - 1):-(len(h) - 1)] time = self.dt * np.arange(0.5, len(lc)) + self.tstart err = np.zeros_like(time) return Lightcurve(time, lc, err_dist='gauss', dt=self.dt, err=err, skip_checks=True)
def test_list_of_light_curves(self): n_lcs = 10 tstart = 0.0 tend = 1.0 dt = 0.0001 time = np.linspace(tstart, tend, int((tend - tstart) / dt)) mean_count_rate = 1000.0 mean_counts = mean_count_rate * dt lc_all = [] for n in range(n_lcs): poisson_counts = np.random.poisson(mean_counts, size=len(time)) lc = Lightcurve(time, counts=poisson_counts) lc_all.append(lc) segment_size = 0.5 assert AveragedPowerspectrum(lc_all, segment_size)
def _simulate_model(self, model): """ For generating a light curve from a pre-defined model Parameters ---------- model: astropy.modeling.Model derived function the pre-defined model (library-based, available in astropy.modeling.models or custom-defined) Returns ------- lightCurve: `LightCurve` object """ # Frequencies at which the PSD is to be computed # (only positive frequencies, since the signal is real) nbins = self.red_noise * self.N simfreq = np.fft.rfftfreq(nbins, d=self.dt)[1:] # Compute PSD from model simpsd = model(simfreq) fac = np.sqrt(simpsd / 2.) pos_real = self.random_state.normal(size=nbins // 2) * fac pos_imag = self.random_state.normal(size=nbins // 2) * fac pos_freq_transform = pos_real + 1j * pos_imag # Simulate light curve from its Fourier transform arg = np.concatenate(([self.mean], pos_freq_transform)) # Inverse Fourier transform long_lc = np.fft.irfft(arg) lc = Lightcurve(self.time, self._extract_and_scale(long_lc), err_dist='gauss', dt=self.dt) return lc
def test_fractional_rms_in_frac_norm_is_consistent(self): """ Copied from test_powerspectrum.py """ time = np.arange(0, 100, 1) + 0.5 poisson_counts = np.random.poisson(100.0, size=time.shape[0]) lc = Lightcurve(time, counts=poisson_counts, dt=1, gti=[[0, 100]]) mtp = Multitaper(lc, norm="leahy") rms_mtp_l, rms_err_l = mtp.compute_rms(min_freq=mtp.freq[1], max_freq=mtp.freq[-1], white_noise_offset=0) mtp = Multitaper(lc, norm="frac") rms_mtp, rms_err = mtp.compute_rms(min_freq=mtp.freq[1], max_freq=mtp.freq[-1], white_noise_offset=0) assert np.allclose(rms_mtp, rms_mtp_l, atol=0.01) assert np.allclose(rms_err, rms_err_l, atol=0.01)
def test_analyze_lc_chunks_fvar_fracstep(self): dt = 0.1 tstart = 0 tstop = 100 times = np.arange(tstart, tstop, dt) gti = np.array([[tstart - dt / 2, tstop - dt / 2]]) # Simulate something *clearly* non-constant counts = np.random.poisson(10000 + 2000 * np.sin(2 * np.pi * times)) lc = Lightcurve(times, counts, gti=gti) def excvar(lc): from stingray.utils import excess_variance return excess_variance(lc, normalization='fvar') start, stop, res = lc.analyze_lc_chunks(20, excvar, fraction_step=0.5) # excess_variance returns fvar and fvar_err res, res_err = res assert np.allclose(start[0], gti[0, 0]) assert np.all(res > 0) # This must be a clear measurement of fvar assert np.all(res > res_err)
def test_list_with_nonsense_component(self): n_lcs = 10 tstart = 0.0 tend = 1.0 dt = 0.0001 time = np.linspace(tstart, tend, int((tend - tstart) / dt)) mean_count_rate = 1000.0 mean_counts = mean_count_rate * dt lc_all = [] for n in range(n_lcs): poisson_counts = np.random.poisson(mean_counts, size=len(time)) lc = Lightcurve(time, counts=poisson_counts) lc_all.append(lc) lc_all.append(1.0) segment_size = 0.5 with pytest.raises(TypeError): assert AveragedPowerspectrum(lc_all, segment_size)
def test_timeseries_roundtrip_ctrate(self): """Test that io methods raise Key Error when wrong format is provided. """ N = len(self.times) dt = 0.5 mean_counts = 2.0 times = np.arange(0 + dt / 2, 5 - dt / 2, dt) countrate = np.zeros_like(times) + mean_counts lc = Lightcurve(times, countrate, mission="BUBU", instr="BABA", mjdref=53467., input_counts=False) ts = lc.to_astropy_timeseries() new_lc = lc.from_astropy_timeseries(ts) for attr in ['time', 'gti', 'countrate']: assert np.allclose(getattr(lc, attr), getattr(new_lc, attr)) assert np.allclose(new_lc.counts, lc.countrate * lc.dt) for attr in ['mission', 'instr', 'mjdref']: assert getattr(lc, attr) == getattr(new_lc, attr)
def test_multitaper_lombscargle(self): rng = np.random.default_rng() N = 1000 white_noise_irregular = rng.normal(loc=0.0, scale=7, size=N) start = 0.0 end = 9.0 # Generating uneven sampling times by adding white noise. Do tell a better way time_irregular = np.linspace(start, end, N) + rng.normal(loc=0.0, scale=(end-start)/(3*N), size=N) time_irregular = np.sort(time_irregular) with pytest.warns(UserWarning) as record: lc_nonuni = Lightcurve(time=time_irregular, counts=white_noise_irregular, err_dist="gauss", err=np.ones_like(time_irregular) + np.sqrt(0.)) # Zero mean assert np.any(["aren't equal" in r.message.args[0] for r in record]) mtls_white = Multitaper(lc_nonuni, lombscargle=True, low_bias=True, NW=4) assert mtls_white.norm == "frac" assert mtls_white.fullspec is False assert mtls_white.meancounts == lc_nonuni.meancounts assert mtls_white.nphots == np.float64(np.sum(lc_nonuni.counts)) assert mtls_white.err_dist == lc_nonuni.err_dist assert mtls_white.dt == lc_nonuni.dt assert mtls_white.n == lc_nonuni.time.shape[0] assert mtls_white.df == 1.0 / lc_nonuni.tseg assert mtls_white.m == 1 assert mtls_white.freq is not None assert mtls_white.multitaper_norm_power is not None assert mtls_white.power is not None assert mtls_white.power_err is not None assert mtls_white.jk_var_deg_freedom is None # Not supported yet assert len(mtls_white.eigvals) > 0
def _simulate_model(self, mod, p): """ For generating a light curve from pre-defined model Parameters ---------- mod: str name of the pre-defined model p: list iterable model parameters. For details, see model definitions in model.py Returns ------- lightCurve: `LightCurve` object """ # Define frequencies at which to compute PSD w = np.fft.rfftfreq(self.red_noise * self.N, d=self.dt)[1:] if mod in dir(models): mod = 'models.' + mod s = eval(mod + '(w, p)') # Draw two set of 'N' guassian distributed numbers a1 = np.random.normal(size=len(s)) a2 = np.random.normal(size=len(s)) long_lc = self._find_inverse(a1 * s, a2 * s) lc = Lightcurve(self.time, self._extract_and_scale(long_lc)) return lc else: raise ValueError('Model is not defined!')
def test_n(self): lc = Lightcurve(self.times, self.counts) assert lc.n == 4
def test_io_with_ascii(self): lc = Lightcurve(self.times, self.counts) lc.write('ascii_lc.txt', format_='ascii') lc.read('ascii_lc.txt', format_='ascii') os.remove('ascii_lc.txt')
def test_plot_title(self): lc = Lightcurve(self.times, self.counts) lc.plot(title="Test Lightcurve") assert plt.fignum_exists(1)
def test_plot_axis(self): lc = Lightcurve(self.times, self.counts) lc.plot(axis=[0, 1, 0, 100]) assert plt.fignum_exists(1)
def test_plot_custom_filename(self): lc = Lightcurve(self.times, self.counts) lc.plot(save=True, filename='lc.png') assert os.path.isfile('lc.png') os.unlink('lc.png')