Exemplo n.º 1
0
def test_transits():
    """Test transit light curve generation."""
    # Input params
    u1 = 0.4
    u2 = 0.26
    mstar = 1       # solar masses
    rstar = 1       # solar radii
    rplanet = 0.1   # fraction of stellar radius
    b0 = 0.5        # impact parameter
    P = 50          # orbital period in days
    npts = 25
    time = np.linspace(-0.25, 0.25, npts)

    # Compute the semi-major axis from Kepler's third law in units of rstar
    a = ((P * 86400) ** 2 * (1.32712440018e20 * mstar) /
         (4 * np.pi ** 2)) ** (1. / 3.) / (6.957e8 * rstar)

    # Get the inclination in degrees
    inc = np.arccos(b0 / a) * 180 / np.pi

    # Compute the flux from numerical integration
    f = 2 * np.pi / P * time
    b = a * np.sqrt(1 - np.sin(np.pi / 2. + f) ** 2
                    * np.sin(inc * np.pi / 180) ** 2)
    nF = np.zeros_like(time)
    for i in range(npts):
        nF[i] = NumericalFlux(b[i], rplanet, u1, u2)
    nF /= np.nanmax(nF)
    den = (1 - nF)
    den[den == 0] = 1e-10

    # Compute the starry flux
    # Instantiate a second-order map and a third-order map with u(3) = 0
    # The second-order map is optimized for speed and uses different
    # equations, but they should yield identical results.
    for lmax in [2, 3]:
        star = Primary(lmax)
        star[1] = u1
        star[2] = u2
        planet = Secondary()
        planet.r = rplanet
        planet.a = a
        planet.inc = inc
        planet.porb = P
        planet.lambda0 = 90
        system = System(star, planet)
        system.compute(time)
        sF = np.array(star.lightcurve)
        sF /= sF[0]

        # Compute the error, check that it's better than 1 ppb
        error = np.max((np.abs(nF - sF) / den)[np.where(nF < 1)])
        assert error < 1e-9
Exemplo n.º 2
0
def generate(x, tstart=1, tend=5.3, npts=100, ning=100, neg=100):
    """Generate a synthetic light curve."""
    # Instantiate the star (params known exactly)
    star = Primary()
    star[1] = 0.4
    star[2] = 0.26

    # Instantiate the planet
    planet = Secondary(lmax=1)
    planet.lambda0 = 270
    planet.r = 0.0916
    planet.L = 5e-3
    planet.inc = 87
    planet.a = 11.12799
    planet.prot = 4.3
    planet.porb = 4.3
    planet.tref = 2.0

    # Instantiate the system
    system = System(star, planet)

    # Set the map coeffs
    set_coeffs(x, planet)

    # Time array w/ extra resolution at ingress/egress
    ingress = (1.94, 1.96)
    egress = (2.04, 2.06)
    time = np.linspace(tstart, tend, npts)
    if ingress is not None:
        t = np.linspace(ingress[0], ingress[1], ning)
        time = np.append(time, t)
    if egress is not None:
        t = np.linspace(egress[0], egress[1], neg)
        time = np.append(time, t)
    time = time[np.argsort(time)]

    # Compute and plot the starry flux
    system.compute(time)
    flux = np.array(system.lightcurve)

    # Noise it
    yerr = 1e-4 * np.nanmedian(flux)
    y = flux + yerr * np.random.randn(len(flux))

    # Compute the flux at hi res for plotting
    time_hires = np.linspace(tstart, tend, npts * 100)
    system.compute(time_hires)
    flux_hires = np.array(system.lightcurve)

    return time, y, yerr, star, planet, system, time_hires, flux_hires
Exemplo n.º 3
0
# System #1: A one-planet system with a hotspot offset
# ----------------------------------------------------

# Instantiate the star
star = Primary()

# Give the star a quadratic limb darkening profile
star[1] = 0.4
star[2] = 0.26

