Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

1D Schrödinger Equation: Finite Difference Method

Hello! Welcome to the first lesson of our new module on numerical methods in quantum mechanics.

In our previous module, we explored fascinating collective phenomena like the Fractional Quantum Hall Effect, where the breakdown of analytical methods for strongly-correlated systems necessitated brilliant intuitive leaps like the Laughlin wavefunction. This highlights a crucial theme in modern physics: many, if not most, interesting problems cannot be solved with pen and paper alone. This is where computational physics becomes an indispensable tool.

Your background in writing simulations makes this module a natural fit. We will begin building a practical toolkit for solving quantum problems numerically. Our goal for today is to:

  • Implement a finite difference method to find the bound-state energies of the 1D time-independent Schrödinger equation.

We will transform the familiar differential equation into a matrix problem that a computer can solve, allowing us to find the quantum states for virtually any one-dimensional potential you can imagine.

1. The Schrödinger Equation as a Matrix Problem

The time-independent Schrödinger equation (TISE) is the cornerstone for finding stationary states:

where the Hamiltonian for a particle in one dimension is:

For potentials like the infinite square well or the harmonic oscillator, we can solve this differential equation analytically. But what about a more complex potential, like an electron in a disordered lattice or the double-well potential we'll see later? The analytical path is often blocked.

The core idea of the finite difference method is to discretize the problem. Instead of trying to find the continuous function , we will find its value at a series of discrete points separated by a small step . We represent our wavefunction as a vector:

To discretize the TISE, we need to approximate the second derivative. We can do this using the central difference formula:

Finite Difference Approximation for Quantum Mechanics
This diagram illustrates how the second derivative of the wavefunction at a point \(i\), \(\psi_i''\), can be approximated using the values at its neighboring points, \(\psi_{i-1}\) and \(\psi_{i+1}\). The distance between points is the grid spacing, \(\Delta x\).

The formula for the second derivative at point is:

By substituting this into the TISE for each point , we convert the single differential equation into a system of coupled algebraic equations:

Rearranging this gives:

This equation has a very specific structure: the value is related only to its nearest neighbors, and . When we write the entire system of equations for all , it takes the form of a matrix eigenvalue equation:

Here, is the vector of wavefunction values, and is the Hamiltonian, now represented as a matrix.

2. Constructing the Hamiltonian Matrix

The equation above defines the elements of our Hamiltonian matrix .

  • Diagonal elements (): These correspond to the terms multiplying .
  • Off-diagonal elements (): These correspond to the terms multiplying the neighbors and .
  • All other elements are zero.

This structure results in a tridiagonal matrix, which is a sparse matrix with non-zero elements only on the main diagonal, the super-diagonal (above the main one), and the sub-diagonal (below the main one).

For bound-state problems, we solve the equation on a finite grid and assume the wavefunction vanishes at the boundaries: . This "Dirichlet boundary condition" is naturally incorporated into our matrix equation if we construct the matrix for the interior points only.

The problem is now perfectly set up for a numerical solution: construct the matrix and find its eigenvalues and eigenvectors. The eigenvalues will give us the quantized energy levels , and the corresponding eigenvectors will give us the shape of the wavefunctions .

3. Python Implementation

Let's see this in action. The following video provides an excellent walkthrough of the entire process, from the initial equation to a Python implementation that can handle any potential.

Eigenstates of ANY 1D Potential in PYTHON

This video by Mr. P Solver demonstrates how to translate the theory we just discussed into a working Python script. It covers the discretization, the matrix formulation, and the use of SciPy's efficient solvers.

Please watch the following segments: Discretization & Dimensionless Form (03:20 - 06:23): This covers the finite difference approximation, similar to our discussion. The video also introduces the useful practice of making the equation dimensionless, which simplifies the constants involved. The Matrix Eigenvalue Problem (06:23 - 09:45): This part visualizes how the system of equations becomes a tridiagonal matrix eigenvalue problem. Python Code: Setup and Matrix Construction (09:45 - 014:59): Follow how the spatial grid, potential, and the diagonals of the Hamiltonian matrix are defined in NumPy. Python Code: Solving and Plotting (14:59 - 17:28): See how scipy.linalg.eigh_tridiagonal is used to find the energies and wavefunctions, and how to plot the results.

The video brilliantly demonstrates the power of this method. Once the framework is built, swapping out the harmonic oscillator for a more complex potential—like the one with a Gaussian bump—is trivial and yields fascinating physical results that would be very difficult to obtain analytically.

