def build_ktransit_model(ticid, lc, rprs=0.02, vary_transit=True): from ktransit import FitTransit fitT = FitTransit() model = BoxLeastSquares(lc.time, lc.flux) results = model.autopower(0.16, minimum_period=2., maximum_period=21.) period = results.period[np.argmax(results.power)] t0 = results.transit_time[np.argmax(results.power)] if rprs is None: depth = results.depth[np.argmax(results.power)] rprs = depth ** 2 fitT.add_guess_star(rho=0.022, zpt=0, ld1=0.6505,ld2=0.1041) #come up with better way to estimate this using AS fitT.add_guess_planet(T0=t0, period=period, impact=0.5, rprs=rprs) ferr = np.ones_like(lc.time) * 0.00001 fitT.add_data(time=lc.time,flux=lc.flux,ferr=ferr)#*1e-3) vary_star = ['zpt'] # free stellar parameters if vary_transit: vary_planet = (['period', 'impact', # free planetary parameters 'T0', #'esinw', 'ecosw', 'rprs']) #'impact', # free planet parameters are the same for every planet you model else: vary_planet = (['rprs']) fitT.free_parameters(vary_star, vary_planet) fitT.do_fit() # run the fitting return fitT
def pdf_summary(self, ticid, out_fname): """ """ self.ticid = ticid with PdfPages(out_fname) as pdf: ql_fig = self.plot(self.ticid, save_postcard=True) pdf.savefig(ql_fig) plt.close() lc = self.lc time, flux, flux_err = lc.time, lc.flux, lc.flux_err model = BoxLeastSquares(time, flux) results = model.autopower(0.16, minimum_period=2., maximum_period=21.) period = results.period[np.argmax(results.power)] t0 = results.transit_time[np.argmax(results.power)] vt_fig = plot_transit_vetting(self.ticid, period, t0, lc=self.lc) pdf.savefig(vt_fig) plt.close() ica_fig = make_ica_plot(self.ticid) pdf.savefig(ica_fig) plt.close() star_fig = self.plot_starry_model(lc) pdf.savefig(star_fig) plt.close()
def make_transit_periodogram(t, y, dy=0.01): """ Plots a periodogram to determine likely period of planet transit candidtaes in a dataset, based on a box least squared method. """ model = BoxLeastSquares(t * u.day, y, dy=0.01) periodogram = model.autopower(0.2, objective="snr") plt.figure() plt.plot(periodogram.period, periodogram.power, 'k') plt.xlabel('Period [days]') plt.ylabel('Power') max_power_i = np.argmax(periodogram.power) best_fit = periodogram.period[max_power_i] print('Best Fit Period: {} days'.format(best_fit)) stats = model.compute_stats(periodogram.period[max_power_i], periodogram.duration[max_power_i], periodogram.transit_time[max_power_i]) return stats, best_fit
def get_bls_features(x, t): features = [] # print(x[0]) for i in range(x.shape[0]): # adapted from http://docs.astropy.org/en/stable/stats/bls.html#peak-statistics bls = BoxLeastSquares(t, x[i]) periodogram = bls.autopower( 40, minimum_n_transit=5 ) # arg is the granularity of considered durations max_power = np.argmax(periodogram.power) stats = bls.compute_stats(periodogram.period[max_power], periodogram.duration[max_power], periodogram.transit_time[max_power]) # TODO: use dataframe? features.append([stats[s][0] / stats[s][1] for s in stat_names]) # based on https://arxiv.org/pdf/astro-ph/0206099.pdf # ratios.append(stats["depth"][0] / stats["depth"][1]) # depth over uncertainty if (i + 1) % 10 == 0: print(".", end="") if (i + 1) % 500 == 0: print() print() return np.array(features)
def validate_transit(self, ticid=None, lc=None, rprs=0.02): """Take a closer look at potential transit signals.""" from .plotting import create_starry_model if ticid is not None: lc = self.from_eleanor(ticid)[1] lc = self._clean_data(lc) elif lc is None: lc = self.lc model = BoxLeastSquares(lc.time, lc.flux) results = model.autopower(0.16) period = results.period[np.argmax(results.power)] t0 = results.transit_time[np.argmax(results.power)] if rprs is None: depth = results.depth[np.argmax(results.power)] rprs = depth**2 # create the model model_flux = create_starry_model( lc.time, period=period, t0=t0, rprs=rprs) - 1 model_lc = lk.LightCurve(time=lc.time, flux=model_flux) fig, ax = plt.subplots(3, 1, figsize=(12, 14)) fig.patch.set_facecolor('white') ''' Plot unfolded transit --------------------- ''' lc.scatter(ax=ax[0], c='k', label='Corrected Flux') model_lc.plot(ax=ax[0], c='r', lw=2, label='Transit Model') ax[0].set_ylim([-.002, .002]) ax[0].set_xlim([lc.time[0], lc.time[-1]]) ''' Plot folded transit ------------------- ''' lc.fold(period, t0).scatter(ax=ax[1], c='k', label=f'P={period:.3f}, t0={t0}') lc.fold(period, t0).bin(binsize=7).plot(ax=ax[1], c='b', label='binned', lw=2) model_lc.fold(period, t0).plot(ax=ax[1], c='r', lw=2, label="transit Model") ax[1].set_xlim([-0.5, .5]) ax[1].set_ylim([-.002, .002]) ''' Zoom folded transit ------------------- ''' lc.fold(period, t0).scatter(ax=ax[2], c='k', label=f'folded at {period:.3f} days') lc.fold(period, t0).bin(binsize=7).plot(ax=ax[2], c='b', label='binned', lw=2) model_lc.fold(period, t0).plot(ax=ax[2], c='r', lw=2, label="transit Model") ax[2].set_xlim([-0.1, .1]) ax[2].set_ylim([-.002, .002]) ax[0].set_title(f'{ticid}', fontsize=14) plt.show()
f = [] for fn in files: ti, fi = np.genfromtxt(fn, usecols=(0,1), unpack=True) t.append(ti) f.append(fi / np.nanmedian(fi)) t = np.concatenate(t) f = np.concatenate(f) fig, ax = plt.subplots(figsize=[15,3]) ax.plot(t, f, '-k', lw=1, zorder=-2) ax.scatter(t, f, c='gold', edgecolor='black', s=15, lw=.5, zorder=-1) durations = np.linspace(0.05, 0.2, 50)# * u.day model = BLS(t,f) result = model.autopower(durations, frequency_factor=5.0, maximum_period=30.0) idx = np.argmax(result.power) period = result.period[idx] t0 = result.transit_time[idx] dur = result.duration[idx] depth = result.depth[idx] ph = (t - t0 + 0.5*period) % period - 0.5*period fig2, ax2 = plt.subplots(figsize=[8,2]) ax2.scatter(ph, f, c='gold', edgecolor='black', s=15, lw=.5) plt.show()
def build_model(x, y, yerr, period_prior, t0_prior, depth, minimum_period=2, maximum_period=30, r_star_prior=5.0, t_star_prior=5000, m_star_prior=None, start=None): """Build an exoplanet model for a dataset and set of planets Paramters --------- x : array-like The time series (in days); this should probably be centered y : array-like The relative fluxes (in parts per thousand) yerr : array-like The uncertainties on ``y`` period_prior : list The literature values for periods of the planets (in days) t0_prior : list The literature values for phases of the planets in the same coordinates as `x` rprs_prior : list The literature values for the ratio of planet radius to star radius start : dict A dictionary of model parameters where the optimization should be initialized Returns: A PyMC3 model specifying the probabilistic model for the light curve """ model = BoxLeastSquares(x, y) results = model.autopower(0.16, minimum_period=minimum_period, maximum_period=maximum_period) if period_prior is None: period_prior = results.period[np.argmax(results.power)] if t0_prior is None: t0_prior = results.transit_time[np.argmax(results.power)] if depth is None: depth = results.depth[np.argmax(results.power)] period_prior = np.atleast_1d(period_prior) t0_prior = np.atleast_1d(t0_prior) # rprs_prior = np.atleast_1d(rprs_prior) with pm.Model() as model: # Set model variables model.x = np.asarray(x, dtype=np.float64) model.y = np.asarray(y, dtype=np.float64) model.yerr = np.asarray(yerr + np.zeros_like(x), dtype=np.float64) '''Stellar Parameters''' # The baseline (out-of-transit) flux for the star in ppt mean = pm.Normal("mean", mu=0.0, sd=10.0) try: r_star_mu = target_list[target_list['ID'] == ticid]['rad'].values[0] except: r_star_mu = r_star_prior if m_star_prior is None: try: m_star_mu = target_list[target_list['ID'] == ticid]['mass'].values[0] except: m_star_mu = 1.2 if np.isnan(m_star_mu): m_star_mu = 1.2 else: m_star_mu = m_star_prior r_star = pm.Normal("r_star", mu=r_star_mu, sd=1.) m_star = pm.Normal("m_star", mu=m_star_mu, sd=1.) t_star = pm.Normal("t_star", mu=t_star_prior, sd=200) rho_star_mu = ((m_star_mu*u.solMass).to(u.g) / ((4/3) * np.pi * ((r_star_mu*u.solRad).to(u.cm))**3)).value rho_star = pm.Normal("rho_star", mu=rho_star_mu, sd=.25) '''Orbital Parameters''' # The time of a reference transit for each planet t0 = pm.Normal("t0", mu=t0_prior, sd=2., shape=1) period = pm.Uniform("period", testval=period_prior, lower=minimum_period, upper=maximum_period, shape=1) b = pm.Uniform("b", testval=0.5, shape=1) # Set up a Keplerian orbit for the planets model.orbit = xo.orbits.KeplerianOrbit( period=period, t0=t0, b=b, r_star=r_star, m_star=m_star)#rho_star=rho_star) # track additional orbital parameters a = pm.Deterministic("a", model.orbit.a) incl = pm.Deterministic("incl", model.orbit.incl) '''Planet Parameters''' # quadratic limb darkening paramters u_ld = xo.distributions.QuadLimbDark("u_ld") estimated_rpl = r_star*(depth)**(1/2) # logr = pm.Normal("logr", testval=np.log(estimated_rpl), sd=1.) r_pl = pm.Uniform("r_pl", testval=estimated_rpl, lower=0., upper=1.) # r_pl = pm.Deterministic("r_pl", tt.exp(logr)) rprs = pm.Deterministic("rprs", r_pl / r_star) teff = pm.Deterministic('teff', t_star * tt.sqrt(0.5*(1/a))) # Compute the model light curve using starry model.light_curves = xo.StarryLightCurve(u_ld).get_light_curve( orbit=model.orbit, r=r_pl, t=model.x) model.light_curve = pm.math.sum(model.light_curves, axis=-1) + mean pm.Normal("obs", mu=model.light_curve, sd=model.yerr, observed=model.y) # Fit for the maximum a posteriori parameters, I've found that I can get # a better solution by trying different combinations of parameters in turn if start is None: start = model.test_point map_soln = xo.optimize(start=start, vars=[period, t0]) map_soln = xo.optimize(start=map_soln, vars=[r_pl, mean]) map_soln = xo.optimize(start=map_soln, vars=[period, t0, mean]) map_soln = xo.optimize(start=map_soln, vars=[r_pl, mean]) map_soln = xo.optimize(start=map_soln) model.map_soln = map_soln return model
def find_and_mask_transits(time, flux, flux_err, periods, durations, nplanets=1): """ Iteratively find and mask transits in the flattened light curve. Args: time (array): The time array. flux (array): The flux array. You'll get the best results if this is flattened. flux_err (array): The array of flux uncertainties. periods (array): The array of periods to search over for BLS. For example, periods = np.linspace(0.5, 20, 10) durations (array): The array of durations to search over for BLS. For example, durations = np.linspace(0.05, 0.2, 10) nplanets (Optional[int]): The number of planets you'd like to search for. This function will interatively find and remove nplanets. Default is 1. Returns: transit_masks (list): a list of masks that correspond to the in transit points of each light curve. To mask out transits do time[~transit_masks[index]], etc. """ cum_transit = np.ones(len(time), dtype=bool) _time, _flux, _flux_err = time * 1, flux * 1, flux_err * 1 t0s, durs, porbs = [np.zeros(nplanets) for i in range(3)] transit_masks = [] for i in range(nplanets): bls = BoxLeastSquares(t=_time, y=_flux, dy=_flux_err) bls.power(periods, durations) print("periods") periods = bls.autoperiod(durations, minimum_n_transit=3, frequency_factor=5.0) print("results") results = bls.autopower(durations, frequency_factor=5.0) # Find the period of the peak print("find_period") period = results.period[np.argmax(results.power)] print("extract") # Extract the parameters of the best-fit model index = np.argmax(results.power) porbs[i] = results.period[index] t0s[i] = results.transit_time[index] durs[i] = results.duration[index] # # Plot the periodogram # fig, ax = plt.subplots(1, 1, figsize=(10, 5)) # ax.plot(results.period, results.power, "k", lw=0.5) # ax.set_xlim(results.period.min(), results.period.max()) # ax.set_xlabel("period [days]") # ax.set_ylabel("log likelihood") # # Highlight the harmonics of the peak period # ax.axvline(period, alpha=0.4, lw=4) # for n in range(2, 10): # ax.axvline(n*period, alpha=0.4, lw=1, linestyle="dashed") # ax.axvline(period / n, alpha=0.4, lw=1, linestyle="dashed") # plt.show() # plt.plot(_time, _flux, ".") # plt.xlim(1355, 1360) print("mask") in_transit = bls.transit_mask(_time, porbs[i], 2 * durs[i], t0s[i]) transit_masks.append(in_transit) _time, _flux, _flux_err = _time[~in_transit], _flux[~in_transit], \ _flux_err[~in_transit] return transit_masks, t0s, durs, porbs
def superplot(lc, ticid, breakpoints, target_list, save_data=False, outdir=None): """ """ time, flux, flux_err = lc.time, lc.flux, lc.flux_err model = BoxLeastSquares(time, flux) results = model.autopower(0.16, minimum_period=2., maximum_period=21.) period = results.period[np.argmax(results.power)] t0 = results.transit_time[np.argmax(results.power)] depth = results.depth[np.argmax(results.power)] depth_snr = results.depth_snr[np.argmax(results.power)] ''' Plot Filtered Light Curve ------------------------- ''' plt.subplot2grid((8,16),(1,0),colspan=4, rowspan=1) plt.plot(time, flux, 'k', label="filtered") for val in breakpoints: plt.axvline(val, c='b', linestyle='dashed') plt.legend() plt.ylabel('Normalized Flux') plt.xlabel('Time') osample=5. nyq=283. # calculate FFT freq, amp, nout, jmax, prob = lomb.fasper(time, flux, osample, 3.) freq = 1000. * freq / 86.4 bin = freq[1] - freq[0] fts = 2. * amp * np.var(flux * 1e6) / (np.sum(amp) * bin) use = np.where(freq < nyq + 150) freq = freq[use] fts = fts[use] # calculate ACF acf = np.correlate(fts, fts, 'same') freq_acf = np.linspace(-freq[-1], freq[-1], len(freq)) fitT = build_ktransit_model(ticid=ticid, lc=lc, vary_transit=False) dur = _individual_ktransit_dur(fitT.time, fitT.transitmodel) freq = freq fts1 = fts/np.max(fts) fts2 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5) fts3 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50) ''' Plot Periodogram ---------------- ''' plt.subplot2grid((8,16),(0,4),colspan=4,rowspan=4) plt.loglog(freq, fts/np.max(fts)) plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5), color='C1', lw=2.5) plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50), color='r', lw=2.5) plt.axvline(283,-1,1, ls='--', color='k') plt.xlabel("Frequency [uHz]") plt.ylabel("Power") plt.xlim(10, 400) plt.ylim(1e-4, 1e0) # annotate with transit info font = {'family':'monospace', 'size':10} plt.text(10**1.04, 10**-3.50, f'depth = {depth:.4f} ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.04, 10**-3.62, f'depth_snr = {depth_snr:.4f} ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.04, 10**-3.74, f'period = {period:.3f} days ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.04, 10**-3.86, f't0 = {t0:.3f} ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) try: # annotate with stellar params # won't work for TIC ID's not in the list if isinstance(ticid, str): ticid = int(re.search(r'\d+', str(ticid)).group()) Gmag = target_list[target_list['ID'] == ticid]['GAIAmag'].values[0] Teff = target_list[target_list['ID'] == ticid]['Teff'].values[0] R = target_list[target_list['ID'] == ticid]['rad'].values[0] M = target_list[target_list['ID'] == ticid]['mass'].values[0] plt.text(10**1.7, 10**-3.50, rf"G mag = {Gmag:.3f} ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.7, 10**-3.62, rf"Teff = {int(Teff)} K ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.7, 10**-3.74, rf"R = {R:.3f} $R_\odot$ ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.7, 10**-3.86, rf"M = {M:.3f} $M_\odot$ ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) except: pass '''# plot ACF inset ax = plt.gca() axins = inset_axes(ax, width=2.0, height=1.4) axins.plot(freq_acf, acf) axins.set_xlim(1,25) axins.set_xlabel("ACF [uHz]")''' ''' Plot BLS -------- ''' plt.subplot2grid((8,16),(2,0),colspan=4, rowspan=1) plt.plot(results.period, results.power, "k", lw=0.5) plt.xlim(results.period.min(), results.period.max()) plt.xlabel("period [days]") plt.ylabel("log likelihood") # Highlight the harmonics of the peak period plt.axvline(period, alpha=0.4, lw=4) for n in range(2, 10): plt.axvline(n*period, alpha=0.4, lw=1, linestyle="dashed") plt.axvline(period / n, alpha=0.4, lw=1, linestyle="dashed") phase = (t0 % period) / period foldedtimes = (((time - phase * period) / period) % 1) foldedtimes[foldedtimes > 0.5] -= 1 foldtimesort = np.argsort(foldedtimes) foldfluxes = flux[foldtimesort] plt.subplot2grid((8,16), (3,0),colspan=2) plt.scatter(foldedtimes, flux, s=2) plt.plot(np.sort(foldedtimes), scipy.ndimage.filters.median_filter(foldfluxes, 40), lw=2, color='r', label=f'P={period:.2f} days, dur={dur:.2f} hrs') plt.xlabel('Phase') plt.ylabel('Flux') plt.xlim(-0.5, 0.5) plt.ylim(-0.0025, 0.0025) plt.legend(loc=0) fig = plt.gcf() fig.patch.set_facecolor('white') fig.suptitle(f'{ticid}', fontsize=14) fig.set_size_inches(12, 10) if save_data: np.savetxt(outdir+'/timeseries/'+str(ticid)+'.dat.ts', np.transpose([time, flux]), fmt='%.8f', delimiter=' ') np.savetxt(outdir+'/fft/'+str(ticid)+'.dat.ts.fft', np.transpose([freq, fts]), fmt='%.8f', delimiter=' ') with open(os.path.join(outdir,"transit_stats.txt"), "a+") as file: file.write(f"{ticid} {depth} {depth_snr} {period} {t0} {dur}\n") """ --------------- TRANSIT VETTING --------------- """ tpf = get_cutout(ticid, cutout_size=11) ica_lcs = find_ica_components(tpf) fig = plt.subplot2grid((8,16),(0,8),colspan=4,rowspan=4) fig.patch.set_facecolor('white') tpf.plot(ax=fig, title='', show_colorbar=False) add_gaia_figure_elements(tpf, fig) fig = plt.subplot2grid((8,16),(2,8),colspan=4,rowspan=2) lc.fold(2*period, t0+period/2).scatter(ax=fig, c='k', label='Odd Transit') lc.fold(2*period, t0+period/2).bin(3).plot(ax=fig, c='C1', lw=2) plt.xlim(-.5, 0) rms = np.std(lc.flux) plt.ylim(-3*rms, rms) fig = plt.subplot2grid((8,16),(3,8),colspan=4,rowspan=2) lc.fold(2*period, t0+period/2).scatter(ax=fig, c='k', label='Even Transit') lc.fold(2*period, t0+period/2).bin(3).plot(ax=fig, c='C1', lw=2) plt.xlim(0, .5) plt.ylim(-3*rms, rms) fig = plt.subplot2grid((8,16),(0,12),colspan=4,rowspan=4) for i,ilc in enumerate(ica_lcs): scale = 1 plt.plot(ilc + i*scale) plt.xlim(0, len(ica_lcs[0])) plt.ylim(-scale, len(ica_lcs)*scale) """ STARRY MODEL ------------ """ from .utils import _fit x, y, yerr = lc.time, lc.flux, lc.flux_err model, static_lc = _fit(x, y, yerr, target_list=target_list) model_lc = lk.LightCurve(time=x, flux=static_lc) with model: period = model.map_soln['period'][0] t0 = model.map_soln['t0'][0] r_pl = model.map_soln['r_pl'] * 9.96 a = model.map_soln['a'][0] b = model.map_soln['b'][0] try: r_star = target_list[target_list['ID'] == ticid]['rad'].values[0] except: r_star = 10. fig = plt.subplot2grid((8,16),(4,0),colspan=4,rowspan=2) ''' Plot unfolded transit --------------------- ''' lc.scatter(c='k', label='Corrected Flux') lc.bin(binsize=7).plot(c='b', lw=1.5, alpha=.75, label='binned') model_lc.plot(c='r', lw=2, label='Transit Model') plt.ylim([-.002, .002]) plt.xlim([lc.time[0], lc.time[-1]]) fig = plt.subplot2grid((8,16),(6,0),colspan=4,rowspan=2) ''' Plot folded transit ------------------- ''' lc.fold(period, t0).scatter(c='k', label=rf'$P={period:.3f}, t0={t0:.3f}, ' 'R_p={r_pl:.3f} R_J, b={b:.3f}') lc.fold(period, t0).bin(binsize=7).plot(c='b', alpha=.75, lw=2) model_lc.fold(period, t0).plot(c='r', lw=2) plt.xlim([-0.5, .5]) plt.ylim([-.002, .002])
def make_ica_plot(tic, tpf=None): """ """ if tpf is None: tpf = lk.search_tesscut(f'TIC {tic}').download(cutout_size=11) raw_lc = tpf.to_lightcurve(aperture_mask='all') ##Perform ICA n_components = 20 X = np.ascontiguousarray(np.nan_to_num(tpf.flux), np.float64) X_flat = X.reshape(len(tpf.flux), -1) #turns three dimensional into two dimensional f1 = np.reshape(X_flat, (len(X), -1)) X_pix = f1 / np.nansum(X_flat, axis=-1)[:, None] ica = FastICA(n_components=n_components) #define n_components S_ = ica.fit_transform(X_pix) A_ = ica.mixing_ #combine x_flat to get x a = np.dot(S_.T, S_) a[np.diag_indices_from(a)] += 1e-5 b = np.dot(S_.T, raw_lc.flux) w = np.linalg.solve(a, b) comp_lcs = [] blss = [] max_powers = [] for i,s in enumerate(S_.T): component_lc = s * w[i] comp_lcs.append(component_lc) # plt.plot(component_lc + i*1e5) model = BoxLeastSquares(tpf.time, component_lc) results = model.autopower(0.16, minimum_period=.5, maximum_period=24.) # model = transitleastsquares(tpf.time, component_lc) # results = model.power() period, power = results.period, results.power blss.append([period, power]) # print(results.depth_snr[np.argmax(power)]) if (np.std(component_lc) > 1e4) or (np.abs(period[np.argmax(power)] - 14) < 2) or (results.depth[np.argmax(power)]/np.median(component_lc) < 0): power = [0] max_powers.append(np.max(power)) # plt.ylim(-1e5, 10e5) best_pers = blss[np.argmax(max_powers)][0] best_powers = blss[np.argmax(max_powers)][1] period = best_pers[np.argmax(best_powers)] transit_lc = lk.LightCurve(time=tpf.time, flux=comp_lcs[np.argmax(max_powers)]) fig, ax = plt.subplots(2, 3, figsize=(10, 7)) fig.suptitle(f'TIC {tic}') for i,c in enumerate(comp_lcs): ax[0,0].plot(tpf.time, c + i*1e5) ax[0,0].set_ylim(-1e5, n_components*1e5) ax[0,0].set_xlim(tpf.time[0], tpf.time[-1]) ax[0,0].set_xlabel('Time') ax[0,0].set_ylabel('Flux') ax[0,0].yaxis.set_major_formatter(mtick.FormatStrFormatter('%.e')) ax[0,0].set_title('ICA Components') transit_lc.plot(ax=ax[0,1]) ax[0,1].set_xlim(tpf.time[0], tpf.time[-1]) ax[0,1].yaxis.set_major_formatter(mtick.FormatStrFormatter('%.e')) ax[0,1].set_title('ICA comp with max BLS power') transit_lc.remove_outliers(9).fold(period).scatter(ax=ax[0,2], c='k', label=f'Period={period:.2f}') transit_lc.remove_outliers(9).fold(period).bin(7).plot(ax=ax[0,2], c='r', lw=2, C='C1', label='Binned') ax[0,2].set_ylim(-5*np.std(transit_lc.flux), 2*np.std(transit_lc.flux)) ax[0,2].set_xlim(-.5,.5) ax[0,2].set_title('Folded ICA Transit Component') A_useful = A_.reshape(11,11,n_components).T #reshape from 2d to 3d weighted_comp = A_useful[np.argmax(max_powers)].T * w[np.argmax(max_powers)] ax[1,0].imshow(weighted_comp, origin='lower') ax[1,1].imshow(tpf.flux[200], origin='lower') im = ax[1,2].imshow(weighted_comp / tpf.flux[200], origin='lower') ax[1,0].set_title('Weighted Transit Component') ax[1,1].set_title('TPF') ax[1,2].set_title('Model / Flux') plt.colorbar(im) fig.tight_layout(rect=[0, 0.03, 1, 0.95]) fig.patch.set_facecolor('white') fig.set_size_inches(10, 7) return fig
def plot_quicklook(lc, ticid, breakpoints, target_list, save_data=True, outdir=None): if outdir is None: outdir = os.path.join(self.PACKAGEDIR, 'outputs') time, flux, flux_err = lc.time, lc.flux, lc.flux_err model = BoxLeastSquares(time, flux) results = model.autopower(0.16, minimum_period=2., maximum_period=21.) period = results.period[np.argmax(results.power)] t0 = results.transit_time[np.argmax(results.power)] depth = results.depth[np.argmax(results.power)] depth_snr = results.depth_snr[np.argmax(results.power)] ''' Plot Filtered Light Curve ------------------------- ''' plt.subplot2grid((4,4),(1,0),colspan=2) plt.plot(time, flux, 'k', label="filtered") for val in breakpoints: plt.axvline(val, c='b', linestyle='dashed') plt.legend() plt.ylabel('Normalized Flux') plt.xlabel('Time') osample=5. nyq=283. # calculate FFT freq, amp, nout, jmax, prob = lomb.fasper(time, flux, osample, 3.) freq = 1000. * freq / 86.4 bin = freq[1] - freq[0] fts = 2. * amp * np.var(flux * 1e6) / (np.sum(amp) * bin) use = np.where(freq < nyq + 150) freq = freq[use] fts = fts[use] # calculate ACF acf = np.correlate(fts, fts, 'same') freq_acf = np.linspace(-freq[-1], freq[-1], len(freq)) fitT = build_ktransit_model(ticid=ticid, lc=lc, vary_transit=False) dur = _individual_ktransit_dur(fitT.time, fitT.transitmodel) freq = freq fts1 = fts/np.max(fts) fts2 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5) fts3 = scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50) ''' Plot Periodogram ---------------- ''' plt.subplot2grid((4,4),(0,2),colspan=2,rowspan=4) plt.loglog(freq, fts/np.max(fts)) plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 5), color='C1', lw=2.5) plt.loglog(freq, scipy.ndimage.filters.gaussian_filter(fts/np.max(fts), 50), color='r', lw=2.5) plt.axvline(283,-1,1, ls='--', color='k') plt.xlabel("Frequency [uHz]") plt.ylabel("Power") plt.xlim(10, 400) plt.ylim(1e-4, 1e0) # annotate with transit info font = {'family':'monospace', 'size':10} plt.text(10**1.04, 10**-3.50, f'depth = {depth:.4f} ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.04, 10**-3.62, f'depth_snr = {depth_snr:.4f} ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.04, 10**-3.74, f'period = {period:.3f} days ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.04, 10**-3.86, f't0 = {t0:.3f} ', fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) try: # annotate with stellar params # won't work for TIC ID's not in the list if isinstance(ticid, str): ticid = int(re.search(r'\d+', str(ticid)).group()) Gmag = target_list[target_list['ID'] == ticid]['GAIAmag'].values[0] Teff = target_list[target_list['ID'] == ticid]['Teff'].values[0] R = target_list[target_list['ID'] == ticid]['rad'].values[0] M = target_list[target_list['ID'] == ticid]['mass'].values[0] plt.text(10**1.7, 10**-3.50, rf"G mag = {Gmag:.3f} ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.7, 10**-3.62, rf"Teff = {int(Teff)} K ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.7, 10**-3.74, rf"R = {R:.3f} $R_\odot$ ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) plt.text(10**1.7, 10**-3.86, rf"M = {M:.3f} $M_\odot$ ", fontdict=font).set_bbox(dict(facecolor='white', alpha=.9, edgecolor='none')) except: pass # plot ACF inset ax = plt.gca() axins = inset_axes(ax, width=2.0, height=1.4) axins.plot(freq_acf, acf) axins.set_xlim(1,25) axins.set_xlabel("ACF [uHz]") ''' Plot BLS -------- ''' plt.subplot2grid((4,4),(2,0),colspan=2) plt.plot(results.period, results.power, "k", lw=0.5) plt.xlim(results.period.min(), results.period.max()) plt.xlabel("period [days]") plt.ylabel("log likelihood") # Highlight the harmonics of the peak period plt.axvline(period, alpha=0.4, lw=4) for n in range(2, 10): plt.axvline(n*period, alpha=0.4, lw=1, linestyle="dashed") plt.axvline(period / n, alpha=0.4, lw=1, linestyle="dashed") phase = (t0 % period) / period foldedtimes = (((time - phase * period) / period) % 1) foldedtimes[foldedtimes > 0.5] -= 1 foldtimesort = np.argsort(foldedtimes) foldfluxes = flux[foldtimesort] plt.subplot2grid((4,4), (3,0),colspan=2) plt.scatter(foldedtimes, flux, s=2) plt.plot(np.sort(foldedtimes), scipy.ndimage.filters.median_filter(foldfluxes, 40), lw=2, color='r', label=f'P={period:.2f} days, dur={dur:.2f} hrs') plt.xlabel('Phase') plt.ylabel('Flux') plt.xlim(-0.5, 0.5) plt.ylim(-0.0025, 0.0025) plt.legend(loc=0) fig = plt.gcf() fig.patch.set_facecolor('white') fig.suptitle(f'{ticid}', fontsize=14) fig.set_size_inches(10, 7) if save_data: np.savetxt(outdir+'/timeseries/'+str(ticid)+'.dat.ts', np.transpose([time, flux]), fmt='%.8f', delimiter=' ') np.savetxt(outdir+'/fft/'+str(ticid)+'.dat.ts.fft', np.transpose([freq, fts]), fmt='%.8f', delimiter=' ') with open(os.path.join(outdir,"transit_stats.txt"), "a+") as file: file.write(f"{ticid} {depth} {depth_snr} {period} {t0} {dur}\n") return fig
plot = figure(plot_height=200, plot_width=1000, title='Curva de luz', x_range=[np.nanmin(t), np.nanmax(t)]) plot.xaxis.axis_label = 'Tiempo (dias)' plot.yaxis.axis_label = 'Flujo' plot.circle('t', 'f', source=src, size=1) #plot.line('t', 'trn', source=ndata, line_width=1, color='lime') #BLS print('Calculando período...') durations = np.linspace(0.05, 0.2, 60) model = BLS(t, f) result = model.autopower(durations, frequency_factor=2.0) idx = np.argmax(result.power) per = result.period[idx] if args.period is None else args.period pgram = figure(width=1000, height=200, x_range=[0, 20], title='Periodograma (BLS)') pgram.xaxis.axis_label = 'Periodo' pgram.yaxis.axis_label = 'Potencia' freqs = 1 / np.arange(1 / 30., 1 / 30. + 50000 * 1e-4, 1e-4) #blsda = ColumnDataSource(data=dict(per=freqs, pow=blsre[0])) #pgram.line('per', 'pow', source=blsda) print('Done!') '''