예제 #1
0
    def compute_transit_prob(self):
        self.transit_prob, self.etransit_prob = np.zeros_like(self.sens), \
                                                       np.zeros_like(self.sens)
        self.logtransit_prob,self.elogtransit_prob = np.zeros_like(self.sens), \
                                                            np.zeros_like(self.sens)
        for i in range(self._xlen):
            for j in range(self._ylen):

                # compute transit probability in log-linear space
                Pmid = 10**(np.log10(self.logPgrid[i]) + \
                            np.diff(np.log10(self.logPgrid[:2])/2))
                rpmid = self.rpgrid[j] + np.diff(self.rpgrid)[0] / 2.
                sma = rvs.AU2m(
                    rvs.semimajoraxis(Pmid, unp.uarray(self.Ms, self.e_Ms), 0))
                transit_prob =  (rvs.Rsun2m(unp.uarray(self.Rs, self.e_Rs)) + \
                                 rvs.Rearth2m(rpmid)) / sma
                self.transit_prob[i, j] = unp.nominal_values(transit_prob)
                self.etransit_prob[i, j] = unp.std_devs(transit_prob)

                # compute transit probability in log-linear space
                rpmid = 10**(np.log10(self.logrpgrid[j]) + \
                             np.diff(np.log10(self.logrpgrid[:2])/2))
                transit_prob =  (rvs.Rsun2m(unp.uarray(self.Rs, self.e_Rs)) + \
                                               rvs.Rearth2m(rpmid)) / sma
                self.logtransit_prob[i, j] = unp.nominal_values(transit_prob)
                self.elogtransit_prob[i, j] = unp.std_devs(transit_prob)

        # correction from beta distribution fit (Kipping 2013)
        factor = 1.08
        self.transit_prob *= factor
        self.etransit_prob *= factor
        self.logtransit_prob *= factor
        self.elogtransit_prob *= factor
예제 #2
0
def compute_transit_duration(rp, P, K, Rs, b=0):
    mp = np.array([runTESS.get_planet_mass(i) for i in rp])
    Ms = runTESS.get_stellar_mass(P, mp, K)
    sma = rvs.AU2m(rvs.semimajoraxis(P, Ms, mp))
    Rs2 = rvs.Rsun2m(Rs)
    tau0 = P * Rs2 / (2 * np.pi * sma)
    return 2. * tau0 * np.sqrt(1. - b**2)
예제 #3
0
def _fit_params(params, bjd, fcorr, ef, Ms, Rs, Teff, Kep=False, TESS=False):
    '''Get best-fit parameters.'''
    assert params.shape == (4, )
    P, T0, depth, duration = params
    if Kep:
        u1, u2 = llnl.get_LDcoeffs_Kepler(Ms, Rs, Teff)
    elif TESS:
        u1, u2 = llnl.get_LDcoeffs_TESS(Ms, Rs, Teff)

    aRs = rvs.AU2m(rvs.semimajoraxis(P, Ms, 0)) / rvs.Rsun2m(Rs)
    rpRs = np.sqrt(depth)
    p0 = aRs, rpRs, 90.
    bnds = ((aRs * .9, 0, float(rvs.inclination(P, Ms, Rs, 1.1))),
            (aRs * 1.1, 1, float(rvs.inclination(P, Ms, Rs, -1.1))))
    try:
        popt, _ = curve_fit(transit_model_func_curve_fit(P, T0, u1, u2),
                            bjd,
                            fcorr,
                            p0=p0,
                            sigma=ef,
                            absolute_sigma=True,
                            bounds=bnds)
        aRs, rpRs, inc = popt
        depth = rpRs**2
        b = rvs.impactparam_inc(P, Ms, Rs, inc)
        duration = P / (np.pi * aRs) * np.sqrt((1 + np.sqrt(depth))**2 - b * b)
        return P, T0, depth, duration
    except RuntimeError:
        return params
