def get_fold_fit(dt_tra, f_tra, depth, period, window, fig=None): """Uses lmfit to get a good estimate of the Mandel-Agol parameters from the folded light curve. The curve fitting routine will then be rerun using these better parameters. :param dt_tra: array of selected dt that fall within transit windows. :param f_tra: array of selected fluxes that fall within transit windows. :param depth: estimate of transit depth obtained from sech fit. Defined as negative. :param period: estimate of transit period (days). :param window: approximate length of transit window (days). Include at least half a transit's worth of out-of-transit light curve on either side of dip. :param fig: plot handle indicating desired plot dimensions. e.g. fig = plt.figure(figsize=(10,4)). No plots will be made if set to None. :return: fit - best-fit Mandel-Agol parameters from lmfit.minimise(). Contains the following params: tc - midtransit time. Centred at 0. b - impact parameter. Rs_a - radius of star/semimajor axis. F - out-of-transit flux, fixed at 1. gamma1, gamma2 - quadratic limb darkening parameters from Mandel & Agol (2002) fig - plot handle of folded transit with best-fit model. """ # plotting can always be skipped now unless you want to debug params = Parameters() params.add('tc', value=0, vary=False, min=-0.1, max=0.1) params.add('b', value=0.7, vary=True) params.add('Rs_a', value=0.1, vary=True, min=0., max=0.5) params.add('Rp_Rs', value=(-depth)**0.5, vary=True) params.add('F', value=1, vary=False) params.add('gamma1', value=0.3, vary=True, min=0, max=0.5) # should I let these float? params.add('gamma2', value=0.3, vary=True, min=0, max=0.5) params.add('a0', value=1, vary=False) params.add('a1', value=0, vary=False) fit = minimize(residual, params, args=(dt_tra, f_tra, period, False)) tarr = np.linspace(min(dt_tra), max(dt_tra), 100) fmod = model_transits.modeltransit([ fit.params['tc'].value, fit.params['b'].value, fit.params['Rs_a'].value, fit.params['Rp_Rs'].value, 1, fit.params['gamma1'].value, fit.params['gamma2'].value ], model_transits.occultquad, period, tarr) if fig is not None: plt.close('all') plt.plot(dt_tra, f_tra, lw=0, marker='.') plt.plot(tarr, fmod, color='r') plt.axvline(x=-window, color='k', ls='--') plt.axvline(x=window, color='k', ls='--') plt.xlabel('Time from midtransit (days)') plt.ylabel('Relative flux') if fig is not None: return fit, fig else: return fit
def residual(params,t,data,period): #residual function for fitting for midtransit times vals = params.valuesdict() t0 = vals['t0'] b = vals['b'] r_a = vals['r_a'] Rp_Rs = vals['Rp_Rs'] F = vals['F'] gamma1 = vals['gamma1'] gamma2 = vals['gamma2'] model = model_transits.modeltransit([t0,b,r_a,Rp_Rs,F,gamma1,gamma2],model_transits.occultquad,period,t) return (data-model)
def transit_likelihoodfunc(params,period,times,dt_new,n_ev,data,sigma,priors_info): # PARAMS: # params[0, 1, 2, 3, 5] = ['T0', 'b', 'R/a', 'Rp/Rs', 'Fstar'] , for i = 0 ... len(a)-2 ---- the last ones are the limb darkening, so len(params) = 1 + len(data) # params[len(params)-1] = ['q1','q2'] u1_param = params[-2] u2_param = params[-1] # check physical boundaries for LD parameters and return -inf if they exceed those boundaries if ( (u1_param + u2_param) > 1.) or ( u1_param < 0. ) or ( u2_param < 0. ): print 'unphysical limb darkening coeffs', u1_param, u2_param return -inf if (params[3]<0): print 'Rp/Rs<0' return -inf if (params[2]<0): print 'Rs/a<0' return -inf params[1] = abs(params[1]) # calculate the likelihoods for all different transit models and sum them together log_likelihood = [] prior = [] prior.append( logp(array([params[0],params[1],params[2],params[3],params[4],u1_param,u2_param]),priors_info) ) # the prior has to be evaluated for q1 and q2, NOT u1 and u2 if not isfinite(prior[0]): return -inf new_params = array([params[0],params[1],params[2],params[3],params[4],u1_param,u2_param]) model_oversamp = model_transits.modeltransit(new_params,model_transits.occultquad,period,dt_new) if type(model_oversamp) is int: return -inf transit_model = [] for i in range(0,len(times)): mean_f = mean(model_oversamp[i*n_ev:i*n_ev+n_ev-1]) transit_model.append(mean_f) log_likelihood.append( -sum( ((array(transit_model)-array(data))**2. / ((2.**0.5)*array(sigma)**2) ) + (log(array(sigma)) * (2.*pi)**0.5 ) ) ) #print 'prior / likelihood' #print prior #print log_likelihood return sum(array(prior)) + sum(array(log_likelihood))
def residual(params, t, data, period=1, sech=True): """Residual function for fitting for midtransit times. INPUTS: params - lmfit.Parameters() object containing parameters to be fitted. t - nd array of light curve times (days). data - nd array of normalized light curve fluxes. Median out-of-transit flux should be set to 1. period - period of transit (days). sech - boolean. If True, will use sech model. Otherwise will fit Mandel-Agol model instead. The params argument must match the format of the model chosen. RETURNS: res - residual of data - model, to be used in lmfit. """ if sech: vals = params.valuesdict() tc = vals['tc'] b = vals['b'] w = vals['w'] a0 = vals['a0'] a1 = vals['a1'] model = rect_sechmod(t, b, tc, w, a0, a1) else: vals = params.valuesdict() tc = vals['tc'] b = vals['b'] r_a = vals['Rs_a'] Rp_Rs = vals['Rp_Rs'] F = vals['F'] gamma1 = vals['gamma1'] gamma2 = vals['gamma2'] a0 = vals['a0'] a1 = vals['a1'] model = model_transits.modeltransit( [tc, b, r_a, Rp_Rs, F, gamma1, gamma2], model_transits.occultquad, period, t) model *= (a0 + a1 * t) return data - model
def get_period(t,f_t,get_mandelagolmodel=True,outputpath='',starname=''): # # here we use a BLS algorithm to create a periodogram and find the best periods. The BLS is implemented in Python by Ruth Angus and Dan Foreman-Macey # outputfolder = os.path.join(outputpath,str(starname)) fmin = 0.03 # minimum frequency. we can't find anything longer than 90 days obviously nf = 60000 # amount of frequencies to try df = 0.00001 # frequency step qmi = 0.0005 # min relative length of transit (in phase unit) qma = 0.1 # max relative length of transit (in phase unit) nb = 200 # number of bins in folded LC u = np.linspace(fmin,fmin + nf*df,nf) v = np.array(0) t = np.array(t) print t[0] f_t = np.array(f_t) t_orig = np.copy(t) f_t_orig = f_t results = bls.eebls(t,f_t,t,f_t,nf,fmin,df,nb,qmi,qma) freqlist = u powers = results[0] period = results[1] folded,f_t_folded = fold_data(t,f_t,period) np.savetxt(os.path.join(outputfolder, 'folded_P' + str(period) + 'star_' + str(starname) + '.txt'),np.transpose([folded,f_t_folded]),header='Time, Flux') t_foldbin,f_t_foldbin,stdv_foldbin = rebin_dataset(folded,f_t_folded,15) f_t_smooth = savitzky_golay(f_t_folded,29,1) pl.figure('my data folded bls') pl.plot(folded,f_t_folded+1.,'.',color='black',label='K2 photometry') pl.xlabel('Time [d]') pl.ylabel('Relative Flux') if get_mandelagolmodel: # this is not a core part of the module and uses a transit model by Mandel & Agol, implemented in Python by Ian Crossfield. #[T0,b,R_over_a,Rp_over_Rstar,flux_star,gamma1,gamma2] transit_params = np.array([4.11176,0.9,0.104,np.sqrt(0.0036),1.,0.2,0.2]) import model_transits times_full = np.linspace(0.,period,10000) model = model_transits.modeltransit(transit_params,model_transits.occultquad,period,times_full) pl.figure('Transit model') pl.scatter((folded-transit_params[0])*24.,f_t_folded+1.,color='black',label='K2 photometry',s=10.) pl.plot((times_full-transit_params[0])*24.,model,color='grey',lw=4,label='Transit model') pl.xlabel('Time from mid-transit [hr]',fontsize=17) pl.ylabel('Relative flux',fontsize=17) legend = pl.legend(loc='upper center',numpoints=1,scatterpoints=1,fontsize=15,prop={'size':15},title='EPIC 205071984') pl.tick_params(labelsize=17) pl.tick_params(axis='both', which='major', width=1.5) pl.tight_layout() pl.setp(legend.get_title(),fontsize=17) pl.savefig(os.path.join(outputfolder, 'folded_P_' + 'star_' + str(starname) +str(period) + '.png')) # unravel again n_start = int(np.round(t[0] / period)) n_end = np.round(t[-1] / period) + 1 i = n_start pl.figure() pl.plot(t_orig,f_t,'*') t_unravel = [] f_t_unravel = [] while i < n_end: t_unravel.append(np.array(folded) + i*period + t_orig[0]) f_t_unravel.append(np.array(f_t_smooth)) pl.plot(t_unravel[i],f_t_unravel[i],color='black',lw='1.5') i = i + 1 print 'best period is ' print period return folded,f_t_folded,period,freqlist,powers
def run_mcmc(epic,transit_params,period,times,data,sigma,nwalkers=50,nthread=1,burnintime=100,iterations=400,saveacc=200,saveval=200,thin=100): # Parameters are [T0,b,R_over_a,Rp_over_Rstar,flux_star,gamma1,gamma2] T0_prior = ['gauss', 0, 0.1] # should be around 0. b_prior = ['flat', -1, 1] R_over_a_prior = ['flat', 0.01, 0.4] Rp_over_Rstar_prior = ['flat',0.0001, 0.3] flux_star_prior = ['flat', 0.999, 1.001] # should be normalised to one #FIXME gamma1_prior = ['flat',0.1,0.5] gamma2_prior = ['flat',0.1,0.5] priors_info = [T0_prior, b_prior, R_over_a_prior, Rp_over_Rstar_prior, flux_star_prior, gamma1_prior, gamma2_prior] ndim = 7 cad = 29.4/60./24. #cadence in days n_pt = len(times) n_ev = 25 n_tot = n_ev*n_pt dt_new = zeros(n_tot) for i,this_t in enumerate(times): for i_ev in range(0,n_ev-1): dt_new[i*n_ev+i_ev] = this_t + 1.0/n_ev *cad*(i_ev-ceil(n_ev/2)) # Initialize sampler: sampler = emcee.EnsembleSampler(nwalkers, ndim, transit_likelihoodfunc, args=[period,times,dt_new,n_ev,data,sigma,priors_info], threads=nthread) starting_pos = [transit_params + 1e-6*random.randn(ndim) for i in range(nwalkers)] # all start out in more or less the location of our best guess. pos,prob,state = sampler.run_mcmc(starting_pos,1000) samples = sampler.chain[:, burnintime:, :].reshape((-1, ndim)) fig = corner.corner(samples,labels=['t0','b','R/a','Rp/Rs','F_norm','gamma1','gamma2']) fig.savefig('outputs/'+epic+'_triangle.png') parnames = ['t0','b','R/a','Rp/Rs','F','gamma1','gamma2'] for i in range(0,7): print parnames[i], percentile(array(samples[:,i]),[(100-68.3)/2,50,50+68.3/2]) params = median(samples,axis=0) timearr = linspace(times[0],times[-1],100) model_oversamp = model_transits.modeltransit(params,model_transits.occultquad,period,dt_new) model = [] for i in range(0,len(times)): mean_f = mean(model_oversamp[i*n_ev:i*n_ev+n_ev-1]) model.append(mean_f) model2 = interp(timearr,times,model) dt = linspace(min(times),max(times),100) model = model_transits.modeltransit(params,model_transits.occultquad,period,dt) plt.close('all') fig = plt.figure(figsize=(11,5)) plt.plot(times*24,data,lw=0,marker='.') plt.plot(dt*24.,model,color='g',ls='--',lw=1.5) plt.plot(timearr*24.,model2,color='r',lw=1.5) plt.xlabel('Time from midtransit (hours)') plt.ylabel('Relative flux') plt.savefig('outputs/'+epic+'_7final.pdf',dpi=150,bbox_inches='tight') return params
def odd_even(dt_tra, f_tra, epochs_tra, window, period, p0): """Plots odd vs. even transits and calculates difference in depth. :param dt_tra: see get_fold_fit. :param f_tra: see get_fold_fit. :param epochs_tra: see get_fold_fit. :param window: see get_fold_fit. :param period: see get_fold_fit. :param p0: good estimate of Mandel-Agol parameters from get_fold_fit. p0 = [b, Rs_a, Rp_Rs, gamma1, gamma2] :return: fig - plot handle for odd-even comparison plot. """ # odd = np.where(epochs_tra % 2 != 0)[0] even = np.where(epochs_tra % 2 == 0)[0] params = Parameters() params.add('tc', value=0, vary=False) params.add('b', value=p0[0], vary=True) params.add('Rs_a', value=p0[1], vary=True, min=0., max=0.5) params.add('Rp_Rs', value=p0[2], vary=True) params.add('F', value=1, vary=False) params.add('gamma1', value=p0[3], vary=False) params.add('gamma2', value=p0[4], vary=False) params.add('a0', value=1, vary=False) params.add('a1', value=0, vary=False) fit_odd = minimize(residual, params, args=(dt_tra[odd], f_tra[odd], period, False)) fit_even = minimize(residual, params, args=(dt_tra[even], f_tra[even], period, False)) oot = np.where(abs(dt_tra) > window)[0] sigma = np.std(dt_tra[oot]) tarr = np.linspace(min(dt_tra), max(dt_tra), 200) oddmod = model_transits.modeltransit([ fit_odd.params['tc'].value, fit_odd.params['b'].value, fit_odd.params['Rs_a'].value, fit_odd.params['Rp_Rs'].value, 1, fit_odd.params['gamma1'].value, fit_odd.params['gamma2'].value ], model_transits.occultquad, period, tarr) evenmod = model_transits.modeltransit([ fit_even.params['tc'].value, fit_even.params['b'].value, fit_even.params['Rs_a'].value, fit_even.params['Rp_Rs'].value, 1, fit_even.params['gamma1'].value, fit_even.params['gamma2'].value ], model_transits.occultquad, period, tarr) odd_depth = min(oddmod) even_depth = min(evenmod) diff = abs(odd_depth - even_depth) / sigma plt.close('all') fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(13, 5)) plt.subplots_adjust(wspace=0, hspace=0) ax1.plot(dt_tra[odd] * 24., f_tra[odd], lw=0, marker='.') ax1.plot(tarr * 24., oddmod, color='r') ax1.axhline(y=odd_depth, color='k', ls='--') ax1.set_xlabel('Time from midtransit (hours)') ax1.set_ylabel('Relative flux') ax1.set_xlim(min(dt_tra) * 24, max(dt_tra) * 24) ax1.annotate('Odd', xy=(0.75, 0.15), xycoords='axes fraction', size=15) ax2.plot(dt_tra[even] * 24., f_tra[even], lw=0, marker='.') ax2.plot(tarr * 24., evenmod, color='r') ax2.axhline(y=even_depth, color='k', ls='--') ax2.set_xlabel('Time from midtransit (hours)') ax2.set_xlim(min(dt_tra) * 24, max(dt_tra) * 24) ax2.annotate('Even', xy=(0.75, 0.15), xycoords='axes fraction', size=15) ax2.annotate('Diff: %.3f sigma' % diff, xy=(0.62, 0.05), xycoords='axes fraction', size=15) # plt.savefig('outputs/' + name + '_oddeven.pdf', dpi=150, bbox_inches='tight') return fig
def plot_indiv_trans(name, t, f, p, t0, window, p0, plotbad=True, plots=True, sech=True): """ Plot individual transits with a choice of sech or Mandel-Agol fit. INPUTS: t - nd array of light curve times. f - nd array of normalized light curve fluxes. window - approximate length of transit window (days). Include at least half a transit's worth of out-of-transit light curve on either side of dip. p0 - best guess of fit parameters. If sech, p0 = [w0, depth]. w0 is fractional width of transit from read_lc. If Mandel-Agol, p0 = [b,Rs_a,Rp_Rs,gamma1,gamma2]. plotbad - set to True if you want to plot incomplete or misshapen transits along with good ones. sech - set to True if you want a sech fit. Otherwise use Mandel-Agol model. RETURNS: dt_all - nd array showing the time (days) to the nearest transit for each point. epochs - nd array of epoch number of each point. midpts - nd array of midtransit times associated with all points. err - array of errors on each midtransit time. """ end = int(floor((t[-1] - t0) / p) + 1) start = int(floor((t[0] - t0) / p)) cnt = 0 epochs = [] dt_all = [] midpts = [] err = [] valid_trans = [] params = Parameters() if sech: w0 = p0[0] depth = p0[1] params.add('tc', value=0, vary=True, min=-0.1, max=0.1) params.add('b', value=depth * 2, vary=False) params.add('w', value=w0 * p, vary=False) params.add('a0', value=1) params.add('a1', value=0) else: depth = -p0[2]**2 params.add('tc', value=0, vary=True, min=-0.1, max=0.1) params.add('b', value=p0[0], vary=False) params.add('Rs_a', value=p0[1], vary=False) params.add('Rp_Rs', value=p0[2], vary=False) params.add('F', value=1, vary=False) params.add('gamma1', value=p0[3], vary=False) # should I let these float? params.add('gamma2', value=p0[4], vary=False) params.add('a0', value=1, vary=True) params.add('a1', value=0, vary=True) for i in range(start, end): print 'Transit number ' + str(cnt) midt = i * p + t0 dt = t - midt oot = np.where((abs(dt) > window) & (abs(dt) < window + 0.2 * p))[0] if len(oot) <= 1: continue fn = f / np.median(f[oot]) select = np.where( abs(dt) < (window + 0.1 * p))[0] # select single transit good = np.where( abs(dt) <= p / 2)[0] # all points belonging to current transit if plots: if cnt % 8 == 0: plt.close('all') fig, ax = plt.subplots(8, figsize=(6, 12), sharex=True) if plotbad or (len(select) > 5): ax[cnt % 8].plot(dt[select], fn[select], lw=0, marker='.') ax[cnt % 8].axvline(x=0, color='k', ls='--') ax[cnt % 8].set_xlabel('Time from midtransit (days)') ax[cnt % 8].set_ylabel('Relative flux') ax[cnt % 8].set_ylim(1 + depth - 0.0003, 1 + 0.0003) ax[cnt % 8].set_xlim(-0.3, 0.3) ax[cnt % 8].locator_params(axis='y', nbins=5) ax[cnt % 8].get_yaxis().get_major_formatter().set_useOffset(False) ax[cnt % 8].annotate(str(cnt), xy=(0.85, 0.1), xycoords='axes fraction', size=15) dt_all += list(dt[good]) if len(select) > 5: # fit sech to each transit try: fit = minimize(residual, params, args=(dt[select], fn[select], p, sech)) fiterr = np.sqrt(fit.covar[0][0]) err.append(fiterr) midpts += len(good) * [fit.params['tc'].value + i * p + t0] epochs += len(good) * [i] if plots: tc = fit.params['tc'].value a0 = fit.params['a0'].value a1 = fit.params['a1'].value tarr = np.linspace(dt[select][0], dt[select][-1], 200) if sech: fmod = rect_sechmod(tarr, depth * 2, tc, w0 * p, a0, a1) else: fmod = model_transits.modeltransit([ fit.params['tc'].value, fit.params['b'].value, fit.params['Rs_a'].value, fit.params['Rp_Rs'].value, 1, fit.params['gamma1'].value, fit.params['gamma2'].value ], model_transits.occultquad, p, tarr) fmod *= (fit.params['a0'].value + fit.params['a1'].value * tarr) ax[cnt % 8].plot(tarr, fmod, color='r') valid_trans.append(i) except TypeError: midpts += len(good) * [np.nan] epochs += len(good) * [np.nan] err.append(np.nan) print 'Fit failed' pass else: midpts += len(good) * [np.nan] err.append(np.nan) epochs += len(good) * [np.nan] print 'Too few data points' if plots and ((cnt % 8 == 7) or (i == end - 1)): plt.savefig('outputs/' + name + 'alltrans' + str(ceil(cnt / 8. + 0.01)) + '.pdf', dpi=150, bbox_inches='tight') if plotbad or (len(select) > 5): cnt += 1 print 'total transits:', cnt epochs = np.array(epochs) print 'good transits:', np.unique(epochs[np.where(~np.isnan(epochs))[0]]) return np.array(dt_all), epochs, np.array(midpts), np.array(err)