This IPython Notebook is for performing a fit and generating a figure of the spectrum of sample VG05, which is a Double Side Polished Si puck, with no gap possible. This measurement will inform the limit of our technique.

The filename of the figure is VG05_DSP.pdf.

Author: Michael Gully-Santiago, gully@astro.as.utexas.edu

Date: January 13, 2015


In [1]:
%pylab inline
import emcee
import triangle
import pandas as pd
import seaborn as sns


Populating the interactive namespace from numpy and matplotlib

In [2]:
sns.set_context("paper", font_scale=2.0, rc={"lines.linewidth": 2.5})
sns.set(style="ticks")

Read in the data. We want "VG12"


In [3]:
df = pd.read_csv('../data/cln_20130916_cary5000.csv', index_col=0)

In [4]:
df.head()


Out[4]:
Baseline 100%T run1 run2 run3 run4 run5 run6 run7 run8 run9 ... run11 run12 run13 Baseline 100%T.1 run14 run15 run16 run17 run18 run19
wavelength
2500 97.571663 99.992661 99.925652 104.687546 100.544990 100.344467 100.074829 100.892555 101.091972 99.815392 ... 98.359612 99.398651 99.965683 97.481911 99.436729 100.292900 99.310913 100.170853 100.220047 99.987968
2498 97.561852 99.989677 99.943489 104.685280 100.568642 100.358917 100.081726 100.906097 101.112663 99.864021 ... 98.373856 99.429382 99.930801 97.524010 99.409943 100.256905 99.300064 100.145210 100.170815 100.001633
2496 97.545395 99.988541 99.963799 104.657723 100.592682 100.387237 100.085518 100.922897 101.129448 99.914932 ... 98.406830 99.436935 99.905930 97.560188 99.360924 100.242569 99.258934 100.110313 100.128174 100.025574
2494 97.522675 100.005188 100.007843 104.648781 100.625801 100.419998 100.109528 100.943352 101.161323 99.973755 ... 98.431221 99.452408 99.902763 97.605339 99.308495 100.208557 99.215111 100.089607 100.086441 100.030670
2492 97.519447 99.998352 100.011482 104.618713 100.635017 100.427994 100.125870 100.954353 101.170097 99.994553 ... 98.394218 99.451698 99.917610 97.653282 99.261490 100.174156 99.171951 100.041878 100.041367 100.033066

5 rows × 21 columns


In [3]:
df = df[df.index > 1250.0]

In [4]:
plt.plot(df.index[::4], df.run9[::4]/100.0, '.',label='DSP')
plt.legend(loc='best')
plt.ylim(0.99, 1.005)


Out[4]:
(0.99, 1.005)

Import all the local models, saved locally as etalon.py. See the paper for derivations of these equations.


In [5]:
from etalon import *
np.random.seed(78704)

In [6]:
# Introduce the Real data, decimate the data.
x = df.index.values[::4]
N = len(x)
# Define T_DSP for the model
T_DSP = T_gap_Si(x, 0.0)
n1 = sellmeier_Si(x)

# Define uncertainty
yerr = 0.0004*np.ones(N)
iid_cov = np.diag(yerr ** 2)

# Select the spectrum of interest
# Normalize the spectrum by measured DSP Si wafer.
y = df.run9.values[::4]/100.0

Define the likelihood.


In [7]:
def lnlike(d, f, lna, lns):
    a, s = np.exp(lna), np.exp(lns)
    off_diag_terms = a**2 * np.exp(-0.5 * (x[:, None] - x[None, :])**2 / s**2)
    C = iid_cov + off_diag_terms
    sgn, logdet = np.linalg.slogdet(C)
    if sgn <= 0:
        return -np.inf
    r = y - T_gap_Si_withFF_fast(x, d, f, n1)/T_DSP
    return -0.5 * (np.dot(r, np.linalg.solve(C, r)) + logdet)

Define the prior.


In [8]:
def lnprior(d, f, lna, lns):
    if not (0.0 < d < 1000.0 and 0.0< f < 1.0 and -12 < lna < -2 and 0 < lns < 10):
        return -np.inf
    return 0.0

Combine likelihood and prior to obtain the posterior.


In [9]:
def lnprob(p):
    lp = lnprior(*p)
    if not np.isfinite(lp):
        return -np.inf
    return lp + lnlike(*p)

Set up emcee.


In [10]:
ndim, nwalkers = 4, 32
d_Guess = 5.0
f_Guess = 0.95
p0 = np.array([d_Guess, f_Guess, np.log(0.003), np.log(25.0)])
pos = [p0 + 1.0e-2*p0 * np.random.randn(ndim) for i in range(nwalkers)]

sampler = emcee.EnsembleSampler(nwalkers, ndim, lnprob)

Run the burn-in phase.


In [11]:
pos, lp, state = sampler.run_mcmc(pos, 200)

Run the full MCMC.


In [12]:
sampler.reset()
pos, lp, state = sampler.run_mcmc(pos, 600)
chain = sampler.chain

Inspect the chain.


In [13]:
fig, axes = plt.subplots(4, 1, figsize=(5, 6), sharex=True)
fig.subplots_adjust(left=0.1, bottom=0.1, right=0.96, top=0.98,
                    wspace=0.0, hspace=0.05)
[a.plot(np.arange(chain.shape[1]), chain[:, :, i].T, "k", alpha=0.5)
 for i, a in enumerate(axes)]
[a.set_ylabel("${0}$".format(l)) for a, l in zip(axes, ["d", "f", "\ln a", "\ln s"])]
axes[-1].set_xlim(0, chain.shape[1])
axes[-1].set_xlabel("iteration");


Linearize $a$ and $s$ for graphical purposes.


In [14]:
samples_lin = copy(sampler.flatchain)
samples_lin[:, 2:] = np.exp(samples_lin[:, 2:])

Make a triangle corner plot.


In [15]:
fig = triangle.corner(samples_lin, 
                      labels=map("${0}$".format, ["d", "f", "a", "s"]), 
                      quantiles=[0.16, 0.84])


Quantiles:
[(0.16, 4.9099941743068225), (0.84, 14.238637561094768)]
Quantiles:
[(0.16, 0.10553881830355584), (0.84, 0.74484973700746182)]
Quantiles:
[(0.16, 0.00076280601590054714), (0.84, 0.0032355942320698369)]
Quantiles:
[(0.16, 2657.960285487175), (0.84, 16129.646282288006)]

In [16]:
fig = triangle.corner(samples_lin[:,0:2], 
                      labels=map("${0}$".format, ["d", "f"]), 
                      quantiles=[0.16, 0.84])
plt.savefig("VG05_corner.pdf")


Quantiles:
[(0.16, 4.9099941743068225), (0.84, 14.238637561094768)]
Quantiles:
[(0.16, 0.10553881830355584), (0.84, 0.74484973700746182)]
/Users/gully/anaconda/lib/python2.7/site-packages/matplotlib/backends/backend_pdf.py:2264: FutureWarning: comparison to `None` will result in an elementwise object comparison in the future.
  different = bool(ours != theirs)

Calculate confidence intervals.


In [17]:
d_mcmc, f_mcmc, a_mcmc, s_mcmc = map(lambda v: (v[1], v[2]-v[1], v[1]-v[0]),
                             zip(*np.percentile(samples_lin, [16, 50, 84],
                                                axis=0)))
d_mcmc, f_mcmc, a_mcmc, s_mcmc


Out[17]:
((7.7462704108910003, 6.4923671502037674, 2.8362762365841778),
 (0.36259167239121715, 0.38225806461624467, 0.25705285408766132),
 (0.0013682563108928388, 0.0018673379211769981, 0.00060545029499229166),
 (7422.8640173039348, 8706.7822649840709, 4764.9037318167593))

Overlay draws from the Gaussian Process.


In [18]:
plt.figure(figsize=(6,3))

for d, f, a, s in samples_lin[np.random.randint(len(samples_lin), size=60)]:
    off_diag_terms = a**2 * np.exp(-0.5 * (x[:, None] - x[None, :])**2 / s**2)
    C = iid_cov + off_diag_terms
    fit = T_gap_Si_withFF_fast(x, d, f, n1)/T_DSP
    vec = np.random.multivariate_normal(fit, C)
    plt.plot(x, vec,"-b", alpha=0.06)

plt.step(x, y,color="k", label='Measurement')
fit = T_gap_Si_withFF_fast(x, d_mcmc[0], f_mcmc[0], n1)/T_DSP
fit_label = 'Model with $d={:.0f}$ nm, $f={:.3f}$'.format(d_mcmc[0], f_mcmc[0])
plt.plot(x, fit, '--', color=sns.xkcd_rgb["pale red"], alpha=1.0, label=fit_label)

#fit1 = T_gap_Si_withFF_fast(x, 43, 0.5, n1)/T_DSP
#fit2 = T_gap_Si_withFF_fast(x, 55, 0.5, n1)/T_DSP
#fit2_label = 'Model with $d={:.0f}\pm{:.0f}$ nm, $f={:.2f}$'.format(49, 6, 0.5)
#plt.fill_between(x, fit1, fit2, alpha=0.6, color=sns.xkcd_rgb["green apple"])
#plt.plot([-10, -9], [-10, -9],"-", alpha=0.85, color=sns.xkcd_rgb["green apple"], label=fit2_label)

plt.plot([-10, -9], [-10, -9],"-b", alpha=0.85, label='Draws from GP')
plt.plot([0, 5000], [1.0, 1.0], '-.k', alpha=0.5)
plt.fill_between([1200, 1250], 2.0, 0.0, hatch='\\', alpha=0.4, color='k', label='Si absorption cutoff')

plt.xlabel('$\lambda$ (nm)');
plt.ylabel('$T_{gap}$');
plt.xlim(1200, 2501);
plt.ylim(0.98, 1.005);
plt.legend(loc='lower right')
plt.savefig("VG05_DSP.pdf",  bbox_inches='tight')


The end.