예제 #4
0
def _is_Vshaped(params,
                bjd,
                fcorr,
                ef,
                Ms,
                Rs,
                Teff,
                Kep,
                TESS,
                duration_frac=.05):
    '''check if transit is V-shaped although this does not imply an EB 
    because inclined transiting planets can look like this as well.'''
    # fit transit model
    assert params.shape == (4, )
    P, T0, depth = params[:3]
    if Kep:
        u1, u2 = llnl.get_LDcoeffs_Kepler(Ms, Rs, Teff)
    elif TESS:
        u1, u2 = llnl.get_LDcoeffs_TESS(Ms, Rs, Teff)

    aRs = rvs.AU2m(rvs.semimajoraxis(P, Ms, 0)) / rvs.Rsun2m(Rs)
    rpRs = np.sqrt(depth)
    p0 = aRs, rpRs, 90.
    bnds = ((aRs * .9, 0, float(rvs.inclination(P, Ms, Rs, 1.1))),
            (aRs * 1.1, 1, float(rvs.inclination(P, Ms, Rs, -1.1))))
    try:
        popt, _ = curve_fit(transit_model_func_curve_fit(P, T0, u1, u2),
                            bjd,
                            fcorr,
                            p0=p0,
                            sigma=ef,
                            absolute_sigma=True,
                            bounds=bnds)
        aRs, rpRs, inc = popt
    except RuntimeError:
        return False, 0.

    # get ingress, egress times and duration
    transit_func = transit_model_func_curve_fit(P, T0, 0, 0)
    fmodel = transit_func(bjd, *popt)
    phase = foldAt(bjd, P, T0)
    phase[phase > .5] -= 1
    depth = fmodel.min()
    T1, T4 = phase[(phase<=0) & (fmodel==1)].max()*P, \
             phase[(phase>=0) & (fmodel==1)].min()*P
    in_ingress = (phase <= 0) & np.isclose(fmodel, depth, rtol=1e-4)
    T2 = phase[in_ingress].min() * P if in_ingress.sum() > 0 else (T4 -
                                                                   T1) * .1
    in_egress = (phase >= 0) & np.isclose(fmodel, depth, rtol=1e-4)
    T3 = phase[in_egress].max() * P if in_egress.sum() > 0 else (T4 - T1) * .1
    Tingress, Tegress, duration = T2 - T1, T4 - T3, T4 - T1
    Tedge = Tingress + Tegress

    # V-shaped if T2==T3 or if ingress+egress time is the same as the duration
    if T2 == T3:
        return True, duration
    elif np.isclose(Tedge, duration, rtol=duration_frac):
        return True, duration
    else:
        return False, duration
예제 #5
0
def depth2rp(P_days, depth, duration_days, Ms, Rs):
    '''Compute the planet radius from the transit depth and 
    duration using the analtyical treatment from Mandel & Agol 2002'''
    assert 0 < depth < 1

    # compute distance from centres at T0
    sma = rvs.semimajoraxis(P_days, Ms, 0)
    a_Rs = rvs.AU2m(sma) / rvs.Rsun2m(Rs)
    assert a_Rs > 1
    b = rvs.impactparam_T(P_days, Ms, Rs, duration_days)
    assert abs(b) <= 1
    inc = float(rvs.inclination(P_days, Ms, Rs, b))
    z = compute_distance_center(a_Rs, inc)

    # compute size ratio (p=rp/Rs)
    p_simple = unp.sqrt(depth)
    if z <= 1 - p_simple:
        p = p_simple

    else:
        ps = np.logspace(-6, 0, 1000)
        depths = p2depth_grazing(ps, z)
        if (np.nanmax(depths) < z) or (np.nanmin(depths) > z):
            p = p_simple
        else:
            fint = interp1d(ps, depths)
            p = float(fint(depth))

    # compute planet radius
    rp = rvs.m2Rearth(rvs.Rsun2m(p * Rs))
    return rp
