PHY 411-506 Home Home  |  Course Outline  |  Lectures  |  Homework  |  Files

Lecture 23: March 19


Ising phase transition and finite size scaling

The most interesting feature of the 2-D Ising model is the phase transition between ferromagnetic and paramagnetic behavior. In the infinite volume or thermodynamic limit, various observables exhibit singular behavior near the critical temperature Tc. Because it is not possible for singularities (infinities) to occur in a finite system being simulated on a computer, it is necessary to use the theory of finite size scaling to infer singular behavior in the infinite volume limit.

The following applet, which is generated by the program FiniteSizeScaling.java, generates data for the susceptibility that is similar to the heat capacity data given in Figure 17.2 on page 587 in the textbook.

Here is the code which generates this applet:

// FiniteSizeScaling.java

import comphys.graphics.*;
import comphys.Easy;

public class FiniteSizeScaling extends Animation {

    // 2-D Ising Model simulation using the Metropolis algorithm
    // finite size scaling data for the isothermal susceptibility

    int L;                      // linear size of lattice
    int N;                      // number of spins
    int[][] spin;               // spin values
    double T;                   // absolute temperature
    double H;                   // magnetic field
    double[][] w;               // Boltzmann factors

    int mcs;                    // Monte Carlo step number
    int nequil = 1000;          // thermalization steps
    int ndata = 2000;           // number of data steps

    int M;                      // magnetization
    int SS;                     // sum s_i s_j
    double mcum;                // accumulate magnetization per spin
    double m2cum;               // square of magnetization per spin

    int Lmin = 4;               // minimum lattice dimension
    int Lsteps = 3;             // number of L doublings
    double Tmin = 1.5;          // minimum temperature
    double Tmax = 3.5;          // maximum temperature
    int Tsteps = 10;            // number of temperature steps

    double[][] chi;             // isothermal susceptibility data
    double chiMax = 0.1;        // for plotting
    int Lindex;                 // index of current L value
    int Tindex;                 // index of current T value
    double TcExact = 2 / Math.log(1 + Math.sqrt(2));

    void initial () {
        N = L * L;
        if (spin == null || spin.length < L)
            spin = new int[L][L];
        if (T == Tmin) {
            // initialize all spins up
            for (int x = 0; x < L; x++)
                for (int y = 0; y < L; y++)
                    spin[x][y] = +1;
            M = N;
            SS = 2 * N;
        }
        // Boltzmann factors
        if (w == null)
            w = new double[17][3];
        for (int i = -8; i <= 8; i += 4) {
            w[i + 8][0] = Math.exp( - (i + 2 * H) / T);
            w[i + 8][2] = Math.exp( - (i - 2 * H) / T);
        }
        mcs = 0;
        mcum = m2cum = 0;
    }    

    void data () {
        if (mcs == nequil + 1)
            mcum = m2cum = 0;
        double m = M;
        m /= N;
        if (m < 0)
            m = -m;
        mcum += m;
        m2cum += m * m;
        int n = mcs;            // number of data points so far
        if (mcs > nequil)
            n -= nequil;
        double mAv = mcum / n;
        double m2Av = m2cum / n;
        double chiValue = N / T * (m2Av - mAv * mAv);
        chi[Lindex][Tindex] = chiValue;
        if (mcs == nequil + ndata && chiValue > chiMax)
            chiMax = chiValue;
    }

    int sumOfNeighbors (int x, int y) {
        // periodic boundary conditions
        int left = 0;
        if (x == 0)
            left = spin[L - 1][y];
        else left = spin[x - 1][y];
        int right = 0;
        if (x == L - 1)
            right = spin[0][y];
        else right = spin[x + 1][y];
        int down = 0;
        if (y == 0)
            down = spin[x][L - 1];
        else down = spin[x][y - 1];
        int up = 0;
        if (y == L - 1)
            up = spin[x][0];
        else up = spin[x][y + 1];

        return left + right + up + down;
    }

    void Metropolis () {
        // one Monte Carlo step per spin
        for (int ispin = 0; ispin < N; ispin++) {
            int x = (int) (L * Math.random());
            if (x == L)
                --x;
            int y = (int) (L * Math.random());
            if (y == L)
                --y;
            int dSS = 2 * spin[x][y] * sumOfNeighbors(x, y);
            if (Math.random() < w[dSS + 8][spin[x][y] + 1]) {
                spin[x][y] = -spin[x][y]; // flip spin
                M += 2 * spin[x][y];
                SS -= dSS;
            }
        }
        ++mcs;
        data();
    }

    void initializeSimulation () {
        if (chi == null ||
            chi.length < Lsteps + 1 ||
            chi[0].length < Tsteps + 1) {
            chi = new double[Lsteps + 1][Tsteps + 1];
        }
        for (int i = 0; i <= Lsteps; i++)
            for (int j = 0; j <= Tsteps; j++)
                chi[i][j] = 0;
        L = Lmin;
        Lindex = 0;
        T = Tmin;
        Tindex = 0;
        initial();
    }

