This post provides a practical guide for creating a Monte Carlo program to simulate the square lattice Ising model. The example program is written in JavaScript and is intentionally kept simple. However, for these types of simulations, you might prefer to use programming languages such as C++, Rust, C, or Fortran.
You can find the code used for this simulation at this link.
Let’s start with some important concepts you may find useful before reading this post.
The Ising model is a simple and important idea in statistical physics, first created to explain how ferromagnets work. In a ferromagnet, each atom acts like a small “spin” that can point either up or down. These spins want to be next to other spins pointing the same way because of a quantum effect called the exchange interaction. When the temperature is very low, all the spins align in the same direction to reach the lowest possible energy. However, as the temperature increases, the atoms “move” more because of the heat energy. This thermal “motion” breaks their alignment, so the spins start to flip and become less ordered.
We need a way to measure how “ordered” the spins are. For this, we use a property called magnetization. At low temperatures, magnetization is high. At high temperatures, magnetization is low. There is a temperature where magnetization changes drastically. This is the critical temperature. The critical temperature (Curie temperature for ferromagnets) is the temperature at which a material loses ferromagnetic order and becomes paramagnetic.
Having said that, let’s describe the Ising model. The Ising model is a simple lattice model of magnetism where each site carries a spin (up or down), representing a tiny magnetic moment. Neighboring spins interact with energy , where is the exchange constant. If , aligned neighbors (both +1 or both −1) are energetically favored, mimicking ferromagnetism.
It is worth mentioning that the Ising model can be applied in 1D, 2D, and 3D. For the sake of simplicity, we will focus on the 2D model, but the same principles apply to the 1D and 3D cases.
In 2D, each site at position on the square lattice has exactly four neighboring sites: (below), (above), (to the right), and (to the left). If one of these neighboring indices would fall outside the lattice, we use periodic boundary conditions: the lattice “wraps around” so that an edge site is neighbors with the site on the opposite edge. For example, in a lattice of size (where indices go from to ), the site at has as its neighbor below, and similarly, the top and bottom rows are neighbors due to this wrapping. This creates a lattice surface shaped like a torus, where every site always has four neighbors, regardless of its position.
The local energy at a site (assuming all neighbor interactions have the same ) is calculated as follows:
For simplicity, let’s refer to the site as site . Please do not be confused by this. It is still a 2D lattice.
where means the sum over the nearest neighbors.
The total energy is given by:
Note that we divide by 2 because each interaction is counted twice: if site is a neighbor of site , then site is also a neighbor of site .
The magnetization can be calculated as:
You’ve read quite a bit so far (I hope!). Let’s look at some diagrams to make these concepts clearer. In the plot below, you can see a
From now on, indices increase to the right and downward, and decrease to the left and upward. Specifically, index increases downward (and decreases upward), and index increases to the right (and decreases to the left).
Let’s focus on the site at position (top-left corner). The site at position has a spin of value
- (below)
- (right)
- (above, wraps around)
- (left, wraps around)
as shown here:
The spins at these neighbor sites are:
- :
- :
- :
- :
The local energy at site is
Metropolis algorithm
In a small lattice of sites, there are a total of possible configurations, which is approximately . Even if you had a very fast computer that could process configurations per second, it would still take seconds (about 1000 times the age of the universe) to analyze all possible states. Don’t worry about it! We have learned to solve this problem by performing importance sampling using the Metropolis algorithm.
We use the Metropolis algorithm to simulate the thermal fluctuations of the 2D Ising model at a given temperature . The algorithm proceeds as follows:
-
Choose a random site in the lattice.
-
Flip the spin at site (), and calculate the change in energy that this flip would cause. You may compute only the local energy at site .
-
Decide whether to accept the flip:
- If (the energy decreases), always accept the flip.
- If , accept the flip with probability , where is the Boltzmann constant (here set to 1 for simplicity).
-
Repeat steps 1–3 times (one “Monte Carlo step”), where is the number of sites in the lattice.
-
Repeat step 4 (perform many Monte Carlo steps) until the system reaches equilibrium.
Below you can interact with a simulation at constant temperature. You can advance the simulation step by step, or press play to watch how the lattice evolves over time.
Temperature annealing
Now let’s see what happens when we vary the temperature. In the process called “annealing,” we slowly decrease the temperature and observe how the system evolves. This helps us understand how the magnetization and energy change as the system moves from a disordered (high-temperature) state to an ordered (low-temperature) state.
Two important physical quantities measured in Monte Carlo simulations of the Ising model are the magnetic susceptibility and the specific heat.
The magnetic susceptibility, usually denoted , quantifies how strongly the magnetization of the system responds to an applied external magnetic field (even though we simulate at in our model, can be computed from equilibrium fluctuations via statistical mechanics). In practical simulations, it is computed via fluctuations of the magnetization:
where is the temperature, and angle brackets denote averaging over the simulation.
The specific heat describes how much the energy of the system fluctuates as we change the temperature:
where is the total energy of the system. Again, this is obtained from the variance of the energy measured during simulation.
Both quantities are examples of response functions: susceptibility measures the response of the magnetization to a field, while specific heat measures the response of energy to temperature. As you change the temperature, you will observe that both and typically exhibit sharp peaks near the critical temperature , indicating a phase transition from a disordered to an ordered phase.
Finally, we have a simulation that explores a range of temperatures. You can use the controls to observe how the magnetization approaches (the total number of sites) at low temperature, and trends toward at high temperature. Note that we work in units where , so the dimensionless coupling is . You can also choose to simulate antiferromagnetic behavior, but we will discuss this case later.
Note that the peaks happened around 2.26, which was demonstrated to be the theoretical critical temperature:
You can find the code used for this simulation at this link.