def test_lnlike_grad(param, marginalize_over_inclination): # Generate a fake dataset np.random.seed(42) t = np.linspace(0, 3, 100) flux = np.random.randn(len(t)) data_cov = 1.0 with change_flags(compute_test_value="off"): if param in ["i", "p"]: if param == "i" and marginalize_over_inclination: return theano.gradient.verify_grad( lambda x: StarryProcess( marginalize_over_inclination=marginalize_over_inclination, normalized=False, ).log_likelihood(t, flux, data_cov, **{param: x}), (defaults[param],), n_tests=1, rng=np.random, ) else: theano.gradient.verify_grad( lambda x: StarryProcess( marginalize_over_inclination=marginalize_over_inclination, normalized=False, **{param: x} ).log_likelihood(t, flux, data_cov), (defaults[param],), n_tests=1, rng=np.random, )
def test_sample(tol=5): # Instantiate the two GPs a, b = gauss2beta(45, 1) sp1 = StarryProcess(r=10, a=a, b=b) a, b = gauss2beta(0, 1) sp2 = StarryProcess(r=10, a=a, b=b) # Sum them and draw a sample sp = sp1 + sp2 y = sp.sample_ylm().eval() # Instantiate a starry map to compute # the longitudinally-averaged intensity map = starry.Map(15, lazy=False) map[:, :] = y lat = np.linspace(-90, 90, 300) lon = np.linspace(-180, 180, 600) lat_, lon_ = np.meshgrid(lat, lon) lat_ = lat_.flatten() lon_ = lon_.flatten() I = np.mean(map.intensity(lat=lat_, lon=lon_).reshape(len(lon), len(lat)), axis=0) # Get the 3 lowest local minima grad = np.gradient(I) idx = (grad[1:] > 0) & (grad[:-1] < 0) k = np.argsort(I[:-1][idx])[:3] min_lats = np.sort(lat[:-1][idx][k]) # Now check that these are about (-45, 0, 45) assert np.abs(min_lats[0] - (-45)) < tol assert np.abs(min_lats[1]) < tol assert np.abs(min_lats[2] - 45) < tol
def test_variance(): sp = StarryProcess(normalized=False) cov = sp.cov([0.0, 0.1]).eval() var = sp.cov([0.0]).eval() assert np.allclose(cov[0, 0], var)
def _lnlike(r, a, b, c, n, i, p, t, flux, data_cov): gp = StarryProcess( r=r, a=a, b=b, c=c, n=n, marginalize_over_inclination=marginalize_over_inclination, normalized=False, ) return gp.log_likelihood(t, flux, data_cov, p=p, i=i)
def _sample(r, a, b, c, n, i, p, t): gp = StarryProcess( r=r, a=a, b=b, c=c, n=n, marginalize_over_inclination=marginalize_over_inclination, normalized=False, ) gp.random.seed(seed) return tt.reshape(gp.sample(t, p=p, i=i), (-1,))
def get_numerical_mean_and_cov(t, nsamples=10000): """ Compute the empirical covariance of the flux marginalized over inclination. """ # Draw random Ylm samples sp = StarryProcess() mu = sp.mean_ylm.eval() cho_cov = sp.cho_cov_ylm.eval() y = mu[:, None] + np.dot(cho_cov, np.random.randn(256, nsamples)) # Draw sin-distributed inclinations inc = np.arccos(np.random.random(nsamples)) * 180 / np.pi # Compute all the light curves map = starry.Map(sp._ydeg) f = np.zeros((nsamples, len(t))) for k in tqdm(range(nsamples)): map.inc = inc[k] A = map.design_matrix(theta=360 * t) f[k] = np.transpose(A @ y[:, k]) # Return the empirical mean and covariance return np.mean(f, axis=0), np.cov(f.T)
def plot_trace(results, **kwargs): """ Plot the nested sampling trace. """ # Get kwargs kwargs = update_with_defaults(**kwargs) gen_kwargs = kwargs["generate"] labels = ["r", "a", "b", "c", "n", "bm", "blv"] # Get truths try: a, b = StarryProcess().latitude._transform.transform( gen_kwargs["latitude"]["mu"], gen_kwargs["latitude"]["sigma"]) except: a = np.nan b = np.nan truths = [ gen_kwargs["radius"]["mu"], a, b, gen_kwargs["contrast"]["mu"], gen_kwargs["nspots"]["mu"], np.nan, np.nan, ] ndim = results.samples.shape[-1] fig, _ = dyplot.traceplot(results, truths=truths[:ndim], labels=labels[:ndim]) return fig
def test_norm(ftol=0.05): # GP mean mu = 0.75 # Dimension of the problem K = 3 # Number of samples in numerical estimate M = 100000 # Random covariance matrix np.random.seed(0) L = 0.1 * np.tril(0.25 * np.random.randn(K, K) + np.eye(K)) cov = L @ L.T # Compute the series approximation to the normalized covariance cov_norm = StarryProcess()._normalize(mu, cov).eval() # Compute it by sampling u = np.random.randn(K, M) x = mu + L @ u xnorm = x / np.mean(x, axis=0).reshape(1, -1) cov_norm_num = np.cov(xnorm) # Fractional error error = np.abs((cov_norm - cov_norm_num) / cov_norm) try: assert np.all(error < ftol) except AssertionError as e: print(cov_norm) print(cov_norm_num) raise e
def test_sample_conditional(): # Sample the flux from the prior sp = StarryProcess(normalized=False, marginalize_over_inclination=False) t = np.linspace(0, 2, 300) flux = sp.sample(t, p=1.0, i=60.0).eval().reshape(-1) # Now sample the ylms conditioned on the flux data_cov = 1e-6 y = sp.sample_ylm_conditional(t, flux, data_cov, p=1.0, i=60.0).eval() map = starry.Map(15, inc=60, lazy=False) map[:, :] = y.reshape(-1) flux_pred = map.flux(theta=360 * t) # The computed flux should match the data pretty well chisq = np.sum((flux - flux_pred)**2 / data_cov) assert chisq / len(t) < 1
def compile(self): # Compile the GP print("Compiling. This may take up to one minute...") r = tt.dscalar() a = tt.dscalar() b = tt.dscalar() c = tt.dscalar() n = tt.dscalar() self.gp = StarryProcess(ydeg=self.ydeg, r=r, a=a, b=b, c=c, n=n) self.gp.random.seed(238) self.sample_function = theano.function( [r, a, b, c, n], [self.gp.sample_ylm(nsamples=self.nmaps)], no_default_updates=True, ) self._compiled = True print("Done!")
def get_loglike_function(ydeg, marginalize_over_inclination=False): t = tt.dvector() return theano.function( [t], StarryProcess( ydeg=ydeg, marginalize_over_inclination=marginalize_over_inclination, ).log_likelihood(t, tt.ones_like(t), 1.0), )
def test_inclination(nsamples=10000, plot=False, rtol=1e-4, ftol=0.25): """ Test the inclination marginalization algorithm. """ # Time array t = np.linspace(0, 1, 1000) # Compute the analytic moments sp = StarryProcess(normalized=False, marginalize_over_inclination=True) mean = sp.mean(t).eval() cov = sp.cov(t).eval() # Compute the numerical moments np.random.seed(0) mean_num, cov_num = get_numerical_mean_and_cov(t, nsamples=nsamples) # Visualize if plot: # The radial kernel plt.figure() plt.plot(cov[0]) plt.plot(cov_num[0]) # The full covariance fig, ax = plt.subplots(1, 3) vmin = np.min(cov) vmax = np.max(cov) im = ax[0].imshow(cov, vmin=vmin, vmax=vmax) plt.colorbar(im, ax=ax[0]) im = ax[1].imshow(cov_num, vmin=vmin, vmax=vmax) plt.colorbar(im, ax=ax[1]) im = ax[2].imshow(np.log10(np.abs((cov - cov_num) / cov))) plt.colorbar(im, ax=ax[2]) plt.show() # Check rerr = np.abs(cov[0] - cov_num[0]) assert np.max(rerr) < rtol, "relative error too large" ferr = np.abs((cov[0] - cov_num[0]) / cov[0, 0]) assert np.max(ferr) < ftol, "fractional error too large"
def test_jacobian(): # Compile the Jacobian _a = tt.dscalar() _b = tt.dscalar() log_jac = theano.function([_a, _b], StarryProcess(a=_a, b=_b).log_jac()) # Log probability def log_prob(p): if np.any(p < 0): return -np.inf elif np.any(p > 1): return -np.inf else: return log_jac(*p) # Run the sampler ndim, nwalkers, nsteps = 2, 50, 10000 p0 = np.random.random(size=(nwalkers, ndim)) sampler = emcee.EnsembleSampler(nwalkers, ndim, log_prob) sampler.run_mcmc(p0, nsteps) # Transform to latitude params a, b = sampler.chain.T.reshape(2, -1) mu, sigma = beta2gauss(a, b) # Compute the 2d histogram m1, m2 = 0, 80 s1, s2 = 0, 45 hist, _, _ = np.histogram2d(mu, sigma, range=((m1, m2), (s1, s2))) hist /= np.max(hist) # Check that the variation is less than 10% across the domain std = 1.4826 * mad(hist.flatten()) mean = np.mean(hist.flatten()) assert std / mean < 0.1
fig, ax = plt.subplots( 3, nsamples + 1, figsize=(12, 5), gridspec_kw={ "height_ratios": [1, 1, 1], "width_ratios": np.append(np.ones(nsamples), 0.1), }, ) for n, c in enumerate([0.1, -0.1]): # Draw samples sp = StarryProcess(marginalize_over_inclination=False, c=c, **kwargs) y = sp.sample_ylm(nsamples=nsamples).eval() flux = 1e3 * sp.flux(y, t, i=inc).eval() for k in range(nsamples): sp.visualize(y[k], ax=ax[n, k], vmin=0.8, vmax=1.2) ax[n, k].set_ylim(-1.5, 2.25) ax[n, k].set_rasterization_zorder(1) ax[2, k].plot(t, flux[k], color=color[n], lw=0.75) if k == 0: ax[2, k].spines["top"].set_visible(False) ax[2, k].spines["right"].set_visible(False) ax[2, k].set_xlabel("rotations", fontsize=8) ax[2, k].set_ylabel("flux [ppt]", fontsize=8) ax[2, k].set_xticks([0, 0.25, 0.5, 0.75, 1.0])
def plot_latitude_pdf(results, **kwargs): """ Plot posterior draws from the latitude hyperdistribution. """ # Get kwargs kwargs = update_with_defaults(**kwargs) plot_kwargs = kwargs["plot"] gen_kwargs = kwargs["generate"] mu_true = gen_kwargs["latitude"]["mu"] sigma_true = gen_kwargs["latitude"]["sigma"] nlat_pts = plot_kwargs["nlat_pts"] nlat_samples = plot_kwargs["nlat_samples"] # Resample to equal weight samples = np.array(results.samples) try: weights = np.exp(results["logwt"] - results["logz"][-1]) except: weights = results["weights"] samples = dyfunc.resample_equal(samples, weights) # Function to compute the pdf for a draw _draw_pdf = lambda x, a, b: StarryProcess(a=a, b=b).latitude.pdf(x) _x = tt.dvector() _a = tt.dscalar() _b = tt.dscalar() # The true pdf draw_pdf = theano.function([_x, _a, _b], _draw_pdf(_x, _a, _b)) x = np.linspace(-89.9, 89.9, nlat_pts) if np.isfinite(sigma_true): pdf_true = 0.5 * (Normal.pdf(x, mu_true, sigma_true) + Normal.pdf(x, -mu_true, sigma_true)) else: # Isotropic (special case) pdf_true = 0.5 * np.cos(x * np.pi / 180) * np.pi / 180 # Draw sample pdfs pdf = np.empty((nlat_samples, nlat_pts)) for k in range(nlat_samples): idx = np.random.randint(len(samples)) pdf[k] = draw_pdf(x, samples[idx, 1], samples[idx, 2]) # Plot fig, ax = plt.subplots(1) for k in range(nlat_samples): ax.plot(x, pdf[k], "C0-", lw=1, alpha=0.05, zorder=-1) ax.plot(x, pdf_true, "C1-", label="truth") ax.plot(x, np.nan * x, "C0-", label="samples") ax.legend(loc="upper right") ax.set_xlim(-90, 90) xticks = [-90, -75, -60, -45, -30, -15, 0, 15, 30, 45, 60, 75, 90] ax.set_xticks(xticks) ax.set_xticklabels(["{:d}$^\circ$".format(xt) for xt in xticks]) ax.set_xlabel("latitude", fontsize=16) ax.set_ylabel("probability", fontsize=16) # Constrain y lims? mx1 = np.max(pdf_true) mx2 = np.sort(pdf.flatten())[int(0.9 * len(pdf.flatten()))] mx = max(2.0 * mx1, 1.2 * mx2) ax.set_ylim(-0.1 * mx, mx) ax.set_rasterization_zorder(1) return fig
def _run(self, doc=None): # Get current document if needed if doc is None: doc = curdoc() # Compile if needed if not self._compiled: self.compile() print("Rendering...") # The GP samples self.Samples = Samples( self.ydeg, self.npix, self.npts, self.nmaps, self.throttle_time, self.nosmooth, self.gp, self.sample_function, ) # The integrals sp = StarryProcess(ydeg=self.ydeg) pdf = lambda x, mu, sigma: sp.latitude._pdf(x, *gauss2beta(mu, sigma)) pdf_gauss = lambda x, mu, sigma: 0.5 * (Normal.pdf(x, -mu, sigma) + Normal.pdf(x, mu, sigma)) npts = 300 T = spot_transform(self.ydeg, npts) self.Latitude = Integral( params["latitude"], self.Samples.callback, funcs=[pdf, pdf_gauss], labels=["pdf", "laplace"], xlabel="latitude distribution", ylabel="probability", distribution=True, legend_location="top_left", ) self.Size = Integral( params["size"], self.Samples.callback, funcs=[ lambda x, r: T @ (1 / (1 + np.exp(-300 * np.pi / 180 * (np.abs(x) - r))) - 1), lambda x, r: (1 / (1 + np.exp(-300 * np.pi / 180 * (np.abs(x) - r))) - 1), ], labels=["ylm", "true"], xlabel="spot profile", ylabel="intensity", npts=npts, ) self.Contrast = Integral(params["contrast"], self.Samples.callback) # Tell the GP about the sliders self.Samples.Latitude = self.Latitude self.Samples.Size = self.Size self.Samples.Contrast = self.Contrast # Settings ControlPanel = column( Div(text="<h1>settings</h1>", css_classes=["control-title"]), self.Contrast.layout, self.Samples.slider, row( self.Samples.smooth_button, self.Samples.auto_button, self.Samples.seed_button, self.Samples.reset_button, sizing_mode="scale_both", css_classes=["button-row"], ), Div(text=description, css_classes=["control-description"]), sizing_mode="scale_both", ) # Full layout layout = column( row( self.Latitude.layout, self.Size.layout, ControlPanel, sizing_mode="scale_both", ), self.Samples.layout, style(), sizing_mode="scale_both", ) print("Done rendering.") # Remove the loading screen doc.remove_root(self.layout) # Add the interface self.layout = layout doc.add_root(self.layout)
def test_null_limb_darkening(): t = np.linspace(0, 1, 300) cov1 = StarryProcess(udeg=0).cov(t).eval() cov2 = StarryProcess(udeg=2).cov(t, u=[0.0, 0.0]).eval() assert np.allclose(cov1, cov2)
class Application(object): def __init__( self, ydeg=15, npix=100, npts=300, nmaps=5, throttle_time=0.40, load_timeout=1.0, nosmooth=False, ): self.ydeg = ydeg self.npix = npix self.npts = npts self.nmaps = nmaps self.throttle_time = throttle_time self.load_timeout = load_timeout self.nosmooth = nosmooth self._compiled = False def compile(self): # Compile the GP print("Compiling. This may take up to one minute...") r = tt.dscalar() a = tt.dscalar() b = tt.dscalar() c = tt.dscalar() n = tt.dscalar() self.gp = StarryProcess(ydeg=self.ydeg, r=r, a=a, b=b, c=c, n=n) self.gp.random.seed(238) self.sample_function = theano.function( [r, a, b, c, n], [self.gp.sample_ylm(nsamples=self.nmaps)], no_default_updates=True, ) self._compiled = True print("Done!") def run(self, doc=None): # Get current document if needed if doc is None: doc = curdoc() doc.title = "starry process" doc.template = TEMPLATE # Show the loading screen self.layout = Div(text=LOADING_SCREEN, css_classes=["body-wrapper"]) doc.add_root(self.layout) # Set a delay timer for safety; when it's done, load the widgets doc.add_timeout_callback(lambda: self._run(doc), int(1000 * self.load_timeout)) def _run(self, doc=None): # Get current document if needed if doc is None: doc = curdoc() # Compile if needed if not self._compiled: self.compile() print("Rendering...") # The GP samples self.Samples = Samples( self.ydeg, self.npix, self.npts, self.nmaps, self.throttle_time, self.nosmooth, self.gp, self.sample_function, ) # The integrals sp = StarryProcess(ydeg=self.ydeg) pdf = lambda x, mu, sigma: sp.latitude._pdf(x, *gauss2beta(mu, sigma)) pdf_gauss = lambda x, mu, sigma: 0.5 * (Normal.pdf(x, -mu, sigma) + Normal.pdf(x, mu, sigma)) npts = 300 T = spot_transform(self.ydeg, npts) self.Latitude = Integral( params["latitude"], self.Samples.callback, funcs=[pdf, pdf_gauss], labels=["pdf", "laplace"], xlabel="latitude distribution", ylabel="probability", distribution=True, legend_location="top_left", ) self.Size = Integral( params["size"], self.Samples.callback, funcs=[ lambda x, r: T @ (1 / (1 + np.exp(-300 * np.pi / 180 * (np.abs(x) - r))) - 1), lambda x, r: (1 / (1 + np.exp(-300 * np.pi / 180 * (np.abs(x) - r))) - 1), ], labels=["ylm", "true"], xlabel="spot profile", ylabel="intensity", npts=npts, ) self.Contrast = Integral(params["contrast"], self.Samples.callback) # Tell the GP about the sliders self.Samples.Latitude = self.Latitude self.Samples.Size = self.Size self.Samples.Contrast = self.Contrast # Settings ControlPanel = column( Div(text="<h1>settings</h1>", css_classes=["control-title"]), self.Contrast.layout, self.Samples.slider, row( self.Samples.smooth_button, self.Samples.auto_button, self.Samples.seed_button, self.Samples.reset_button, sizing_mode="scale_both", css_classes=["button-row"], ), Div(text=description, css_classes=["control-description"]), sizing_mode="scale_both", ) # Full layout layout = column( row( self.Latitude.layout, self.Size.layout, ControlPanel, sizing_mode="scale_both", ), self.Samples.layout, style(), sizing_mode="scale_both", ) print("Done rendering.") # Remove the loading screen doc.remove_root(self.layout) # Add the interface self.layout = layout doc.add_root(self.layout)
p = 1.0 tmax = 10.0 npts = 1000 inc = 60.0 kwargs = dict(r=15) seed = 0 # Plotting settings nimg = 5 pad = 85 vmin = -0.15 vmax = 0.075 # Spatial covariance np.random.seed(seed) sp = StarryProcess(ydeg=ydeg, seed=seed, **kwargs) cov_y = sp.cov_ylm.eval() Ly = np.tril(cho_factor(cov_y, lower=True)[0]) Ny = Ly.shape[0] # Temporal covariance t = np.linspace(0, tmax, npts) kernel = lambda t1, t2: np.exp(-((t1 - t2)**2) / (2 * tau)) Nt = len(t) eps = 1e-12 cov_t = kernel(t.reshape(1, -1), t.reshape(-1, 1)) Lt = np.tril(cho_factor(cov_t + eps * np.eye(Nt), lower=True)[0]) # Sample the map and the flux # These operations are identical to the extremely memory # intensive, excrutiatingly slow operations
def test_profile_marg(gradient, profile, ydeg=15, npts=1000): # Free parameters r = tt.dscalar() a = tt.dscalar() b = tt.dscalar() c = tt.dscalar() n = tt.dscalar() p = tt.dscalar() t = tt.dvector() flux = tt.dvector() data_cov = tt.dscalar() # Compute the mean and covariance gp = StarryProcess( r=r, a=a, b=b, c=c, n=n, marginalize_over_inclination=True ) # Compile the function if gradient: g = lambda f, x: tt.grad(f, x) else: g = lambda f, x: f func = theano.function( [r, a, b, c, n, p, t, flux, data_cov], [ g(gp.log_likelihood(t, flux, data_cov, p=p), a) ], # wrt a for definiteness profile=profile, ) # Run it t = np.linspace(0, 1, npts) flux = np.random.randn(npts) data_cov = 1.0 run = lambda: func( defaults["r"], defaults["a"], defaults["b"], defaults["c"], defaults["n"], defaults["p"], t, flux, data_cov, ) if profile: # Profile the full function run() print(func.profile.summary()) else: # Time the execution number = 100 time = timeit.timeit(run, number=number) / number print("time elapsed: {:.4f} s".format(time)) if (gradient and time > 0.2) or (not gradient and time > 0.1): warnings.warn("too slow! ({:.4f} s)".format(time))
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import make_axes_locatable from starry_process import StarryProcess, gauss2beta import os # GP settings r = 15 # spot radius in degrees mu, sig = 30, 5 # spot latitude and std. dev. in degrees c = 0.05 # spot contrast n = 20 # number of spots t = np.linspace(0, 1.5, 1000) a, b = gauss2beta(mu, sig) # Covariance of the original process sp = StarryProcess(r=r, a=a, b=b, c=c, n=n, normalized=False) Sigma = sp.cov(t).eval() # Covariance of the normalized process sp_norm = StarryProcess(r=r, a=a, b=b, c=c, n=n, normalized=True) Sigma_norm = sp_norm.cov(t).eval() # Figure setup fig, ax = plt.subplots(1, 2, figsize=(12, 6)) vmin = Sigma_norm.min() vmax = Sigma_norm.max() # Original im = ax[0].imshow(Sigma, cmap="viridis", vmin=vmin, vmax=vmax) divider = make_axes_locatable(ax[0]) cax = divider.append_axes("right", size="5%", pad=0.1)
def plot_samples(): # Settings nsamples = 5 norm = Normalize(vmin=0.5, vmax=1.1) incs = [15, 30, 45, 60, 75, 90] t = np.linspace(0, 4, 1000) cmap = plt.get_cmap("plasma_r") color = lambda i: cmap(0.1 + 0.8 * i / (len(incs) - 1)) map = starry.Map(15, lazy=False) kwargs = [ dict(r=10, a=0.40, b=0.27, c=0.1, n=10, seed=0), dict(r=10, a=0.31, b=0.36, c=0.1, n=10, seed=1), dict(r=30, a=0.28, b=0.0, c=0.05, n=10, seed=2), dict(r=10, a=0.06, b=0.0, c=0.1, n=20, seed=3), ] # One figure per `kwargs` for n in range(len(kwargs)): # Set up the plot fig, ax = plt.subplots( 2, nsamples + 1, figsize=(12, 2.5), gridspec_kw={ "height_ratios": np.array([1, 0.5]), "width_ratios": np.append(np.ones(nsamples), 0.1), }, ) # Draw samples sp = StarryProcess(marginalize_over_inclination=False, **kwargs[n]) y = sp.sample_ylm(nsamples=nsamples).eval() # Normalize so that the background photosphere # has unit intensity (for plotting) y[:, 0] += 1 y *= np.pi # Visualize each sample for k in range(nsamples): map[:, :] = y[k] map.show(ax=ax[0, k], projection="moll", norm=norm) ax[0, k].set_ylim(-1.5, 2.25) ax[0, k].set_rasterization_zorder(1) for i, inc in enumerate(incs): map.inc = inc flux = map.flux(theta=360.0 * t) flux -= np.mean(flux) flux *= 1e3 ax[1, k].plot(t, flux, color=color(i), lw=0.75) if k == 0: ax[1, k].spines["top"].set_visible(False) ax[1, k].spines["right"].set_visible(False) ax[1, k].set_xlabel("rotations", fontsize=8) ax[1, k].set_ylabel("flux [ppt]", fontsize=8) ax[1, k].set_xticks([0, 1, 2, 3, 4]) for tick in (ax[1, k].xaxis.get_major_ticks() + ax[1, k].yaxis.get_major_ticks()): tick.label.set_fontsize(6) ax[1, k].tick_params(direction="in") else: ax[1, k].axis("off") # Appearance tweaks cax = inset_axes(ax[0, -1], width="70%", height="50%", loc="lower center") cbar = fig.colorbar(ax[0, k].images[0], cax=cax, orientation="vertical") cbar.set_label("intensity", fontsize=8) cbar.set_ticks([0.5, 0.75, 1]) cbar.ax.tick_params(labelsize=6) ax[0, -1].axis("off") lax = inset_axes(ax[1, -1], width="80%", height="100%", loc="center right") for i, inc in enumerate(incs): lax.plot(0, 0, color=color(i), lw=1, label=r"{}$^\circ$".format(inc)) lax.legend(loc="center left", fontsize=5, frameon=False) lax.axis("off") ax[1, -1].axis("off") dy = max([max(np.abs(ax[1, k].get_ylim())) for k in range(nsamples)]) for k in range(nsamples): ax[1, 0].set_ylim(-dy, dy) # We're done fig.savefig("samples_{}.png".format(n), bbox_inches="tight", dpi=100)
def plot_corner(results, transform_beta=False, **kwargs): """ Plot the posterior corner plot. """ # Get kwargs kwargs = update_with_defaults(**kwargs) gen_kwargs = kwargs["generate"] sample_kwargs = kwargs["sample"] plot_kwargs = kwargs["plot"] span = [ (sample_kwargs["rmin"], sample_kwargs["rmax"]), (sample_kwargs["amin"], sample_kwargs["amax"]), (sample_kwargs["bmin"], sample_kwargs["bmax"]), (sample_kwargs["cmin"], sample_kwargs["cmax"]), (sample_kwargs["nmin"], sample_kwargs["nmax"]), 0.995, 0.995, ] labels = [ r"$r$", r"$a$", r"$b$", r"$c$", r"$n$", r"$\mu_b$", r"$\ln\sigma^2_b$", ] # Get truths sp = StarryProcess() try: a, b = gauss2beta(gen_kwargs["latitude"]["mu"], gen_kwargs["latitude"]["sigma"]) except: a = np.nan b = np.nan truths = [ gen_kwargs["radius"]["mu"], a, b, gen_kwargs["contrast"]["mu"], gen_kwargs["nspots"]["mu"], np.nan, np.nan, ] samples = np.array(results.samples) ndim = samples.shape[-1] if transform_beta: # Transform from `a, b` to `mode, std` a = samples[:, 1] b = samples[:, 2] mu, sigma = beta2gauss(a, b) samples[:, 1] = mu samples[:, 2] = sigma labels[1] = r"$\mu_\phi$" labels[2] = r"$\sigma_\phi$" if np.isfinite(gen_kwargs["latitude"]["sigma"]): truths[1] = gen_kwargs["latitude"]["mu"] truths[2] = gen_kwargs["latitude"]["sigma"] else: truths[1] = np.nan truths[2] = np.nan span[1] = (0, 90) span[2] = (0, 45) # Get sample weights try: weights = np.exp(results["logwt"] - results["logz"][-1]) except: weights = results["weights"] fig = corner(samples[:, :ndim], plot_datapoints=False, plot_density=False, truths=truths[:ndim], labels=labels[:ndim], range=span[:ndim], fill_contours=True, weights=weights, smooth=2.0, smooth1d=2.0, bins=100, hist_kwargs=dict(lw=1), truth_color="#ff7f0e", **plot_kwargs) return fig
fig, ax = plt.subplots( 2 * len(kwargs), nsamples + 1, figsize=(12, 2.5 * len(kwargs)), gridspec_kw={ "height_ratios": np.tile([1, 0.5], len(kwargs)), "width_ratios": np.append(np.ones(nsamples), 0.1), }, ) ax = np.swapaxes(np.swapaxes(ax.T.reshape(nsamples + 1, len(kwargs), 2), 0, 2), 0, 1) for n in range(len(kwargs)): # Draw samples sp = StarryProcess(marginalize_over_inclination=False, **kwargs[n]) y = sp.sample_ylm(nsamples=nsamples).eval() # Normalize so that the background photosphere # has unit intensity (for plotting) y[:, 0] += 1 y *= np.pi for k in range(nsamples): map[:, :] = y[k] map.show(ax=ax[n, 0, k], projection="moll", norm=norm) ax[n, 0, k].set_ylim(-1.5, 2.25) ax[n, 0, k].set_rasterization_zorder(1) for i, inc in enumerate(incs): map.inc = inc flux = map.flux(theta=360.0 * t)
import matplotlib.pyplot as plt from starry_process import StarryProcess, gauss2beta import theano import theano.tensor as tt from tqdm import tqdm import os # Compile the function to get the covariance matrix r = tt.dscalar() a = tt.dscalar() b = tt.dscalar() c = tt.dscalar() n = tt.dscalar() get_cov = theano.function( [r, a, b, c, n], StarryProcess(ydeg=20, epsy=1e-12, epsy15=0, r=r, a=a, b=b, c=c, n=n).cov_ylm, ) # Plot the condition number for 100 prior samples C = lambda cov, l: np.linalg.cond(cov[:(l + 1)**2, :(l + 1)**2]) ls = np.arange(1, 21) nsamples = 100 fig, ax = plt.subplots(1) np.random.seed(0) for j in tqdm(range(nsamples), disable=bool(int(os.getenv("NOTQDM", "0")))): r = np.random.uniform(10, 45) c = np.random.random() n = np.random.uniform(1, 50) mu = np.random.uniform(0, 85) sigma = np.random.uniform(5, 40)
map = starry.Map(15, lazy=False) fig, ax = plt.subplots( 2, nsamples + 1, figsize=(12, 2.5), gridspec_kw={ "height_ratios": [1, 0.5], "width_ratios": np.append(np.ones(nsamples), 0.1), }, ) # Draw samples from a sum of two StarryProcess instances sp = StarryProcess(marginalize_over_inclination=False, r=10, mu=60, sigma=3, c=0.15) sp += StarryProcess(marginalize_over_inclination=False, r=20, mu=0, sigma=3, n=5, c=0.1) y = sp.sample_ylm(nsamples=nsamples).eval() # Normalize so that the background photosphere # has unit intensity (for plotting) y[:, 0] += 1 y *= np.pi
def test_likelihood(): t = np.linspace(0, 1, 100) flux = np.random.randn(100) sp = StarryProcess(r=10) + StarryProcess(r=20) ll = sp.log_likelihood(t, flux, 1.0).eval() assert np.isfinite(ll)