예제 #6
0
def optimize_singletransit_params(params,
                                  bjd,
                                  fcorr,
                                  ef,
                                  Ms,
                                  Rs,
                                  u1,
                                  u2,
                                  pltt=True):
    '''Get best-fit parameters using the periodic fit parameters for 
    initialization (i.e. P_input < P_singletransit).'''
    assert params.shape == (4, )
    P, T0, depth, duration = params
    if depth >= .9:  # sometimes the dimming is passed instead of depth
        return np.nan, np.nan, np.nan, np.nan, \
            np.repeat(np.nan, bjd.size), np.repeat(np.nan, 7)
    # focus on data centered around T0
    g = (bjd >= T0 - 10 * duration) & (bjd <= T0 + 10 * duration)
    bjdred, fcorrred, efred = bjd[g], fcorr[g], ef[g]

    # initialize
    aRs = rvs.AU2m(rvs.semimajoraxis(P, Ms, 0)) / rvs.Rsun2m(Rs)
    rpRs = np.sqrt(depth)
    p0 = P, T0, aRs, rpRs, 90.
    incs = np.array([
        float(rvs.inclination(P, Ms, Rs, 1)),
        float(rvs.inclination(P, Ms, Rs, -1))
    ])
    bnds = ((0, T0 - .2, 0, 0, incs.min()), (P * 100, T0 + .2, aRs * 100, 1,
                                             incs.max()))
    try:
        popt, _ = curve_fit(llnl.transit_model_func_curve_fit(u1, u2),
                            bjdred,
                            fcorrred,
                            p0=p0,
                            sigma=efred,
                            absolute_sigma=True,
                            bounds=bnds)
        P, T0, aRs, rpRs, inc = popt
        depth = rpRs**2
        b = rvs.impactparam_inc(P, Ms, Rs, inc)
        duration = P / (np.pi * aRs) * np.sqrt((1 + np.sqrt(depth))**2 - b * b)
        func = llnl.transit_model_func_curve_fit(u1, u2)
        fmodel = func(bjdred, P, T0, aRs, rpRs, inc)
        params = np.array([P, T0, aRs, rpRs, inc, u1, u2])
    except RuntimeError, ValueError:
        func = llnl.transit_model_func_curve_fit(u1, u2)
        fmodel = func(bjdred, P, T0, aRs, rpRs, 90.)
        P, T0, depth, duration = np.repeat(np.nan, 4)
        params = np.repeat(np.nan, 7)
예제 #7
0
def fit_params(params, bjd, fcorr, ef, Ms, Rs, Teff, Kep=False, TESS=False):
    '''Get best-fit parameters.'''
    assert params.shape == (4, )
    P, T0, depth, duration = params
    if depth >= .9:  # sometimes the dimming is passed instead of depth
        return np.nan, np.nan, np.nan, np.nan, \
               np.repeat(np.nan, bjd.size), np.repeat(np.nan, 7)
    if Kep:
        u1, u2 = get_LDcoeffs_Kepler(Ms, Rs, Teff)
    if TESS:
        u1, u2 = get_LDcoeffs_TESS(Ms, Rs, Teff)
    assert np.all(np.isfinite([u1, u2]))
    aRs = rvs.AU2m(rvs.semimajoraxis(P, Ms, 0)) / rvs.Rsun2m(Rs)
    rpRs = np.sqrt(depth)
    p0 = P, T0, aRs, rpRs, 90.
    incs = np.array([
        float(rvs.inclination(P, Ms, Rs, 1)),
        float(rvs.inclination(P, Ms, Rs, -1))
    ])
    bnds = ((P * .9, T0 - P * 1.1, aRs * .9, 0, incs.min()),
            (P * 1.1, T0 + P * 1.1, aRs * 1.1, 1, incs.max()))
    try:
        popt, _ = curve_fit(transit_model_func_curve_fit(u1, u2),
                            bjd,
                            fcorr,
                            p0=p0,
                            sigma=ef,
                            absolute_sigma=True,
                            bounds=bnds)
        P, T0, aRs, rpRs, inc = popt
        depth = rpRs**2
        b = rvs.impactparam_inc(P, Ms, Rs, inc)
        duration = P / (np.pi * aRs) * np.sqrt((1 + np.sqrt(depth))**2 - b * b)
        func = transit_model_func_curve_fit(u1, u2)
        fmodel = func(bjd, P, T0, aRs, rpRs, inc)
        params = np.array([P, T0, aRs, rpRs, inc, u1, u2])
    except RuntimeError, ValueError:
        func = transit_model_func_curve_fit(u1, u2)
        fmodel = func(bjd, P, T0, aRs, rpRs, 90.)
        P, T0, depth, duration = np.repeat(np.nan, 4)
        params = np.repeat(np.nan, 7)
