4.4
Solving the Schrödinger equation numerically
Swap the continuous x axis for a row of grid points and the Schrödinger equation becomes a tridiagonal matrix eigenvalue problem — ten lines of code solve the bound states of any potential.
Recommended first
After this section you should be able to
- Derive the three-point difference formula for the second derivative from Taylor expansions, and state the order of the error
- Write the Hamiltonian as a tridiagonal matrix and account for where every matrix element comes from
- Solve the harmonic oscillator with a stock eigenvalue routine and compare against the exact solution
- Run grid-convergence checks, identifying the two independent error sources: grid spacing and box size
Last section ended by saying it plainly: real potentials are smooth, and a staircase of piecewise-constant slabs is no long-term plan. And looking back at chapter 2, the potentials we can solve exactly can be counted on one hand — infinite well, finite well, harmonic oscillator, square barrier — each cracked by its own bespoke trick (a standing-wave condition, a transcendental equation, ladder operators). Change the potential even slightly — two wells of unequal depth, say, or a tilted floor from an applied field — and every trick fails at once.
But chapter 3 wrote down the way out long ago, even if it sounded like philosophy at the time: wavefunctions are components of a vector, operators are matrices (section 3.1, section 3.4). The “matrices” there were infinite-dimensional and would not fit in a computer. This section does something impolite: it chops the infinite dimensions down to finite — the axis becomes a row of grid points, becomes a column of numbers, and genuinely becomes a matrix you can print out and look at. Energy levels? The matrix’s eigenvalues. Wavefunctions? Its eigenvectors. The rest goes to the linear algebra library.
Step one: turn the function into an array
Choose an interval large enough that the bound-state wavefunctions have long since decayed to nothing at the endpoints, and scatter equally spaced grid points across it:
The wavefunction is demoted from a continuous curve to a column of samples . The potential likewise becomes a column of numbers — and this is why no potential is special any more: however exotic the potential, it is just a different column of numbers in an array.
The kinetic term of the stationary Schrödinger equation contains . Here comes the trouble: with only a row of discrete points left, what do we do about derivatives?
Step two: compute the second derivative from the neighbours
Derivation: the three-point difference formula and its errorbasic~7 min
The idea: the second derivative at a point measures how much the curve bends there, and bending can be probed by asking “how much higher is the average of the two neighbours than the point itself”. The tool for turning that sentence into a formula is the Taylor expansion.
Step 1: expand to both sides. Assuming is smooth enough, expand about to fourth order:
Step 2: add. When the two expansions are added, every odd-order term (, ) comes with opposite signs and cancels in pairs — which is the entire motivation for taking neighbours placed symmetrically left and right:
Step 3: solve for . Rearrange and divide by :
Dropping the correction term gives the three-point difference formula:
The error is : the leading error term shrinks with the square of the grid spacing. Halve and the error drops to a quarter — this “halve and check for four” fingerprint is one we will verify with our own eyes in the numerical experiment shortly.
Read the formula’s face: the numerator is exactly “sum of the two neighbours minus twice the point itself”, i.e. twice the gap between the neighbours’ average and the point — dovetailing perfectly with the opening intuition. Where is locally a straight line the numerator vanishes: straight lines do not bend, the second derivative is zero, correct.
Step three: the Hamiltonian shows its matrix form
Insert the difference formula into the stationary equation ; at grid point :
The left side is a linear operation on the column vector — which is to say a matrix multiplication, , with
A tridiagonal matrix: the diagonal holds “kinetic baseline + local potential”, the entries hugging the diagonal hold the coupling between neighbouring grid points, and everything else is zero — because the three-point formula only talks to its immediate neighbours.
Two details to settle properly:
- Boundary conditions: the equation at involves , and at involves — the values at the interval’s endpoints. We simply set , which amounts to locking the system into an infinite box of width . As long as is big enough that the bound states have decayed exponentially to zero well before the walls, the two fake walls are harmless (how big is “big enough” — see the warning below).
- The matrix is real and symmetric — the discrete incarnation of chapter 3’s Hermitian operator. The theorem of section 3.5 is honoured verbatim: all eigenvalues real, all eigenvectors mutually orthogonal. Theory’s guarantee and numerics’ verification settle their accounts on the spot, in the code below.
The picture
Look back at section 3.1 — that sentence is now literal fact. ” is the components of a state vector in the position basis” — now the components really are numbers sitting in an array. ” is an operator” — now it is an real symmetric matrix. “Solve the stationary equation” — now it is one call to an eigenvalue decomposition.
Abstract language first, concrete computation catching up later: that order of events replays again and again in physics.
The mathematics
The in the inner product is the relic of the integration measure — do not lose it when normalising.
Step four: run it
Practise on the harmonic oscillator (in dimensionless units , the levels should be ). Tridiagonal matrices have a dedicated fast routine, eigh_tridiagonal, so there is no need to store zeros:
import numpy as np
from scipy.linalg import eigh_tridiagonal
def solve(V, L, N):
"""Solve -psi''/2 + V(x) psi = E psi on [-L/2, L/2] with N interior grid points."""
x = np.linspace(-L/2, L/2, N + 2)[1:-1] # drop the two boundary points
h = x[1] - x[0]
diag = 1.0 / h**2 + V(x) # diagonal: kinetic baseline + potential
off = -0.5 / h**2 * np.ones(N - 1) # off-diagonal: neighbour coupling
E, psi = eigh_tridiagonal(diag, off, select='i', select_range=(0, 5))
return x, E, psi / np.sqrt(h) # divide by √h so that Σ|ψ|²h = 1
x, E, psi = solve(lambda x: 0.5 * x**2, L=16, N=1000)
print(E) # [0.499992 1.499960 2.499896 3.499800 4.499673 5.499513]
All six levels deviate from the exact values only in the fourth or fifth decimal place. And verify chapter 3’s promise while we are here: psi[:,0] @ psi[:,1] * h prints — distinct eigenstates strictly orthogonal, to machine precision.
Step five: doubt your results
The most important discipline in numerical work: a result must prove that it has converged. The numbers above carry two independent error sources, each with its own check.
Error one: finite grid spacing . Refine the grid and watch what moves:
| 50 | 100 | 200 | 400 | 800 | |
|---|---|---|---|---|---|
| error in |
Each doubling of (halving of ) shrinks the error almost exactly to — the fingerprint the derivation predicted, plain as day. The practical version of this discipline: double , recompute, and only quote the digits that did not move.
Error two: finite box . Fake walls placed too close pinch the wavefunction. The check is the same in spirit: enlarge , recompute, and trust the result only if it stays put.
Key formulas
Three-point difference
Odd-order terms cancel by symmetry; halving h cuts the error to 1/4
Discrete Hamiltonian
Real symmetric tridiagonal matrix; real eigenvalues, orthogonal eigenvectors
Exact discrete well spectrum
The difference method computes levels low; the error grows as j² for higher levels
Discrete inner product
Normalisation and orthogonality checks must carry the measure h
Self-check4 questions
- 1.
In deriving the three-point difference formula, the purpose of adding the expansions of ψ(x+h) and ψ(x−h) is:
- 2.
The discrete Hamiltonian matrix is real and symmetric. Which of chapter 3's promises does this cash in numerically? (Select all that apply.)
Select all that apply
- 3.
With N = 400 the ground-state energy error is 5.0×10⁻⁵. Everything else unchanged, raising N to 800 makes the error roughly:
- 4.
An infinite well of width L is solved by finite differences with grid spacing h = L/10. Using the exact discrete spectrum E₁⁽ʰ⁾/E₁ ≈ 1 − (πh/L)²/12, estimate the relative error of the ground-state energy, as a percentage.
%10% relative tolerance
What comes next
The method is in place and the code exists, but every change of potential still means fiddling afresh with the grid, the units, and the checks — like cooking every meal starting from lighting the fire. The next section packages all of it into a general-purpose solver: feed it any potential curve and it returns levels and wavefunctions, quality checklist included. Then we use it to do something analytic methods cannot — solve the double well — and watch a pair of levels squeeze to within a percent of each other, reading off tunneling, the ammonia maser, and the embryo of the chemical bond.
Section 34 of 106 · use ← → to turn the page