예제 #1
0
        def __init__(self):
            # Instantiate a star with a dipole map
            A = starry.Primary(starry.Map(ydeg=1), prot=0.0)
            amp_true = 0.75
            y_true = np.array([1, 0.1, 0.2, 0.3])
            inc_true = 60
            A.map.amp = amp_true
            A.map[1, :] = y_true[1:]
            A.map.inc = inc_true

            # Instantiate two transiting planets with different longitudes of
            # ascending node. This ensures there's no null space!
            b = starry.Secondary(starry.Map(amp=0),
                                 porb=1.0,
                                 r=0.1,
                                 t0=-0.05,
                                 Omega=30.0)
            c = starry.Secondary(starry.Map(amp=0),
                                 porb=1.0,
                                 r=0.1,
                                 t0=0.05,
                                 Omega=-30.0)
            sys = starry.System(A, b, c)

            # Generate a synthetic light curve with just a little noise
            t = np.linspace(-0.1, 0.1, 100)
            flux = sys.flux(t)
            sigma = 1e-5
            np.random.seed(1)
            flux += np.random.randn(len(t)) * sigma

            # Store
            self.A = A
            self.b = b
            self.c = c
            self.sys = sys
            self.t = t
            self.flux = flux
            self.sigma = sigma
            self.amp_true = amp_true
            self.y_true = y_true
            self.inc_true = inc_true
예제 #2
0
def test_period_semi():
    # Check that an error is raised if neither a nor porb is given
    with pytest.raises(ValueError) as e:
        body = starry.Secondary(starry.Map())
    assert "Must provide a value for either `porb` or `a`" in str(e.value)

    # Check that the semi --> period conversion works
    pri = starry.Primary(starry.Map(), m=1.0, mass_unit=u.Msun)
    sec = starry.Secondary(starry.Map(),
                           a=10.0,
                           m=1.0,
                           length_unit=u.AU,
                           mass_unit=u.Mearth)
    sys = starry.System(pri, sec)
    period = sys._get_periods()[0]
    true_period = (
        ((2 * np.pi) * (sec.a * sec.length_unit)**(3 / 2) /
         (np.sqrt(G * (pri.m * pri.mass_unit + sec.m * sec.mass_unit)))).to(
             u.day).value)
    assert np.allclose(period, true_period)
예제 #3
0
def test_sys_flux():
    """Test the normalization of the flux."""
    # Instantiate a system. Planet has radius `r` and is at
    # distance `d` from a point illumination source.
    d = 10
    r = 2
    planet = starry.Secondary(starry.Map(reflected=True), a=d, r=r)
    star = starry.Primary(starry.Map(), r=0)
    sys = starry.System(star, planet)

    # Get the star & planet flux when it's at full phase
    t_full = 0.5 * sys._get_periods()[0]
    f_star, f_planet = sys.flux(t=t_full, total=False)

    # Star should have unit flux
    assert np.allclose(f_star, 1.0)

    # Planet should have flux equal to (2 / 3) r^2 / d^2
    f_expected = (2.0 / 3.0) * r ** 2 / d ** 2
    assert np.allclose(f_planet, f_expected)
예제 #4
0
def test_compare_to_exoplanet():
    """Ensure we get the same result with `starry` and `exoplanet`.
    """
    # Define the star
    A = starry.Primary(
        starry.Map(rv=True, veq=0),
        r=1.0,
        m=1.0,
        prot=0,
        length_unit=u.Rsun,
        mass_unit=u.Msun,
    )

    # Define the planet
    b = starry.Secondary(
        starry.Map(rv=True, veq=0),
        r=0.1,
        porb=1.0,
        m=0.01,
        t0=0.0,
        inc=86.0,
        ecc=0.3,
        w=60,
        length_unit=u.Rsun,
        mass_unit=u.Msun,
        angle_unit=u.degree,
        time_unit=u.day,
    )

    # Define the planet
    c = starry.Secondary(
        starry.Map(rv=True, veq=0),
        r=0.1,
        porb=1.7,
        m=0.02,
        t0=0.3,
        inc=87.0,
        ecc=0.2,
        w=70,
        length_unit=u.Rsun,
        mass_unit=u.Msun,
        angle_unit=u.degree,
        time_unit=u.day,
    )

    # Define the system
    sys = starry.System(A, b, c)

    # Compute with starry
    time = np.linspace(-0.5, 0.5, 1000)
    rv1 = sys.rv(time, keplerian=True, total=True)

    # Compute with exoplanet
    orbit = exoplanet.orbits.KeplerianOrbit(
        period=[1.0, 1.7],
        t0=[0.0, 0.3],
        incl=[86.0 * np.pi / 180, 87.0 * np.pi / 180],
        ecc=[0.3, 0.2],
        omega=[60 * np.pi / 180, 70 * np.pi / 180],
        m_planet=[0.01, 0.02],
        m_star=1.0,
        r_star=1.0,
    )
    rv2 = orbit.get_radial_velocity(time).eval().sum(axis=1)

    assert np.allclose(rv1, rv2)
