Example #1
0
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
Example #2
0
    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()
Example #3
0
    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)]
Example #4
0
    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)]
Example #5
0
    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()
Example #6
0
    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
Example #7
0
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()
Example #8
0
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()
Example #9
0
    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
Example #10
0
    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
Example #11
0
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(',')]
Example #12
0
 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)
Example #13
0
 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)
Example #14
0
 def test_mai_multiband(self):
     self.mbt(MandelAgol(interpolate=True))
Example #15
0
 def test_mai_singleband(self):
     self.sbt(MandelAgol(interpolate=True))
Example #16
0
 def test_mad_multiband(self):
     self.mbt(MandelAgol(interpolate=False))
Example #17
0
 def test_mad_singleband(self):
     self.sbt(MandelAgol(interpolate=False))
Example #18
0
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
Example #19
0
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)
Example #20
0
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()
Example #21
0
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=[])
Example #22
0
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()
Example #23
0
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')
Example #24
0
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
Example #25
0
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=[])
Example #26
0
#!/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)