This notebook explores how light gets reflected from an interface.
In [1]:
import numpy as np
def perpendicularFresnelCoefficient(n1, n2, theta):
ci = np.cos(theta*np.pi/180)
si = np.sin(theta*np.pi/180)
temp1 = n1*ci
temp2 = n2*np.sqrt(1-(n1/n2*si)**2)
num = temp1-temp2
den = temp1+temp2
return num/den
def parallelFresnelCoefficient(n1, n2, theta):
ci = np.cos(theta*np.pi/180)
si = np.sin(theta*np.pi/180)
temp1 = n1*np.sqrt(1-(n1/n2*si)**2)
temp2 = n2*ci
num = temp1-temp2
den = temp1+temp2
return num/den
And now the perpendicular and parallel reflectivities.
In [2]:
def perpendicularReflectivity(n1,k1,n2,k2,theta):
return np.abs(perpendicularFresnelCoefficient(n1+k1*1j, n2+k2*1j, theta))**2
def parallelReflectivity(n1,k1,n2,k2,theta):
return np.abs(parallelFresnelCoefficient(n1+k1*1j, n2+k2*1j, theta))**2
Now, some imports to be able to plot and handle data
In [3]:
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
output_notebook()
from bokeh.io import push_notebook
from bokeh.models import ColumnDataSource
from ipywidgets import interact
To plot the reflectivities as a function of the angle of incidence we need to do some coding!
The starting point will be an interface defined by vacuum and a material with $n=1.5$ and no absorption.
In [4]:
angle = np.arange(0, 90.5, 0.5)
Rs = perpendicularReflectivity(1, 0, 1.5, 0, angle)
Rp = parallelReflectivity(1, 0, 1.5, 0, angle)
source1 = ColumnDataSource(data=dict(x=angle, y=Rs))
source2 = ColumnDataSource(data=dict(x=angle, y=Rp))
reflectivityPlot = figure(title="Reflectivity", plot_height=300, plot_width=600, y_range=(0, 1), x_range=(0,90))
reflectivityPlot.line(angle, Rs, color="#2222aa", alpha=0.5, line_width=2, source=source1, name="1")
reflectivityPlot.line(angle, Rp, color="#222222", alpha=0.5, line_width=2, source=source2, name="2")
show(reflectivityPlot, notebook_handle=True)
Out[4]:
There we have the reflectivity. But it would be very interesting if we were able to interact and explore the behavior of the reflectivity given different index of refraction for the two media defining the interface.
We add interaction capability in the following.
In [5]:
def updateReflectivityPlot(n1=1, k1=0, n2=1.5, k2=0):
source1.data['y'] = perpendicularReflectivity(n1, k1, n2, k2, angle)
source2.data['y'] = parallelReflectivity(n1, k1, n2, k2, angle)
push_notebook()
interact(updateReflectivityPlot, n1=(1, 5, 0.05), k1=(0, 2, 0.01), n2=(1, 5, 0.05), k2=(0, 2, 0.01))
In [6]:
def ellipsometricAngles(n1, n2, angle):
rp = parallelFresnelCoefficient(n1, n2, angle)
rs = perpendicularFresnelCoefficient(n1, n2, angle)
psi = np.arctan(np.abs(rp)/np.abs(rs))*180/np.pi
delta = np.angle(rp, deg=True)-np.angle(rs, deg=True)
return psi, delta
In [7]:
psi, delta = ellipsometricAngles(1, 1.5, angle)
source1 = ColumnDataSource(data=dict(x=angle, y=psi))
#source2 = ColumnDataSource(data=dict(x=angle, y=delta))
ellipsometryPlot = figure(title="Psi and Delta", plot_height=300, plot_width=600, y_range=(0, 50), x_range=(0,90))
ellipsometryPlot.line(angle, psi, color="#2222aa", alpha=0.5, line_width=2, source=source1, name="1")
#ellipsometryPlot.line(angle, delta, color="#222222", alpha=0.5, line_width=2, source=source1, name="2")
def updateEllipsometryPlot(n1=1, k1=0, n2=1.5, k2=0):
source1.data['y'] = ellipsometricAngles(n1+1j*k1, n2+1j*k2, angle)[0]
#source2.data['y'] = ellipsometricAngles(n1+1j*k1, n2+1j*k2, angle)[1]
push_notebook()
show(ellipsometryPlot, notebook_handle=True)
Out[7]:
In [8]:
interact(updateEllipsometryPlot, n1=(1,5, 0.05), k1=(0, 2, 0.01), n2=(1,5, 0.05), k2=(0, 2, 0.01))