    class Lattice extends Plot {
        Lattice () {
            setSize(300, 300);
        }

        public void paint () {
            clear();
            setWindow(0, L, 0, L);
            for (int x = 0; x < L; x++) {
                for (int y = 0; y < L; y++) {
                    if (spin[x][y] == 1)
                        setColor("red");
                    else
                        setColor("green");
                    boxArea(x, x + 1.1, y, y + 1.1);
                }
            }
        }
    }

    class Graph extends Plot {
        Graph () {
            setSize(300, 300);
        }

        public void paint () {
            clear();
            setColor("black");
            drawAxes(Tmin - TcExact, Tmax - TcExact, 0, chiMax);
            setColor("blue");
            plotStringCenter("T = T_c", 0, -0.07 * chiMax);
            plotStringLeft("chi = " + Easy.format(chiMax, 3),
                           0, 1.02 * chiMax);
            double dT = (Tmax - Tmin) / Tsteps;
            double rx = 0.01 * (Tmax - Tmin);
            double ry = 0.01 * chiMax;
            double T0 = Tmin - TcExact;
            for (int l = 0; l <= Lindex; l++) {
                int tmax = Tsteps;
                if (l == Lindex)
                    tmax = Tindex;
                if (l == Lindex && mcs < nequil + ndata)
                    setColor("green");
                else
                    setColor("magenta");
                for (int t = 0; t < tmax; t++)
                    plotLine(T0 + t * dT, chi[l][t],
                             T0 + t * dT + dT, chi[l][t + 1]);
                if (l == Lindex && mcs < nequil + ndata)
                    setColor("red");
                else
                    setColor("blue");
                for (int t = 0; t <= Tsteps; t++)
                    floodCircle(T0 + t * dT - rx, T0 + t * dT + rx,
                                chi[l][t] - ry, chi[l][t] + ry);
            }
        }
    }

    class Output extends Plot {
        Output () {
            setSize(600, 30);
        }

        public void paint () {
            clear();
            setWindow(0, 100, 0, 3);
            setColor("blue");
            boxArea(0, 100, 0, 3);
            setColor("white");
            plotString("L = " + L, 5, 1);
            plotString("T = " + Easy.format(T, 4), 20, 1);
            plotString("MC step = " + mcs, 35, 1);
            if (mcs > nequil)
                plotString("Data step = " + (mcs - nequil), 55, 1);
            else
                plotString("Therm step = " + mcs, 55, 1);
            plotString("chi = " + Easy.format(chi[Lindex][Tindex], 4), 80, 1);
        }
    }

    Lattice lattice;
    Graph graph;
    Output output;
    Reader LminReader, LstepsReader, TminReader, TmaxReader, TstepsReader;
    Reader nequilReader, ndataReader, skipReader;
    int skip = 20;
    
    public void init () {
        initializeSimulation();
        add(lattice = new Lattice());
        add(graph = new Graph());
        add(output = new Output());
        add(LminReader = new Reader("L_min = ", Lmin));
        add(LstepsReader = new Reader("L steps = ", Lsteps));
        add(TminReader = new Reader("T_min = ", Tmin, 4));
        add(TmaxReader = new Reader("T_max = ", Tmax, 4));
        add(TstepsReader = new Reader("T steps = ", Tsteps));
        add(nequilReader = new Reader("Therm steps", nequil));
        add(ndataReader = new Reader("Data steps", ndata));
        add(skipReader = new Reader("Skip steps", skip));
        addControlPanel();
    }

    void check () {
        if (mcs > nequil + ndata) {         // current T data done
            if (Tindex == Tsteps) {         // current L data done
                if (Lindex == Lsteps) {     // simulation done
                    stopAnimation();
                    return;
                } else {                    // proceed to next L value
                    L *= 2;         
                    ++Lindex;
                    T = Tmin;
                    Tindex = 0;
                }
            } else {                        // proceed to next T value
                T += (Tmax - Tmin) / Tsteps;
                ++Tindex;
            }
            initial();                      // initialize lattice
        }
    }
    
    public void step () {
        for (int step = 0; step < skip; step++) {
            Metropolis();
            check();
        }
        Metropolis();
        check();
        lattice.repaint();
        graph.repaint();
        output.repaint();
    }

    public void reset () {
        Lmin = LminReader.readInt();
        Lsteps = LstepsReader.readInt();
        Tmin = TminReader.readDouble();
        Tmax = TmaxReader.readDouble();
        Tsteps = TstepsReader.readInt();
        nequil = nequilReader.readInt();
        ndata = ndataReader.readInt();
        skip = skipReader.readInt();
        initializeSimulation();
        lattice.repaint();
        graph.repaint();
        output.repaint();
    }

    public static void main (String[] args) {
        FiniteSizeScaling fss = new FiniteSizeScaling();
        fss.frame("Finite Size Scaling in the 2-D Ising model", 630, 550);
    }
}


UB Physics Home Questions or comments: phygons@acsu.buffalo.edu