def test_omega_w(): """Ensure `w` and `omega` are equivalent.""" body = starry.Secondary(starry.Map(), porb=1.0, w=30.0) assert np.allclose(body.omega, 30) body.omega = 60 assert np.allclose(body.w, 60) body = starry.Secondary(starry.Map(), porb=1.0, omega=30.0) assert np.allclose(body.w, 30) body.w = 60 assert np.allclose(body.omega, 60)
def test_orientation(Omega=45, inc=35): # Instantiate pri = starry.Primary(starry.Map(amp=0)) sec = starry.Secondary( starry.Map(ydeg=1, amp=1), porb=1.0, r=0, m=0, inc=inc, Omega=Omega, prot=1.0, theta0=180.0, ) sec.map[1, 0] = 1.0 sys = starry.System(pri, sec) # Align the rotational axis with the orbital axis sec.map.inc = sec.inc sec.map.obl = sec.Omega # Compute the flux t = np.linspace(-0.5, 0.5, 1000) flux = sys.flux(t) # This is the analytic result flux_analytic = 1.0 - np.sin(inc * np.pi / 180.0) * ( 2.0 / np.sqrt(3.0) ) * np.cos(2 * np.pi * t) assert np.allclose(flux, flux_analytic)
def test_bad_sys_data(): pri = starry.Primary(starry.Map(ydeg=1)) sec = starry.Secondary(starry.Map(ydeg=1), porb=1.0) sys = starry.System(pri, sec) # User didn't provide the covariance with pytest.raises(ValueError) as e: sys.set_data([0.0]) # User didn't provide a dataset with pytest.raises(ValueError) as e: sys.solve(t=[0.0]) # Provide a dummy dataset sys.set_data([0.0], C=1.0) # User didn't provide a prior for the primary with pytest.raises(ValueError) as e: sys.solve(t=[0.0]) # Provide a prior for the primary pri.map.set_prior(L=1.0) # Provide a prior for the secondary sec.map.set_prior(L=1.0) # Now check that this works sys.solve(t=[0.0])
def test_system(ydeg, nw): # Oblate map map = starry.Map(udeg=2, ydeg=ydeg, oblate=True, nw=nw) map[1] = 0.5 map[2] = 0.25 map.omega = 0.5 map.beta = 1.23 map.tpole = 8000 map.f = 1 - 2 / (map.omega**2 + 2) map.obl = 30 # Compute system flux star = starry.Primary(map, r=1.5) planet = starry.Secondary(starry.Map(amp=0, nw=nw), porb=1.0, r=0.1, m=0) sys = starry.System(star, planet) t = np.linspace(-0.1, 0.1, 1000) flux_sys = sys.flux(t, integrated=True) # Compute map flux manually x, y, z = sys.position(t) xo = x[1] / star._r yo = y[1] / star._r flux_map = map.flux(xo=xo, yo=yo, ro=planet._r / star._r, integrated=True) # Check that they agree assert np.allclose(flux_map, flux_sys)
def test_integration(): pri = starry.Primary(starry.Map(udeg=2), r=1.0) pri.map[1:] = [0.5, 0.25] sec = starry.Secondary(starry.Map(ydeg=1), porb=1.0, r=0.25) # Manual integration t = np.linspace(-0.1, 0.1, 10000) sys = starry.System(pri, sec, texp=0) flux = sys.flux(t) t = t.reshape(-1, 1000).mean(axis=1) flux = flux.reshape(-1, 1000).mean(axis=1) sys0 = starry.System(pri, sec, texp=0.02, order=0, oversample=999) assert sys0.order == 0 assert sys0.oversample == 999 flux0 = sys0.flux(t) assert np.allclose(flux, flux0) sys1 = starry.System(pri, sec, texp=0.02, order=1, oversample=999) assert sys1.order == 1 assert sys1.oversample == 999 flux1 = sys1.flux(t) assert np.allclose(flux, flux1) sys2 = starry.System(pri, sec, texp=0.02, order=2, oversample=999) assert sys2.order == 2 assert sys2.oversample == 999 flux2 = sys2.flux(t) assert np.allclose(flux, flux2)
def test_solve_with_zero_degree_primary(): """ Test for https://github.com/rodluger/starry/issues/253. """ # Random data t = np.linspace(-0.1, 0.1, 100) flux = np.random.randn(len(t)) sigma = 1.0 # Instantiate a primary with ydeg = 0 star_0 = starry.Primary(starry.Map(ydeg=0)) star_0.map.set_prior(L=1) # Instantiate a secondary with ydeg > 0 star_1 = starry.Secondary(starry.Map(ydeg=1), porb=1.0) # The system sys = starry.System(star_0, star_1) # Place a generous prior on the map coefficients star_1.map.set_prior(L=1) sys.set_data(flux, C=sigma**2) # Solve the linear problem mu, cho_cov = sys.solve(t=t) # Check that it didn't fail horribly assert not np.any(np.isnan(mu)) assert not np.any(np.isnan(np.tril(cho_cov)))
def test_system_rv_show_pymc3(): with pm.Model(**theano_config) as model: pri = starry.Primary(starry.Map(rv=True)) sec = starry.Secondary(starry.Map(rv=True), porb=1.0) sec.inc = pm.Uniform("inc", 0, 90) sys = starry.System(pri, sec) sys.show(0.1, file="tmp.pdf", point=model.test_point) os.remove("tmp.pdf")
def test_system_rv_show(): pri = starry.Primary(starry.Map(rv=True)) sec = starry.Secondary(starry.Map(rv=True), porb=1.0) sys = starry.System(pri, sec) sys.show(0.1, file="tmp.pdf") os.remove("tmp.pdf") sys.show([0.1, 0.2], file="tmp.mp4") os.remove("tmp.mp4")
def test_bad_sys_settings(): pri = starry.Primary(starry.Map()) sec = starry.Secondary(starry.Map(), porb=1.0) # Bad exposure time with pytest.raises(AssertionError) as e: sys = starry.System(pri, sec, texp=-1.0) # Bad oversample factor with pytest.raises(AssertionError) as e: sys = starry.System(pri, sec, oversample=-1) # Bad integration order with pytest.raises(AssertionError) as e: sys = starry.System(pri, sec, order=99) # Bad primary with pytest.raises(AssertionError) as e: sys = starry.System(sec, sec) # Reflected light primary with pytest.raises(AssertionError) as e: sys = starry.System(starry.Primary(starry.Map(reflected=True)), sec) # Bad secondary with pytest.raises(AssertionError) as e: sys = starry.System(pri, pri) # No secondaries with pytest.raises(AssertionError) as e: sys = starry.System(pri) # Different number of wavelength bins with pytest.raises(AssertionError) as e: sys = starry.System( pri, starry.Secondary(starry.Map(ydeg=1, nw=2), porb=1.0)) # RV for secondary, but not primary with pytest.raises(AssertionError) as e: sys = starry.System(pri, starry.Secondary(starry.Map(rv=True), porb=1.0)) # Reflected light for first secondary, but not second with pytest.raises(ValueError) as e: sys = starry.System( pri, sec, starry.Secondary(starry.Map(reflected=True), porb=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
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)
def test_system_show(mp4=False): pri = starry.Primary(starry.Map()) sec = starry.Secondary(starry.Map(), porb=1.0) sys = starry.System(pri, sec) sys.show(0.1, file="tmp.pdf") os.remove("tmp.pdf") if mp4: sys.show([0.1, 0.2], file="tmp.mp4") os.remove("tmp.mp4") sys.show([0.1, 0.2], file="tmp.gif") os.remove("tmp.gif")
def test_compare_to_map_rv(): """Ensure we get the same result by calling `map.rv()` and `sys.rv()`.""" # Define the map map = starry.Map(ydeg=1, udeg=2, rv=True, amp=1, veq=1, alpha=0, lazy=True) map[1, 0] = 0.5 # Define the star A = starry.Primary( map, r=1.0, m=1.0, prot=0, length_unit=u.Rsun, mass_unit=u.Msun, lazy=True, ) # Define the planet b = starry.Secondary( starry.Map(rv=True, amp=1, veq=0, lazy=True), 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 system sys = starry.System(A, b) # Time array time = np.linspace(-0.05, 0.05, 1000) # Get the positions of both bodies x, y, z = sys.position(time) # Compute the relative positions xo = x[1] - x[0] yo = y[1] - y[0] zo = z[1] - z[0] ro = b.r / A.r # Compare rv1 = map.rv(xo=xo, yo=yo, ro=ro).eval() rv2 = sys.rv(time, keplerian=False).eval() assert np.allclose(rv1, rv2)
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 system sys = starry.System(A, b) # Compute with starry time = np.linspace(-0.5, 0.5, 1000) rv1 = sys.rv(time, keplerian=True) # Compute with exoplanet orbit = exoplanet.orbits.KeplerianOrbit( period=1.0, t0=0.0, incl=86.0 * np.pi / 180, ecc=0.3, omega=60 * np.pi / 180, m_planet=0.01, m_star=1.0, r_star=1.0, ) rv2 = orbit.get_radial_velocity(time).eval() assert np.allclose(rv1, rv2)
def test_normalization(d=10, r=1): """Test the normalization of the flux.""" # Instantiate a system. Planet has radius `r` and is at # distance `d` from a point illumination source. 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 assert np.allclose(f_planet, (2.0 / 3.0) * r**2 / d**2)
def test_unit_conversions(): body = starry.Secondary( starry.Map(ydeg=1, inc=1.0, obl=1.0, angle_unit=u.radian), r=1.0, m=1.0, inc=1.0, porb=1.0, prot=1.0, t0=1.0, theta0=1.0, Omega=1.0, length_unit=u.cm, mass_unit=u.gram, time_unit=u.second, angle_unit=u.radian, ) assert body.r == 1.0 assert body._r == body.length_unit.in_units(u.Rsun) assert body.m == 1.0 assert body._m == body.mass_unit.in_units(u.Msun) assert body.inc == 1.0 assert body._inc == body.angle_unit.in_units(u.radian) assert body.theta0 == 1.0 assert body._theta0 == body.angle_unit.in_units(u.radian) assert body.Omega == 1.0 assert body._Omega == body.angle_unit.in_units(u.radian) assert body.prot == 1.0 assert body._prot == body.time_unit.in_units(u.day) assert body.t0 == 1.0 assert body._t0 == body.time_unit.in_units(u.day) assert body.ecc == 0.0 assert body.map.inc == 1.0 assert body.map._inc == body.map.angle_unit.in_units(u.radian) assert body.map.obl == 1.0 assert body.map._obl == body.map.angle_unit.in_units(u.radian) # First test the orbital period assert body.porb == 1.0 assert body._porb == body.time_unit.in_units(u.day) # Now test the semi-major axis assert body.a is None body.a = 1.0 assert body.a == 1.0 assert body._a == body.length_unit.in_units(u.Rsun) assert body.porb is None
porb=1.481, 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)
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
star = starry.Primary(starry.Map(udeg=2, amp=1), r=0.805, m=0.846, length_unit=u.Rsun, mass_unit=u.Msun) star.map[1:] = [0.5, 0.25] planet_amp = 0.6 * 0.0035 # ensure depth is 3.85 ppt planet = starry.Secondary( starry.Map( 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
woodbury = [False, True] solve_inputs = itertools.product(vals, vals) 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":
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
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)
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
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)