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)
Exemple #2
0
import theano
import theano.tensor as tt
import numpy as np
import starry
import matplotlib.pyplot as plt
import pytest

map = starry.Map(ydeg=1, reflected=True)
_b = tt.dvector("b")
_theta = tt.dvector("theta")
_bo = tt.dvector("bo")
_ro = tt.dscalar("ro")
_sigr = tt.dscalar("sigr")
_s = theano.function([_b, _theta, _bo, _ro, _sigr],
                     map.ops.sT(_b, _theta, _bo, _ro, _sigr))


def s(b, theta, bo, ro, sigr, n=0):
    if hasattr(ro, "__len__"):
        assert not (hasattr(b, "__len__") or hasattr(theta, "__len__")
                    or hasattr(bo, "__len__") or hasattr(sigr, "__len__"))
        return [
            _s([b], [theta], [bo], ro[i], sigr)[0, n] for i in range(len(ro))
        ]
    elif hasattr(sigr, "__len__"):
        assert not (hasattr(b, "__len__") or hasattr(theta, "__len__")
                    or hasattr(bo, "__len__") or hasattr(ro, "__len__"))
        return [
            _s([b], [theta], [bo], ro, sigr[i])[0, n] for i in range(len(sigr))
        ]
    else:
Exemple #3
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
Exemple #4
0
def earth_eclipse(lmax=20):
    """Compute the error on the secondary eclipse of the Earth."""
    npts = 1000

    # Create our map
    map = starry.Map(lmax)
    map.load_image('earth')

    # Compute. Ingress duration is
    # dt = (2 REARTH) / (2 PI * 1 AU / 1 year) ~ 7 minutes
    yo = 0
    ro = 6.957e8 / 6.3781e6
    time = np.linspace(0, 7 * 1.5, npts)
    xo = np.linspace(-(ro + 1.5), -(ro - 1.5), npts, -1)
    flux = np.array(map.flux(xo=xo, yo=yo, ro=ro))

    # Compute at high precision
    map_128 = starry.Map(lmax, multi=True)
    map_128[:, :] = map[:, :]
    flux128 = np.array(map_128.flux(xo=xo, yo=yo, ro=ro))

    # Show
    fig = pl.figure(figsize=(7, 6))
    nim = 10
    ax = [pl.subplot2grid((7, nim), (1, 0), colspan=nim, rowspan=3),
          pl.subplot2grid((7, nim), (4, 0), colspan=nim, rowspan=3)]
    fig.subplots_adjust(hspace=0.6)
    ax[0].plot(time, flux / flux[0])
    ax[1].plot(time, np.abs(flux - flux128))
    ax[1].set_yscale('log')
    ax[1].axhline(1e-3, color='k', ls='--', alpha=0.75, lw=0.5)
    ax[1].axhline(1e-6, color='k', ls='--', alpha=0.75, lw=0.5)
    ax[1].axhline(1e-9, color='k', ls='--', alpha=0.75, lw=0.5)
    ax[1].annotate("ppt", xy=(1e-3, 1e-3), xycoords="data", xytext=(3, -3),
                   textcoords="offset points", ha="left", va="top", alpha=0.75)
    ax[1].annotate("ppm", xy=(1e-3, 1e-6), xycoords="data", xytext=(3, -3),
                   textcoords="offset points", ha="left", va="top", alpha=0.75)
    ax[1].annotate("ppb", xy=(1e-3, 1e-9), xycoords="data", xytext=(3, -3),
                   textcoords="offset points", ha="left", va="top", alpha=0.75)
    ax[1].set_ylim(5e-17, 20.)
    ax[0].set_xlim(0, time[-1])
    ax[1].set_xlim(0, time[-1])
    ax[1].set_xlabel("Time [minutes]", fontsize=16)
    ax[0].set_ylabel("Normalized flux", fontsize=16, labelpad=15)
    ax[1].set_ylabel("Relative error", fontsize=16)

    # Plot the earth images
    res = 100
    ax_im = [pl.subplot2grid((7, nim), (0, n)) for n in range(nim)]
    x, y = np.meshgrid(np.linspace(-1, 1, res), np.linspace(-1, 1, res))
    map.axis = [0, 1, 0]
    for n in range(nim):
        i = int(np.linspace(0, npts - 1, nim)[n])
        I = [map(theta=0, x=x[j], y=y[j]) for j in range(res)]
        ax_im[n].imshow(I, origin="lower", interpolation="none", cmap='plasma',
                        extent=(-1, 1, -1, 1))
        xm = np.linspace(xo[i] - ro + 1e-5, xo[i] + ro - 1e-5, 10000)
        ax_im[n].fill_between(xm, yo - np.sqrt(ro ** 2 - (xm - xo[i]) ** 2),
                              yo + np.sqrt(ro ** 2 - (xm - xo[i]) ** 2),
                              color='w')
        ax_im[n].axis('off')
        ax_im[n].set_xlim(-1.05, 1.05)
        ax_im[n].set_ylim(-1.05, 1.05)

    fig.savefig("stability_earth.pdf", bbox_inches='tight')