# Instantiate planet b
b = Secondary()
b.r = 0.091679
b.L = 5e-3
b.inc = 90
b.porb = 4.3
b.prot = 4.3
b.a = 11.127991
b.lambda0 = 90
b.tref = 2
b.axis = [0, 1, 0]

# Give the planet a simple dipole map
b[1, 0] = 0.5

# Rotate the planet map to produce a hotspot offset of 15 degrees
b.rotate(theta=15)

# Compute and plot the starry flux
time = np.linspace(0, 20, 10000)
Exemplo n.º 4
0
# Time arrays
time_transit = np.linspace(-0.3, 0.2, 2500)
time_secondary = np.linspace(24.75, 25.5, 2500)

# Limb-darkened star
star = Primary()
star[1] = 0.4
star[2] = 0.26
star.r_m = 0

# Dipole-map hot jupiter
planet = Secondary()
planet.r = 0.1
planet.a = 60
planet.inc = 89.5
planet.porb = 50
planet.prot = 2.49
planet.lambda0 = 89.9
planet.ecc = 0.3
planet.w = 89
planet.L = 1e-3
planet[1, 0] = 0.5

# Instantiate the system
system = System(star, planet)
system.exposure_time = 0

# Set up the plot
fig = pl.figure(figsize=(8, 8))
fig.subplots_adjust(hspace=0, bottom=0.05, top=0.95)
Exemplo n.º 5
0
def test_gradients(plot=False):
    """Test the gradients in the `System` class."""
    # Limb-darkened star
    A = Primary(lmax=3)
    A[1] = 0.4
    A[2] = 0.26
    A[3] = -0.25
    A.r_m = 1e11

    # Dipole-map hot jupiter
    b = Secondary(lmax=2)
    b.r = 0.09
    b.a = 60
    b.inc = 89.943
    b.porb = 50
    b.prot = 2.49
    b.lambda0 = 89.9
    b.ecc = 0.3
    b.w = 89
    b.L = 1.75e-3
    b[1, 0] = 0.5
    b[2, 1] = 0.1
    b[2, 2] = -0.05

    # Dipole-map hot jupiter
    c = Secondary(lmax=1)
    c.r = 0.12
    c.a = 80
    c.inc = 89.95
    c.porb = 100
    c.prot = 7.83
    c.lambda0 = 85
    c.ecc = 0.29
    c.w = 87.4
    c.L = 1.5e-3
    c[1, 0] = 0.4

    # Instantiate the system
    # We're adding a ton of light travel delay
    # and a finite exposure time: this is a
    # comprehensive test of the main `starry` features
    system = System(A, b, c)
    system.exposure_time = 0.02

    # Light curves and gradients of this object
    object = system

    # Let's plot transit, eclipse, and a PPO
    for t1, t2, figname in zip([-0.425, 25.1, -2.6], [0.0, 25.75, -2.0], [
            "gradients_transit.png", "gradients_eclipse.png",
            "gradients_ppo.png"
    ]):

        # Time arrays
        time = np.linspace(t1, t2, 500)
        time_num = np.linspace(t1, t2, 50)

        # Set up the plot
        if plot:
            fig = pl.figure(figsize=(6, 10))
            fig.subplots_adjust(hspace=0, bottom=0.05, top=0.95)

        # Run!
        system.compute(time, gradient=True)
        flux = np.array(object.lightcurve)
        grad = dict(object.gradient)

        # Numerical flux
        system.compute(time_num, gradient=True)
        flux_num = np.array(object.lightcurve)

        # Plot it
        if plot:
            ax = pl.subplot2grid((18, 3), (0, 0), rowspan=5, colspan=3)
            ax.plot(time, flux, color='C0')
            ax.plot(time_num, flux_num, 'o', ms=3, color='C1')
            ax.set_yticks([])
            ax.set_xticks([])
            [i.set_linewidth(0.) for i in ax.spines.values()]
            col = 0
            row = 0
        eps = 1e-8
        error_rel = []
        for key in grad.keys():
            if key.endswith('.y') or key.endswith('.u'):
                for i, gradient in enumerate(grad[key]):
                    if plot:
                        axg = pl.subplot2grid((18, 3), (5 + row, col),
                                              colspan=1)
                        axg.plot(time, gradient, lw=1, color='C0')
                    if key.endswith('.y'):
                        y0 = eval(key)
                        y = np.array(y0)
                        y[i + 1] += eps
                        exec(key[0] + "[:, :] = y")
                        system.compute(time)
                        exec(key[0] + "[:, :] = y0")
                    else:
                        u0 = eval(key)
                        u = np.array(u0)
                        u[i] += eps
                        exec(key[0] + "[:] = u")
                        system.compute(time)
                        exec(key[0] + "[:] = u0")
                    numgrad = (object.lightcurve - flux) / eps
                    error_rel.append(np.max(abs(numgrad - gradient)))
                    if plot:
                        axg.plot(time, numgrad, lw=1, alpha=0.5, color='C1')
                        axg.set_ylabel(r"$%s_%d$" % (key, i), fontsize=5)
                        axg.margins(None, 0.5)
                        axg.set_xticks([])
                        axg.set_yticks([])
                        [i.set_linewidth(0.) for i in axg.spines.values()]
                        if row < 12:
                            row += 1
                        else:
                            row = 0
                            col += 1
            else:
                if plot:
                    axg = pl.subplot2grid((18, 3), (5 + row, col), colspan=1)
                    axg.plot(time, grad[key], lw=1, color='C0')
                exec(key + " += eps")
                system.compute(time)
                exec(key + " -= eps")
                numgrad = (object.lightcurve - flux) / eps
                error_rel.append(np.max(abs(numgrad - grad[key])))
                if plot:
                    axg.plot(time, numgrad, lw=1, alpha=0.5, color='C1')
                    axg.margins(None, 0.5)
                    axg.set_xticks([])
                    axg.set_yticks([])
                    axg.set_ylabel(r"$%s$" % key, fontsize=5)
                    [i.set_linewidth(0.) for i in axg.spines.values()]
                    if row < 12:
                        row += 1
                    else:
                        row = 0
                        col += 1

        # Generous error tolerance
        assert np.all(np.array(error_rel) < 1e-5)

        # Save the figure
        if plot:
            fig.savefig(figname, bbox_inches='tight', dpi=300)
            pl.close()
Exemplo n.º 6
0
def test_light_travel():
    """Run the test."""
    # No delay
    star = Primary()
    star[1] = 0.40
    star[2] = 0.26
    star.r_m = 0
    planet = Secondary()
    planet.L = 1e-3
    planet.r = 0.1
    planet.porb = 10
    planet.prot = 10
    planet.a = 22
    planet[1, 0] = 0.5
    system = System(star, planet)
    time = np.concatenate(
        (np.linspace(0, 0.5, 10000,
                     endpoint=False), np.linspace(0.5,
                                                  4.5,
                                                  100,
                                                  endpoint=False),
         np.linspace(4.5, 5.5, 10000,
                     endpoint=False), np.linspace(5.5,
                                                  9.5,
                                                  100,
                                                  endpoint=False),
         np.linspace(9.5, 10, 10000)))
    phase = time / 10.
    system.compute(time)
    transit = phase[np.argmax(planet.Z)]
    eclipse = phase[np.argmin(planet.Z)]
    assert transit == 0
    assert eclipse == 0.5

    # Let's give the system a real length scale now
    star.r_m = 6.95700e8
    eps = 1e-3
    time = np.concatenate(
        (np.linspace(0, 0.5, 100000, endpoint=False),
         np.linspace(0.5, 5 - eps, 100, endpoint=False),
         np.linspace(5 - eps, 5 + eps, 1000000, endpoint=False),
         np.linspace(5 + eps, 9.5, 100,
                     endpoint=False), np.linspace(9.5, 10, 100000)))
    phase = time / planet.porb
    system.compute(time)
    transit = phase[np.argmin(np.abs(planet.X) + (planet.Z < 0))]
    eclipse = phase[np.argmin(np.abs(planet.X) + (planet.Z > 0))]
    assert transit == 0.999940999409994
    assert eclipse == 0.5000590894

    # Run some extra tests
    c = 299792458.
    RSUN = 6.957e8
    time = np.concatenate(
        (np.linspace(0, 0.5, 100000,
                     endpoint=False), np.linspace(0.5,
                                                  4.5,
                                                  100,
                                                  endpoint=False),
         np.linspace(4.5, 5.5, 100000,
                     endpoint=False), np.linspace(5.5,
                                                  9.5,
                                                  100,
                                                  endpoint=False),
         np.linspace(9.5, 10, 100000)))
    phase = time / planet.porb

    # Test this on an inclined orbit
    planet.inc = 30
    system.compute(time)
    transit = phase[np.argmax(planet.Z)]
    eclipse = phase[np.argmin(planet.Z)]
    delay_starry = (0.5 - (transit - eclipse)) * planet.porb * 86400
    a = planet.a * star.r_m
    delay_analytic = 2 * a / c * np.sin(planet.inc * np.pi / 180)
    assert np.abs(1 - delay_starry / delay_analytic) < 0.01

    # Test this on an orbit with nonzero Omega
    planet.inc = 90
    planet.Omega = 90
    system.compute(time)
    transit = phase[np.argmax(planet.Z)]
    eclipse = phase[np.argmin(planet.Z)]
    delay_starry = (0.5 - (transit - eclipse)) * planet.porb * 86400
    a = planet.a * star.r_m
    delay_analytic = 2 * a / c
    assert np.abs(1 - delay_starry / delay_analytic) < 0.01

    # Compute the light travel time from the secondary
    # eclipse to the barycenter for an eccentric orbit.
    # First, compute the phase of secondary eclipse
    # with no light travel time delay:
    planet.inc = 90
    planet.Omega = 0
    planet.w = 30
    planet.ecc = 0.25
    star.r_m = 0
    system.compute(time)
    eclipse0 = phase[np.argmin(planet.Z)]
    z0 = planet.Z[np.argmin(planet.Z)]
    # Now, compute the phase w/ the delay
    star.r_m = 6.95700e8
    system.compute(time)
    eclipse = phase[np.argmin(planet.Z)]
    # Compute the light travel time to the barycenter in days:
    travel_time_starry = (eclipse - eclipse0) * planet.porb * 86400
    # Compute the analytic light travel time to the barycenter in days:
    travel_time_analytic = (0 - z0) * star.r_m / c
    assert np.abs(1 - travel_time_starry / travel_time_analytic) < 0.01
Exemplo n.º 7
0
# Compute the semi-major axis from Kepler's third law in units of rstar
a = ((P * 86400)**2 * (1.32712440018e20 * mstar) /
     (4 * np.pi**2))**(1. / 3.) / (6.957e8 * rstar)

# Get the inclination in degrees
inc = np.arccos(b0 / a) * 180 / np.pi

# Compute and plot the starry flux
star = Primary()
star[1] = u1
star[2] = u2

planet = Secondary()
planet.r = rplanet
planet.inc = inc
planet.porb = P
planet.a = a
planet.lambda0 = 90
system = System(star, planet)
system.compute(time)
sF = np.array(star.lightcurve)
sF /= sF[0]
ax[0].plot(time, sF, '-', color='C0', label='starry')

# Compute and plot the flux from numerical integration
print("Computing numerical flux...")
f = 2 * np.pi / P * time
b = a * np.sqrt(1 - np.sin(np.pi / 2. + f)**2 * np.sin(inc * np.pi / 180)**2)
nF = np.zeros_like(time)
for i in tqdm(range(npts)):