예제 #5
0
파일: inclined.py 프로젝트: dflemin3/starry
    inc = planet.inc * np.pi / 180
    Omega = planet.Omega * np.pi / 180

    # Rotate the map to the correct orientation on the sky
    planet.map.rotate(axis=(1, 0, 0), theta=np.pi / 2 - inc)
    planet.map.rotate(axis=(0, 0, 1), theta=Omega)

    # Rotate the axis of rotation in the same way
    planet.axis = np.dot(R((1, 0, 0), np.pi / 2 - inc), planet.axis)
    planet.axis = np.dot(R((0, 0, 1), Omega), planet.axis)


# Instantiate the system
planet = starry.Planet(L=1, porb=1, prot=1)
star = starry.Star()
sys = starry.System([star, planet])
time = np.linspace(0, 1, 1000)
Omega = 0
planet.Omega = Omega

# Set up the figure
fig = pl.figure(figsize=(12, 6))
ax = np.array([[pl.subplot2grid((5, 16), (i, j)) for j in range(8)]
               for i in range(5)])
ax_lc = pl.subplot2grid((5, 16), (0, 9), rowspan=5, colspan=8)
x, y = np.meshgrid(np.linspace(-1, 1, 100), np.linspace(-1, 1, 100))
lam = np.linspace(0, 2 * np.pi, 8, endpoint=False)
phase = np.linspace(90, 450, 1000)
phase[np.argmax(phase > 360)] = np.nan
phase[phase > 360] -= 360
예제 #6
0
        6,
        amp=planet_amp,
        inc=85.76,
    ),
    r=1.138,
    m=1.162,
    inc=85.76,
    porb=2.22,
    prot=2.22,
    theta0=180,
    length_unit=u.Rjup,
    mass_unit=u.Mjup,
    angle_unit=u.degree,
)

sys = starry.System(star, planet)
time = np.arange(-2, 2, MINUTE)

A0 = planet_amp * sys.design_matrix(time)[:, 1]
A = planet_amp * sys.design_matrix(time)[:, 2:]

# Generate
sigma = 2.9e-5
N = (planet.map.ydeg + 1)**2 - 1
for lon in np.linspace(-180, 180, 30, endpoint=False):
    planet.map.add_spot(intensity=0.01,
                        sigma=0.1,
                        lat=0,
                        lon=lon,
                        relative=False)
planet.map.rotate([0, 1, 0], 15)
예제 #7
0
lnlike_inputs = itertools.product(vals, vals, woodbury)

# Instantiate a star with a dipole map
A = starry.Primary(starry.Map(ydeg=1), prot=0.0)
amp_true = 0.75
y_true = np.array([1, 0.1, 0.2, 0.3])
inc_true = 60
A.map.amp = amp_true
A.map[1, :] = y_true[1:]
A.map.inc = inc_true

# Instantiate two transiting planets with different longitudes of
# ascending node. This ensures there's no null space!
b = starry.Secondary(starry.Map(amp=0), porb=1.0, r=0.1, t0=-0.05, Omega=30.0)
c = starry.Secondary(starry.Map(amp=0), porb=1.0, r=0.1, t0=0.05, Omega=-30.0)
sys = starry.System(A, b, c)

# Generate a synthetic light curve with just a little noise
t = np.linspace(-0.1, 0.1, 100)
flux = sys.flux(t)
sigma = 1e-5
np.random.seed(1)
flux += np.random.randn(len(t)) * sigma


@pytest.mark.parametrize("L,C", solve_inputs)
def test_solve(L, C):
    # Place a generous prior on the map coefficients
    if L == "scalar":
        A.map.set_prior(L=1)
    elif L == "vector":