def test_lightcurve(b, theta, ro, ydeg=1, ns=1000, nb=50, res=999, plot=False):

    # Array over full occultation, including all singularities
    xo = 0.0
    yo = np.linspace(0, 1 + ro, ns, endpoint=True)
    for pt in [ro, 1, 1 - ro, b + ro]:
        if pt >= 0:
            yo[np.argmin(np.abs(yo - pt))] = pt
    if theta == 0:
        xs = 0
        ys = 1
    else:
        xs = 0.5
        ys = -xs / np.tan(theta)
    rxy2 = xs ** 2 + ys ** 2
    if b == 0:
        zs = 0
    elif b == 1:
        zs = -1
        xs = 0
        ys = 0
    elif b == -1:
        zs = 1
        xs = 0
        ys = 0
    else:
        zs = -np.sign(b) * np.sqrt(rxy2 / (b ** -2 - 1))

    # Compute analytic
    map = starry.Map(ydeg=ydeg, reflected=True)
    map[1:, :] = 1
    flux = map.flux(xs=xs, ys=ys, zs=zs, xo=xo, yo=yo, ro=ro)

    # Compute numerical
    flux_num = np.zeros_like(yo) * np.nan
    computed = np.zeros(ns, dtype=bool)
    (lat, lon), (x, y, z) = map.ops.compute_ortho_grid(res)
    img = map.render(xs=xs, ys=ys, zs=zs, res=res).flatten()
    for i, yoi in tqdm(enumerate(yo), total=len(yo)):
        if (i == 0) or (i == ns - 1) or (i % (ns // nb) == 0):
            idx = (x - xo) ** 2 + (y - yoi) ** 2 > ro ** 2
            flux_num[i] = np.nansum(img[idx]) * 4 / res ** 2
            computed[i] = True

    # Interpolate over numerical result
    f = interp1d(yo[computed], flux_num[computed], kind="cubic")
    flux_num_interp = f(yo)

    # Plot
    if plot:
        fig = plt.figure()
        plt.plot(yo, flux, "C0-", label="starry", lw=2)
        plt.plot(yo, flux_num, "C1o", label="brute")
        plt.plot(yo, flux_num_interp, "C1-", lw=1)
        plt.legend(loc="best")
        plt.xlabel("impact parameter")
        plt.ylabel("flux")
        fig.savefig(
            "test_lightcurve[{}-{}-{}].pdf".format(b, theta, ro),
            bbox_inches="tight",
        )
        plt.close()

    # Compare with very lax tolerance; we're mostly looking
    # for gross outliers
    diff = np.abs(flux - flux_num_interp)
    assert np.max(diff) < 0.001
Exemple #6
0
def test_show_moll():
    map = starry.Map(ydeg=1, udeg=1)
    map.show(file="tmp.pdf", projection="moll")
    os.remove("tmp.pdf")
Exemple #7
0
def test_show_ld():
    map = starry.Map(udeg=2)
    map.show(file="tmp.pdf")
    os.remove("tmp.pdf")
ax[0, 0].set_visible(False)
ax[0, 1].set_visible(False)
ax[1, 0].set_ylabel("flux [normalized]", fontsize=10)
ax[1, 0].set_title("thermal phase curve", fontsize=12, fontweight="bold")
ax[1, 1].set_title("reflected phase curve", fontsize=12, fontweight="bold")
ax[2, 0].set_ylabel("flux [normalized]", fontsize=10)
ax[3, 0].set_title("thermal occultation", fontsize=12, fontweight="bold")
ax[3, 1].set_title("reflected occultation", fontsize=12, fontweight="bold")
for axis in np.append(ax[1, :], ax[3, :]):
    axis.tick_params(labelsize=8)
    axis.set_ylim(-0.05, 1.65)

# Show the true map
ax_top = fig.add_subplot(5, 1, 1)
ax_top.set_title("input", fontsize=12, fontweight="bold")
map = starry.Map(20)
map.load("earth", sigma=0.1)
map.show(ax=ax_top, projection="moll")

# Solve the least-squares problem for thermal & reflected phase curves
for j, rmoon in enumerate([0, 0.25]):
    for i, reflected in enumerate([False, True]):

        # Instantiate a map of the Earth
        map = starry.Map(20, reflected=reflected)
        map.load("earth", sigma=0.1)
        obl = 23.5
        porb = 365.25
        prot = 1.0
        pmoon = 1.37
        amoon = 2.0
Exemple #9
0
def test_I_stability(noon, plot=False):
    # FB found this unstable limit. The instability comes
    # from two places:
    # 1. The upward recursion in the I integral is unstable.
    #    We need to either implement a tridiagonal solver as
    #    in the J integral and/or refine our computation of kappa.
    # 2. The terminator parameter b = 1, which causes `get_angles` to
    #    oscillate between different integration codes. When b
    #    approaches unity, we should switch to the regular starry
    #    solver, since the terminator is so close to the limb that its
    #    presence doesn't matter.
    xo, yo, zo, ro = (
        31.03953239062832,
        23.892679948795926,
        1.0,
        39.10406741663172,
    )
    # Exactly noon?
    if noon:
        xs = 0.0
    else:
        xs = 0.1
    ys = 0.0
    zs = 1.0
    xo = np.linspace(xo - 2, xo + 2, 1000)

    # Compute analytic
    map = starry.Map(ydeg=10, reflected=True)
    map[10, :] = 1
    flux1 = map.flux(xo=xo, yo=yo, zo=zo, ro=ro, xs=xs, ys=ys, zs=zs)

    if noon:
        # The flux above should be *exactly* equal to 2/3 the flux of a
        # linearly-limb darkened source with u_1 = 1.0, since linear
        # limb darkening weights the surface brightness by the same
        # cosine-like profile (2/3 is the geometrical albedo of a
        # perfect Lambert sphere)
        map_e = starry.Map(ydeg=10, udeg=1)
        map_e[10, :] = 1
        map_e[1] = 1
        flux2 = (2.0 / 3.0) * map_e.flux(xo=xo, yo=yo, zo=zo, ro=ro)
        atol = 1e-12

    else:

        # Compute numerical
        res = 500
        x, y, z = map.ops.compute_ortho_grid(res)
        image = map.render(xs=xs, ys=ys, zs=zs, res=res).flatten()
        flux2 = np.zeros_like(flux1)
        for k in range(len(xo)):
            idx = (x - xo[k]) ** 2 + (y - yo) ** 2 > ro ** 2
            flux2[k] = np.nansum(image[idx])
        flux2 *= 4 / res ** 2
        atol = 1e-3

    # Plot it
    if plot:
        plt.plot(xo, flux1)
        plt.plot(xo, flux2)
        plt.show()

    # Compare
    assert np.allclose(flux1, flux2, atol=atol)
def map():
    return starry.Map(1, reflected=True)
Exemple #11
0
# -*- coding: utf-8 -*-
"""
There's a bug in tt.mgrid that causes different
behavior whether it's compiled or not. We implemented
some hacks in `starry` to circumvent this.
See docstring of `compute_ortho_grid` in "core.py"

"""
import starry
import pytest
import theano.tensor as tt
import itertools
import numpy as np

map = starry.Map(1)


@pytest.mark.parametrize("compile", [True, False])
def test_ortho_grid(compile):
    for res in np.arange(30, 101):
        if compile:
            (lat, lon), (x, y, z) = map.ops.compute_ortho_grid(res)
        else:
            latlon, xyz = map.ops.compute_ortho_grid(
                tt.as_tensor_variable(res))
            x, y, z = xyz.eval()
        assert len(x) == res**2
Exemple #12
0
"""55 cancrie e secondary eclipse example."""
import starry
import matplotlib.pyplot as plt
import numpy as np
import astropy.units as u

# Config
starry.config.lazy = False

# Star
star_map = starry.Map(udeg=2, amp=1)
star_map[1:] = [0.5, 0.25]
star = starry.Primary(star_map,
                      m=0.905,
                      mass_unit=u.M_sun,
                      r=0.943,
                      length_unit=u.R_sun)

# Planet
kwargs = dict(
    m=7.99,
    mass_unit=u.earthMass,
    porb=0.73654737,
    r=1.875,
    length_unit=u.earthRad,
    inc=83.59,
    t0=0.400473685,
)

# Time arrays (secondary eclipse ingress / full phase curve)
t_ingress = np.linspace(0, 0.002, 1000)
Exemple #13
0
# -*- coding: utf-8 -*-
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import starry

ydeg = 10
theta = np.linspace(-180, 180, 1000)
s = np.zeros(((ydeg + 1)**2, len(theta)))
map = starry.Map(ydeg, lazy=False)
n = 0
for l in range(ydeg + 1):
    for m in range(-l, l + 1):
        map.reset()
        if l > 0:
            map[l, m] = 1.0
        s[n] = map.flux(theta=theta)
        n += 1

# Set up the plot
fig, ax = plt.subplots(ydeg + 1,
                       2 * ydeg + 1,
                       figsize=(16, 10),
                       sharex=True,
                       sharey=True)
fig.subplots_adjust(hspace=0)
for axis in ax.flatten():
    axis.spines['top'].set_visible(False)
    axis.spines['right'].set_visible(False)
    axis.spines['bottom'].set_visible(False)
    axis.spines['left'].set_visible(False)
def map(request):
    (nw, ) = request.param
    map = starry.Map(ydeg=5, udeg=2, nw=nw)
    return map
Exemple #15
0
# -*- coding: utf-8 -*-
"""
Show the effect a rotating spot has on an absorption line.

"""
import matplotlib.pyplot as plt
import numpy as np
import starry
import paparazzi as pp
from matplotlib.animation import FuncAnimation

# Generate two maps
ydeg = 20
N = (ydeg + 1)**2
map1 = starry.Map(ydeg)
map1.add_spot(amp=-0.03, sigma=0.05, lat=30, lon=0)
map1.inc = 90

map2 = starry.Map(ydeg)
map2.load("spot")
map2.inc = 40

for map, name in zip([map1, map2], ["spot1", "spot2"]):

    # Get the map coeffs
    y1 = np.array(map.y.eval())[1:]

    # Generate the dataset
    vsini = 40.0  # km/s
    nt = 100
    theta = np.linspace(-180, 180, nt)
Exemple #16
0
def map(request):
    ydeg, udeg, nw, rv, reflected = request.param
    map = starry.Map(ydeg=ydeg, udeg=udeg, nw=nw, reflected=reflected, rv=rv)
    map.reflected = reflected
    return map
Exemple #17
0
def test_show_with_figure():
    map = starry.Map(ydeg=1, udeg=1)
    fig, ax = plt.subplots(1)
    map.show(ax=ax, file="tmp.pdf", projection="ortho")
    os.remove("tmp.pdf")
Exemple #18
0
def test_amplitude():
    """Test the amplitude attribute of a multi-wavelength map."""
    map = starry.Map(ydeg=1, nw=5)
    assert np.allclose(map.amp, np.ones(5))
    map.amp = 10.0
    assert np.allclose(map.amp, 10.0 * np.ones(5))
Exemple #19
0
def test_show_colorbar():
    map = starry.Map(ydeg=1, udeg=1)
    map.show(file="tmp.pdf", projection="ortho", colorbar=True)
    os.remove("tmp.pdf")
Exemple #20
0
def test_edges(xs,
               ys,
               zs,
               ro,
               y=[1, 1, 1],
               ns=100,
               nb=50,
               res=999,
               atol=1e-2,
               plot=False):

    # Instantiate
    ydeg = np.sqrt(len(y) + 1) - 1
    map = starry.Map(ydeg=ydeg, reflected=True)
    map[1:, :] = y

    # bo - ro singularities
    singularities = [ro - 1, 0, ro, 1, 1 - ro, 1 + ro]
    labels = [
        "$b_o = r_o - 1$",
        "$b_o = 0$",
        "$b_o = r_o$",
        "$b_o = 1$",
        "$b_o = 1 - r_o$",
        "$b_o = 1 + r_o$",
        "grazing",
        "grazing",
    ]

    # Find where the occultor grazes the terminator
    rs = np.sqrt(xs**2 + ys**2 + zs**2)
    b = -zs / rs
    theta = -np.arctan2(xs, ys)
    tol = 1e-15
    nx = 10
    c = np.cos(theta)
    s = np.sin(theta)
    t = np.tan(theta)
    q2 = c**2 + b**2 * s**2

    # Bottom / top half of occultor
    for sgn0 in [1, -1]:

        # Successively refine x array
        xest = 0
        xdel = ro
        for j in range(10):
            x = np.linspace(xest - xdel, xest + xdel, nx)

            # Divide & conquer
            yomax = 1 + ro
            yomin = -1 - ro
            niter = 0
            xest = 0
            while niter < 100 and np.abs(yomax - yomin) > tol:
                yo_ = 0.5 * (yomax + yomin)
                y = yo_ + sgn0 * np.sqrt(ro**2 - x**2)
                try:

                    # Scan the x axis for an intersection
                    for i in range(nx):

                        # There are two solutions to the quadratic; pick
                        # the one that's actually on the ellipse
                        p = (x[i] * c - b * s * np.sqrt(q2 - x[i]**2)) / q2
                        yt1 = p * s + b * np.sqrt(1 - p**2) * c
                        xr = x[i] * c + yt1 * s
                        yr = -x[i] * s + yt1 * c
                        arg1 = np.abs(xr**2 + (yr / b)**2 - 1)
                        p = (x[i] * c + b * s * np.sqrt(q2 - x[i]**2)) / q2
                        yt2 = p * s + b * np.sqrt(1 - p**2) * c
                        xr = x[i] * c + yt2 * s
                        yr = -x[i] * s + yt2 * c
                        arg2 = np.abs(xr**2 + (yr / b)**2 - 1)
                        if arg1 < arg2:
                            if arg1 < 1e-6:
                                yt = yt1
                            else:
                                continue
                        elif arg2 < arg1:
                            if arg2 < 1e-6:
                                yt = yt2
                            else:
                                continue
                        else:
                            continue

                        if (sgn0 == -1) and (y[i] < yt):
                            # Part of the occultor has dipped below the terminator
                            yomin = yo_
                            xest = x[i]
                            raise StopIteration

                        if (sgn0 == 1) and (y[i] > yt):
                            # Part of the occultor has dipped above the terminator
                            yomax = yo_
                            xest = x[i]
                            raise StopIteration

                except StopIteration:
                    niter += 1
                    continue
                else:
                    niter += 1
                    if sgn0 == -1:
                        # The occultor is above the terminator everywhere
                        yomax = yo_
                    else:
                        # The occultor is below the terminator everywhere
                        yomin = yo_

            # Increase res by 10x
            xdel /= 10

        singularities.append(yo_)

    # Arrays over singularities
    yo_s = np.zeros((8, ns))
    logdelta = np.append(-np.inf, np.linspace(-16, -2, ns // 2 - 1))
    delta = np.concatenate((-(10**logdelta[::-1]), 10**logdelta))
    for i, pt in enumerate(singularities):
        yo_s[i] = pt + delta
    yo_s = yo_s[np.argsort(singularities)]
    labels = list(np.array(labels)[np.argsort(singularities)])

    # Array over full occultation
    yo_full = np.linspace(yo_s[0, 0], yo_s[-1, -1], ns, endpoint=True)

    # All
    yo = np.concatenate((yo_full.reshape(1, -1), yo_s))

    # Compute analytic
    flux = np.zeros_like(yo)
    msg = [["" for n in range(yo.shape[1])] for m in range(yo.shape[0])]
    for i in range(len(yo)):
        for k in tqdm(range(ns)):
            try:
                flux[i, k] = map.flux(xs=xs,
                                      ys=ys,
                                      zs=zs,
                                      xo=0,
                                      yo=yo[i, k],
                                      ro=ro)
            except Exception as e:
                flux[i, k] = 0.0
                msg[i][k] = str(e).split("\n")[0]

    # Compute numerical
    flux_num = np.zeros_like(yo) * np.nan
    flux_num_interp = np.zeros_like(yo) * np.nan
    x, y, z = map.ops.compute_ortho_grid(res)
    img = map.render(xs=xs, ys=ys, zs=zs, res=res).flatten()
    for i in range(len(yo)):
        for k in tqdm(range(ns)):
            idx = x**2 + (y - yo[i, k])**2 > ro**2
            flux_num_interp[i, k] = np.nansum(img[idx]) * 4 / res**2
            if (k == 0) or (k == ns - 1) or (k % (ns // nb) == 0):
                flux_num[i, k] = flux_num_interp[i, k]

        # Adjust the baseline
        offset = np.nanmedian(flux[i]) - np.nanmedian(flux_num_interp[i])
        flux_num_interp[i] += offset
        flux_num[i] += offset

    # Plot
    if plot:

        fig = plt.figure(figsize=(10, 8))
        fig.subplots_adjust(hspace=0.35)
        ax = [
            plt.subplot2grid((40, 40), (0, 0), rowspan=15, colspan=40),
            plt.subplot2grid((40, 40), (20, 0), rowspan=10, colspan=10),
            plt.subplot2grid((40, 40), (20, 10), rowspan=10, colspan=10),
            plt.subplot2grid((40, 40), (20, 20), rowspan=10, colspan=10),
            plt.subplot2grid((40, 40), (20, 30), rowspan=10, colspan=10),
            plt.subplot2grid((40, 40), (30, 0), rowspan=10, colspan=10),
            plt.subplot2grid((40, 40), (30, 10), rowspan=10, colspan=10),
            plt.subplot2grid((40, 40), (30, 20), rowspan=10, colspan=10),
            plt.subplot2grid((40, 40), (30, 30), rowspan=10, colspan=10),
        ]

        # Prepare image for plotting
        img[(img < 0) | (img > 0.0)] = 1
        img = img.reshape(res, res)
        cmap = plt.get_cmap("plasma")
        cmap.set_under("grey")

        # Full light curve
        ax[0].plot(yo[0], flux[0], "k-", lw=1)
        ax[0].plot(yo[0], flux_num[0], "k.", lw=1)
        ax[0].tick_params(labelsize=10)
        ax[0].set_xlabel("$b_o$")
        ax[0].set_ylabel("flux")

        # Each singularity
        for i in range(1, len(yo)):
            ax[0].plot(yo[i], flux[i], lw=3, color="C{}".format(i - 1))
            ax[i].plot(
                2 + logdelta,
                flux[i][:ns // 2],
                lw=2,
                color="C{}".format(i - 1),
            )
            ax[i].plot(
                -(2 + logdelta)[::-1],
                flux[i][ns // 2:],
                lw=2,
                color="C{}".format(i - 1),
            )
            ax[i].plot(2 + logdelta, flux_num[i][:ns // 2], "k.", ms=2)
            ax[i].plot(-(2 + logdelta)[::-1],
                       flux_num[i][ns // 2:],
                       "k.",
                       ms=2)
            ax[i].set_xticks([])
            ax[i].set_yticks([])

            # Show the map
            axins = inset_axes(ax[i],
                               width="30%",
                               height="30%",
                               loc=4,
                               borderpad=1)
            axins.imshow(
                img,
                origin="lower",
                cmap=cmap,
                extent=(-1, 1, -1, 1),
                vmin=1e-8,
            )
            circ = plt.Circle(
                (0, yo[i, ns // 2]),
                ro,
                fc="k",
                ec="k",
                clip_on=(ro > 0.75),
                zorder=99,
            )
            axins.add_artist(circ)
            axins.annotate(
                labels[i - 1],
                xy=(0.5, -0.1),
                xycoords="axes fraction",
                clip_on=False,
                ha="center",
                va="top",
                fontsize=8,
            )
            axins.set_xlim(-1.01, 1.01)
            axins.set_ylim(-1.01, 1.01)
            axins.axis("off")

        plt.show()

    # Compare
    if not np.allclose(flux, flux_num_interp, atol=atol):
        index = np.unravel_index(np.argmax(np.abs(flux - flux_num_interp)),
                                 flux.shape)
        if index[0] > 0:
            raise ValueError("Error in singular region {}/8: {}".format(
                index[0], labels[index[0] - 1]))
Exemple #21
0
    foo = subprocess.check_output(['julia', "compare_to_batman_grad.jl"])
    agol_grad_time[i] = float(foo.decode('utf-8'))

    # pytransit
    m = pytransit.Gimenez(nldc=len(u_g), interpolate=False)
    tstart = time.time()
    for k in range(10):
        pytransit_flux = m(b, 0.1, u_g)
    pytransit_time[i] = (time.time() - tstart) / 10

    # starry (sph)
    # Using the dense spherical harmonic
    # integration algorithm (slow, since we don't
    # actually need the majority of the terms!)
    if N < 30:
        map = starry.Map(ydeg=1, udeg=N)
        map[1:] = u
        tstart = time.time()
        for k in range(10):
            starry_ylm_flux = map.flux(xo=b, ro=0.1)
        starry_ylm_time[i] = (time.time() - tstart) / 10
        tstart = time.time()
    else:
        # Let's not even bother computing these!
        starry_ylm_flux = np.zeros_like(b) * np.nan
        starry_ylm_time[i] = np.nan

    # starry (ld)
    map = starry.Map(ydeg=0, udeg=N)
    map[1:] = u
    tstart = time.time()
Exemple #22
0
nlam = 199
nt = 3
P = 1
inc = 90.0
ydeg = 5
vsini = 40.0
sigma = 7.5e-6
dlam = np.log(1.0 + 1.0 / R)
lam = np.arange(-(nlam // 2), nlam // 2 + 1) * dlam
t = np.linspace(-0.5 * P, 0.5 * P, nt + 1)[:-1]
doppler = pp.Doppler(lam, ydeg=ydeg, vsini=vsini, inc=inc, P=P)
D = doppler.D(t=t)
lam_padded = doppler.lam_padded
vT = np.ones_like(lam_padded)
vT = 1 - 0.5 * np.exp(-0.5 * lam_padded ** 2 / sigma ** 2)
map = starry.Map(ydeg)
map.load("vogtstar.jpg")
u = np.array(map.y.eval())
A = u.reshape(-1, 1).dot(vT.reshape(1, -1))

for i in tqdm(range(100)):
    F = D.dot(A.reshape(-1)).reshape(nt, -1)

# Conv
A_t = tt.dmatrix()
F_t = theano.function(
    [A_t], flux(lam, t, A_t, ydeg=ydeg, vsini=vsini, inc=inc, P=P)
)

for i in tqdm(range(100)):
    foo = F_t(A)
Exemple #23
0
def test_rotate_spectral():
    map = starry.Map(1, nw=2)
    map[1, 1, 0] = 1
    map[1, -1, 1] = 1
    map.rotate(np.array([0, 0, 1]), np.array(90.0))
    assert np.allclose(map.y, [[1, 1], [1, 0], [0, 0], [0, -1]])
Exemple #24
0
 def __init__(self, lmax=5):
     self.map = starry.Map(lmax, oblate=True, gdeg=0)
def test_X(xs, ys, zs, theta=0, ro=0.1, res=300, ydeg=2, tol=1e-3, plot=False):
    # Params
    npts = 250
    xo = np.linspace(-1.5, 1.5, npts)
    yo = np.linspace(-0.3, 0.5, npts)
    theta = 0
    ro = 0.1
    res = 300
    ydeg = 2
    tol = 1e-3

    # Instantiate
    map = starry.Map(ydeg=ydeg, reflected=True)

    # Analytic
    X = map.amp * map.design_matrix(
        xs=xs, ys=ys, zs=zs, theta=theta, xo=xo, yo=yo, ro=ro
    )

    # Numerical
    (lat, lon), (x, y, z) = map.ops.compute_ortho_grid(res)
    image = np.zeros((map.Ny, res * res))
    image[0] = map.render(theta=theta, xs=xs, ys=ys, zs=zs, res=res).flatten()
    n = 1
    for l in range(1, map.ydeg + 1):
        for m in range(-l, l + 1):
            map.reset()
            map[l, m] = 1
            image[n] = (
                map.render(theta=theta, xs=xs, ys=ys, zs=zs, res=res).flatten()
            ) - image[0]
            n += 1
    X_num = np.zeros_like(X)
    for k in range(len(xo)):
        idx = (x - xo[k]) ** 2 + (y - yo[k]) ** 2 > ro ** 2
        for n in range(map.Ny):
            X_num[k, n] = np.nansum(image[n][idx])
    X_num *= 4 / res ** 2

    # Plot
    if plot:

        fig, ax = plt.subplots(
            ydeg + 1, 2 * ydeg + 1, figsize=(9, 6), sharex=True, sharey=True
        )
        for axis in ax.flatten():
            axis.set_xticks([])
            axis.set_yticks([])
            axis.spines["top"].set_visible(False)
            axis.spines["right"].set_visible(False)
            axis.spines["bottom"].set_visible(False)
            axis.spines["left"].set_visible(False)
        n = 0
        for i, l in enumerate(range(ydeg + 1)):
            for j, m in enumerate(range(-l, l + 1)):
                j += ydeg - l
                med = np.median(X_num[:, n])
                ax[i, j].plot(X[:, n] - med, lw=2)
                ax[i, j].plot(X_num[:, n] - med, lw=1)
                n += 1

        fig.savefig(
            "test_X_{}.pdf".format(datetime.now().strftime("%d%m%Y%H%M%S")),
            bbox_inches="tight",
        )
        plt.close()

    # Compare
    diff = (X - X_num).flatten()
    assert np.max(np.abs(diff)) < tol
Exemple #26
0
import starry
import numpy as np

map = starry.Map(15, inc=40)
map.load("spot")
map.show(theta=np.linspace(0, 360, 100), res=300, file="spot.mp4")
Exemple #27
0
def design_matrix(time,
                  ydeg=10,
                  nt=2,
                  period=1.0,
                  phase0=0.0,
                  fit_linear_term=False):
    """
    Compute and return the design matrix.

    Args:
        time: The time array in TJD.
        ydeg: The maximum spherical harmonic degree.
        nt: The number of map temporal components.
        phase0: The phase of the map at `t = 0` in degrees.
    """
    # Instantiate a `starry` map
    map = starry.Map(ydeg=ydeg, udeg=0, reflected=True, nt=nt)

    # Load the SPICE data
    ephemFiles = glob.glob('../data/TESS_EPH_PRE_LONG_2018*.bsp')
    tlsFile = '../data/tess2018338154046-41240_naif0012.tls'
    solarSysFile = '../data/tess2018338154429-41241_de430.bsp'
    #print(spice.tkvrsn('TOOLKIT'))
    for ephFil in ephemFiles:
        spice.furnsh(ephFil)
    spice.furnsh(tlsFile)
    spice.furnsh(solarSysFile)

    # JD time range
    allTJD = time + TJD0
    nT = len(allTJD)
    allET = np.zeros((nT, ), dtype=np.float)
    for i, t in enumerate(allTJD):
        allET[i] = spice.unitim(t, 'JDTDB', 'ET')

    # Calculate positions of TESS, the Earth, and the Sun
    tess = np.zeros((3, len(allET)))
    sun = np.zeros((3, len(allET)))
    for i, et in enumerate(allET):
        outTuple = spice.spkezr('Mgs Simulation', et, 'J2000', 'NONE', 'Earth')
        tess[0, i] = outTuple[0][0] * REARTH
        tess[1, i] = outTuple[0][1] * REARTH
        tess[2, i] = outTuple[0][2] * REARTH
        outTuple = spice.spkezr('Sun', et, 'J2000', 'NONE', 'Earth')
        sun[0, i] = outTuple[0][0] * REARTH
        sun[1, i] = outTuple[0][1] * REARTH
        sun[2, i] = outTuple[0][2] * REARTH

    # Compute the linear starry model
    t = (time - time[0]) / (time[-1] - time[0])
    t = 2 * (t - 0.5)
    X = np.empty((nT, map.Ny * map.nt))
    for i in tqdm(range(len(time))):
        # Find the rotation matrix `R` that rotates TESS onto the +z axis
        r = np.sqrt(np.sum(tess[:, i]**2))
        costheta = np.dot(tess[:, i], [0, 0, r])
        axis = np.cross(tess[:, i], [0, 0, r])
        sintheta = np.sqrt(np.sum(axis**2))
        axis /= sintheta
        R = starry.RAxisAngle(axis,
                              180. / np.pi * np.arctan2(sintheta, costheta))

        # Rotate into this new frame. The Earth is still
        # at the origin, TESS is along the +z axis, and
        # the Sun is at `source`.
        nx, ny, nz = np.dot(R, [0, 0, 1])
        source = np.dot(R, sun[:, i])
        source /= np.sqrt(np.sum(source**2, axis=0))

        # We need to rotate the map of the Earth so the
        # north pole is at (nx, ny, nz). We also need to
        # rotate the Earth about the pole to get it to the
        # correct phase. We'll do this with a compound
        # rotation by an angle `theta` about the axis computed
        # below.
        phase = 2 * np.pi / period * (time[i]) + np.pi / 180. * phase0
        cosphase = np.cos(phase)
        sinphase = np.sin(phase)
        map.axis = [
            nz + nz * cosphase + nx * sinphase, (1 + ny) * sinphase,
            -nx - nx * cosphase + nz * sinphase
        ]
        costheta = 0.5 * (-1 + ny + cosphase + ny * cosphase)
        sintheta = np.sqrt(1 - costheta**2)
        theta = 180 / np.pi * np.arctan2(sintheta, costheta)
        X[i] = map.linear_flux_model(t=t[i], theta=theta, source=source)

    if fit_linear_term:
        return X
    else:
        # Let's remove the Y_{0,0} from the design matrix and return
        # the static constant term so that it can be subtracted from the data.
        X00 = np.array(X[:, 0])
        X = np.delete(X, [n * map.Ny for n in range(map.nt)], axis=1)
        return X, X00
Exemple #28
0

from multiprocessing import Pool


time, vels, verr = np.loadtxt('../data/vst222259.ascii', usecols=[1,2,3], unpack=True)
ha = np.loadtxt('../data/222259_mbcvel.ascii', usecols=[-2])

time = time[:-4]
vels = vels[:-4]
verr = verr[:-4]
ha   = ha[:-7]

time -= 18706.5

map = starry.Map(ydeg=4, udeg=2, rv=True, lazy=False)
map.reset()


Prot = 2.85             # days
P = 8.1387              # days
e = 0.0
w = 0.0
inc = 90.0

tuse = time + 0.0
euse = verr + 0.0
vuse = vels + 0.0

bnds = ((12000, 24000), (0.04, 0.09), (-1.0, 0.0), (15,25), (0,1),(0,1), (-30,90), (-500,500), (0.0, 3.0), (0, 40.0), (0.0, 1.0), (0.16, 0.175), (-100000, 0), (-1000, 0.539), (0.0, 10.0))
Exemple #29
0
def test_rotate_spectral():
    map = starry.Map(1, nw=2)
    map[1, 1, 0] = 1
    map[1, -1, 1] = 1
    map.rotate([0, 0, 1], 90.0)
    assert np.allclose(map.y.eval(), [[1, 1], [1, 0], [0, 0], [0, -1]])
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