In [1]:
import numpy as np
from bokeh.plotting import figure, show
from bokeh.layouts import grid, column, row
from bokeh.io import output_notebook
from bokeh.models import Span, Arrow, VeeHead
output_notebook()
Loading BokehJS ...

Brillouin zones of the two-dimensional square lattice¶

This notebook demonstrates construction of the first three Brillouin zones of square lattice

In [2]:
# Constructing real space lattice
a1 = np.array([0,2]);
a2 = np.array([2,0]);
N = 3;
x = range(-N, N+1)*np.linalg.norm(a1);
y = range(-N, N+1)*np.linalg.norm(a2);
xg,yg = np.meshgrid(x,y);
In [3]:
# Constructing reciprocal space lattice
b1 = np.array([0,2*np.pi / a1[1]]);
b2 = np.array([2*np.pi / a2[0],0]);
N = 3;
xx = range(-N, N+1)*np.linalg.norm(b1);
yy = range(-N, N+1)*np.linalg.norm(b2);
xxg,yyg = np.meshgrid(xx,yy);
In [4]:
real = figure(title = "Real space lattice", tools = "", x_range = [-10, 10], y_range = [-10, 10], width = 400, height = 400);
real.scatter(xg.flatten(),yg.flatten(),size = 10,fill_color = "blue",line_color = None,line_width = 3);
In [5]:
img = figure(title = "Reciprocal space lattice", tools = "", x_range = [-10, 10], y_range = [-10, 10], width = 400, height = 400);
img.scatter(xxg.flatten(),yyg.flatten(),size = 10,fill_color = "red", line_color = None,line_width = 3);
In [6]:
# plot the real and reciprocal lattice
show(row(real,img))

Constrution of the first Brillouin zone¶

The first Brillouin zone is the Wigner-Seitz cell of the reciprocal lattice. Hence, to construct it one must:¶

1. Draw the vectors from the origin to the nearest reciprocal lattice points¶

In [7]:
# draw the reciprocal lattice vectors from the origin to the nearest neighbour 
vec1 = img.multi_line([[b1[1], -b1[1]], [0, 0]],[[0, 0], [b2[0], -b2[0]]], line_width = 2, line_color = "black");
arrow1 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=b2[0], y_end=0);
arrow2 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=-b2[0], y_end=0);
arrow3 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=0, y_end=b1[1]);
arrow4 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=0, y_end=-b1[1]);
img.add_layout(arrow1);
img.add_layout(arrow2);
img.add_layout(arrow3);
img.add_layout(arrow4);
show(row(real, img))

2. Draw the Bragg plane bisecting these vectors. Any point on these bisectors will be as close to the origin as it is to the respective nearest reciprocal lattice point.¶

In [8]:
# constructing bragg planes (bisecting the reciprocal vectors drawn in the previous step)
bgp1 = Span(location = b2[0]/2, dimension = "height", line_dash="dashed");
bgp2 = Span(location = -b2[0]/2, dimension = "height", line_dash="dashed");
bgp3 = Span(location = b1[1]/2, dimension = "width", line_dash="dashed");
bgp4 = Span(location = -b1[1]/2, dimension = "width", line_dash="dashed");
bragg1 = img.renderers.extend([bgp1,bgp2,bgp3,bgp4]);
show(row(real, img))

3. Hence the first Brillouin zone will be the area defined by the intersection of these bisectors.¶

In [9]:
# Color the first Brillouin zone, which is the Wigner-Seitz unit cell in the reciprocal lattice
bz1 = img.patch([b2[0]/2, b2[0]/2, -b2[0]/2, -b2[0]/2, b2[0]/2],[b1[1]/2, -b1[1]/2, -b1[1]/2, b1[1]/2, b1[1]/2],line_width = 2, color = "red");
show(row(real,img))
In [10]:
# hide the first brillouin zone elements
vec1.visible = False;
arrow1.visible = False;
arrow2.visible = False;
arrow3.visible = False;
arrow4.visible = False;
bz1.visible = False;

Constrution of the 1st+2nd Brillouin zones¶

The second (or n-th) Brillouin zone is defined as set of points having one (or n-1) Bragg plane between it and the origin¶

To draw the second plane, we repeat the above process for the second nearest neighbours¶

