def get_transit_model(time, k=0.1, u=[0.4, 0.1], t0=0.1, p=3., a=10., i=np.deg2rad(90.), error_sigma=0.): tm = MA(supersampling=12, nthr=1) error = np.random.normal(0., error_sigma, len(time)) flux = error + tm.evaluate(t=time, k=k, u=u, t0=t0, p=p, a=a, i=i) return flux
def __init__(self, time, flux, nthreads=1): # Set up the transit model # ------------------------ self.tm = MA(interpolate=True, klims=(0.08, 0.13), nthr=nthreads) self.nthr = nthreads # Initialise data # --------------- self.time = time.copy() if time is not None else array([]) self.flux_o = flux.copy() if flux is not None else array([]) self.npt = self.time.size # Set the optimiser and the MCMC sampler # -------------------------------------- self.de = None self.sampler = None # Set up the parametrisation and priors # ------------------------------------- psystem = [ GParameter('tc', 'zero_epoch', 'd', NP(1.01, 0.02), (-inf, inf)), GParameter('pr', 'period', 'd', NP(2.50, 1e-7), (0, inf)), GParameter('rho', 'stellar_density', 'g/cm^3', UP(0.90, 2.50), (0.90, 2.5)), GParameter('b', 'impact_parameter', 'R_s', UP(0.00, 1.00), (0.00, 1.0)), GParameter('k2', 'area_ratio', 'A_s', UP(0.08**2, 0.13**2), (1e-8, inf)) ] pld = [ PParameter('q1', 'q1_coefficient', '', UP(0, 1), bounds=(0, 1)), PParameter('q2', 'q2_coefficient', '', UP(0, 1), bounds=(0, 1)) ] pbl = [ LParameter('es', 'white_noise', '', UP(1e-6, 1e-2), bounds=(1e-6, 1e-2)) ] per = [ LParameter('bl', 'baseline', '', NP(1.00, 0.001), bounds=(0.8, 1.2)) ] self.ps = ParameterSet() self.ps.add_global_block('system', psystem) self.ps.add_passband_block('ldc', 2, 1, pld) self.ps.add_lightcurve_block('baseline', 1, 1, pbl) self.ps.add_lightcurve_block('error', 1, 1, per) self.ps.freeze()
def __init__(self, time, flux, airmass, tcenter, tduration, priors, nthr=4, tmodel=None, verbosity=0): self.tmodel = tmodel or MandelAgol(nthr=nthr, lerp=False) self.nldc = tmodel.nldc self.time = asarray(time) self.flux = atleast_2d(flux) self.airmass = asarray(airmass) self.npt = self.flux.shape[0] self.npb = self.flux.shape[1] self.mask_oot = (self.time < tcenter-0.55*tduration) | (self.time > tcenter+0.55*tduration) self.ld = zeros(2*self.npb) self.informative_limb_darkening = False self.verbosity = verbosity self.baseline = zeros_like(self.flux) self.tmparr = zeros_like(self.flux) elc = [f[self.mask_oot].std() for f in self.flux.T] self.priors = [priors['transit_center'], ## 0 transit center, required priors['period'], ## 1 period, required priors['stellar_density'], ## 2 stellar density, required priors.get('impact_parameter', UP(0.0, 0.99, 'b'))] ## 3 impact parameter kmin, kmax = priors['radius_ratio'].limits() for i in range(self.npb): self.priors.append(UP(kmin**2, kmax**2, 'k2_{}'.format(i))) ## as + i squared radius ratios for i in range(self.npb): self.priors.append(UP(0.15*elc[i], 2*elc[i], 'el_{}'.format(i))) ## es + i point-to-point scatter for i in range(self.npb): for j in range(self.nldc): ldc_label = 'ldc_{:d}_{:d}'.format(i,j) if ldc_label in priors.keys(): if self.verbosity > 0: print ('Using an informative prior on limb darkening: ' + ldc_label) self.informative_limb_darkening = True self.priors.append(priors.get(ldc_label, UP(-0.5, 1, ldc_label))) ## ls + 0 + nldc*i ldc coefficients blmin, blmax = priors.get('baseline', UP(0.99,1.01)).limits() for i in range(self.npb): self.priors.extend([UP( blmin, blmax, 'bl_{}'.format(i)), ## bs + 0 + 2*i baseline level UP( -0.020, 0.020, 'am_{}'.format(i))]) ## bs + 1 + 2*i airmass correction self.ps = PriorSet(self.priors) ks = self.k2_start = 4 es = self.err_start = ks+self.npb ls = self.ldc_start = es+self.npb bs = self.baseline_start = ls + self.nldc*self.npb self.k2_slice = s_[ks:es] self.err_slice = s_[es:ls] self.ldc_slice = s_[ls:bs] self.bsl_slices = [s_[bs+2*i:bs+2*(i+1)] for i in range(self.npb)]
def __init__(self, time, flux, airmass, tcenter, tduration, priors, nthr=4, tmodel=None): self.tmodel = tmodel or MandelAgol(nthr=nthr, lerp=True) self.time = asarray(time) self.flux = asarray(flux) self.airmass = asarray(airmass) self.npb = self.flux.shape[1] self.mask_oot = (self.time < tcenter-0.55*tduration) | (self.time > tcenter+0.55*tduration) self.ld = zeros(2*self.npb) self.baseline = zeros_like(self.flux) self.tmparr = zeros_like(self.flux) elc = [f[self.mask_oot].std() for f in self.flux.T] self.priors = [priors['transit_center'], ## 0 transit center, required priors['period'], ## 1 period, required priors['stellar_density'], ## 2 stellar density, required priors.get('impact_parameter', UP(0.0, 0.99, 'b'))] ## 3 impact parameter kmin, kmax = priors['radius_ratio'].limits() for i in range(self.npb): self.priors.append(UP(kmin**2, kmax**2, 'k2_{}'.format(i))) ## as + i squared radius ratios for i in range(self.npb): self.priors.append(UP(0.15*elc[i], 2*elc[i], 'el_{}'.format(i))) ## es + i point-to-point scatter for i in range(self.npb): self.priors.extend([UP( 0.0001, 1, 'u_{}'.format(i)), ## ls + 0 + 2*i linear ldc UP( 0.0001, 1, 'v_{}'.format(i))]) ## ls + 1 + 2*i quadratic ldc blmin, blmax = priors.get('baseline', UP(0.99,1.01)).limits() for i in range(self.npb): self.priors.extend([UP( blmin, blmax, 'bl_{}'.format(i)), ## bs + 0 + 2*i baseline level UP( 0.000, 0.020, 'am_{}'.format(i))]) ## bs + 1 + 2*i airmass correction self.ps = PriorSet(self.priors) ks = self.k2_start = 4 es = self.err_start = ks+self.npb ls = self.ldc_start = es+self.npb bs = self.baseline_start = ls + 2*self.npb self.k2_slice = s_[ks:es] self.err_slice = s_[es:ls] self.ldc_slice = s_[ls:bs] self.bsl_slices = [s_[bs+2*i:bs+2*(i+1)] for i in range(self.npb)]
def __init__(self, time, flux, nthreads=1): # Set up the transit model # ------------------------ self.tm = MA(interpolate=True, klims=(0.08, 0.13), nthr=nthreads) self.nthr = nthreads # Initialise data # --------------- self.time = time.copy() if time is not None else array([]) self.flux_o = flux.copy() if flux is not None else array([]) self.npt = self.time.size # Set the optimiser and the MCMC sampler # -------------------------------------- self.de = None self.sampler = None # Set up the parametrisation and priors # ------------------------------------- psystem = [ GParameter('tc', 'zero_epoch', 'd', NP(1.01, 0.02), (-inf, inf)), GParameter('pr', 'period', 'd', NP(2.50, 1e-7), (0, inf)), GParameter('rho', 'stellar_density', 'g/cm^3', UP(0.90, 2.50), (0.90, 2.5)), GParameter('b', 'impact_parameter', 'R_s', UP(0.00, 1.00), (0.00, 1.0)), GParameter('k2', 'area_ratio', 'A_s', UP(0.08 ** 2, 0.13 ** 2), (1e-8, inf))] pld = [ PParameter('q1', 'q1_coefficient', '', UP(0, 1), bounds=(0, 1)), PParameter('q2', 'q2_coefficient', '', UP(0, 1), bounds=(0, 1))] pbl = [LParameter('es', 'white_noise', '', UP(1e-6, 1e-2), bounds=(1e-6, 1e-2))] per = [LParameter('bl', 'baseline', '', NP(1.00, 0.001), bounds=(0.8, 1.2))] self.ps = ParameterSet() self.ps.add_global_block('system', psystem) self.ps.add_passband_block('ldc', 2, 1, pld) self.ps.add_lightcurve_block('baseline', 1, 1, pbl) self.ps.add_lightcurve_block('error', 1, 1, per) self.ps.freeze()
def fit_transit(self, pv_init, time, flux, period_fit_prior=None, t0_fit_prior=None): """ Fit folded transit """ pbls = pv_init[0] t0bls = pv_init[1] self.tm = MA(supersampling=30, nthr=1) #self.time_fitting = self.t#self.df_folded.time #self.flux_fitting = self.f#self.df_folded.flux def minfun(pv): if any(pv <= 0) or (pv[3] <= 1) or (pv[4] > 1) or not ( 0.75 < pv[0] < 80.) or abs(pv[0] - pbls) > 0.1: return np.inf if period_fit_prior is not None: if (pv[0] < period_fit_prior[0]) or (pv[0] > period_fit_prior[1]): return np.inf if t0_fit_prior is not None: if (pv[1] < t0_fit_prior[0]) or (pv[1] > t0_fit_prior[1]): return np.inf elif abs(pv[1] - t0bls) > 0.4: return np.inf return -ll_normal_ev_py(flux, self.transit_model(pv, time), 1e-5) self.mr = minimize(minfun, pv_init, method='Nelder-Mead') mr = self.mr #mr = minimize(minfun, self.pv_bls, method='powell') self.pv_min = self.mr.x print(mr.message) lnlike, x = -mr.fun, mr.x
import numpy as np import matplotlib.pyplot as pl from pytransit import Gimenez, MandelAgol, z_circular m_mad = MandelAgol() m_mal = MandelAgol(interpolate=True) m_gmd = Gimenez(interpolate=False) m_gml = Gimenez(interpolate=True) u = np.array([[0.1, 0.1], [0.2, 0.2], [0.6, 0.3]]) t = np.linspace(-0.2, 0.2, 500) pl.plot(t, m_mad.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47 * np.pi), 'b-', alpha=0.5) pl.plot(t, m_mal.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47 * np.pi), 'r-', alpha=0.5) pl.plot(t, m_gmd.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47 * np.pi), 'k--', alpha=1.0) pl.show()
import numpy as np import matplotlib.pyplot as pl from pytransit import Gimenez, MandelAgol, MandelAgolCL, z_circular mgfd = Gimenez() mgfl = Gimenez(lerp=True) macl = MandelAgolCL() mafl = MandelAgol(lerp=True) mafd = MandelAgol(lerp=False) u = [[0.1,0.0], [0.2,0.05], [0.5,0.4]] u1 = [0.5,0.4] t = np.linspace(-0.2, 0.2, 500) pl.plot(t, mafd.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi), ls='-', c='0.5', lw=1, alpha=0.5) #, drawstyle='steps-mid') pl.plot(t, macl.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi), 'b-', alpha=0.5) #, drawstyle='steps-mid') pl.plot(t, mgfd.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi)+1e-4, 'b-', alpha=0.5) #, drawstyle='steps-mid') pl.plot(t, mgfl.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi)+2e-4, 'b-', alpha=0.5) #, drawstyle='steps-mid') #pl.plot(t, mafl.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi), ls='--', c='0.5', lw=3, alpha=0.5) #, drawstyle='steps-mid') #pl.plot(t, mafl.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi), 'k-', alpha=0.5) #, drawstyle='steps-mid') #pl.plot(t, macl.evaluate(t, 0.1, u1, 0.0, 5, 5, 0.47*np.pi), 'b--', alpha=0.5) #, drawstyle='steps-mid') pl.ylim(0.98,1.005) pl.xlim(-0.2,0.2) pl.show()
def __init__(self, infile, inject=False, **kwargs): self.d = d = pf.getdata(infile, 1) m = isfinite(d.flux_1) & (~(d.mflags_1 & 2**3).astype(np.bool)) m &= ~binary_dilation((d.quality & 2**20) != 0) self.Kp = pf.getval(infile, 'kepmag') self.Kp = self.Kp if not isinstance(self.Kp, Undefined) else nan self.tm = MA(supersampling=12, nthr=1) self.em = MA(supersampling=10, nldc=0, nthr=1) self.epic = int(basename(infile).split('_')[1]) self.time = d.time[m] self.flux = (d.flux_1[m] - d.trend_t_1[m] + nanmedian(d.trend_t_1[m]) - d.trend_p_1[m] + nanmedian(d.trend_p_1[m])) self.mflux = nanmedian(self.flux) self.flux /= self.mflux self.flux_e = d.error_1[m] / abs(self.mflux) self.flux_r = d.flux_1[m] / self.mflux self.trend_t = d.trend_t_1[m] / self.mflux self.trend_p = d.trend_p_1[m] / self.mflux self.period_range = kwargs.get( 'period_range', (0.7, 0.98 * (self.time.max() - self.time.min()))) self.nbin = kwargs.get('nbin', 900) self.qmin = kwargs.get('qmin', 0.002) self.qmax = kwargs.get('qmax', 0.115) self.nf = kwargs.get('nfreq', 10000) self.bls = BLS(self.time, self.flux, self.flux_e, period_range=self.period_range, nbin=self.nbin, qmin=self.qmin, qmax=self.qmax, nf=self.nf, pmean='running_median') def ndist(p=0.302): return 1. - 2 * abs(((self.bls.period - p) % p) / p - 0.5) def cmask(s=0.05): return 1. - np.exp(-ndist() / s) self.bls.pmul = cmask() try: ar, ac, ap, at = acor(self.flux_r)[0], acor(self.flux)[0], acor( self.trend_p)[0], acor(self.trend_t)[0] except RuntimeError: ar, ac, ap, at = nan, nan, nan, nan self.lcinfo = array( (self.epic, self.mflux, self.flux.std(), nan, nan, ar, ac, ap, at), dtype=dt_lcinfo) self._rbls = None self._rtrf = None self._rvar = None self._rtoe = None self._rpol = None self._recl = None ## Transit fit pv [k u t0 p a i] self._pv_bls = None self._pv_trf = None self.period = None self.zero_epoch = None self.duration = None
def __init__(self, infile, inject=False, **kwargs): self.d = d = pf.getdata(infile,1) m = isfinite(d.flux_1) & (~(d.mflags_1 & 2**3).astype(np.bool)) m &= ~binary_dilation((d.quality & 2**20) != 0) self.Kp = pf.getval(infile,'kepmag') self.Kp = self.Kp if not isinstance(self.Kp, Undefined) else nan self.tm = MA(supersampling=12, nthr=1) self.em = MA(supersampling=10, nldc=0, nthr=1) self.epic = int(basename(infile).split('_')[1]) self.time = d.time[m] self.flux = (d.flux_1[m] - d.trend_t_1[m] + nanmedian(d.trend_t_1[m]) - d.trend_p_1[m] + nanmedian(d.trend_p_1[m])) self.mflux = nanmedian(self.flux) self.flux /= self.mflux self.flux_e = d.error_1[m] / abs(self.mflux) self.flux_r = d.flux_1[m] / self.mflux self.trend_t = d.trend_t_1[m] / self.mflux self.trend_p = d.trend_p_1[m] / self.mflux self.period_range = kwargs.get('period_range', (0.7,0.98*(self.time.max()-self.time.min()))) self.nbin = kwargs.get('nbin',900) self.qmin = kwargs.get('qmin',0.002) self.qmax = kwargs.get('qmax',0.115) self.nf = kwargs.get('nfreq',10000) self.bls = BLS(self.time, self.flux, self.flux_e, period_range=self.period_range, nbin=self.nbin, qmin=self.qmin, qmax=self.qmax, nf=self.nf, pmean='running_median') def ndist(p=0.302): return 1.-2*abs(((self.bls.period-p)%p)/p-0.5) def cmask(s=0.05): return 1.-np.exp(-ndist()/s) self.bls.pmul = cmask() try: ar,ac,ap,at = acor(self.flux_r)[0], acor(self.flux)[0], acor(self.trend_p)[0], acor(self.trend_t)[0] except RuntimeError: ar,ac,ap,at = nan,nan,nan,nan self.lcinfo = array((self.epic, self.mflux, self.flux.std(), nan, nan, ar, ac, ap, at), dtype=dt_lcinfo) self._rbls = None self._rtrf = None self._rvar = None self._rtoe = None self._rpol = None self._recl = None ## Transit fit pv [k u t0 p a i] self._pv_bls = None self._pv_trf = None self.period = None self.zero_epoch = None self.duration = None
parser = argparse.ArgumentParser(description="plot the results of fitting" "PLD-corrected Spitzer light curves") parser.add_argument('setup', help='path to the setup file for the star/planet') parser.add_argument('data', help='path to the corrected data') parser.add_argument('fit', help='path to the JSON fit results') parser.add_argument('-b', '--binsize', help='override automatic bin size', type=int, default=None) args = parser.parse_args() def auto_bin(t): p2 = [2**i for i in range(10)] ts_len = len(t) bs = min(p2, key=lambda x:abs(x-ts_len/128.)) return bs m = MandelAgol() setup = yaml.load(open(args.setup)) t,f,s = np.loadtxt(args.data).T params = yaml.load(open(args.fit)) if args.binsize: bs = args.binsize else: bs = auto_bin(t) outfile = args.fit.replace('.json','_pub_plot.pdf') #k,t0,a,i = [params['mode_mcmc1'].get(j) for j in 'k,t0,a,i'.split(',')] k,t0,a,i = [params['mu_mcmc1'].get(j) for j in 'k,t0,a,i'.split(',')] u, p = [setup['astro'].get(j) for j in 'u,p'.split(',')]
def test_mai_special_z(self): """Test the interpolated Mandel & Agol model with z in [0,k,1-k,1,1+k]""" tm = MandelAgol(interpolate=True, klims=[0.09, 1.11]) npt.assert_array_almost_equal(tm(self.z, self.k, self.u), self.f, decimal=4)
def test_mad_special_z(self): """Test the direct Mandel & Agol model with z in [0,k,1-k,1,1+k]""" tm = MandelAgol(interpolate=False) npt.assert_array_almost_equal(tm(self.z, self.k, self.u), self.f, decimal=4)
def test_mai_multiband(self): self.mbt(MandelAgol(interpolate=True))
def test_mai_singleband(self): self.sbt(MandelAgol(interpolate=True))
def test_mad_multiband(self): self.mbt(MandelAgol(interpolate=False))
def test_mad_singleband(self): self.sbt(MandelAgol(interpolate=False))
class LPFunction(object): """A basic log posterior function class. """ def __init__(self, time, flux, nthreads=1): # Set up the transit model # ------------------------ self.tm = MA(interpolate=True, klims=(0.08, 0.13), nthr=nthreads) self.nthr = nthreads # Initialise data # --------------- self.time = time.copy() if time is not None else array([]) self.flux_o = flux.copy() if flux is not None else array([]) self.npt = self.time.size # Set the optimiser and the MCMC sampler # -------------------------------------- self.de = None self.sampler = None # Set up the parametrisation and priors # ------------------------------------- psystem = [ GParameter('tc', 'zero_epoch', 'd', NP(1.01, 0.02), (-inf, inf)), GParameter('pr', 'period', 'd', NP(2.50, 1e-7), (0, inf)), GParameter('rho', 'stellar_density', 'g/cm^3', UP(0.90, 2.50), (0.90, 2.5)), GParameter('b', 'impact_parameter', 'R_s', UP(0.00, 1.00), (0.00, 1.0)), GParameter('k2', 'area_ratio', 'A_s', UP(0.08**2, 0.13**2), (1e-8, inf)) ] pld = [ PParameter('q1', 'q1_coefficient', '', UP(0, 1), bounds=(0, 1)), PParameter('q2', 'q2_coefficient', '', UP(0, 1), bounds=(0, 1)) ] pbl = [ LParameter('es', 'white_noise', '', UP(1e-6, 1e-2), bounds=(1e-6, 1e-2)) ] per = [ LParameter('bl', 'baseline', '', NP(1.00, 0.001), bounds=(0.8, 1.2)) ] self.ps = ParameterSet() self.ps.add_global_block('system', psystem) self.ps.add_passband_block('ldc', 2, 1, pld) self.ps.add_lightcurve_block('baseline', 1, 1, pbl) self.ps.add_lightcurve_block('error', 1, 1, per) self.ps.freeze() def compute_baseline(self, pv): """Constant baseline model""" return full_like(self.flux_o, pv[8]) def compute_transit(self, pv): """Transit model""" _a = as_from_rhop( pv[2], pv[1] ) # Scaled semi-major axis from stellar density and orbital period _i = mt.acos( pv[3] / _a) # Inclination from impact parameter and semi-major axis _k = mt.sqrt(pv[4]) # Radius ratio from area ratio a, b = mt.sqrt(pv[5]), 2 * pv[6] _uv = array([a * b, a * (1. - b)]) # Quadratic limb darkening coefficients return self.tm.evaluate(self.time, _k, _uv, pv[0], pv[1], _a, _i) def compute_lc_model(self, pv): """Combined baseline and transit model""" return self.compute_baseline(pv) * self.compute_transit(pv) def lnprior(self, pv): """Log prior""" if any(pv < self.ps.lbounds) or any(pv > self.ps.ubounds): return -inf else: return self.ps.lnprior(pv) def lnlikelihood(self, pv): """Log likelihood""" flux_m = self.compute_lc_model(pv) return ll_normal_es(self.flux_o, flux_m, pv[7]) def lnposterior(self, pv): """Log posterior""" lnprior = self.lnprior(pv) if isinf(lnprior): return lnprior else: return lnprior + self.lnlikelihood(pv) def create_pv_population(self, npop=50): return self.ps.sample_from_prior(npop) def optimize(self, niter=200, npop=50, population=None, label='Optimisation'): """Global optimisation using Differential evolution""" if self.de is None: self.de = DiffEvol(self.lnposterior, clip(self.ps.bounds, -1, 1), npop, maximize=True) if population is None: self.de._population[:, :] = self.create_pv_population(npop) else: self.de._population[:, :] = population for _ in tqdm(self.de(niter), total=niter, desc=label): pass def sample(self, niter=500, thin=5, label='MCMC sampling', reset=False): """MCMC sampling using emcee""" if self.sampler is None: self.sampler = EnsembleSampler(self.de.n_pop, self.de.n_par, self.lnposterior) pop0 = self.de.population else: pop0 = self.sampler.chain[:, -1, :].copy() if reset: self.sampler.reset() for _ in tqdm(self.sampler.sample(pop0, iterations=niter, thin=thin), total=niter, desc=label): pass
class EPICBLSMULTI(object): KEPLER_JD_OFFSET = 2454833.0 limbdark = [0.4, 0.1] mask = [] def __init__(self, epicname=None, time=None, flux=None): self.epicname = epicname self.time = time self.flux = flux if epicname is not None: self.star = k2help.EverestGK(epicname) self.star.get_flattened_flux(plot=False) #self.flux_savgol = everest.math.SavGol(np.delete(self.star.flux,self.star.mask),win=win) #self.flux_savgol_norm = self.flux_savgol/np.median(self.flux_savgol) if self.time is None and self.flux is None: self.star.transitmask = np.append(self.star.transitmask, self.mask) self.t = np.delete(self.star.time, self.star.mask) self.f = self.star.flux_savgol_norm else: self.t = self.time #np.delete(self.star.time,self.star.mask) self.f = self.flux #self.star.flux_savgol_norm def __call__(self, qmi=0.02, qma=0.25, df=0.0001, nf=10000, nb=1000, fmin=1. / 50., dur=0.2, period_range=None, plot=False, win=49, period_fit_prior=None, t0_fit_prior=None): self.bb = blsMOD.blsMOD(self.t, self.f, nf, fmin, df, nb, qmi, qma, period_range) print("Computing bls...") self.bb.compute() self.pv_bls = [ self.bb._best_period, self.bb._epoch, np.sqrt(self.bb._depth), as_from_rhop(2.5, self.bb._best_period), 0.1 ] self.fit_transit(pv_init=self.pv_bls, time=self.t, flux=self.f, period_fit_prior=period_fit_prior, t0_fit_prior=t0_fit_prior) print("Per=", self.pv_min[0], "epoch=", self.pv_min[1]) if plot: self.fig, self.ax = plt.subplots(nrows=4) self.bb.plot_power_spectrum(inverse=True, ax=self.ax.flat[0]) self.bb.plot_folded(ax=self.ax.flat[1]) self.bb.plot_transits(ax=self.ax.flat[2]) if self.time is not None: self.t_folded, self.f_folded = k2help.fold_transit_everest( self.t, self.f, t0=self.bb._epoch, period=self.bb._best_period, dur=dur) self.ax.flat[3].plot(self.t_folded, self.f_folded, "k.", label="BLS", alpha=0.5) self.t_folded, self.f_folded = k2help.fold_transit_everest( self.t, self.f, t0=self.pv_min[1], period=self.pv_min[0], dur=dur) self.ax.flat[3].plot(self.t_folded, self.f_folded, "r.", label="Best Fit", markersize=5) self.ax.flat[3].legend(loc="lower left", fontsize=8) else: self.t_folded, self.f_folded = self.star.get_folded_transit( t0=self.bb._epoch, period=self.bb._best_period, dur=dur, plot=False) self.ax.flat[3].plot(self.t_folded, self.f_folded, "k.", label="BLS", alpha=0.5) self.t_folded, self.f_folded = self.star.get_folded_transit( t0=self.pv_min[1], period=self.pv_min[0], dur=dur, plot=False) self.ax.flat[3].plot(self.t_folded, self.f_folded, "r.", label="Best Fit", markersize=5) self.ax.flat[3].legend(loc="lower left", fontsize=8) def fit_transit(self, pv_init, time, flux, period_fit_prior=None, t0_fit_prior=None): """ Fit folded transit """ pbls = pv_init[0] t0bls = pv_init[1] self.tm = MA(supersampling=30, nthr=1) #self.time_fitting = self.t#self.df_folded.time #self.flux_fitting = self.f#self.df_folded.flux def minfun(pv): if any(pv <= 0) or (pv[3] <= 1) or (pv[4] > 1) or not ( 0.75 < pv[0] < 80.) or abs(pv[0] - pbls) > 0.1: return np.inf if period_fit_prior is not None: if (pv[0] < period_fit_prior[0]) or (pv[0] > period_fit_prior[1]): return np.inf if t0_fit_prior is not None: if (pv[1] < t0_fit_prior[0]) or (pv[1] > t0_fit_prior[1]): return np.inf elif abs(pv[1] - t0bls) > 0.4: return np.inf return -ll_normal_ev_py(flux, self.transit_model(pv, time), 1e-5) self.mr = minimize(minfun, pv_init, method='Nelder-Mead') mr = self.mr #mr = minimize(minfun, self.pv_bls, method='powell') self.pv_min = self.mr.x print(mr.message) lnlike, x = -mr.fun, mr.x def mask_planet(self, planet=None, P=None, T0=None, dur=0.2): print("Masking planet with:") if planet is not None: print("Using planet", planet._pl_name, "to mask") P = planet._pl_orbper T0 = planet._pl_tranmid - k2help.KEPLER_JD_OFFSET print("T0=", T0) print("P=", P) self.mask = k2help.mask_planet_everest(self.t, T0, P, dur=dur) self.t = np.delete(self.t, self.mask) self.f = np.delete(self.f, self.mask) def get_nexoplanet(self, pv=None, epicname=None): if pv is None: pv = self.pv_min self._pl_orbper = pv[0] self._pl_tranmid = pv[1] + self.KEPLER_JD_OFFSET self._pl_ratror = pv[2] self._pl_ratdor = pv[3] self._pl_orbincl = np.rad2deg(mt.acos(pv[4] / pv[3])) self._pl_trandur = exoplanet_functions.calc_transit_duration( self._pl_orbper, self._pl_ratror, self._pl_ratdor, np.deg2rad(self._pl_orbincl)) if epicname is not None: self.k2star = k2help.K2Star(epicname) self.planet = self.k2star.get_nexopl() self.planet._pl_tranmid = self._pl_tranmid self.planet._pl_orbper = self._pl_orbper self.planet._pl_trandur = self._pl_trandur self.planet._pl_ratror = self._pl_ratror self.planet._pl_ratdor = self._pl_ratdor self.planet._pl_orbincl = self._pl_orbincl self.planet._pl_orbeccen = 0. self.planet._pl_trandep = self.planet._pl_ratror**2. return self.planet else: print("pl_orbper", self._pl_orbper) print("pl_tranmid", self._pl_tranmid) print("pl_ratror", self._pl_ratror) print("pl_ratdor", self._pl_ratdor) print("pl_orbincl", self._pl_orbincl) print("pl_trandur", self._pl_trandur) def transit_model(self, pv, time): """ Define the transit model for a given pv vector INPUT: pv[0] - period pv[1] - epoch (0) pv[2] - Rp/Rs (sqrt(depth)) pv[3] - a/Rs (estimate from stellar density) pv[4] - impact param """ #time = self.time_fitting if time is None else time #time p, t0, RpRs, aRs, dur = pv _i = mt.acos(pv[4] / pv[3]) return self.tm.evaluate(time, RpRs, self.limbdark, t0, p, aRs, _i, e=0.0, w=0.0, c=0.0) def plot_lc_simple(self, pv=None, time=None, flux=None, ax=None, OFFSET=0.99): if pv is None: pv = self.pv_min if time is None or flux is None: time = self.t flux = self.f if ax == None: fig, self.ax = plt.subplots() else: self.ax = ax self.ax.plot(time, flux, label="Data") self.ax.plot(time, flux - self.transit_model(pv, time) + OFFSET, label="Residual") self.ax.plot(time, self.transit_model(pv, time), label="Best fit model") self.ax.legend(loc="lower left", fontsize=9) def plot_lc(self, pv, time=None, flux=None, ax=None, OFFSET=0.99, p_fold=None, t0_fold=None, dur_fold=0.2): if time is None or flux is None: time = self.t flux = self.f if ax == None: fig, self.ax = plt.subplots() else: self.ax = ax if p_fold is not None and t0_fold is not None: time, flux = k2help.fold_transit_everest(time, flux, t0=t0_fold, period=p_fold, dur=dur_fold) pv[1] = 0. tt = np.linspace(time.min(), time.max(), 2000) self.ax.plot(time, flux, label="Data") self.ax.plot(time, flux - self.transit_model(pv, time) + OFFSET, label="Residual") self.ax.plot(time, self.transit_model(pv, time), label="Best fit model") self.ax.legend(loc="lower left", fontsize=9) self.ax.grid(lw=0.5, alpha=0.3) def plot_lc_min(self, time=None, flux=None, ax=None, OFFSET=0.99, fold_best=True, dur_fold=0.2): if fold_best: p_fold = self.pv_min[0] t0_fold = self.pv_min[1] else: p_fold = None t0_fold = None self.plot_lc(self.pv_min, time, flux, ax=ax, OFFSET=OFFSET, p_fold=p_fold, t0_fold=t0_fold, dur_fold=dur_fold)
import numpy as np import matplotlib.pyplot as pl from pytransit import Gimenez, MandelAgol k, t0, p, a, i, e, w = 0.1, 1., 4., 8., 0.5 * np.pi, 0.01, 0.5 * np.pi t = np.linspace(0.9, 1.1, 20) #u = np.array([[0.04*iu, 0.025*iu, 0.01*iu] for iu in range(21)]) u = np.array([[0.04 * iu, 0.025 * iu] for iu in range(4)]) c = np.linspace(0, 0.9, u.shape[0]) * 0 m = Gimenez(lerp=True, npol=100, nldc=2) m = MandelAgol(lerp=True, nthr=4) f = m.evaluate(t, k, u, t0, p, a, i, e, w, c=c) fig, ax = pl.subplots(1, 1, figsize=(7, 7)) ax.plot(t, f + np.arange(u.shape[0]) * 0.00, 'k') pl.setp(ax, ylim=(0.9875, 1.011), yticks=[], xlabel='Time [d]', ylabel='Normalised flux', title='Light curve for a set of multiple limb darkening coefficients') fig.tight_layout() pl.show()
class TransitSearch(object): """kepler transit search and candidate vetting Overview -------- The main idea is that we carry out a basic BLS search, continue with several model fits, and fit all the (possibly sensible) statistics to a random forest classifier. Transit search - BLS Transit fitting - basic transit fitting - even-odd transit fitting - calculation of per-orbit average log likelihoods - (Secondary eclipse search, not implemented) Sine fitting - fits a sine curve to the data to test for variability """ def __init__(self, infile, inject=False, **kwargs): self.d = d = pf.getdata(infile,1) m = isfinite(d.flux_1) & (~(d.mflags_1 & 2**3).astype(np.bool)) m &= ~binary_dilation((d.quality & 2**20) != 0) self.Kp = pf.getval(infile,'kepmag') self.Kp = self.Kp if not isinstance(self.Kp, Undefined) else nan self.tm = MA(supersampling=12, nthr=1) self.em = MA(supersampling=10, nldc=0, nthr=1) self.epic = int(basename(infile).split('_')[1]) self.time = d.time[m] self.flux = (d.flux_1[m] - d.trend_t_1[m] + nanmedian(d.trend_t_1[m]) - d.trend_p_1[m] + nanmedian(d.trend_p_1[m])) self.mflux = nanmedian(self.flux) self.flux /= self.mflux self.flux_e = d.error_1[m] / abs(self.mflux) self.flux_r = d.flux_1[m] / self.mflux self.trend_t = d.trend_t_1[m] / self.mflux self.trend_p = d.trend_p_1[m] / self.mflux self.period_range = kwargs.get('period_range', (0.7,0.98*(self.time.max()-self.time.min()))) self.nbin = kwargs.get('nbin',900) self.qmin = kwargs.get('qmin',0.002) self.qmax = kwargs.get('qmax',0.115) self.nf = kwargs.get('nfreq',10000) self.bls = BLS(self.time, self.flux, self.flux_e, period_range=self.period_range, nbin=self.nbin, qmin=self.qmin, qmax=self.qmax, nf=self.nf, pmean='running_median') def ndist(p=0.302): return 1.-2*abs(((self.bls.period-p)%p)/p-0.5) def cmask(s=0.05): return 1.-np.exp(-ndist()/s) self.bls.pmul = cmask() try: ar,ac,ap,at = acor(self.flux_r)[0], acor(self.flux)[0], acor(self.trend_p)[0], acor(self.trend_t)[0] except RuntimeError: ar,ac,ap,at = nan,nan,nan,nan self.lcinfo = array((self.epic, self.mflux, self.flux.std(), nan, nan, ar, ac, ap, at), dtype=dt_lcinfo) self._rbls = None self._rtrf = None self._rvar = None self._rtoe = None self._rpol = None self._recl = None ## Transit fit pv [k u t0 p a i] self._pv_bls = None self._pv_trf = None self.period = None self.zero_epoch = None self.duration = None def create_transit_arrays(self): p = self._rbls['bls_period'] tc = self._rbls['bls_zero_epoch'] dur = max(0.15, self._rbls['bls_duration']) tid_arr = np.round((self.time - tc) / p).astype(np.int) tid_arr -= tid_arr.min() tids = unique(tid_arr) phase = p*(fold(self.time, p, tc, shift=0.5) - 0.5) pmask = abs(phase) < 5*dur self.times = [self.time[tid_arr==tt] for tt in unique(tids)] self.fluxes = [self.flux[tid_arr==tt] for tt in unique(tids)] self.flux_es = [self.flux_e[tid_arr==tt] for tt in unique(tids)] self.time_even = concatenate(self.times[0::2]) self.time_odd = concatenate(self.times[1::2]) self.flux_even = concatenate(self.fluxes[0::2]) self.flux_odd = concatenate(self.fluxes[1::2]) self.flux_e_even = concatenate(self.flux_es[0::2]) self.flux_e_odd = concatenate(self.flux_es[1::2]) @property def result(self): return merge_arrays([self.lcinfo, self._rbls, self._rtrf, self._rvar, self._rtoe, self._rpol, self._recl], flatten=True) def __call__(self): """Runs a BLS search, fits a transit, and fits an EB model""" self.run_bls() self.fit_transit() self.fit_variability() self.fit_even_odd() self.per_orbit_likelihoods() self.test_eclipse() def run_bls(self): b = self.bls r = self.bls() self._rbls = array((b.bsde, b.tc, b.bper, b.duration, b.depth, sqrt(b.depth), floor(diff(self.time[[0,-1]])[0]/b.bper)), dt_blsresult) self._pv_bls = [b.bper, b.tc, sqrt(b.depth), as_from_rhop(2.5, b.bper), 0.1] self.create_transit_arrays() self.lcinfo['lnlike_constant'] = ll_normal_es(self.flux, ones_like(self.flux), self.flux_e) self.period = b.bper self.zero_epoch = b.tc self.duration = b.duration def fit_transit(self): def minfun(pv): if any(pv<=0) or (pv[3] <= 1) or (pv[4] > 1) or not (0.75<pv[0]<80) or abs(pv[0]-pbls) > 1.: return inf return -ll_normal_es(self.flux, self.transit_model(pv), self.flux_e) pbls = self._pv_bls[0] mr = minimize(minfun, self._pv_bls, method='powell') lnlike, x = -mr.fun, mr.x self._rtrf = array((lnlike, x[1], x[0], of.duration_circular(x[0],x[3],mt.acos(x[4]/x[3])), x[2]**2, x[2], x[3], x[4]), dt_trfresult) self._pv_trf = mr.x.copy() self.period = x[0] self.zero_epoch = x[1] self._rtrf['trf_duration'] def per_orbit_likelihoods(self): pv = self._pv_trf lnl = array([ll_normal_es(f, self.transit_model(pv, t), e) / t.size for t,f,e in zip(self.times, self.fluxes, self.flux_es)]) self._tr_lnlike_po = lnl self._tr_lnlike_med = lmed = median(lnl) self._tr_lnlike_std = lstd = lnl.std() self._tr_lnlike_max = lmax = (lnl.max() - lmed) / lstd self._tr_lnlike_min = lmin = (lnl.min() - lmed) / lstd self._rpol = array((lmed, lstd, lmax, lmin), dt_poresult) def fit_even_odd(self): def minfun(pv, time, flux, flux_e): if any(pv<=0) or (pv[3] <= 1) or (pv[4] > 1): return inf return -ll_normal_es(flux, self.transit_model(pv, time), flux_e) mr_even = minimize(minfun, self._pv_bls, args=(self.time_even, self.flux_even, self.flux_e_even), method='powell') mr_odd = minimize(minfun, self._pv_bls, args=(self.time_odd, self.flux_odd, self.flux_e_odd), method='powell') pvd = abs(mr_even.x - mr_odd.x) self._rtoe = array((-mr_even.fun-mr_odd.fun, pvd[2], pvd[3], pvd[4]), dt_oeresult) def fit_variability(self): def minfun(pv, period, zero_epoch): if any(pv<0): return inf dummy = [] for j in range(4): dummy.append(-ll_normal_es(self.flux, self.sine_model(pv, j*2*period, zero_epoch), self.flux_e)) return np.nanmin(dummy)#-ll_normal_es(self.flux, self.sine_model(pv, 2*period, zero_epoch), self.flux_e) mr = minimize(minfun, [self.flux.std()], args=(self._rbls['bls_period'],self._rbls['bls_zero_epoch']), method='powell') self._rvar = array((-mr.fun, mr.x), dt_varresult) def test_eclipse(self): self.ec_shifts = shifts = np.linspace(-0.2,0.2, 500) self.ec_ll0 = ll0 = self.eclipse_likelihood(0.0, 0.0) self.ec_ll1 = ll1 = array([self.eclipse_likelihood(0.01, shift) for shift in shifts]) ll1_max = ll1.max() self.ec_lnratio = lnlratio = log(exp(ll1-ll1_max).mean())+ll1_max - ll0 self._recl = array((self.ec_lnratio, self.ec_shifts[np.argmax(self.ec_lnratio)]), dt_ecresult) ## Models ## ------ def sine_model(self, pv, period, zero_epoch): return 1.+pv[0]*sin(2*pi/period*(self.time-zero_epoch) - 0.5*pi) def transit_model(self, pv, time=None): time = self.time if time is None else time _i = mt.acos(pv[4]/pv[3]) return self.tm.evaluate(time, pv[2], [0.4, 0.1], pv[1], pv[0], pv[3], _i) def eclipse_model(self, shift, time=None): time = self.time if time is None else time pv = self._pv_trf _i = mt.acos(pv[4]/pv[3]) return self.em.evaluate(time, pv[2], [], pv[1]+(0.5+shift)*pv[0], pv[0], pv[3], _i) def eclipse_likelihood(self, f, shift, time=None): return ll_normal_es(self.flux, (1-f)+f*self.eclipse_model(shift, time), self.flux_e) ## Plotting ## -------- def bplot(plotf): @wraps(plotf) def wrapper(self, ax=None, *args, **kwargs): if ax is None: fig, ax = subplots(1,1) try: plotf(self, ax, **kwargs) except ValueError: pass return ax return wrapper @bplot def plot_lc_time(self, ax=None): ax.plot(self.time, self.flux_r, lw=1) ax.plot(self.time, self.trend_t+2*(np.percentile(self.flux_r, [99])[0]-1), lw=1) ax.plot(self.time, self.trend_p+4*(np.percentile(self.flux_r, [99])[0]-1), lw=1) ax.plot(self.time, self.flux+1.1*(self.flux_r.min()-1), lw=1) [ax.axvline(self.bls.tc+i*self._rbls['bls_period'], alpha=0.25, ls='--', lw=1) for i in range(35)] setp(ax,xlim=self.time[[0,-1]], xlabel='Time', ylabel='Normalised flux') @bplot def plot_lc(self, ax=None, nbin=None): nbin = nbin or self.nbin r = rarr(self.result) period, t0, trdur = self._rbls['bls_period'], self._rbls['bls_zero_epoch'], self._rbls['bls_duration'] #r.trf_period, r.trf_zero_epoch, r.trf_duration phase = period*(fold(self.time, period, t0, shift=0.5) - 0.5) bp,bfo,beo = uf.bin(phase, self.flux, nbin) bp,bfm,bem = uf.bin(phase, self.transit_model(self._pv_trf), nbin) mo,mm = isfinite(bfo), isfinite(bfm) ax.plot(bp[mo], bfo[mo], '.') ax.plot(bp[mm], bfm[mm], 'k--', drawstyle='steps-mid') if self._rvar: flux_s = self.sine_model([self._rvar['sine_amplitude']], 2*period, t0) bp,bf,be = uf.bin(phase, flux_s, nbin) ax.plot(bp, bf, 'k:', drawstyle='steps-mid') setp(ax,xlim=bp[[0,-1]], xlabel='Phase [d]', ylabel='Normalised flux') setp(ax.get_yticklabels(), visible=False) ax.get_yaxis().get_major_formatter().set_useOffset(False) @bplot def plot_even_odd_lc(self, ax=None, nbin=None): nbin = nbin or self.nbin res = rarr(self.result) period, zero_epoch, duration = res.trf_period, res.trf_zero_epoch, res.trf_duration hdur = array([-0.5,0.5]) * duration for time,flux_o in ((self.time_even,self.flux_even), (self.time_odd,self.flux_odd)): phase = fold(time, period, zero_epoch, shift=0.5, normalize=False) - 0.5*period flux_m = self.transit_model(self._pv_trf, time) bpd,bfd,bed = uf.bin(phase, flux_o, nbin) bpm,bfm,bem = uf.bin(phase, flux_m, nbin) pmask = abs(bpd) < 1.5*duration omask = pmask & isfinite(bfd) mmask = pmask & isfinite(bfm) ax[0].plot(bpd[omask], bfd[omask], marker='o') ax[1].plot(bpm[mmask], bfm[mmask], marker='o') [a.axvline(0, alpha=0.25, ls='--', lw=1) for a in ax] [[a.axvline(hd, alpha=0.25, ls='-', lw=1) for hd in hdur] for a in ax] setp(ax,xlim=3*hdur, xlabel='Phase [d]', ylim=(0.9998*nanmin(bfd[pmask]), 1.0002*nanmax(bfd[pmask]))) setp(ax[0], ylabel='Normalised flux') setp(ax[1].get_yticklabels(), visible=False) @bplot def plot_transits(self, ax=None): offset = 1.1*scoreatpercentile([f.ptp() for f in self.fluxes], 95) twodur = 24*2*self.duration for i,(time,flux) in enumerate(zip(self.times, self.fluxes)[:10]): phase = 24*(fold(time, self.period, self.zero_epoch, 0.5, normalize=False) - 0.5*self.period) sids = argsort(phase) phase, flux = phase[sids], flux[sids] pmask = abs(phase) < 2.5*twodur if any(pmask): ax.plot(phase[pmask], flux[pmask]+i*offset, marker='o') setp(ax, xlim=(-twodur,twodur), xlabel='Phase [h]', yticks=[]) @bplot def plot_transit_fit(self, ax=None): res = rarr(self.result) period, zero_epoch, duration = res.trf_period, res.trf_zero_epoch, res.trf_duration hdur = 24*duration*array([-0.5,0.5]) flux_m = self.transit_model(self._pv_trf) phase = 24*(fold(self.time, period, zero_epoch, 0.5, normalize=False) - 0.5*period) sids = argsort(phase) phase = phase[sids] pmask = abs(phase) < 2*24*duration flux_m = flux_m[sids] flux_o = self.flux[sids] ax.plot(phase[pmask], flux_o[pmask], '.') ax.plot(phase[pmask], flux_m[pmask], 'k') ax.text(2.5*hdur[0], flux_m.min(), '{:6.4f}'.format(flux_m.min()), size=7, va='center', bbox=dict(color='white')) ax.axhline(flux_m.min(), alpha=0.25, ls='--') ax.get_yaxis().get_major_formatter().set_useOffset(False) ax.axvline(0, alpha=0.25, ls='--', lw=1) [ax.axvline(hd, alpha=0.25, ls='-', lw=1) for hd in hdur] setp(ax, xlim=3*hdur, xlabel='Phase [h]', ylabel='Normalised flux') setp(ax.get_yticklabels(), visible=False) @bplot def plot_fit_and_eo(self, ax=None, nbin=None): nbin = nbin or self.nbin res = rarr(self.result) period, zero_epoch, duration = res.trf_period, res.trf_zero_epoch, res.trf_duration hdur = 24*duration*array([-0.5,0.5]) self.plot_transit_fit(ax[0]) for time,flux_o in ((self.time_even,self.flux_even), (self.time_odd,self.flux_odd)): phase = 24*(fold(time, period, zero_epoch, shift=0.5, normalize=False) - 0.5*period) bpd,bfd,bed = uf.bin(phase, flux_o, nbin) pmask = abs(bpd) < 2*24*duration omask = pmask & isfinite(bfd) ax[1].plot(bpd[omask], bfd[omask], marker='o', ms=2) [a.axvline(0, alpha=0.25, ls='--', lw=1) for a in ax] [[a.axvline(24*hd, alpha=0.25, ls='-', lw=1) for hd in hdur] for a in ax] setp(ax[1],xlim=3*hdur, xlabel='Phase [h]') setp(ax[1].get_yticklabels(), visible=False) ax[1].get_yaxis().get_major_formatter().set_useOffset(False) @bplot def plot_eclipse(self, ax=None): shifts = np.linspace(-0.2,0.2, 500) ll0 = self.eclipse_likelihood(0.0, 0.0) ll1 = array([self.eclipse_likelihood(0.01, shift) for shift in shifts]) ll1_max = ll1.max() lnlratio = log(exp(ll1-ll1_max).mean())+ll1_max - ll0 ax.plot(0.5+shifts, ll1-ll1.min()) ax.text(0.02, 0.9, 'ln (P$_e$/P$_f$) = {:3.2f}'.format(lnlratio), size=7, transform=ax.transAxes) setp(ax, xlim=(0.3,0.7), xticks=(0.35,0.5,0.65), ylabel='$\Delta$ ln likelihood', xlabel='Phase shift') setp(ax.get_yticklabels(), visible=False) ax.set_title('Secondary eclipse') for t,l in zip(ax.get_yticks(),ax.get_yticklabels()): if l.get_text(): ax_ec.text(0.31, t, l.get_text()) @bplot def plot_lnlike(self, ax=None): ax.plot(self._tr_lnlike_po, marker='.', markersize=10) ax.axhline(self._tr_lnlike_med, ls='--', alpha=0.6) [ax.axhline(self._tr_lnlike_med+s*self._tr_lnlike_std, ls=':', alpha=a) for s,a in zip((-1,1,-2,2,-3,3), (0.6,0.6,0.4,0.4,0.2,0.2))] setp(ax, xlim=(0,len(self._tr_lnlike_po)-1), ylabel='ln likelihood', xlabel='Orbit number') setp(ax.get_yticklabels(), visible=False) @bplot def plot_sde(self, ax=None): r = rarr(self.result) ax.plot(self.bls.period, self.bls.sde, drawstyle='steps-mid') ax.axvline(r.bls_period, alpha=0.25, ls='--', lw=1) setp(ax,xlim=self.bls.period[[-1,0]], xlabel='Period [d]', ylabel='SDE', ylim=(-3,11)) [ax.axhline(i, c='k', ls='--', alpha=0.5) for i in [0,5,10]] [ax.text(self.bls.period.max()-1,i-0.5,i, va='top', ha='right', size=7) for i in [5,10]] ax.text(0.5, 0.88, 'BLS search', va='top', ha='center', size=8, transform=ax.transAxes) setp(ax.get_yticklabels(), visible=False) @bplot def plot_info(self, ax): res = rarr(self.result) t0,p,tdur,tdep,rrat = res.trf_zero_epoch[0], res.trf_period[0], res.trf_duration[0], res.trf_depth[0], 0 a = res.trf_semi_major_axis[0] ax.text(0.0,1.0, 'EPIC {:9d}'.format(self.epic), size=12, weight='bold', va='top', transform=ax.transAxes) ax.text(0.0,0.83, ('SDE\n' 'Kp\n' 'Zero epoch\n' 'Period [d]\n' 'Transit depth\n' 'Radius ratio\n' 'Transit duration [h]\n' 'Impact parameter\n' 'Stellar density'), size=9, va='top') ax.text(0.97,0.83, ('{:9.3f}\n{:9.3f}\n{:9.3f}\n{:9.3f}\n{:9.5f}\n' '{:9.4f}\n{:9.3f}\n{:9.3f}\n{:0.3f}').format(res.sde[0],self.Kp,t0,p,tdep,sqrt(tdep),24*tdur, res.trf_impact_parameter[0], rho_from_pas(p,a)), size=9, va='top', ha='right') sb.despine(ax=ax, left=True, bottom=True) setp(ax, xticks=[], yticks=[])
import numpy as np import matplotlib.pyplot as pl from pytransit import Gimenez, MandelAgol, z_circular m_mad = MandelAgol() m_mal = MandelAgol(lerp=True) m_gmd = Gimenez(lerp=False) m_gml = Gimenez(lerp=True) u = np.array([[0.1,0.1],[0.2,0.2],[0.6,0.3]]) t = np.linspace(-0.2, 0.2, 500) pl.plot(t, m_mad.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi), 'b-', alpha=0.5) pl.plot(t, m_mal.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi), 'r-', alpha=0.5) pl.plot(t, m_gmd.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47*np.pi), 'k--', alpha=1.0) pl.show()
import numpy as np import matplotlib.pyplot as pl from pytransit import Gimenez, MandelAgol, MandelAgolCL, z_circular mgfd = Gimenez() mgfl = Gimenez(lerp=True) macl = MandelAgolCL() mafl = MandelAgol(lerp=True) mafd = MandelAgol(lerp=False) u = [[0.1, 0.0], [0.2, 0.05], [0.5, 0.4]] u1 = [0.5, 0.4] t = np.linspace(-0.2, 0.2, 500) pl.plot(t, mafd.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47 * np.pi), ls='-', c='0.5', lw=1, alpha=0.5) #, drawstyle='steps-mid') pl.plot(t, macl.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47 * np.pi), 'b-', alpha=0.5) #, drawstyle='steps-mid') pl.plot(t, mgfd.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47 * np.pi) + 1e-4, 'b-', alpha=0.5) #, drawstyle='steps-mid') pl.plot(t, mgfl.evaluate(t, 0.1, u, 0.0, 5, 5, 0.47 * np.pi) + 2e-4, 'b-', alpha=0.5) #, drawstyle='steps-mid')
class LPFunction(object): """A basic log posterior function class. """ def __init__(self, time, flux, nthreads=1): # Set up the transit model # ------------------------ self.tm = MA(interpolate=True, klims=(0.08, 0.13), nthr=nthreads) self.nthr = nthreads # Initialise data # --------------- self.time = time.copy() if time is not None else array([]) self.flux_o = flux.copy() if flux is not None else array([]) self.npt = self.time.size # Set the optimiser and the MCMC sampler # -------------------------------------- self.de = None self.sampler = None # Set up the parametrisation and priors # ------------------------------------- psystem = [ GParameter('tc', 'zero_epoch', 'd', NP(1.01, 0.02), (-inf, inf)), GParameter('pr', 'period', 'd', NP(2.50, 1e-7), (0, inf)), GParameter('rho', 'stellar_density', 'g/cm^3', UP(0.90, 2.50), (0.90, 2.5)), GParameter('b', 'impact_parameter', 'R_s', UP(0.00, 1.00), (0.00, 1.0)), GParameter('k2', 'area_ratio', 'A_s', UP(0.08 ** 2, 0.13 ** 2), (1e-8, inf))] pld = [ PParameter('q1', 'q1_coefficient', '', UP(0, 1), bounds=(0, 1)), PParameter('q2', 'q2_coefficient', '', UP(0, 1), bounds=(0, 1))] pbl = [LParameter('es', 'white_noise', '', UP(1e-6, 1e-2), bounds=(1e-6, 1e-2))] per = [LParameter('bl', 'baseline', '', NP(1.00, 0.001), bounds=(0.8, 1.2))] self.ps = ParameterSet() self.ps.add_global_block('system', psystem) self.ps.add_passband_block('ldc', 2, 1, pld) self.ps.add_lightcurve_block('baseline', 1, 1, pbl) self.ps.add_lightcurve_block('error', 1, 1, per) self.ps.freeze() def compute_baseline(self, pv): """Constant baseline model""" return full_like(self.flux_o, pv[8]) def compute_transit(self, pv): """Transit model""" _a = as_from_rhop(pv[2], pv[1]) # Scaled semi-major axis from stellar density and orbital period _i = mt.acos(pv[3] / _a) # Inclination from impact parameter and semi-major axis _k = mt.sqrt(pv[4]) # Radius ratio from area ratio a, b = mt.sqrt(pv[5]), 2 * pv[6] _uv = array([a * b, a * (1. - b)]) # Quadratic limb darkening coefficients return self.tm.evaluate(self.time, _k, _uv, pv[0], pv[1], _a, _i) def compute_lc_model(self, pv): """Combined baseline and transit model""" return self.compute_baseline(pv) * self.compute_transit(pv) def lnprior(self, pv): """Log prior""" if any(pv < self.ps.lbounds) or any(pv > self.ps.ubounds): return -inf else: return self.ps.lnprior(pv) def lnlikelihood(self, pv): """Log likelihood""" flux_m = self.compute_lc_model(pv) return ll_normal_es(self.flux_o, flux_m, pv[7]) def lnposterior(self, pv): """Log posterior""" lnprior = self.lnprior(pv) if isinf(lnprior): return lnprior else: return lnprior + self.lnlikelihood(pv) def create_pv_population(self, npop=50): return self.ps.sample_from_prior(npop) def optimize(self, niter=200, npop=50, population=None, label='Optimisation'): """Global optimisation using Differential evolution""" if self.de is None: self.de = DiffEvol(self.lnposterior, clip(self.ps.bounds, -1, 1), npop, maximize=True) if population is None: self.de._population[:, :] = self.create_pv_population(npop) else: self.de._population[:, :] = population for _ in tqdm(self.de(niter), total=niter, desc=label): pass def sample(self, niter=500, thin=5, label='MCMC sampling', reset=False): """MCMC sampling using emcee""" if self.sampler is None: self.sampler = EnsembleSampler(self.de.n_pop, self.de.n_par, self.lnposterior) pop0 = self.de.population else: pop0 = self.sampler.chain[:, -1, :].copy() if reset: self.sampler.reset() for _ in tqdm(self.sampler.sample(pop0, iterations=niter, thin=thin), total=niter, desc=label): pass
class TransitSearch(object): """kepler transit search and candidate vetting Overview -------- The main idea is that we carry out a basic BLS search, continue with several model fits, and fit all the (possibly sensible) statistics to a random forest classifier. Transit search - BLS Transit fitting - basic transit fitting - even-odd transit fitting - calculation of per-orbit average log likelihoods - (Secondary eclipse search, not implemented) Sine fitting - fits a sine curve to the data to test for variability """ def __init__(self, infile, inject=False, **kwargs): self.d = d = pf.getdata(infile, 1) m = isfinite(d.flux_1) & (~(d.mflags_1 & 2**3).astype(np.bool)) m &= ~binary_dilation((d.quality & 2**20) != 0) self.Kp = pf.getval(infile, 'kepmag') self.Kp = self.Kp if not isinstance(self.Kp, Undefined) else nan self.tm = MA(supersampling=12, nthr=1) self.em = MA(supersampling=10, nldc=0, nthr=1) self.epic = int(basename(infile).split('_')[1]) self.time = d.time[m] self.flux = (d.flux_1[m] - d.trend_t_1[m] + nanmedian(d.trend_t_1[m]) - d.trend_p_1[m] + nanmedian(d.trend_p_1[m])) self.mflux = nanmedian(self.flux) self.flux /= self.mflux self.flux_e = d.error_1[m] / abs(self.mflux) self.flux_r = d.flux_1[m] / self.mflux self.trend_t = d.trend_t_1[m] / self.mflux self.trend_p = d.trend_p_1[m] / self.mflux self.period_range = kwargs.get( 'period_range', (0.7, 0.98 * (self.time.max() - self.time.min()))) self.nbin = kwargs.get('nbin', 900) self.qmin = kwargs.get('qmin', 0.002) self.qmax = kwargs.get('qmax', 0.115) self.nf = kwargs.get('nfreq', 10000) self.bls = BLS(self.time, self.flux, self.flux_e, period_range=self.period_range, nbin=self.nbin, qmin=self.qmin, qmax=self.qmax, nf=self.nf, pmean='running_median') def ndist(p=0.302): return 1. - 2 * abs(((self.bls.period - p) % p) / p - 0.5) def cmask(s=0.05): return 1. - np.exp(-ndist() / s) self.bls.pmul = cmask() try: ar, ac, ap, at = acor(self.flux_r)[0], acor(self.flux)[0], acor( self.trend_p)[0], acor(self.trend_t)[0] except RuntimeError: ar, ac, ap, at = nan, nan, nan, nan self.lcinfo = array( (self.epic, self.mflux, self.flux.std(), nan, nan, ar, ac, ap, at), dtype=dt_lcinfo) self._rbls = None self._rtrf = None self._rvar = None self._rtoe = None self._rpol = None self._recl = None ## Transit fit pv [k u t0 p a i] self._pv_bls = None self._pv_trf = None self.period = None self.zero_epoch = None self.duration = None def create_transit_arrays(self): p = self._rbls['bls_period'] tc = self._rbls['bls_zero_epoch'] dur = max(0.15, self._rbls['bls_duration']) tid_arr = np.round((self.time - tc) / p).astype(np.int) tid_arr -= tid_arr.min() tids = unique(tid_arr) phase = p * (fold(self.time, p, tc, shift=0.5) - 0.5) pmask = abs(phase) < 5 * dur self.times = [self.time[tid_arr == tt] for tt in unique(tids)] self.fluxes = [self.flux[tid_arr == tt] for tt in unique(tids)] self.flux_es = [self.flux_e[tid_arr == tt] for tt in unique(tids)] self.time_even = concatenate(self.times[0::2]) self.time_odd = concatenate(self.times[1::2]) self.flux_even = concatenate(self.fluxes[0::2]) self.flux_odd = concatenate(self.fluxes[1::2]) self.flux_e_even = concatenate(self.flux_es[0::2]) self.flux_e_odd = concatenate(self.flux_es[1::2]) @property def result(self): return merge_arrays([ self.lcinfo, self._rbls, self._rtrf, self._rvar, self._rtoe, self._rpol, self._recl ], flatten=True) def __call__(self): """Runs a BLS search, fits a transit, and fits an EB model""" self.run_bls() self.fit_transit() self.fit_variability() self.fit_even_odd() self.per_orbit_likelihoods() self.test_eclipse() def run_bls(self): b = self.bls r = self.bls() self._rbls = array( (b.bsde, b.tc, b.bper, b.duration, b.depth, sqrt(b.depth), floor(diff(self.time[[0, -1]])[0] / b.bper)), dt_blsresult) self._pv_bls = [ b.bper, b.tc, sqrt(b.depth), as_from_rhop(2.5, b.bper), 0.1 ] self.create_transit_arrays() self.lcinfo['lnlike_constant'] = ll_normal_es(self.flux, ones_like(self.flux), self.flux_e) self.period = b.bper self.zero_epoch = b.tc self.duration = b.duration def fit_transit(self): def minfun(pv): if any(pv <= 0) or (pv[3] <= 1) or (pv[4] > 1) or not ( 0.75 < pv[0] < 80) or abs(pv[0] - pbls) > 1.: return inf return -ll_normal_es(self.flux, self.transit_model(pv), self.flux_e) pbls = self._pv_bls[0] mr = minimize(minfun, self._pv_bls, method='powell') lnlike, x = -mr.fun, mr.x self._rtrf = array( (lnlike, x[1], x[0], of.duration_circular(x[0], x[3], mt.acos(x[4] / x[3])), x[2]** 2, x[2], x[3], x[4]), dt_trfresult) self._pv_trf = mr.x.copy() self.period = x[0] self.zero_epoch = x[1] self._rtrf['trf_duration'] def per_orbit_likelihoods(self): pv = self._pv_trf lnl = array([ ll_normal_es(f, self.transit_model(pv, t), e) / t.size for t, f, e in zip(self.times, self.fluxes, self.flux_es) ]) self._tr_lnlike_po = lnl self._tr_lnlike_med = lmed = median(lnl) self._tr_lnlike_std = lstd = lnl.std() self._tr_lnlike_max = lmax = (lnl.max() - lmed) / lstd self._tr_lnlike_min = lmin = (lnl.min() - lmed) / lstd self._rpol = array((lmed, lstd, lmax, lmin), dt_poresult) def fit_even_odd(self): def minfun(pv, time, flux, flux_e): if any(pv <= 0) or (pv[3] <= 1) or (pv[4] > 1): return inf return -ll_normal_es(flux, self.transit_model(pv, time), flux_e) mr_even = minimize(minfun, self._pv_bls, args=(self.time_even, self.flux_even, self.flux_e_even), method='powell') mr_odd = minimize(minfun, self._pv_bls, args=(self.time_odd, self.flux_odd, self.flux_e_odd), method='powell') pvd = abs(mr_even.x - mr_odd.x) self._rtoe = array((-mr_even.fun - mr_odd.fun, pvd[2], pvd[3], pvd[4]), dt_oeresult) def fit_variability(self): def minfun(pv, period, zero_epoch): if any(pv < 0): return inf dummy = [] for j in range(4): dummy.append(-ll_normal_es( self.flux, self.sine_model(pv, j * 2 * period, zero_epoch), self.flux_e)) return np.nanmin( dummy ) #-ll_normal_es(self.flux, self.sine_model(pv, 2*period, zero_epoch), self.flux_e) mr = minimize(minfun, [self.flux.std()], args=(self._rbls['bls_period'], self._rbls['bls_zero_epoch']), method='powell') self._rvar = array((-mr.fun, mr.x), dt_varresult) def test_eclipse(self): self.ec_shifts = shifts = np.linspace(-0.2, 0.2, 500) self.ec_ll0 = ll0 = self.eclipse_likelihood(0.0, 0.0) self.ec_ll1 = ll1 = array( [self.eclipse_likelihood(0.01, shift) for shift in shifts]) ll1_max = ll1.max() self.ec_lnratio = lnlratio = log( exp(ll1 - ll1_max).mean()) + ll1_max - ll0 self._recl = array( (self.ec_lnratio, self.ec_shifts[np.argmax(self.ec_lnratio)]), dt_ecresult) ## Models ## ------ def sine_model(self, pv, period, zero_epoch): return 1. + pv[0] * sin(2 * pi / period * (self.time - zero_epoch) - 0.5 * pi) def transit_model(self, pv, time=None): time = self.time if time is None else time _i = mt.acos(pv[4] / pv[3]) return self.tm.evaluate(time, pv[2], [0.4, 0.1], pv[1], pv[0], pv[3], _i) def eclipse_model(self, shift, time=None): time = self.time if time is None else time pv = self._pv_trf _i = mt.acos(pv[4] / pv[3]) return self.em.evaluate(time, pv[2], [], pv[1] + (0.5 + shift) * pv[0], pv[0], pv[3], _i) def eclipse_likelihood(self, f, shift, time=None): return ll_normal_es(self.flux, (1 - f) + f * self.eclipse_model(shift, time), self.flux_e) ## Plotting ## -------- def bplot(plotf): @wraps(plotf) def wrapper(self, ax=None, *args, **kwargs): if ax is None: fig, ax = subplots(1, 1) try: plotf(self, ax, **kwargs) except ValueError: pass return ax return wrapper @bplot def plot_lc_time(self, ax=None): ax.plot(self.time, self.flux_r, lw=1) ax.plot(self.time, self.trend_t + 2 * (np.percentile(self.flux_r, [99])[0] - 1), lw=1) ax.plot(self.time, self.trend_p + 4 * (np.percentile(self.flux_r, [99])[0] - 1), lw=1) ax.plot(self.time, self.flux + 1.1 * (self.flux_r.min() - 1), lw=1) [ ax.axvline(self.bls.tc + i * self._rbls['bls_period'], alpha=0.25, ls='--', lw=1) for i in range(35) ] setp(ax, xlim=self.time[[0, -1]], xlabel='Time', ylabel='Normalised flux') @bplot def plot_lc(self, ax=None, nbin=None): nbin = nbin or self.nbin r = rarr(self.result) period, t0, trdur = self._rbls['bls_period'], self._rbls[ 'bls_zero_epoch'], self._rbls[ 'bls_duration'] #r.trf_period, r.trf_zero_epoch, r.trf_duration phase = period * (fold(self.time, period, t0, shift=0.5) - 0.5) bp, bfo, beo = uf.bin(phase, self.flux, nbin) bp, bfm, bem = uf.bin(phase, self.transit_model(self._pv_trf), nbin) mo, mm = isfinite(bfo), isfinite(bfm) ax.plot(bp[mo], bfo[mo], '.') ax.plot(bp[mm], bfm[mm], 'k--', drawstyle='steps-mid') if self._rvar: flux_s = self.sine_model([self._rvar['sine_amplitude']], 2 * period, t0) bp, bf, be = uf.bin(phase, flux_s, nbin) ax.plot(bp, bf, 'k:', drawstyle='steps-mid') setp(ax, xlim=bp[[0, -1]], xlabel='Phase [d]', ylabel='Normalised flux') setp(ax.get_yticklabels(), visible=False) ax.get_yaxis().get_major_formatter().set_useOffset(False) @bplot def plot_even_odd_lc(self, ax=None, nbin=None): nbin = nbin or self.nbin res = rarr(self.result) period, zero_epoch, duration = res.trf_period, res.trf_zero_epoch, res.trf_duration hdur = array([-0.5, 0.5]) * duration for time, flux_o in ((self.time_even, self.flux_even), (self.time_odd, self.flux_odd)): phase = fold(time, period, zero_epoch, shift=0.5, normalize=False) - 0.5 * period flux_m = self.transit_model(self._pv_trf, time) bpd, bfd, bed = uf.bin(phase, flux_o, nbin) bpm, bfm, bem = uf.bin(phase, flux_m, nbin) pmask = abs(bpd) < 1.5 * duration omask = pmask & isfinite(bfd) mmask = pmask & isfinite(bfm) ax[0].plot(bpd[omask], bfd[omask], marker='o') ax[1].plot(bpm[mmask], bfm[mmask], marker='o') [a.axvline(0, alpha=0.25, ls='--', lw=1) for a in ax] [[a.axvline(hd, alpha=0.25, ls='-', lw=1) for hd in hdur] for a in ax] setp(ax, xlim=3 * hdur, xlabel='Phase [d]', ylim=(0.9998 * nanmin(bfd[pmask]), 1.0002 * nanmax(bfd[pmask]))) setp(ax[0], ylabel='Normalised flux') setp(ax[1].get_yticklabels(), visible=False) @bplot def plot_transits(self, ax=None): offset = 1.1 * scoreatpercentile([f.ptp() for f in self.fluxes], 95) twodur = 24 * 2 * self.duration for i, (time, flux) in enumerate(zip(self.times, self.fluxes)[:10]): phase = 24 * (fold( time, self.period, self.zero_epoch, 0.5, normalize=False) - 0.5 * self.period) sids = argsort(phase) phase, flux = phase[sids], flux[sids] pmask = abs(phase) < 2.5 * twodur if any(pmask): ax.plot(phase[pmask], flux[pmask] + i * offset, marker='o') setp(ax, xlim=(-twodur, twodur), xlabel='Phase [h]', yticks=[]) @bplot def plot_transit_fit(self, ax=None): res = rarr(self.result) period, zero_epoch, duration = res.trf_period, res.trf_zero_epoch, res.trf_duration hdur = 24 * duration * array([-0.5, 0.5]) flux_m = self.transit_model(self._pv_trf) phase = 24 * (fold(self.time, period, zero_epoch, 0.5, normalize=False) - 0.5 * period) sids = argsort(phase) phase = phase[sids] pmask = abs(phase) < 2 * 24 * duration flux_m = flux_m[sids] flux_o = self.flux[sids] ax.plot(phase[pmask], flux_o[pmask], '.') ax.plot(phase[pmask], flux_m[pmask], 'k') ax.text(2.5 * hdur[0], flux_m.min(), '{:6.4f}'.format(flux_m.min()), size=7, va='center', bbox=dict(color='white')) ax.axhline(flux_m.min(), alpha=0.25, ls='--') ax.get_yaxis().get_major_formatter().set_useOffset(False) ax.axvline(0, alpha=0.25, ls='--', lw=1) [ax.axvline(hd, alpha=0.25, ls='-', lw=1) for hd in hdur] setp(ax, xlim=3 * hdur, xlabel='Phase [h]', ylabel='Normalised flux') setp(ax.get_yticklabels(), visible=False) @bplot def plot_fit_and_eo(self, ax=None, nbin=None): nbin = nbin or self.nbin res = rarr(self.result) period, zero_epoch, duration = res.trf_period, res.trf_zero_epoch, res.trf_duration hdur = 24 * duration * array([-0.5, 0.5]) self.plot_transit_fit(ax[0]) for time, flux_o in ((self.time_even, self.flux_even), (self.time_odd, self.flux_odd)): phase = 24 * ( fold(time, period, zero_epoch, shift=0.5, normalize=False) - 0.5 * period) bpd, bfd, bed = uf.bin(phase, flux_o, nbin) pmask = abs(bpd) < 2 * 24 * duration omask = pmask & isfinite(bfd) ax[1].plot(bpd[omask], bfd[omask], marker='o', ms=2) [a.axvline(0, alpha=0.25, ls='--', lw=1) for a in ax] [[a.axvline(24 * hd, alpha=0.25, ls='-', lw=1) for hd in hdur] for a in ax] setp(ax[1], xlim=3 * hdur, xlabel='Phase [h]') setp(ax[1].get_yticklabels(), visible=False) ax[1].get_yaxis().get_major_formatter().set_useOffset(False) @bplot def plot_eclipse(self, ax=None): shifts = np.linspace(-0.2, 0.2, 500) ll0 = self.eclipse_likelihood(0.0, 0.0) ll1 = array([self.eclipse_likelihood(0.01, shift) for shift in shifts]) ll1_max = ll1.max() lnlratio = log(exp(ll1 - ll1_max).mean()) + ll1_max - ll0 ax.plot(0.5 + shifts, ll1 - ll1.min()) ax.text(0.02, 0.9, 'ln (P$_e$/P$_f$) = {:3.2f}'.format(lnlratio), size=7, transform=ax.transAxes) setp(ax, xlim=(0.3, 0.7), xticks=(0.35, 0.5, 0.65), ylabel='$\Delta$ ln likelihood', xlabel='Phase shift') setp(ax.get_yticklabels(), visible=False) ax.set_title('Secondary eclipse') for t, l in zip(ax.get_yticks(), ax.get_yticklabels()): if l.get_text(): ax_ec.text(0.31, t, l.get_text()) @bplot def plot_lnlike(self, ax=None): ax.plot(self._tr_lnlike_po, marker='.', markersize=10) ax.axhline(self._tr_lnlike_med, ls='--', alpha=0.6) [ ax.axhline(self._tr_lnlike_med + s * self._tr_lnlike_std, ls=':', alpha=a) for s, a in zip((-1, 1, -2, 2, -3, 3), (0.6, 0.6, 0.4, 0.4, 0.2, 0.2)) ] setp(ax, xlim=(0, len(self._tr_lnlike_po) - 1), ylabel='ln likelihood', xlabel='Orbit number') setp(ax.get_yticklabels(), visible=False) @bplot def plot_sde(self, ax=None): r = rarr(self.result) ax.plot(self.bls.period, self.bls.sde, drawstyle='steps-mid') ax.axvline(r.bls_period, alpha=0.25, ls='--', lw=1) setp(ax, xlim=self.bls.period[[-1, 0]], xlabel='Period [d]', ylabel='SDE', ylim=(-3, 11)) [ax.axhline(i, c='k', ls='--', alpha=0.5) for i in [0, 5, 10]] [ ax.text(self.bls.period.max() - 1, i - 0.5, i, va='top', ha='right', size=7) for i in [5, 10] ] ax.text(0.5, 0.88, 'BLS search', va='top', ha='center', size=8, transform=ax.transAxes) setp(ax.get_yticklabels(), visible=False) @bplot def plot_info(self, ax): res = rarr(self.result) t0, p, tdur, tdep, rrat = res.trf_zero_epoch[0], res.trf_period[ 0], res.trf_duration[0], res.trf_depth[0], 0 a = res.trf_semi_major_axis[0] ax.text(0.0, 1.0, 'EPIC {:9d}'.format(self.epic), size=12, weight='bold', va='top', transform=ax.transAxes) ax.text(0.0, 0.83, ('SDE\n' 'Kp\n' 'Zero epoch\n' 'Period [d]\n' 'Transit depth\n' 'Radius ratio\n' 'Transit duration [h]\n' 'Impact parameter\n' 'Stellar density'), size=9, va='top') ax.text(0.97, 0.83, ('{:9.3f}\n{:9.3f}\n{:9.3f}\n{:9.3f}\n{:9.5f}\n' '{:9.4f}\n{:9.3f}\n{:9.3f}\n{:0.3f}').format( res.sde[0], self.Kp, t0, p, tdep, sqrt(tdep), 24 * tdur, res.trf_impact_parameter[0], rho_from_pas(p, a)), size=9, va='top', ha='right') sb.despine(ax=ax, left=True, bottom=True) setp(ax, xticks=[], yticks=[])
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Fri Jan 25 11:39:53 2019 Script to practice using the PyTransit Tool @author: phrhzn """ import numpy as np from pytransit import MandelAgol import matplotlib.pyplot as plt t = np.linspace(0.8,1.2,500) k, t0, p, a, i, e, w = 0.1, 1.01, 4, 8, 0.48*np.pi, 0.2, 0.5*np.pi u = [0.25,0.10] m = MandelAgol() f = m.evaluate(t, k, u, t0, p, a, i, e, w) plt.plot(t,f)