예제 #8
0
def comparison():
    """Run the main comparison function."""
    # Define SPIDERMAN model parameters
    # Parameters adapted from
    # https://github.com/tomlouden/SPIDERMAN/
    # blob/master/examples/Brightness%20maps.ipynb
    spider_params = sp.ModelParams(brightness_model='spherical')

    spider_params.n_layers = 10  # Will be reset later
    spider_params.t0 = 0  # Central time of PRIMARY transit [d]
    spider_params.per = 0.81347753  # Period [days]
    spider_params.a_abs = 1.0e-30  # Nearly 0 a to ignore light travel
    spider_params.inc = 90.0  # Inclination [degrees]
    spider_params.ecc = 0.0  # Eccentricity
    spider_params.w = 0.0  # Argument of periastron
    spider_params.rp = 0.1594  # Planet to star radius ratio
    spider_params.a = 4.855  # Semi-major axis scaled by rstar
    spider_params.p_u1 = 0.0  # Planetary limb darkening parameter
    spider_params.p_u2 = 0.0  # Planetary limb darkening parameter

    # SPIDERMAN spherical harmonics parameters
    ratio = 1.0e-3  # Planet-star flux ratio
    spider_params.sph = [ratio, ratio / 2, 0, 0]  # vector of Ylm coeffs
    spider_params.degree = 2
    spider_params.la0 = 0.0
    spider_params.lo0 = 0.0

    # Define starry model parameters to match SPIDERMAN system

    # Define star
    star = starry.Star()

    # Define planet
    planet = starry.Planet(
        lmax=2,
        lambda0=90.0,
        w=spider_params.w,
        r=spider_params.rp,
        # Factor of pi to match SPIDERMAN normalization
        L=1.0e-3 * np.pi,
        inc=spider_params.inc,
        a=spider_params.a,
        porb=spider_params.per,
        tref=spider_params.t0,
        prot=spider_params.per,
        ecc=spider_params.ecc)

    # Define spherical harmonic coefficients
    planet.map[0, 0] = 1.0
    planet.map[1, -1] = 0.0
    planet.map[1, 0] = 0.0
    planet.map[1, 1] = 0.5

    # Make a system
    system = starry.System([star, planet])

    # Now make a multiprecision system to compute error estimates
    mstar = starry.multi.Star()
    mplanet = starry.multi.Planet(lmax=2,
                                  lambda0=90.,
                                  w=spider_params.w,
                                  r=spider_params.rp,
                                  L=1.0e-3 * np.pi,
                                  inc=spider_params.inc,
                                  a=spider_params.a,
                                  porb=spider_params.per,
                                  tref=spider_params.t0,
                                  prot=spider_params.per,
                                  ecc=spider_params.ecc)
    mplanet.map[:] = planet.map[:]
    msystem = starry.multi.System([mstar, mplanet])

    # ## Speed test! ## #

    # Number of time array points
    ns = np.array([10, 50, 100, 500, 1000], dtype=int)

    # SPIDERMAN grid resolution points
    ngrid = np.array([5, 10, 20, 50, 100], dtype=int)

    n_repeats = 3
    t_starry = np.nan + np.zeros(len(ns))
    t_spiderman = np.nan + np.zeros((len(ns), len(ngrid)))
    diff1 = np.nan + np.zeros_like(t_starry)
    diff2 = np.nan + np.zeros_like(t_spiderman)
    flux_comp = []

    # Loop over time grid sizes
    for ii, n in enumerate(ns):

        # New time array of length n just around the
        # occulation and some phase curve
        time_arr = np.linspace(0.4 * spider_params.per,
                               0.6 * spider_params.per, n)

        # Compute **exact** flux using multiprecision
        msystem.compute(time_arr)
        mflux = np.array(msystem.flux)

        # Repeat calculation a few times and pick fastest one
        best_starry = np.inf
        for _ in range(n_repeats):

            start = time.time()
            system.compute(time_arr)
            flux = np.array(system.flux)
            dt = time.time() - start

            if dt < best_starry:
                best_starry = dt
                best_starry_flux = flux

        # Save fastest time
        t_starry[ii] = best_starry

        # Compute error
        diff1[ii] = np.max(np.fabs((mflux - best_starry_flux) / mflux))

        # Time batman (for all grid resolutions)
        for jj, ng in enumerate(ngrid):

            # New number of layers
            spider_params.n_layers = ng

            # Repeat calculation a few times
            best_spiderman = np.inf
            for _ in range(n_repeats):

                start = time.time()
                lc = spider_params.lightcurve(time_arr, use_phase=False)
                dt = time.time() - start

                if (ng == 5):
                    spider_lc_5 = np.array(lc)

                if dt < best_spiderman:
                    best_spiderman = dt
                    best_spiderman_flux = lc

            # Save fastest time
            t_spiderman[ii, jj] = best_spiderman

            # Save log maximum relative error
            diff2[ii,
                  jj] = np.max(np.fabs((mflux - best_spiderman_flux) / mflux))

            # For highest time resolution, compute differences
            # between the predictions
            if n == ns[-1]:
                flux_comp.append(
                    np.fabs(best_starry_flux - best_spiderman_flux))

    # ## Generate the figures! ## #

    # First figure: relative error

    fig = plt.figure(figsize=(5, 5))
    ax = plt.subplot2grid((3, 1), (0, 0), colspan=1, rowspan=1)
    ax2 = plt.subplot2grid((3, 1), (1, 0), colspan=1, rowspan=2)

    time_arr = np.linspace(0.4 * spider_params.per, 0.6 * spider_params.per,
                           ns[-1])

    # Flux panel
    ax.plot(time_arr,
            best_starry_flux,
            lw=1,
            alpha=1,
            label='starry',
            color='gray')
    ax.plot(time_arr,
            spider_lc_5,
            lw=1,
            alpha=1,
            ls='--',
            label='spiderman (5)')

    ax.legend(loc='lower left', framealpha=0.0, fontsize=10)
    ax.get_xaxis().set_ticklabels([])
    ax.set_xlim(time_arr.min(), time_arr.max())
    ax.set_ylim(1.000 - 0.001, 1.004 + 0.001)
    ax.set_ylabel("Flux", fontsize=14)

    # Error panel
    for kk in range(len(flux_comp)):
        ax2.plot(time_arr,
                 flux_comp[kk],
                 lw=1,
                 label="n$_{\mathrm{layers}}$=%d" % ngrid[kk])

    ax2.set_ylim(1.0e-11, 1.0e-4)
    ax2.set_xlim(time_arr.min(), time_arr.max())
    ax2.set_yscale("log")
    ax2.set_ylabel("Relative error", fontsize=14)
    ax2.set_xlabel("Time [d]", fontsize=14)
    ax2.legend(loc="best", framealpha=0.0)
    fig.savefig("spidercomp_flux.pdf", bbox_inches="tight")

    # Second figure: speed comparison

    fig = plt.figure(figsize=(7, 4))
    ax = plt.subplot2grid((2, 5), (0, 0), colspan=4, rowspan=2)
    axleg1 = plt.subplot2grid((2, 5), (0, 4))
    axleg2 = plt.subplot2grid((2, 5), (1, 4))
    axleg1.axis('off')
    axleg2.axis('off')
    ax.set_xlabel('Number of points', fontsize=13)
    for tick in ax.get_xticklabels():
        tick.set_fontsize(12)
    ax.set_ylabel('Evaluation time [seconds]', fontsize=13)
    ax.set_yscale("log")
    ax.set_xscale("log")
    for tick in ax.get_yticklabels():
        tick.set_fontsize(12)

    # Starry, loop over all points
    for ii in range(len(ns)):
        ax.plot(ns[ii],
                t_starry[ii],
                "o",
                lw=2,
                color="gray",
                ms=ms(diff1[ii]))
    ax.plot(ns, t_starry, "-", lw=1.5, color="gray", alpha=0.45)

    # Loop over all grid resolutions
    for jj, ng in enumerate(ngrid):
        ax.plot(ns,
                t_spiderman[:, jj],
                "-",
                color="C%d" % (jj),
                alpha=0.25,
                lw=1.5)
        for kk in range(len(ns)):
            ax.plot(ns[kk],
                    t_spiderman[kk, jj],
                    "o",
                    ms=ms(diff2[kk, jj]),
                    color="C%d" % (jj))

    # Legend 1
    axleg1.plot([0, 1], [0, 1], color='gray', label='starry')
    # Loop over all grid resolutions
    for jj, ng in enumerate(ngrid):
        axleg1.plot([0, 1], [0, 1],
                    color="C%d" % (jj),
                    label="n$_{\mathrm{layers}}$=%d" % ng)
    axleg1.set_xlim(2, 3)
    leg = axleg1.legend(loc='center', frameon=False)
    leg.set_title('method', prop={'weight': 'bold'})

    for logerr in [-16, -12, -8, -4, 0]:
        axleg2.plot([0, 1], [0, 1],
                    'o',
                    color='gray',
                    ms=ms(10**logerr),
                    label=r'$%3d$' % logerr)
    axleg2.set_xlim(2, 3)
    leg = axleg2.legend(loc='center', labelspacing=1, frameon=False)
    leg.set_title('log error', prop={'weight': 'bold'})
    fig.savefig("spidercomp.pdf", bbox_inches="tight")
예제 #9
0
def test_light_delay():
    pri = starry.Primary(starry.Map())
    sec = starry.Secondary(starry.Map(), porb=1.0)
    sys = starry.System(pri, sec, light_delay=True)
    assert sys.light_delay is True
예제 #10
0
    r=21.1770214,
    length_unit=u.earthRad,
    inc=87.2,
    t0=-0.65625,
)

# Time arrays (secondary eclipse ingress / full phase curve)
t_ingress = np.linspace(0, 0.017, 1000)
t_egress = 218 / 60 / 24 + t_ingress
t_sec = np.append(t_ingress, t_egress)
t_phase = kwargs["t0"] + kwargs["porb"] * np.linspace(-0.5, 0.5, 1000)

# Uniform
e_map = starry.Map(ydeg=1, reflected=False)
e = starry.Secondary(e_map, **kwargs)
sys = starry.System(star, e)
flux_em = sys.flux(t=t_sec, total=False)[1]

# Noon approximation
e_map = starry.Map(udeg=1, reflected=False)
e_map[1] = 1
e = starry.Secondary(e_map, **kwargs)
sys = starry.System(star, e)
flux_ld = sys.flux(t=t_sec, total=False)[1]

# Reflected, point source
e_map = starry.Map(ydeg=1, reflected=True)
e_map.amp *= 0.2
e = starry.Secondary(e_map, **kwargs)
sys = starry.System(star, e)
flux_ref = sys.flux(t=t_sec, total=False)[1]
예제 #11
0
def test_reflected_light():
    pri = starry.Primary(starry.Map(amp=0), r=1)
    sec = starry.Secondary(starry.Map(reflected=True), porb=1.0, r=1)
    sys = starry.System(pri, sec)
    t = np.concatenate((np.linspace(0.1, 0.4, 50), np.linspace(0.6, 0.9, 50)))
    flux = sys.flux(t)