예제 #8
0
def setupTOI175simv2(bjd0,
                     Ms,
                     eccs,
                     incs_deg,
                     outname,
                     interval_yrs,
                     random=True,
                     DeltaOmegamax=180):
    '''Create a simulation of TOI175 with custom input for the 
    planetary parameters in the form of 1d arrays.'''
    # Initialize
    sim = rebound.Simulation()
    sim.integrator = "whfast"
    sim.units = ('AU', 'Msun', 'yr')
    sim.automateSimulationArchive("%s.bin" % outname, interval=interval_yrs)

    # Get keplerian parameters
    assert eccs.size == 3
    assert incs_deg.size == 3
    Ps = np.array([2.2531, 3.6904, 7.4512])
    if random:
        Ps += np.array([
            np.random.randn() * 4e-4,
            np.random.randn() * 3e-4,
            np.random.randn() * 8e-4
        ])
        while np.any(Ps <= 0):
            Ps = np.array([2.2531, 3.6904, 7.4512]) + np.array([
                np.random.randn() * 4e-4,
                np.random.randn() * 3e-4,
                np.random.randn() * 8e-4
            ])

    T0s = np.array([1366.1708, 1367.2752, 1362.7376]) + 2457000
    if random:
        T0s += np.array([
            np.random.randn() * 1e-4,
            np.random.randn() * 6e-4,
            np.random.randn() * 9e-4
        ])

    # sample mass of the smallest planet directly from the PDF since it's not gaussian (i.e. a non-detection)
    mp_175d03 = np.random.choice(np.load(
        'toi175d03_2d25_planetmass_PDF.npy')) + np.random.randn() * 5e-4
    mps = np.array([mp_175d03, 2.6, 2.4])
    if random:
        mps += np.array([0, np.random.randn() * 0.4, np.random.randn() * 0.6])
        while np.any(mps <= 0):
            mps = np.array([0.34, 2.6, 2.4]) + np.array([
                np.random.randn() * .42,
                np.random.randn() * 0.4,
                np.random.randn() * 0.6
            ])

    smas = rvs.m2AU(rvs.semimajoraxis(Ps, Ms, mps))
    mps = rvs.kg2Msun(rvs.Mearth2kg(mps))
    nplanets = Ps.size
    omegas = np.random.uniform(-np.pi, np.pi, nplanets)
    Omegas = np.random.uniform(-np.pi, np.pi, nplanets)
    thetas = 2 * np.pi * foldAt(bjd0, Ps, T0s) - np.pi

    # Add star
    sim.add(m=Ms, hash='star')

    # Add planets
    for i in range(nplanets):
        sim.add(m=mps[i],
                a=smas[i],
                inc=np.deg2rad(incs_deg[i] - 90),
                e=eccs[i],
                omega=omegas[i],
                Omega=Omegas[i],
                theta=thetas[i])

    sim.move_to_com()

    RHill1 = (mps[:2].sum() / (3. * Ms))**(1. / 3) * smas[:2].mean()
    RHill2 = (mps[1:].sum() / (3. * Ms))**(1. / 3) * smas[1:].mean()
    sim.exit_min_distance = float(np.max([RHill1, RHill2]))

    return sim