In [11]:
# draw the reciprocal lattice vectors from the origin to the next nearst neighbours
vec2 = img.multi_line([[-b2[0], b2[0]], [-b1[1], b1[1]]],[[b2[0], -b2[0]], [-b1[1], b1[1]]], line_width = 2, line_color = "black");
arrow1 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=b2[0], y_end=b1[1]);
arrow2 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=-b2[0], y_end=-b1[1]);
arrow3 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=-b2[0], y_end=b1[1]);
arrow4 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=b2[0], y_end=-b1[1]);
img.add_layout(arrow1);
img.add_layout(arrow2);
img.add_layout(arrow3);
img.add_layout(arrow4);
show(row(real, img))
In [12]:
# construct bragg planes for the second brillouin zone
bragg2 = img.ray(x = [-b2[0], b2[0], b2[1], b2[1], -b2[0], b2[0], b2[1], b2[1]], y = [b1[0], b1[0], -b1[1], b1[1], b1[0], b1[0], -b1[1], b1[1]], length = 0, angle = [45, -135, 135, -45, -135, 45, -45, 135], angle_units = "deg", color = "black", line_width = 1, line_dash = "dashed");
bragg2.level = "annotation";
show(row(real, img))
In [13]:
# Color both the first and second brillouin zones
bz2 = img.patch([b2[1], b2[0], b2[1], -b2[0], b2[1]],[b1[1], b1[0], -b1[1], b1[0], b1[1]], line_width = 2);
show(row(real, img))
In [14]:
# hide the elements of the first and second brillouin zones
bz2.visible = False;
arrow1.visible = False;
arrow2.visible = False;
arrow3.visible = False;
arrow4.visible = False;
vec2.visible = False;

Constrution of the 1st+2nd+3rd Brillouin zones¶

Repeating for 3rd nearest neighbours allows us to construct 3rd Brillouin zone¶

In [15]:
# draw the reciprocal lattice vectors from the origin to the next next nearst neighbours
vec3 = img.multi_line([[2*b1[1], -2*b1[1]], [0, 0]],[[0, 0], [2*b2[0], -2*b2[0]]], line_width = 2, line_color = "black");
arrow1 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=2*b2[0], y_end=0);
arrow2 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=-2*b2[0], y_end=0);
arrow3 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=0, y_end=2*b1[1]);
arrow4 = Arrow(end = VeeHead(size = 10), x_start=0, y_start=0, x_end=0, y_end=-2*b1[1]);
img.add_layout(arrow1);
img.add_layout(arrow2);
img.add_layout(arrow3);
img.add_layout(arrow4);
show(row(real,img))
In [16]:
# construct bragg planes for the third brillouin zone
bgp1 = Span(location = b2[0], dimension = "height", line_dash="dashed");
bgp2 = Span(location = -b2[0], dimension = "height", line_dash="dashed");
bgp3 = Span(location = b1[1], dimension = "width", line_dash="dashed");
bgp4 = Span(location = -b1[1], dimension = "width", line_dash="dashed");
bragg3 = img.renderers.extend([bgp1,bgp2,bgp3,bgp4]);
show(row(real, img))

Note, however, that the zone is not defined just as an intersection of the newly constructed bisectors. If you check any point in the 4 squares we left out from the intersection, the line connecting the point and the origin goes throw more than 2 Bragg planes. Hence, one must be careful with higher order zones and have all the earlier Bragg planes drawn to decide where the zone lies¶

In [17]:
# color the third (along with the first and second) brillouin zones
bz3 = img.patches([[-b2[0], -b2[0], b2[0], b2[0]],[-b2[0]/2, -b2[0]/2, b2[0]/2, b2[0]/2]], [[-b1[1]/2, b1[1]/2, b1[1]/2, -b1[1]/2], [-b1[1], b1[1], b1[1], -b1[1]]], line_width = 2, color = "indigo");
show(row(real,img))

Show all three Brillouin zones together¶

In [18]:
# overlay all three Brillouin zones along with the bragg planes
bz3.visible = True;
bz3.level = "underlay";
bz2.visible = True;
bz2.level = "glyph";
bz1.visible = True;
bz1.level = "overlay";
vec3.visible = False;
arrow1.visible = False;
arrow2.visible = False;
arrow3.visible = False;
arrow4.visible = False;
show(row(real, img))

Questions¶

  • What are the 1st, 2nd, 3rd Brillouin zones of the 1D chain ?
In [ ]:
 
In [ ]:
 
In [ ]:
 
In [ ]: