Chapter 4
18 min read
Section 32 of 70

Nearly Free Electrons and Band Gaps

Quantum Mechanics for Solids

Learning Objectives

In Section 4.1 we ignored the lattice potential entirely and still obtained a startlingly accurate description of simple metals. That can't last. The lattice does exist, and it has one spectacular consequence the free electron gas can never produce: band gaps. Without them, every solid would conduct like sodium. With them, we get diamonds, transistors, lasers, and the entire chemistry of CdSe.

This section turns the dial up gently. We will keep the plane-wave basis, but allow the periodic potential V(r) to scatter electrons between plane waves. Even an infinitesimal V opens a gap whenever two plane-wave energies cross — and those crossings happen, by construction, on the surfaces of Brillouin zones we built in Chapter 3.

By the end of this section you should be able to:

  1. Sketch the free-electron parabola ε(k)=2k2/2m\varepsilon(k) = \hbar^2 k^2 / 2m in the extended-zone, reduced-zone, and periodic-zone schemes, and translate fluently between them.
  2. Explain why a periodic V(r) opens a gap at every Brillouin-zone boundary, using both the Bragg-diffraction argument and the two-plane-wave Hamiltonian.
  3. Diagonalise the two-plane-wave model in your head and predict the gap size Δ=2VG\Delta = 2|V_G|.
  4. Visualise why the two zone-boundary states ψ+\psi_+ and ψ\psi_- sit at different energies, in terms of where their charge density piles up relative to the ions.
  5. Diagonalise the 5-plane-wave 1D NFE Hamiltonian in NumPy and extract the gap from the eigenvalues at k=π/ak = \pi/a.
  6. Use band filling to classify a material as a metal, semiconductor, or insulator — and link this to the NELECT, NBANDS, and band-gap fields in a real VASP OUTCAR.

Where Section 4.1 Left Off

Section 4.1 ended with the Fermi sphere of sodium tucked comfortably inside the first Brillouin zone of BCC sodium. We noted — without proof — that the free-electron model breaks down where the sphere bumps into the BZ surface. This section delivers that proof.

We will keep three results from 4.1 on the table at all times:

  • The dispersion ε(k)=2k2/(2m)\varepsilon(k) = \hbar^2 k^2/(2m) is the spectrum of plane waves ψk(r)=eikr/V\psi_k(\mathbf{r}) = e^{i\mathbf{k}\cdot\mathbf{r}}/\sqrt{V}.
  • With periodic boundary conditions, allowed k\mathbf{k} values form a discrete lattice in k-space with spacing 2π/L2\pi/L per direction.
  • From Chapter 3, the reciprocal-lattice vectors G\mathbf{G} are exactly the wave-vector differences that the lattice can absorb without violating momentum conservation.
The beautiful surprise: every interesting effect of this section is already encoded in those three statements. We are not adding new physics — we are finally using the third one.

Turning On the Crystal Potential

The Schrödinger equation for one electron in a crystal reads:

[22m2+V(r)]ψ(r)=εψ(r),V(r+R)=V(r)\left[-\frac{\hbar^2}{2m}\nabla^2 + V(\mathbf{r})\right]\psi(\mathbf{r}) = \varepsilon\,\psi(\mathbf{r}),\quad V(\mathbf{r} + \mathbf{R}) = V(\mathbf{r})

The new ingredient is the periodic potential V(r)V(\mathbf{r}), periodic on the Bravais lattice. Periodicity has one immediate consequence we will lean on relentlessly: V can be expanded in a Fourier series over reciprocal vectors only,

V(r)=GVGeiGrV(\mathbf{r}) = \sum_{\mathbf{G}} V_{\mathbf{G}}\,e^{i\mathbf{G}\cdot\mathbf{r}}

because no lower-frequency Fourier components survive translation by lattice vectors R\mathbf{R}. The matrix element of V between two plane waves k|\mathbf{k}'\rangle and k|\mathbf{k}\rangle is therefore zero unless they differ by some reciprocal vector:

kVk=VG if k=k+G,0 otherwise\langle \mathbf{k}' | V | \mathbf{k} \rangle = V_{\mathbf{G}}\ \text{if}\ \mathbf{k}' = \mathbf{k} + \mathbf{G},\quad 0\ \text{otherwise}

This is the only formula you really need to derive everything that follows. Periodic V can only scatter k\mathbf{k} into k+G\mathbf{k} + \mathbf{G}. A free-electron state at the centre of the BZ is decoupled from almost everything; one at the BZ boundary is hopelessly entangled with its symmetric partner at kG\mathbf{k} - \mathbf{G}.

The Empty Lattice: Folding the Parabola

Before turning V on, let us pretend the lattice is there only to define a Brillouin zone — the so-called empty lattice approximation. The eigenstates are still plane waves and the spectrum is still ε(k)=2k2/(2m)\varepsilon(k) = \hbar^2 k^2/(2m), but we now agree to plot every quantity inside one Brillouin zone.

Every k outside the first BZ can be brought back inside by subtracting some G\mathbf{G}. So a plane-wave with wavevector k=1.5π/ak = 1.5\,\pi/a is “the same wave” (up to a phase factor of one across each unit cell) as one at kG=0.5π/ak - G = -0.5\,\pi/a. Both end up at the same place in the reduced zone, but at different energies, because their kinetic energies differ. The single parabola in extended-zone plotting becomes infinitely many parabolas in reduced-zone plotting — the bands.

Interactive: Three Ways to Plot the Same Spectrum

Click between the three buttons below. The spectrum is identical; only the convention changes.

The most useful sentence in this chapter: “A band structure is just the free-electron parabola folded into the first Brillouin zone, then perturbed by the lattice potential.” Memorise it. Most band-structure plots you will ever see are weak deformations of the reduced-zone view above.

The Bragg Condition Revisited

On a Brillouin-zone boundary, k2=kG2|\mathbf{k}|^2 = |\mathbf{k} - \mathbf{G}|^2 for some reciprocal vector G\mathbf{G}. Expand the right-hand side and cancel k2|\mathbf{k}|^2:

2kG=G22\,\mathbf{k}\cdot\mathbf{G} = |\mathbf{G}|^2

This is the very same Laue/Bragg condition that governs X-ray diffraction (Section 3.6). The interpretation now is quantum mechanical, not geometrical: at the BZ boundary, an incident plane-wave state k|\mathbf{k}\rangle has the same energy as its lattice-scattered partner kG|\mathbf{k} - \mathbf{G}\rangle. The two states are degenerate — and degenerate states under even an infinitesimal perturbation always rearrange.

The diffraction picture says a wave at the BZ boundary is perfectly reflected by the lattice. The quantum picture says the two reflected halves combine into standing waves. Both are right: that is exactly the “wave-particle” duality of an electron in a crystal.

The Two-Plane-Wave Model

Pick a single reciprocal vector G\mathbf{G}. Project the full Schrödinger equation onto the two-dimensional subspace spanned by k|\mathbf{k}\rangle and kG|\mathbf{k} - \mathbf{G}\rangle. The Hamiltonian in this basis is a 2×2 matrix:

H=(ε0(k)VGVGε0(kG))H = \begin{pmatrix} \varepsilon_0(\mathbf{k}) & V_{\mathbf{G}} \\ V_{\mathbf{G}}^* & \varepsilon_0(\mathbf{k} - \mathbf{G}) \end{pmatrix}

where ε0(q)=2q2/(2m)\varepsilon_0(\mathbf{q}) = \hbar^2 q^2/(2m) is the bare kinetic energy. The diagonal entries are the free-electron energies; the off-diagonal entries are the single Fourier component of V that connects them. Everything else is either zero (the periodic potential cannot scatter by anything other than reciprocal vectors) or far away in energy (other plane waves are pushed off-resonance by their large kinetic energy difference).


Diagonalising the 2 × 2 Hamiltonian

Eigenvalues of a 2×2 Hermitian matrix are textbook:

ε±=ε0(k)+ε0(kG)2±(ε0(k)ε0(kG)2)2+VG2\varepsilon_\pm = \frac{\varepsilon_0(\mathbf{k}) + \varepsilon_0(\mathbf{k} - \mathbf{G})}{2} \pm \sqrt{\left(\frac{\varepsilon_0(\mathbf{k}) - \varepsilon_0(\mathbf{k} - \mathbf{G})}{2}\right)^2 + |V_{\mathbf{G}}|^2}

Two limits matter. Far from the zone boundary, the kinetic-energy difference dwarfs VG|V_{\mathbf{G}}|; the discriminant reduces to the kinetic-energy half-difference and the bands recover their free-electron values with tiny second-order corrections. Standard parabolas, lightly bent.

On the zone boundary kG=G2/2\mathbf{k}\cdot\mathbf{G} = |\mathbf{G}|^2/2, the two diagonal entries are equal: the discriminant collapses to VG|V_{\mathbf{G}}| and:

ε±=ε0(k)±VG,Δ=ε+ε=2VG\varepsilon_\pm = \varepsilon_0(\mathbf{k}) \pm |V_{\mathbf{G}}|,\qquad \Delta = \varepsilon_+ - \varepsilon_- = 2|V_{\mathbf{G}}|

A degeneracy that would otherwise be a single point on the parabola has been lifted by exactly twice the relevant Fourier component of V. That is the band gap.

The size of the gap at G\mathbf{G} is set by a single Fourier component of the potential: Δ(G)=2VG\Delta(\mathbf{G}) = 2|V_{\mathbf{G}}|. Different gaps in the same band structure correspond to different reciprocal vectors, not to different physics — they are all the same mechanism evaluated at different G\mathbf{G}.

Interactive: Watching the Gap Open

Set the slider below to V0=0V_0 = 0: the two free-electron parabolas (centred at k=0k = 0 and k=Gk = G) cross unceremoniously at k=G/2k = G/2. Now nudge V0V_0 up. Watch the crossing transform into an avoided crossing: the lower band bends down, the upper band bends up, and the gap between them is exactly 2V02|V_0|.


Why ψ₊ and ψ₋ Have Different Energies

The eigenvectors at the zone boundary are even and odd combinations of the two plane waves:

ψ±(x)=12(eiπx/a±eiπx/a)=2{cos,sin}(πx/a)\psi_\pm(x) = \frac{1}{\sqrt{2}}\left(e^{i\pi x/a} \pm e^{-i\pi x/a}\right) = \sqrt{2}\,\{\cos,\,\sin\}(\pi x/a)

These are standing waves, not travelling waves — the net momentum flow is zero, in agreement with the Bragg-reflection picture. Their probability densities are ψ+2=2cos2(πx/a)|\psi_+|^2 = 2\cos^2(\pi x/a) (peaked on the ions, troughs midway) and ψ2=2sin2(πx/a)|\psi_-|^2 = 2\sin^2(\pi x/a) (the reverse: peaked midway, troughs on the ions).

Now bring back V(x), which is most negative on the ions (electrons are attracted to positive ion cores). The two densities sample VV at different places, so they have different electrostatic energies:

  • ψ+\psi_+ piles charge on top of the ions where V is most negative → lower energy → bottom of the gap.
  • ψ\psi_- piles charge between ions where V is least negative → higher energy → top of the gap.

This is not abstract perturbation theory. It is electrostatics, and the picture you should keep in your head whenever someone asks why a band gap exists.

Interactive: Standing Waves at the Zone Boundary

The grey dots are the positively charged ion cores. The dashed curves are the wavefunctions ψ±\psi_\pm; the solid curves and shaded regions are their charge densities ψ±2|\psi_\pm|^2. Note the crucial difference in where each one piles up.

Symbolic shortcut: the matrix element of V in the ψ±\psi_\pm basis is ψ±Vψ±=±VG\langle\psi_\pm|V|\psi_\pm\rangle = \pm V_G for an even-parity V about the origin. Same conclusion, less visual: the two states feel V with opposite sign — a gap of 2|V_G|.

Bloch's Theorem Made Concrete: Bands

From Chapter 3 we know Bloch's theorem: every solution in a periodic potential takes the form ψnk(r)=eikrunk(r)\psi_{n\mathbf{k}}(\mathbf{r}) = e^{i\mathbf{k}\cdot\mathbf{r}}\,u_{n\mathbf{k}}(\mathbf{r}) with unk(r+R)=unk(r)u_{n\mathbf{k}}(\mathbf{r} + \mathbf{R}) = u_{n\mathbf{k}}(\mathbf{r}). The integer nn is the band index; k\mathbf{k} ranges over the first Brillouin zone.

We can now identify the abstract nn with the branches of our folded parabola. The lowest folded parabola is band 1; the next one up is band 2; and so on. Wherever two branches would cross at a zone boundary, V opens a gap 2VG2|V_{\mathbf{G}}|. The result is what every solid-state physicist calls a band structure: a discrete set of curves εn(k)\varepsilon_n(\mathbf{k}) defined on the BZ.

StatementFree electronNearly free electron
Eigenstatesplane waves e^{ikx}Bloch waves e^{ikx} u_{nk}(x)
Spectrumsingle parabola ε(k) = ℏ²k²/2minfinitely many bands ε_n(k), one per branch
Behaviour at zone boundarysmooth crossingsavoided crossings → gaps Δ = 2|V_G|
Density of statesg(ε) ∝ √εkinks and gaps; g(ε) = 0 in the gaps
Filling N electronsFermi sphere of radius (3π² n)^{1/3}fills bands from the bottom up; metal/insulator depending on count

Code Walk-Through: Diagonalising the NFE Hamiltonian

Time to compute. The script below builds the 5-plane-wave NFE Hamiltonian for a 1D chain with V(x)=2V0cos(Gx)V(x) = 2 V_0 \cos(Gx), diagonalises it at three representative k-points, and confirms the analytical prediction Δ=2V0\Delta = 2 V_0 at the zone boundary. Click any line on the right to see what is happening inside that line; every variable, every NumPy call, every eigenvalue is traced.

1D Nearly-Free-Electron Diagonaliser — Interactive Trace
🐍nfe_1d.py
1import numpy as np

NumPy provides the ndarray type, plus np.linalg.eigvalsh() — a fast, numerically stable diagonaliser for Hermitian/real-symmetric matrices. We need it because the nearly-free-electron Hamiltonian, expressed in the plane-wave basis, is exactly such a matrix.

EXECUTION STATE
numpy = Numerical-computing library: ndarray, linear algebra, FFT, random numbers
as np = Standard alias so we can write np.zeros, np.pi, np.linalg.eigvalsh, np.arange, etc.
3Comment: the geometry of our 1D crystal

Reminds us that everything is in atomic units (ℏ = m_e = 1) on a chain of period a. Since a = 1, every length is in units of a and every energy is in units of ℏ²/(2 m_e a²).

4a = 1.0

Real-space lattice constant. We work in atomic units where a = 1 means we are choosing a as our unit of length. Any final answers that have to be quoted in eV or Å are rescaled afterward.

EXECUTION STATE
a = 1.0
→ physical role = Period of the crystal: V(x + a) = V(x). Sets the size of the first Brillouin zone, [-π/a, π/a].
5G = 2 * np.pi / a

Computes the (smallest non-zero) reciprocal-lattice vector. From Chapter 3, b = 2π/a in 1D. With a = 1 this is just 2π ≈ 6.2832.

EXECUTION STATE
📚 np.pi = NumPy's pre-defined constant for π = 3.141592653589793
G = 6.283185
→ physical role = Two plane-waves |k⟩ and |k + G⟩ are coupled by a single Fourier component of V(x). G is the lego brick of momentum that the lattice can give or take.
7Comment: plane-wave basis

Bloch states at wavevector k can be written ψ_k(x) = e^{ikx} u_k(x). Expanding the cell-periodic part u_k as a Fourier series gives ψ_k = Σ_n c_n e^{i(k + n G)x}. The states |k + n G⟩ are the basis we work in.

8N = 5

Number of plane waves we keep. The exact theory needs infinitely many; in practice, including ±2 G suffices for the lowest few bands of a weak potential. Increasing N is exactly what you do in VASP by raising ENCUT.

EXECUTION STATE
N = 5
→ convergence remark = If you increase N to, say, 21, the lowest band at k = 0 changes by less than 10⁻⁴. The basis is converged.
9n_indices = np.arange(-2, 3)

Builds the 1D integer array [-2, -1, 0, 1, 2] enumerating the plane-waves we keep. Each entry n is the index of the plane wave |k + n G⟩.

EXECUTION STATE
📚 np.arange(start, stop) = Returns np.array of evenly spaced values from start (inclusive) to stop (exclusive), step = 1. Like Python range() but yields an ndarray.
⬇ arg 1: start = -2 = First integer index — corresponds to plane-wave |k - 2G⟩.
⬇ arg 2: stop = 3 = Stops BEFORE 3, so the last value included is +2. Result has length stop - start = 5.
⬆ result: n_indices = [-2 -1 0 1 2]
11Comment: the periodic potential

We pick the simplest non-trivial V(x): a single cosine. By Euler's identity, 2 V0 cos(G x) = V0 e^{iGx} + V0 e^{-iGx}, so its only non-zero Fourier components are at ±G with amplitude V0. Every off-diagonal coupling in our matrix will be exactly V0.

13V0 = 0.5

Strength of the periodic potential. Compare to the kinetic energy at the zone boundary, (G/2)² = π² ≈ 9.87: V0 = 0.5 is about 5% — well inside the 'nearly free' regime where perturbation theory is meaningful.

EXECUTION STATE
V0 = 0.5
→ expected gap at k = π = Δ = 2 V0 = 1.0 — and we'll verify this on the last line of the script.
15def hamiltonian(k) → np.ndarray

Builds the (5 × 5) matrix representation of H = T + V in the plane-wave basis at fixed wavevector k. The diagonal is kinetic energy; the off-diagonal is the Fourier component V0 of the potential.

EXECUTION STATE
⬇ input: k (float) = Wavevector, in units of 1/a. We will later evaluate the function at k = 0, π/2, and π.
⬆ returns = np.ndarray of shape (5, 5) — the matrix elements ⟨k + i G | H | k + j G⟩.
16Docstring

Documents that the matrix is in atomic units (ℏ = m_e = 1) so the kinetic operator -ℏ²∇²/(2m) reduces to (k + n G)² on a plane wave |k + n G⟩.

17H = np.zeros((N, N))

Allocates an empty 5×5 matrix to fill. np.zeros((shape)) returns a contiguous float64 array initialised to 0.0.

EXECUTION STATE
📚 np.zeros(shape) = Creates an ndarray of given shape, filled with 0.0. Default dtype is float64.
⬇ arg: (N, N) = (5, 5) = A 2-tuple → 2D matrix with 5 rows and 5 columns. Note the double parentheses: shape is the single argument, but it is itself a tuple.
⬆ result: H =
[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]
18for i in range(N): — kinetic energy on the diagonal

Loops over all 5 basis states. For each i, sets H[i, i] = (k + n_i G)². This is just the free-electron energy of plane-wave |k + n_i G⟩.

LOOP TRACE · 5 iterations
i = 0 (n = -2)
H[0,0] = (k - 2G)² — large positive number, e.g. (0 - 2G)² = 4G² ≈ 157.9 at k = 0
i = 1 (n = -1)
H[1,1] = (k - G)² — at k = 0: G² ≈ 39.48; at k = π: π² ≈ 9.87
i = 2 (n = 0)
H[2,2] = k² — the 'central' free-electron band; at k = 0: 0; at k = π: π² ≈ 9.87
i = 3 (n = +1)
H[3,3] = (k + G)²
i = 4 (n = +2)
H[4,4] = (k + 2G)²
19H[i, i] = (k + n_indices[i] * G) ** 2

The kinetic energy of plane-wave |k + n G⟩ is ℏ²(k + n G)²/(2m). In our atomic units that is just (k + n G)². Each diagonal entry is one such kinetic energy.

EXECUTION STATE
n_indices[i] = the integer label of the i-th plane wave: -2, -1, 0, 1, or 2
→ example at k = 0, i = 2 = (0 + 0 · G)² = 0 → H[2,2] = 0
→ example at k = π, i = 1 = (π - G)² = (-π)² = π² ≈ 9.8696 → H[1,1] = 9.8696
→ example at k = π, i = 2 = (π + 0)² = π² ≈ 9.8696 → H[2,2] = 9.8696 — DEGENERATE with H[1,1]!
20Nested loop: off-diagonal V matrix elements

Loops over all (i, j) pairs and sets H[i, j] = V0 whenever the two plane waves differ by exactly one reciprocal vector — that is, |n_i - n_j| = 1. Those are the only matrix elements connected by the cosine potential.

21for j in range(N):

Inner loop running across columns. We do nothing for j ≠ i±1 because the corresponding Fourier component of V(x) is zero.

22if abs(n_indices[i] - n_indices[j]) == 1:

True only when the two plane waves differ by a single reciprocal vector. This is the selection rule: a cos(Gx) potential can only scatter k ↔ k ± G, never k ↔ k ± 2G.

EXECUTION STATE
→ which pairs match? = (i,j) ∈ {(0,1),(1,0),(1,2),(2,1),(2,3),(3,2),(3,4),(4,3)} — 8 entries forming a tridiagonal pattern.
23H[i, j] = V0

Writes the (single) Fourier component of V into the off-diagonal slot. By symmetry V_{+G} = V_{-G}, so both (i, i+1) and (i+1, i) get the same value V0 — the matrix stays Hermitian (here real-symmetric).

EXECUTION STATE
V0 = 0.5
→ completed H at k = π =
[[ 88.83  0.50   0.    0.    0.  ]
 [  0.50  9.87   0.50  0.    0.  ]
 [  0.    0.50   9.87  0.50  0.  ]
 [  0.    0.    0.50  88.83 0.50]
 [  0.    0.    0.    0.50  246.74]]
24return H

Hands back the assembled Hamiltonian matrix. Caller can now diagonalise it with np.linalg.eigvalsh().

EXECUTION STATE
⬆ return: H (5×5) = Real-symmetric matrix containing kinetic energies on the diagonal and ±V0 just above and below.
26for label, k in [...]:

Outer loop: scans the three most pedagogically important k-points — zone centre (k = 0), generic mid-zone (k = π/2), and zone boundary (k = π). Each tuple holds a printable label and the actual numerical k.

LOOP TRACE · 3 iterations
Iteration 1
label = 'k = 0 '
k = 0.0
Iteration 2
label = 'k = pi/2 '
k = 1.5708 (= π/2)
Iteration 3
label = 'k = pi (BZ)'
k = 3.1416 (= π) — zone boundary
29H = hamiltonian(k)

Calls the function we just defined. Each iteration produces a different 5×5 matrix because the diagonal entries depend on k.

EXECUTION STATE
→ at k = 0 = diagonal = [4G², G², 0, G², 4G²] = [157.91, 39.48, 0, 39.48, 157.91]
→ at k = π/2 = diagonal = [120.90, 22.21, 2.467, 61.69, 199.86]
→ at k = π = diagonal = [88.83, 9.870, 9.870, 88.83, 246.74] — note the degeneracy at indices 1 and 2!
30eigs = np.sort(np.linalg.eigvalsh(H))

Computes the eigenvalues of the real-symmetric matrix H, then sorts them in ascending order. eigvalsh is the right choice here because H is Hermitian (no imaginary parts in 1D, but the function is still optimal for symmetric matrices).

EXECUTION STATE
📚 np.linalg.eigvalsh(M) = Returns the 1D ndarray of eigenvalues of a Hermitian matrix M. Only eigenvalues — no eigenvectors. The 'h' in 'eigvalsh' stands for Hermitian. Faster and more accurate than the general eig() for symmetric problems.
📚 np.sort(arr) = Returns a sorted copy of arr (ascending by default). eigvalsh already returns eigenvalues sorted, but np.sort makes our intent explicit and is cheap.
→ eigenvalues at k = 0 = [-0.0127 39.4763 39.4890 157.9158 157.9158] ↑ lowest band slightly pushed BELOW 0 by repulsion from the |±G⟩ states
→ eigenvalues at k = π/2 = [ 2.4505 22.2167 61.6874 120.9052 199.8613]
→ eigenvalues at k = π = [ 9.3665 10.3664 88.8280 88.8296 246.7417] ↑ Δ = 10.3664 - 9.3665 = 0.9999 ≈ 2 V0 ✓
31print(f"{label}: 3 lowest bands = {eigs[:3].round(4)}")

Formats and prints the lowest three eigenvalues at this k-point. eigs[:3] slices the first 3 entries; .round(4) rounds to 4 decimal places; the f-string interpolates the label.

EXECUTION STATE
→ output for k = 0 = k = 0 : 3 lowest bands = [-0.0127 39.4763 39.4890]
→ output for k = π/2 = k = pi/2 : 3 lowest bands = [ 2.4505 22.2167 61.6874]
→ output for k = π = k = pi (BZ): 3 lowest bands = [ 9.3665 10.3664 88.8280]
33Comment: the gap at k = π should be 2 V0

The two-plane-wave approximation predicts ε± = (G/2)² ± V0 at the zone boundary. Our 5-plane-wave result must reproduce this to high accuracy because the two states |k - G⟩ and |k⟩ are isolated from the rest by huge kinetic-energy gaps.

34Final print: explicit gap measurement

Calls hamiltonian(π) twice (a small inefficiency, kept for clarity), grabs the lowest two eigenvalues, and prints their difference. The output should be 1.0 — exactly 2 V0 — confirming the analytic two-plane-wave result.