The key steps of the implementation are:

  1. Define Constants and Grid: Set up physical constants () and the spatial grid using np.linspace. Calculate the grid spacing .
  2. Define Potential: Create a Python function V(x) that returns the potential energy at any point x. This makes the code general.
  3. Construct Matrix Diagonals: Create two NumPy arrays: one for the main diagonal (d) and one for the off-diagonals (e).
    • d_i = \hbar^2 / (m * dx^2) + V(x_i)
    • e_i = -\hbar^2 / (2 * m * dx^2)
  4. Solve the Eigenvalue Problem: Use a numerical library to find the eigenvalues and eigenvectors. scipy.linalg.eigh_tridiagonal(d, e) is highly optimized for this specific type of matrix.
  5. Analyze Results: The returned eigenvalues are the bound-state energies. The eigenvectors are the discretized wavefunctions, which can be plotted. Remember to normalize them!

4. Alternative Approaches and Advanced Considerations

While the method in the video is excellent, it's useful to see other ways to construct and solve the matrix problem, especially as you might encounter them in different contexts.

Quantum Mechanics with Python

This blog post, 'Quantum Mechanics with Python', provides a nice textual summary of the method and introduces an important concept for large-scale computations: sparse matrices.

Please read the sections "Discretizing the 1D Schrödinger Equation" and "Solving the Eigenvalue Problem Numerically". Focus on how the Hamiltonian is constructed and the motivation for using sparse matrix libraries.

As the article mentions, when your grid size N becomes very large (e.g., in 2D or 3D problems, or for very high precision), storing the full Hamiltonian matrix in memory becomes inefficient or impossible. Since our matrix is mostly zeros, we can use sparse matrix formats that only store the non-zero elements. Libraries like scipy.sparse are designed for this. The function scipy.sparse.linalg.eigs is a sparse matrix eigenvalue solver, which is essential for more advanced computational work, including the exact diagonalization you'll encounter later.

For another perspective on building the matrix, the "Dot Physics" video (LINK) shows how to construct the full matrix using np.diag, which can be more explicit if you want to visualize the matrix structure itself before optimizing with a tridiagonal or sparse solver.

Test your understanding! Apply your knowledge.

Now it's your turn to get your hands dirty. Your task is to implement the finite difference solver yourself. You can use the code from the "Mr. P Solver" video as a starting point.

Problem: Solve the TISE for a double-well potential, given by:

This potential has two minima at , separated by a barrier of height .

Instructions:

  1. Write a Python script to find and plot the first 4-5 energy eigenvalues and their corresponding wavefunctions ().
  2. Choose sensible parameters. For example, you could work in atomic units () and try and . You'll need to choose a grid that is large enough to contain the wavefunctions (e.g., from to ).
  3. Observe the first two eigenstates (the ground state and the first excited state). What do you notice about their shapes and their energies?
  4. Experiment by changing the barrier height . How does the energy difference between the first two states change as you increase or decrease ? What does this imply about quantum tunneling?
Show hints on what to expect

You should find that the ground state is an even function (symmetric) with probability density peaked in both wells. The first excited state should be an odd function (antisymmetric) with a node at .

These two states will be very close in energy, forming a "doublet". This is because they correspond to the symmetric and antisymmetric combinations of a particle being in the left well or the right well. As you increase the barrier height , the tunneling between the wells becomes less likely. This should cause the energy splitting to decrease dramatically, as the two states become nearly degenerate.

Conclusion

In this lesson, we have built a powerful and general tool. By discretizing space and approximating the kinetic energy operator, we transformed the time-independent Schrödinger equation from a challenging differential equation into a standard matrix eigenvalue problem.

Key Takeaways:

  • The finite difference method approximates derivatives on a discrete grid, turning differential equations into algebraic ones.
  • The 1D TISE becomes a matrix eigenvalue problem .
  • For a 1D problem with nearest-neighbor interactions, the Hamiltonian matrix is tridiagonal.
  • Numerical libraries like NumPy and SciPy provide efficient functions (eigh_tridiagonal, eigs) to solve this problem for the energy eigenvalues and wavefunction eigenvectors.
  • This method is versatile and can be applied to almost any arbitrary potential .

Preview of the Next Lesson:

We've successfully tackled the time-independent Schrödinger equation. The natural next step is to consider dynamics. In our next lesson, you will implement the Crank-Nicolson method to simulate wavepacket evolution for the 1D time-dependent Schrödinger equation. This will allow us to watch quantum systems evolve in time.

Can't find a good explanation? Sign up and we'll make it for you

Sign up