def sample_planet_params(self, index, postGAIA=True):
    '''sample distribution of planet parameters from observables and stellar pdfs'''
    # get stellar parameters PDFs either from derived from GAIA distances
    # or from original Kepler parameters (approximate distributions as skewnormal)
    g = int(index)
    print self.KepIDs[g]
    if postGAIA:
        path = '../GAIAMdwarfs/Gaia-DR2-distances_custom/DistancePosteriors/'
        try:
            samp_Rs, samp_Teff, samp_Ms = np.loadtxt('%s/KepID_allpost_%i' %
                                                     (path, self.KepIDs[g]),
                                                     delimiter=',',
                                                     usecols=(9, 10, 11)).T
        except IOError:
            samp_Rs, samp_Teff, samp_Ms = np.zeros(1000), np.zeros(
                1000), np.zeros(1000)

        if np.all(np.isnan(samp_Rs)) or np.all(np.isnan(samp_Teff)) or np.all(
                np.isnan(samp_Ms)):
            samp_Rs, samp_Teff, samp_Ms = np.zeros(1000), np.zeros(
                1000), np.zeros(1000)

        samp_Rs = resample_PDF(samp_Rs[np.isfinite(samp_Rs)],
                               samp_Rs.size,
                               sig=1e-3)
        samp_Teff = resample_PDF(samp_Teff[np.isfinite(samp_Teff)],
                                 samp_Teff.size,
                                 sig=5)
        samp_Ms = resample_PDF(samp_Ms[np.isfinite(samp_Ms)],
                               samp_Ms.size,
                               sig=1e-3)
    else:
        _, _, samp_Rs = get_samples_from_percentiles(self.Rss1[g],
                                                     self.ehi_Rss1[g],
                                                     self.elo_Rss1[g],
                                                     Nsamp=1e3)
        _, _, samp_Teff = get_samples_from_percentiles(self.Teffs1[g],
                                                       self.ehi_Teffs1[g],
                                                       self.elo_Teffs1[g],
                                                       Nsamp=1e3)
        _, _, samp_Ms = get_samples_from_percentiles(self.Mss1[g],
                                                     self.ehi_Mss1[g],
                                                     self.elo_Mss1[g],
                                                     Nsamp=1e3)

    # sample rp/Rs distribution from point estimates
    _, _, samp_rpRs = get_samples_from_percentiles(self.rpRs[g],
                                                   self.ehi_rpRs[g],
                                                   self.elo_rpRs[g],
                                                   Nsamp=samp_Rs.size)

    # compute planet radius PDF
    samp_rp = rvs.m2Rearth(rvs.Rsun2m(samp_rpRs * samp_Rs))
    v = np.percentile(samp_rp, (16, 50, 84))
    rps = v[1], v[2] - v[1], v[1] - v[0]

    # compute semi-major axis PDF
    samp_Ps = np.random.normal(self.Ps[g], self.e_Ps[g], samp_Ms.size)
    samp_as = rvs.semimajoraxis(samp_Ps, samp_Ms, 0)
    v = np.percentile(samp_as, (16, 50, 84))
    smas = v[1], v[2] - v[1], v[1] - v[0]

    # compute equilibrium T PDF (Bond albedo=0)
    samp_Teq = samp_Teff * np.sqrt(
        .5 * rvs.Rsun2m(samp_Rs) / rvs.AU2m(samp_as))
    v = np.percentile(samp_Teq, (16, 50, 84))
    Teqs = v[1], v[2] - v[1], v[1] - v[0]

    # compute insolation
    samp_F = samp_Rs**2 * (samp_Teff / 5778.)**4 / samp_as**2
    v = np.percentile(samp_F, (16, 50, 84))
    Fs = v[1], v[2] - v[1], v[1] - v[0]

    return rps, smas, Teqs, Fs
예제 #10
0
def run_mcmc(params,
             bjd,
             fcorr,
             ef,
             Ms,
             eMs,
             Rs,
             eRs,
             Teff,
             eTeff,
             u1,
             u2,
             nwalkers=200,
             burnin=500,
             nsteps=400,
             pltt=True):
    assert params.shape == (4, )
    params_optimized = np.zeros(5)
    nwalkers, burnin, nsteps = int(nwalkers), int(burnin), int(nsteps)
    params_results = np.zeros((3, 5))

    # get optimized parameters and get the LC around T0
    bjdred, fcorrred, efred, fmodel_opt, theta = \
                            optimize_singletransit_params(params, bjd, fcorr,
                                                          ef, Ms, Rs, u1, u2,
                                                          pltt=1)
    params_opt = theta[:5]
    print params, params_opt

    # run MCMC on transit LC
    initialize = [1, 1e-3, 1, 1e-2, 1]
    print 'Running MCMC on single-transit model'
    sampler, samples = run_emcee(params_opt,
                                 bjd,
                                 bjdred,
                                 fcorrred,
                                 efred,
                                 initialize,
                                 u1,
                                 u2,
                                 Ms,
                                 Rs,
                                 a=2,
                                 nwalkers=nwalkers,
                                 burnin=burnin,
                                 nsteps=nsteps,
                                 zeroplanetmodel=False)
    results = get_results(samples)
    params_results = results
    func = llnl.transit_model_func_curve_fit(u1, u2)
    fmodel_mcmc = func(bjdred, *params_results[0])

    # estimate single transit P, aRs, rpRs, and inc
    Nsamp = samples.shape[0]
    samp_Ms = np.random.randn(Nsamp) * eMs + Ms
    samp_Rs = np.random.randn(Nsamp) * eRs + Rs
    samp_rho = rvs.Msun2kg(samp_Ms) / rvs.Rsun2m(samp_Rs)**3
    samp_aRs = samples[:, 2]
    v = np.percentile(samp_aRs, (16, 50, 84))
    aRs_est = [v[1], v[2] - v[1], v[1] - v[0]]
    samp_rpRs = samples[:, 3]
    v = np.percentile(samp_rpRs, (16, 50, 84))
    rpRs_est = [v[1], v[2] - v[1], v[1] - v[0]]
    samp_inc = samples[:, 4]
    v = np.percentile(samp_inc, (16, 50, 84))
    inc_est = [v[1], v[2] - v[1], v[1] - v[0]]
    #samp_P=rvs.sec2days(np.sqrt(4*np.pi*np.pi/(6.67e-11*samp_rho)*samp_aRs**3))
    samp_P = samples[:, 0]
    v = np.percentile(samp_P, (16, 50, 84))
    P_est = [v[1], v[2] - v[1], v[1] - v[0]]

    # estimate F
    samp_Teff = np.random.randn(Nsamp) * eTeff + Teff
    samp_Ls = compute_Ls(samp_Rs, samp_Teff)
    samp_F = compute_F(samp_Ls, rvs.semimajoraxis(samp_P, samp_Ms, 0))
    v = np.percentile(samp_F, (16, 50, 84))
    F_est = [v[1], v[2] - v[1], v[1] - v[0]]

    # plotting
    if pltt:
        t0 = 2457000
        plt.figure(1)
        plt.plot(bjdred - t0, fcorrred, '.')
        plt.plot(bjdred - t0, fmodel_opt, '-', lw=3, label='optimized')
        plt.plot(bjdred - t0, fmodel_mcmc, '-', lw=2, label='MCMC model')
        plt.legend(loc='upper left')
        plt.figure(2)
        plt.hist(samp_P, bins=30)
        plt.show()

    return bjd, fcorr, ef, params_opt, fmodel_opt, samples, params_results, fmodel_mcmc, samp_P, P_est, samp_F, F_est, aRs_est, rpRs_est, inc_est
예제 #11
0
def run_emcee(theta,
              bjd,
              bjdred,
              fred,
              efred,
              initialize,
              u1,
              u2,
              Ms,
              Rs,
              nwalkers=200,
              burnin=200,
              nsteps=400,
              a=2,
              zeroplanetmodel=False):
    '''Run mcmc on an input light curve with no transit model.'''
    # get limits on P and aRs
    P, T0 = theta[:2]
    Plim = np.max([T0 - bjd.min(), bjd.max() - T0])
    aRslim = rvs.AU2m(rvs.semimajoraxis(Plim, Ms, 0)) / rvs.Rsun2m(Rs)
    print 'Plim = %.4f' % Plim
    print 'aRslim = %.4f' % aRslim

    # initialize chains
    assert len(theta) == len(initialize)
    assert len(theta) == 5
    theta[0], theta[2] = Plim + 10, aRslim + 10
    p0 = []
    for i in range(nwalkers):
        p0.append(theta + initialize * np.random.randn(len(theta)))

    # initialize sampler
    P = theta[0]
    inclims = np.array([
        float(rvs.inclination(P, Ms, Rs, 1)),
        float(rvs.inclination(P, Ms, Rs, -1))
    ])
    args = (theta, bjdred, fred, efred, Plim, aRslim, inclims, u1, u2,
            zeroplanetmodel)
    sampler = emcee.EnsembleSampler(nwalkers,
                                    len(theta),
                                    lnprob,
                                    args=args,
                                    a=a)

    # run burnin
    print 'Running burnin...'
    t0 = time.time()
    p0, _, _ = sampler.run_mcmc(p0, burnin)
    print 'Burnin acceptance fraction is %.4f' % np.mean(
        sampler.acceptance_fraction)
    print 'Burnin took %.4f minutes\n' % ((time.time() - t0) / 60.)
    sampler.reset()

    # run MCMC
    print 'Running full MCMC...'
    p0, _, _ = sampler.run_mcmc(p0, nsteps)
    samples = sampler.chain.reshape((-1, len(theta)))
    print "Mean acceptance fraction: %.4f" % np.mean(
        sampler.acceptance_fraction)
    print 'Full MCMC took %.4f minutes' % ((time.time() - t0) / 60.)

    return sampler, samples
예제 #12
0
def setup_sim(Ms, planettheta, bjd0, randomOmega=True, eccupperlim=0):
    '''
    Setup a simulation with a central star and planets.

    Parameters
    ----------
    `Ms` : float
	The mass of the central star in solar masses.
    `planettheta` : tuple of dict
	Tuple containing 5 or 6 dictionaries of each planet's 
	1) orbital period in days,
	2) time of inferior conjuction in BJD,
	3) RV semi-amplitude in m/s,
	4) h = sqrt(e)*cos(omega),
	5) k = sqrt(e)*sin(omega).
	If there are 6 dictionaries, the sixth and last is 
	6) orbital inclination in degrees.
    `bjd0` : scalar
	Reference epoch to begin the simulation at.
    `randomOmega` : bool
	If True, randomly sample the value of each planet's longitude of 
	the ascending node from U(0,2pi).
    `eccupperlim` : float
	The upper limit of eccentricities to sample from. If `eccupperlim` 
	is 0, then don't resample the eccentricities.

    Returns
    -------
    `sim` : rebound simulation object
	The rebound.Simulation containing the all injected particles.

    Example
    -------
    >>> Ms, planettheta = .1, initialize_system_parameters()
    >>> sim = setup_sim(Ms, planettheta, 2450000)

    '''
    # Initialize simulation
    sim = rebound.Simulation()
    sim.integrator = "whfast"
    sim.units = ('AU', 'Msun', 'yr')

    # Set timestep
    if len(planettheta) == 5:
        Ps, T0s, Ks, hs, ks = planettheta
        incs = {}
        for p in Ps.keys():
            incs[p] = 90.
    else:
        Ps, T0s, Ks, hs, ks, incs = planettheta
    hs, ks = np.array(hs.values()), np.array(ks.values())
    eccstmp, omegastmp = hs * hs + ks * ks, np.arctan2(ks, hs)
    eccs, omegas, ind = {}, {}, 0
    for p in Ps.keys():
        eccs[p], omegas[p] = eccstmp[ind], omegastmp[ind]
        ind += 1

    # Add star
    sim.add(m=Ms, hash='star')

    # Add planets
    for p in Ps.keys():
        print Ps[p], Ms, Ks[p], eccs[p]
        mp = rvs.kg2Msun(
            rvs.Mearth2kg(rvs.RV_mp(Ps[p], Ms, Ks[p], ecc=eccs[p])))
        Pp = Ps[p]
        ap = rvs.m2AU(rvs.semimajoraxis(Pp, Ms, 0))
        thetap = 2 * np.pi * foldAt(bjd0, Pp, T0s[p])
        eccp, omegap, incp = eccs[p], omegas[p], np.deg2rad(incs[p])
        if eccupperlim != 0:
            eccp = np.random.uniform(0, eccupperlim)
            omegap = np.random.uniform(0, 2 * np.pi)
        Omegap = np.random.uniform(0, 2 * np.pi) if randomOmega else 0.
        sim.add(m=mp,
                a=ap,
                inc=incp,
                e=eccp,
                omega=omegap,
                Omega=Omegap,
                theta=thetap,
                hash=p)

    sim.move_to_com()

    return sim