EXECUTION STATE
eigvalsh(H)[1] = Second-lowest eigenvalue at k = π → 10.3664
eigvalsh(H)[0] = Lowest eigenvalue at k = π → 9.3665
⬆ printed: Gap at k = pi = 0.9999 ≈ 1.0000 = 2 × V0 ✓
10 lines without explanation
1import numpy as np
2
3# 1D crystal: lattice constant a = 1, so reciprocal vector G = 2*pi/a
4a = 1.0
5G = 2 * np.pi / a
6
7# Plane-wave basis indices: |k + n*G> for n = -2, -1, 0, +1, +2  (5 plane waves)
8N = 5
9n_indices = np.arange(-2, 3)
10
11# Periodic potential V(x) = 2 * V0 * cos(G*x)
12# Fourier components: V_{+G} = V_{-G} = V0, all others = 0
13V0 = 0.5
14
15def hamiltonian(k):
16    """Build the 5x5 plane-wave Hamiltonian at wavevector k (atomic units)."""
17    H = np.zeros((N, N))
18    for i in range(N):
19        H[i, i] = (k + n_indices[i] * G) ** 2
20    for i in range(N):
21        for j in range(N):
22            if abs(n_indices[i] - n_indices[j]) == 1:
23                H[i, j] = V0
24    return H
25
26# Diagonalise at three representative k-points: zone centre, mid-zone, boundary
27for label, k in [("k = 0      ", 0.0),
28                 ("k = pi/2   ", np.pi / 2),
29                 ("k = pi (BZ)", np.pi)]:
30    H = hamiltonian(k)
31    eigs = np.sort(np.linalg.eigvalsh(H))
32    print(f"{label}: 3 lowest bands = {eigs[:3].round(4)}")
33
34# At k = pi the lowest two bands should be split by exactly 2*V0 = 1.0
35print(f"Gap at k = pi : {np.linalg.eigvalsh(hamiltonian(np.pi))[1] - np.linalg.eigvalsh(hamiltonian(np.pi))[0]:.4f}")

Run the script and you will see the following output:

📝text
1k = 0      : 3 lowest bands = [-0.0127 39.4763 39.4890]
2k = pi/2   : 3 lowest bands = [ 2.4505 22.2167 61.6874]
3k = pi (BZ): 3 lowest bands = [ 9.3665 10.3664 88.828 ]
4Gap at k = pi : 0.9999

That last line is the headline result. The lowest band closes in on the second band at k=πk = \pi and a gap of Δ=0.99992V0\Delta = 0.9999 \approx 2 V_0 opens between them — precisely the analytical prediction.

Try increasing N to 21 or doubling V0 and rerun. The qualitative picture is unchanged; the gap remains 2 V0 to four decimal places, and you can read off the whole band structure by sweeping k between 0 and π in a loop.

Filling the Bands: Metals, Semiconductors, Insulators

The free electron gas was always a metal — the spectrum had no gaps. With bands and gaps, three qualitatively different outcomes become possible depending on how many electrons we put in.

ClassHighest occupied bandFermi level εF sits in...Conducts?Examples
Metalpartially filledthe band itselfyes — empty states immediately above εFNa, Cu, Al
Semiconductorfully filled (valence band)in the gap, narrow gap (≲ 3 eV)weakly — thermal excitation across gapSi, Ge, GaAs, CdSe
Insulatorfully filled (valence band)in the gap, wide gap (> 3 eV)no — gap too large to bridge thermallydiamond (5.5 eV), MgO (7.8 eV)

The simplest counting argument: each band holds 2 electrons per unit cell (one for each spin). If the total electron count per cell is even and the bands aren't overlapping, the material is an insulator. If odd, or if bands overlap even when the count is even, you get a metal.

Why is sodium a metal? Each Na atom contributes one valence electron. With one band per cell holding two electrons, sodium fills its first band halfway — the Fermi level sits in the middle of a band. Empty states are immediately above: a metal.
Why is CdSe a semiconductor? Cd contributes 12 valence electrons (4d¹⁰ 5s²) and Se contributes 6 (4s² 4p⁴), giving 18 per primitive cell. The 9 lowest bands are filled, the next 9 are empty, and a 1.74 eV gap separates them. CdSe is therefore a semiconductor — and the Mn-doped quantum-dot project of Chapter 6 lives entirely in this gap.

Interactive 3D: When the Fermi Sphere Meets the BZ

With bands and gaps in mind, return to the picture from Section 4.1. For a small electron density the Fermi sphere fits comfortably inside the first BZ — the free-electron model is essentially exact. As you raise kFk_F the sphere approaches the BZ faces; once it touches them, the sphere is forced to deform around the gap, and parts of the next band start to fill (these become the “necks” of copper or the “holes” in the second zone of aluminium).

Drag the sphere with the slider and watch the colour change at the critical radii.

Loading 3D Brillouin-zone scene…

VASP Connection: Plane-Wave Basis and Band Diagrams

VASP is a plane-wave DFT code, which means our toy Hamiltonian from this section is essentially the same data structure VASP works with, scaled up to thousands of plane waves and a self-consistent potential. Three keywords map directly onto the story of this section.

1. ENCUT — how many plane waves you keep

We chose 5 plane waves; VASP chooses thousands. The basis is defined by a kinetic-energy cutoff:

2k+G22meEcut\frac{\hbar^2 |\mathbf{k} + \mathbf{G}|^2}{2 m_e} \leq E_{\text{cut}}

Larger ENCUT = more plane waves = larger Hamiltonian matrix at each k-point, and a more accurate result. The same cutoff that bounds the basis size also bounds how many bands VASP can produce: tail bands above the cutoff are simply absent from the calculation.

📄ini
1# INCAR — plane-wave cutoff
2ENCUT = 400        # eV — size of the plane-wave basis
3PREC  = Accurate   # tightens default cutoffs and grids

2. KPOINTS — sampling along the band path

To plot a band structure, VASP needs to evaluate εn(k)\varepsilon_n(\mathbf{k}) at a curve of k-points connecting the high-symmetry points of the BZ (Section 3.4). The KPOINTS file in line-mode does exactly that:

📝text
1KPATH for an FCC zone:  Γ → X → W → L → Γ → K
240                          ! intermediate k-points per segment
3Line-mode
4Reciprocal
50.0  0.0  0.0  Gamma
60.5  0.0  0.5  X
7
80.5  0.0  0.5  X
90.5  0.25 0.75 W
10
11...

3. NBANDS, OUTCAR — reading the result

VASP reports band energies in the EIGENVAL file and the band gap (when applicable) in OUTCAR. The data we manually computed for our toy NFE Hamiltonian is exactly the kind of array VASP prints, with one row per band and one column per k-point.

bash
1# Pull the band gap directly from OUTCAR (semiconductors / insulators only)
2grep -A 1 "BandGap" OUTCAR
3
4# Or compute it: max(VBM) − min(CBM)
5awk '/^[ ]+[0-9]/{ if ($3 < 0) vbm = ($2 > vbm ? $2 : vbm);
6                   else        cbm = ($2 < cbm || cbm == 0 ? $2 : cbm) }
7     END{ print "Gap =", cbm - vbm, "eV" }' EIGENVAL
For our Mn:CdSe project (Chapter 6) the band gap of bulk CdSe printed by VASP/PBE will be ~0.7 eV — a notorious DFT underestimate of the experimental 1.74 eV. Section 5.10 will fix this with hybrid functionals or a GW calculation. The gap is real; the functional is approximate.

4. Reading the band structure as folded parabolas

When you plot a real DFT band structure for a simple metal like aluminium, the lowest band along Γ → X is essentially the free-electron parabola, gently warped. The deviation grows toward the zone boundary, where the gap opens just as in our 2×2 analysis. Recognising free-electron echoes inside a complicated band diagram is the single most useful diagnostic skill in electronic structure.


Summary

  1. A periodic potential V(r)V(\mathbf{r}) can only scatter k\mathbf{k} into k+G\mathbf{k} + \mathbf{G} for some reciprocal vector. All non-trivial physics of the NFE model flows from this single selection rule.
  2. The free-electron parabola, plotted in the reduced-zone scheme, becomes infinitely many bands. Crossings happen at Brillouin-zone boundaries.
  3. Two-plane-wave perturbation theory at a zone boundary gives an avoided crossing of size Δ=2VG\Delta = 2|V_{\mathbf{G}}|. The standing-wave eigenstates pile their charge on, or between, the ions — the electrostatic energy difference is the band gap.
  4. Band filling determines whether a material is a metal (partly filled top band), semiconductor (fully filled, narrow gap), or insulator (fully filled, wide gap).
  5. As kFk_F grows, the Fermi sphere bumps into the BZ surface, deforms, and partially fills higher bands — the geometry that shapes copper's necks and aluminium's holes.
  6. In VASP, ENCUT controls the plane-wave basis, KPOINTS traces the band path, and EIGENVAL/OUTCAR give you εn(k)\varepsilon_n(\mathbf{k}) directly.

Next section we drop the plane-wave assumption entirely and take the opposite limit: the tight-binding model, in which electrons live on atomic orbitals and only occasionally hop between neighbours. Most insulators, transition-metal oxides, and molecular crystals are best described that way — including the Mn d-shell that drives the magnetism of our Mn:CdSe quantum dot.

Loading comments...