예제 #12
0
def test_bodies():
    pri = starry.Primary(starry.Map())
    sec = starry.Secondary(starry.Map(ydeg=1), porb=1.0)
    sys = starry.System(pri, sec)
    assert sys.primary == pri
    assert sys.secondaries[0] == sec
예제 #13
0
def test_edge_on_eccentric():
    # Params
    ydeg = 10
    u = [0.5, 0.25]
    y = 0.1 * np.random.randn((ydeg + 1)**2 - 1)
    porb = 1.0
    prot = 1.0
    amp = 0.25
    r = 0.5
    m = 0.25
    ecc = 0.5
    w = 75
    t = np.linspace(-0.75, 0.75, 10000)

    # Beta version
    pri_beta = starry_beta.kepler.Primary(lmax=2)
    pri_beta[1], pri_beta[2] = u
    sec_beta = starry_beta.kepler.Secondary(lmax=ydeg)
    sec_beta[1:, :] = y
    sec_beta.porb = porb
    sec_beta.prot = prot
    sec_beta.L = amp
    sec_beta.r = r
    sec_beta.a = (G_grav * (1.0 + m) * porb**2 / (4 * np.pi**2))**(1.0 / 3)
    sec_beta.inc = 90
    sec_beta.Omega = 0
    sec_beta.ecc = ecc
    sec_beta.w = w
    sys_beta = starry_beta.kepler.System(pri_beta, sec_beta)
    sys_beta.compute(t)
    flux_beta = np.array(sys_beta.lightcurve)

    # Compute the time of transit
    M0 = 0.5 * np.pi - w * np.pi / 180.0
    f = M0
    E = np.arctan2(np.sqrt(1 - ecc**2) * np.sin(f), ecc + np.cos(f))
    M = E - ecc * np.sin(E)
    t0 = (M - M0) * porb / (2 * np.pi)

    # Compute the time of eclipse
    E = np.arctan2(
        np.sqrt(1 - ecc**2) * np.sin(f + np.pi), ecc + np.cos(f + np.pi))
    M = E - ecc * np.sin(E)
    t_ecl = (M - M0) * porb / (2 * np.pi)

    # This is the required phase offset such that the map coefficients
    # correspond to what the observer sees at secondary eclipse
    theta0 = -(t_ecl - t0) * 360

    # Version 1
    pri = starry.Primary(starry.Map(udeg=2))
    pri.map[1:] = u
    sec = starry.Secondary(
        starry.Map(ydeg=ydeg, amp=amp),
        porb=porb,
        r=r,
        m=m,
        inc=90,
        Omega=0,
        ecc=ecc,
        w=w,
        t0=t0,
        theta0=theta0,
    )
    sec.map[1:, :] = y
    sys = starry.System(pri, sec)
    flux = sys.flux(t)

    # Compare
    assert np.allclose(flux, flux_beta)
예제 #14
0
def test_default_system_units():
    pri = starry.Primary(starry.Map())
    sec = starry.Secondary(starry.Map(), porb=1.0)
    sys = starry.System(pri, sec)
    assert sys.time_unit == u.day