Skip to content

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 xx axis becomes a row of grid points, ψ(x)\psi(x) becomes a column of numbers, and H^\hat H 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 [L/2,L/2][-L/2,\,L/2] large enough that the bound-state wavefunctions have long since decayed to nothing at the endpoints, and scatter NN equally spaced grid points across it:

xn=L2+nh,h=LN+1,n=1,2,,N(4.4.1)x_n=-\frac{L}{2}+nh,\qquad h=\frac{L}{N+1},\qquad n=1,2,\dots,N\tag{4.4.1}

The wavefunction is demoted from a continuous curve to a column of samples ψnψ(xn)\psi_n\equiv\psi(x_n). The potential likewise becomes a column of numbers VnV(xn)V_n\equiv V(x_n)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 ψ\psi''. 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

Step three: the Hamiltonian shows its matrix form

Insert the difference formula into the stationary equation 22mψ+Vψ=Eψ-\frac{\hbar^2}{2m}\psi''+V\psi=E\psi; at grid point nn:

22mh2ψn+1+(2mh2+Vn)ψn22mh2ψn1=Eψn(4.4.6)-\frac{\hbar^2}{2mh^2}\psi_{n+1}+\left(\frac{\hbar^2}{mh^2}+V_n\right)\psi_n-\frac{\hbar^2}{2mh^2}\psi_{n-1}=E\,\psi_n\tag{4.4.6}

The left side is a linear operation on the column vector (ψ1,,ψN)(\psi_1,\dots,\psi_N) — which is to say a matrix multiplication, Hψ=EψH\boldsymbol\psi=E\boldsymbol\psi, with

H=(2mh2+V122mh222mh22mh2+V222mh2)(4.4.7)H=\begin{pmatrix} \frac{\hbar^2}{mh^2}+V_1&-\frac{\hbar^2}{2mh^2}&&\\[2pt] -\frac{\hbar^2}{2mh^2}&\frac{\hbar^2}{mh^2}+V_2&-\frac{\hbar^2}{2mh^2}&\\[2pt] &\ddots&\ddots&\ddots \end{pmatrix}\tag{4.4.7}

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 n=1n=1 involves ψ0\psi_0, and at n=Nn=N involves ψN+1\psi_{N+1} — the values at the interval’s endpoints. We simply set ψ0=ψN+1=0\psi_0=\psi_{N+1}=0, which amounts to locking the system into an infinite box of width LL. As long as LL 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.

Step four: run it

Practise on the harmonic oscillator (in dimensionless units =m=ω=1\hbar=m=\omega=1, the levels should be n+12n+\frac12). Tridiagonal matrices have a dedicated fast routine, eigh_tridiagonal, so there is no need to store N2N^2 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 0.5,1.5,,5.50.5,1.5,\dots,5.5 only in the fourth or fifth decimal place. And verify chapter 3’s promise while we are here: psi[:,0] @ psi[:,1] * h prints 0.00.0 — 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 hh. Refine the grid and watch what moves:

NN50100200400800
error in E0E_03.1×1033.1\times10^{-3}7.9×1047.9\times10^{-4}2.0×1042.0\times10^{-4}5.0×1055.0\times10^{-5}1.2×1051.2\times10^{-5}

Each doubling of NN (halving of hh) shrinks the error almost exactly to 1/41/4 — the O(h2)O(h^2) fingerprint the derivation predicted, plain as day. The practical version of this discipline: double NN, recompute, and only quote the digits that did not move.

Error two: finite box LL. Fake walls placed too close pinch the wavefunction. The check is the same in spirit: enlarge LL, recompute, and trust the result only if it stays put.

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