-
Anton Akhmerov authoredAnton Akhmerov authored
jupyter:
jupytext:
text_representation:
extension: .md
format_name: markdown
format_version: '1.0'
jupytext_version: 1.0.2
kernelspec:
display_name: Python 3
language: python
name: python3
import matplotlib.pyplot as plt
import numpy as np
from math import sqrt,pi
from common import draw_classic_axes, configure_plotting
from plotly.subplots import make_subplots
import plotly.graph_objs as go
configure_plotting()
Lecture 9 – Crystal structure
based on chapter 12 of the book
!!! success "Expected prior knowledge"
Before the start of this lecture, you should be able to:
- use elementary vector calculus
!!! summary "Learning goals"
After this lecture you will be able to:
- Describe any crystal using crystallographic terminology, and interpret this terminology
- Compute the volume filling fraction given a crystal structure
- Determine the primitive, conventional, and Wigner-Seitz unit cells of a given lattice
- Determine the Miller planes of a given lattice
??? info "Lecture video"
<iframe width="100%" height="315" src="https://www.youtube-nocookie.com/embed/zl8htOplU1s" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
Crystal classification
In the past few lectures, we derived some very important physical quantities for phonons and electrons, such as the effective mass, the dispersion relation. These systems we considered were mainly 1D. But most solids, such as crystals, are 3D structures. Describing 3D system is not much harder than describing 1D systems. It does however, require a new language and framework in order to fully describe such structures. Therefore the upcoming two lectures will focus on developing, understanding, and applying this language and framework.
Lattices and unit cells
Most of solid state physics deals with crystals, which are periodic multi-atomic structures. To describe such periodic structures, we need a simple framework. Such a framework is given by the concept of a lattice:
A lattice is an infinite set of points defined by an integer sums of a set of linearly independent primitive lattice vectors(will be explained later on).
Which for a 3D system translates to:
\mathbf{R}_{\left[n_{1} n_{2} n_{3}\right]}=n_{1} \mathbf{a}_{1}+n_{2} \mathbf{a}_{2}+n_{3} \mathbf{a}_{3}, \quad \mathrm{for } \:\: n_{1}, n_{2}, n_{3} \in \mathbb{Z}.
With \mathbf{a}_i being the primitive lattice vectors. For a n dimensional system, we have to define n linearly independent primitive lattice vectors in order to be able to map out the entire lattice.
This definition is pretty rigorous. But there exist multiple equivalent definitions of a lattice. A more informal definition is:
A lattice is a set of points where the environment of each point is the same.
In the image below we show a 2D simple square lattice (panel A). Each of the black dots are called lattice points. Because the environment of each lattice point is the same, this configuration of lattice points forms a proper lattice.
# Define the lattice vectors
a1 = np.array([1,0])
a2 = np.array([0,1])
a1_alt = -a1-a2
a2_alt = a1_alt + a1
a2_c = np.array([0,sqrt(3)])
# Produces the lattice to be fed into plotly
def lattice_generation(a1,a2,N = 10):
grid = np.arange(-N//2,N//2,1)
xGrid, yGrid = np.meshgrid(grid,grid)
return np.reshape(np.kron(xGrid.flatten(),a1),(-1,2))+np.reshape(np.kron(yGrid.flatten(),a2),(-1,2))
# Produces the dotted lines of the unit cell
def dash_contour(a1,a2, vec_zero = np.array([0,0]), color='Red'):
dotLine_a1 = np.transpose(np.array([a1,a1+a2])+vec_zero)
dotLine_a2 = np.transpose(np.array([a2,a1+a2])+vec_zero)
def dash_trace(vec,color):
trace = go.Scatter(
x=vec[0],
y=vec[1],
mode = 'lines',
line_width = 2,
line_color = color,
line_dash='dot',
visible=False
)
return trace
return dash_trace(dotLine_a1,color),dash_trace(dotLine_a2,color)
# Makes the lattice vector arrow
def make_arrow(vec,text,color = 'Red',vec_zero = [0,0], text_shift = [-0.2,-0.1]):
annot = [dict(
x = vec[0],
y = vec[1],
ax = vec_zero[0],
ay = vec_zero[1],
xref = 'x',
yref = 'y',
axref = 'x',
ayref = 'y',
showarrow=True,
arrowhead=2,
arrowsize=1,
arrowwidth=3,
arrowcolor = color
),
dict(
x=(vec[0]+vec_zero[0])/2+text_shift[0],
y=(vec[1]+vec_zero[1])/2+text_shift[1],
xref='x',
ayref = 'y',
text = text,
font = dict(
color = color,
size = 20
),
showarrow=False,
)
]
return annot
# Create the pattern
pattern_points = lattice_generation(a1,a2)
# Lattice Choice A
latticeA = go.Scatter(visible = True,x=pattern_points.T[0],y=pattern_points.T[1],mode='markers',marker=dict(
color = 'Black',
size = 10,
)
)
# Annotate the lattice vectors
# Button 1
bt1_annot = make_arrow(a1,r'$\mathbf{a}_1$') + make_arrow(a2,r'$\mathbf{a}_2$',text_shift=[-0.3,-0.1], vec_zero = [0,-.1])
# Button 2
bt2_annot = make_arrow(a1,r'$\mathbf{a}_1$') + make_arrow(a2,r'$\mathbf{a}_2$',text_shift=[-0.3,-0.1], vec_zero = [0,-.1]) + make_arrow(a1_alt,r'$\tilde{\mathbf{a}}_1$',color='Black',text_shift=[-0.6,-0.1]) + make_arrow(a2_alt,r'$\tilde{\mathbf{a}}_2$',color='Black',text_shift=[-0.35,-0.1], vec_zero = [0,.1])
# (0) Button 1, (0, 1-5) Button 2, (0, 6-8) Button 3, (0,1,9,10)
data = [latticeA, *dash_contour(a1,a2), *dash_contour(a1_alt,a2_alt,color='Black'),]
updatemenus = list([
dict(
type="buttons",
direction = "down",
active=0,
buttons=list([
dict(label="A",
method="update",
args=[{"visible": [True, False, False, False, False,]},
{"title": "Lattice",
"annotations": []}]),
dict(label="B",
method="update",
args=[{"visible": [True, True, True, False, False,]},
{"title": "Lattice with a primitive unit cell",
"annotations": bt1_annot}]),
dict(label="C",
method="update",
args=[{"visible": [True, True, True, True, True, ]},
{"title": "Lattice with a two primitive unit cells",
"annotations": bt2_annot}]),
]),
)
]
)
# Setting axis to invisible
plot_range = 2.1
axis = dict(
range=[-plot_range,plot_range],
visible = False,
showgrid = False,
fixedrange = True
)
# Figure propeties
layout = dict(
showlegend = False,
updatemenus = updatemenus,
plot_bgcolor = 'rgb(254, 254, 254)',
width = 600,
height = 600,
xaxis = axis,
yaxis = axis
)
# Displaying the figure
go.Figure(data=data, layout=layout)
A vector connecting any two lattice points is called a lattice vector. Suppose we choose two linearly independent lattice vectors \mathbf{a}_1 and \mathbf{a}_2 (panel B). These two lattice vectors span an area which is called a unit cell:
A unit cell is a region of space such that when many identical units are stacked together it tiles (completely fills) all of space and reconstructs the full structure.
In the case of a 3D lattice, we need to choose three linearly independent lattice vectors and thus the unit cell will be a volume instead of an area. If the chosen unit cell only contains a single lattice point, we speak of a primitive unit cell. The lattice vectors which construct the primitive unit cell are called primitive lattice vectors. Because the primitive unit cell is constructed out of a set of linearly independent primitive lattice vectors, the primitive unit cell can be repeated infinitely many times to map out the entire lattice!
The unit cell, which was conveniently chosen in panel B, is such a primitive unit cell. At first glance it might seem that there are four lattice point inside the primitive unit cell instead of one. However, each point only occupies the lattice by \frac{1}{4}'th. Thus there is exactly 4 \times \frac{1}{4}=1 lattice point in the unit cell and is thus it is primitive!
The choice of the primitive lattice vectors is not unique. In panel C, we show the same lattice plotted with two different unit cells. Both choices are primitive unit cells and thus make it possible to map out the entire lattice!
??? Question "Examine the primitive unit cell spanned by the lattice vectors \tilde{\mathbf{a}}_1 and \tilde{\mathbf{a}}_2. How much does each lattice point occupy the unit cell?"
Two points occupy it for 1/8'th and two points for 3/8'th.
Periodic structures.
Equipped with the basic definitions of a lattice, (primitive) lattice vectors, and (primitive) unit cells, we now apply our knowledge to an actual periodic structure. In the image below we show a periodic star-like structure (panel A).
# Define the lattice vectors
vec_0 = np.array([-.5, 0])
a1 = np.array([1, 0])
a2 = np.array([.5, np.sqrt(3)/2])
a1_alt = -a1-a2
a2_alt = a1_alt + a1
a2_c = np.array([0,sqrt(3)])
# Create the pattern
pattern_points = lattice_generation(a1,a2)
pattern = go.Scatter(x=pattern_points.T[0],y=pattern_points.T[1],mode='markers',marker=dict(
color='Black',
size = 20,
symbol = 'star-open-dot')
)
# Lattice Choice A
latticeA = go.Scatter(visible = False, x = pattern_points.T[0],y = pattern_points.T[1],mode='markers',marker=dict(
color = 'Red',
size = 10,
)
)
# Lattice Choice B
latticeB = go.Scatter(visible = False, x = pattern_points.T[0]+0.5,y = pattern_points.T[1],mode='markers',marker=dict(
color='Blue',
size = 10,
)
)
# Annotate the lattice vectors
# Button 1
bt1_annot = make_arrow(a1,r'$\mathbf{a}_1$') + make_arrow(a2,r'$\mathbf{a}_2$',text_shift=[-0.3,-0.1], vec_zero = [0,-.1])
# Button 2
bt2_annot = make_arrow(a1+vec_0,r'$\mathbf{a}_1$', vec_zero = vec_0, color = 'Blue') + make_arrow(a2+vec_0,r'$\mathbf{a}_2$',text_shift=[-0.3,-0.1], vec_zero = [-.55,-.1], color = 'Blue')
# Button 3
bt3_annot = make_arrow([1,0], r'$\mathbf{a}_1$') + make_arrow([0, np.sqrt(3)], r'$\mathbf{a}_2$',text_shift=[-0.3,-0.1])
# (0) Button 1, (0, 1-5) Button 2, (0, 6-8) Button 3, (0,1,9,10)
data = [pattern, latticeA, latticeB, *dash_contour(a1,a2, color = 'Red'),
*dash_contour(a1, a2, vec_zero = vec_0, color = 'Blue'),
*dash_contour(np.array([1,0]), a2_c, color = 'Red')]
updatemenus = list([
dict(
type="buttons",
direction = "down",
active=0,
buttons=list([
dict(label="A",
method="update",
args=[{"visible": [True, False, False, False, False, False, False, False, False,]},
{"title": "Periodic structure",
"annotations": []}]),
dict(label="B",
method="update",
args=[{"visible": [True, True, False, True, True, False, False, False, False,]},
{"title": "Periodic structure with lattice and primitive unit cell",
"annotations": bt1_annot}]),
dict(label="C",
method="update",
args=[{"visible": [True, False, True, False, False, True, True, False, False,]},
{"title": "Periodic structure with translated lattice and primitive unit cell",
"annotations": bt2_annot}]),
dict(label="D",
method="update",
args=[{"visible": [True, True, False, False, False, False, False, True, True,]},
{"title": "Periodic structure with lattice and conventional unit cell",
"annotations": bt3_annot}]),
]),
)
]
)
# Setting axis to invisible
plot_range = 2.1
axis = dict(
range=[-plot_range,plot_range],
visible = False,
showgrid = False,
fixedrange = True
)
# Figure propeties
layout = dict(
showlegend = False,
updatemenus = updatemenus,
plot_bgcolor = 'rgb(254, 254, 254)',
width = 600,
height = 600,
xaxis = axis,
yaxis = axis
)
go.Figure(data=data, layout=layout)
There are several ways to assign lattice points to the periodic structure. We can assign the lattice points to the stars themselves. This is a valid choice of a lattice for the periodic structure because each lattice point has the same environment. Because the lattice points form triangles, this lattice is called a triangular lattice.
The choice of a lattice also defines two linearly independent primitive lattice vectors \mathbf{a}_1 and \mathbf{a}_2 (panel B):
\mathbf{a}_1 = \hat{\mathbf{x}} = \left[ 1, 0\right], \quad \mathbf{a}_2 = \frac{1}{2}\hat{\mathbf{x}} + \frac{\sqrt{3}}{2} \hat{\mathbf{y}}= \left[1/2, \sqrt{3}/2\right].
With these primitive lattice vector, the lattice is given by
\mathbf{R}_{\left[n_{1}, n_{2}\right]}=n_{1} \left[ 1, 0 \right]+n_{2} \left[ 1/2, \sqrt{3}/2 \right], \quad \mathrm{for} \:\: n_{1}, n_{2} \in \mathbb{Z}.
However, our description so far is insufficient to describe the periodic structure. Although we mapped out the entire lattice, we still do not have any information about the periodic star-like structure itself. To include the information of the periodic structure, we need to define a basis (do not confuse this with the definition of a basis in linear algebra):
The description of objects with respect to the reference lattice point is known as a basis.
The reference lattice point is the chosen lattice point to which we apply the lattice vectors in order to reconstruct the lattice. In our case, we chose the reference point as [0, 0]. With respect to the reference point, the star is located at [0, 0]. The location of all the stars in the lattice with respect to the reference lattice point is then given by: