#!/usr/bin/env python
# coding: utf-8
#
#
#
# # Band Structures and Newton's Method
#
# ### Example – Quantum Mechanics
#
# By Øystein Hiåsen, Henning G. Hugdal and Peter Berg
#
# Last edited: April 15 2016
#
# ___
#
# One of the first great triumphs of quantum mechanics in applied physics was the electron band theory of solids [[1]](#rsc). The band structure arises due to the periodic potential experienced by the electrons in a solid. In the following, we will use Newton's method to calculate the band structure for the simple Dirac comb potential in one dimension.
# ### Particle in a One-Dimensional Lattice
#
# A simple model for a particle in a periodic lattice, i.e. a crystal, is a periodic potential of delta peaks in one dimension, also known as the Dirac comb potential,
#
# $$
# V(x) = V_0 \sum_{j}\delta(x-ja),
# $$
#
# where $a$ is the distance between the delta function peaks. In order to make this seem like a more realistic model, we can imagine that the potential wraps around in a circle that includes a macroscopic amount of peaks, $N \sim 10^{23}$. This means that the wavefunction of the system has to fulfill periodic boundary conditions,
#
# $$
# \psi(x+Na)=\psi(x).
# $$
# ### Bloch's Theorem
#
# Bloch's theorem [[2]](#rsc) states that for a periodic potential
#
# $$
# V(x + a ) = V(x)
# $$
#
# of period $a$, the wavefunction $\psi(x)$ satisfies
#
# $$
# \psi(x +a) = e^{iKa} \psi(x).
# $$
#
# Using periodic boundary conditions as stated above, we find
#
# $$
# \psi(x+Na) = e^{iNKa} \psi(x) = \psi(x).
# $$
#
# Hence, we must have $e^{iKNa} = 1$ which means
#
# $$
# K=\frac{2\pi n}{Na}, \qquad n\in \mathbb{Z}.
# $$
#
# For large $N$, which is the case in macroscopic materials, these values of $K$ essentially represent a continuum.
#
# The above implies that one only needs to find $\psi(x)$ within a single period with respect to $x$, for example $0 PRECISION):
iteration += 1
assert iteration <= MAX_NEWTON_ITERATIONS, "The method has run for max iterations={}".format(MAX_NEWTON_ITERATIONS)
z_new = newton_iteration(z_new, beta, y0)
return z_new
# This function will be used to calculate the lower bound of each of the first ten bands.
# Since we know the end value of each band, it might be a good idea to begin the search from values close to, but slightly smaller than those end values. This is what the following code does, including a plot of the final band structure.
# In[7]:
def calculate_bands(beta=DEFAULT_BETA, num_bands=10, start_band=0):
"""Returns the z-values of the beginning and end of each band.
The values are formatted as a 2xN matrix where N is the number of bands.
"""
band_numbers = np.arange(start_band, num_bands+start_band)
end_points = (band_numbers+1)*pi # The known end points
start_points = np.zeros(num_bands) # Initializing the array of start points
previous_end_point = 0
# Loop through each band and find the start point of the band
# by guessing a value close to the end point.
for n in range(num_bands):
band_number = band_numbers[n]
end_point = end_points[n]
z0 = end_point - 0.2*pi # Initial guess
y0 = (-1)**(band_number) # The value of f(z) we are looking for.
# Find new possible start_point
possible_start_point = run_newton(z0, y0, beta)
# If not between end points try a new initial guess z0
while(not (previous_end_point < possible_start_point < end_point) ):
z0 -= pi*0.1
assert (z0 > previous_end_point) # Make sure the initial guess is between end points
possible_start_point = run_newton(z0, y0, beta)
start_points[n] = possible_start_point
previous_end_point = end_point
# Assert that all end points comes after the start_points
assert (end_points > start_points).all(), "Not all end points are after start points"
return np.array([start_points, end_points])
# Using the above function, the width of the energy bands are calculated.
# In[8]:
b = calculate_bands(start_band=2)
print('Band widths:\n', b[1]-b[0])
# The following code will plot the energy bands for a given $\beta$.
# In[9]:
def plot_bands(bands, ax=None):
"""Plots the bands given a list of tuples containing beginning and end positions of the band."""
if ax is None:
ax=plt.gca()
xranges = zip(bands[0], bands[1]-bands[0])
ylim = ax.get_ylim()
collection=collections.BrokenBarHCollection(xranges=xranges, yrange=ylim, facecolor='#bb9999')
ax.add_collection(collection)
return ax
beta = DEFAULT_BETA
zstop = 30
num_bands= int(zstop//pi)
bands = calculate_bands(beta=beta, num_bands=num_bands)
plot_f(beta=beta, zstop=zstop)
plot_bands(bands)
plt.ylim([-2,2])
plt.title(r"Energy bands for $\beta=$ %d " % beta);
# As we see, the band widths increase with increasing $z$. Let's calculate the lowest allowed energy value:
# In[10]:
print(r'Lowest allowed value of z = %.4f.' % bands[0,0])
# We know that $z$ is related to $k$ by
#
# $$
# z=ka,
# $$
#
# and that $k$ is related to the energy $E$ by
#
# $$
# k = \frac{\sqrt{2mE}}{\hbar}.
# $$
#
# Setting $\hbar=m=a=1$ for simplicity, we obtain
#
# $$
# E = \frac{z^2}{2}.
# $$
#
# Hence, the lowest allowed electron energy in the crystal is $E_0 = 3.5703$. In this case $\beta=10$, which corresponds to a delta function strength $V_0=10$. Similarly, one can calculate the range of allowed energies in each band.
#
# It is also interesting to investigate how the band widths depend on $\beta$.
# In[11]:
def plot_bandwidths(betas, num_bands):
"""Plots the bandwidths against band_number for different betas."""
for beta in betas:
bands = calculate_bands(beta, num_bands)
width = bands[1,:] - bands[0,:]
plt.plot(width, label=str(beta))
plt.title(r'Band widths for different values of $\beta$')
plt.xlabel('Band number')
plt.ylabel('Band width')
plt.legend(loc=4)
plot_bandwidths(betas=[5,10,20,30,40,50], num_bands=60)
plt.plot([0,60],[pi, pi],':');
# We see that the width of the bands increases towards $\pi$. When the band width is equal to $\pi$, it means that the bands are in fact connected and can be regarded as one continuous band.
#
# ___
#
# ## References:
#
# [1]: Hemmer, P. C. _Kvantemekanikk_. Tapir Akademisk Forlag, 2005
#
# [2]: Griffiths, D. J. _Introduction to Quantum Mechanics_. Pearson Education, 2004.