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

Lecture 22: March 16


Autocorrelations in the 2-D Ising model simulation

There are two ways suggested in the textbook to check the standard Monte Carlo error estimates in the Ising model simulation:

The following applet, which is generated by the program Autocorrelation.java, measures correlation times in the energy and magnetization:

Here is the code which generates this applet:

// Autocorrelation.java

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

public class Autocorrelation extends Animation {

    // compute energy and magnetization autocorrelations
    // in the 2-d Ising model using the Metropolis method

    int L = 16;                 // linear size of lattice
    int N = L * L;              // number of spins
    int[][] spin;               // spin values
    double T = 3;               // absolute temperature
    double H;                   // magnetic field

    int M;                      // magnetization
    int SS;                     // sum s_i s_j
    double e;                   // energy / spin
    double m;                   // magnetization / spin
    double[][] w;               // Boltzmann factors

    int nequil = 20;            // equilibration steps
    int pass;                   // Monte Carlo steps after nequil
    int nsave = 10;             // values to save for correlations
    double[] esave;             // saved E values
    double[] msave;             // saved M values
    double[] Ce;                // energy correlation sums
    double[] Cm;                // magnetization correlation sums
    double[] ecum;              // to accumulate E and E*E
    double[] mcum;              // to accumulate M and M*M

    void initial () {
        N = L * L;
        if (spin == null || spin.length < L)
            spin = new int[L][L];
        // 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;
        // initialize correlation data
        pass = 0;
        if (esave == null || esave.length < nsave) {
            esave = new double[nsave];
            msave = new double[nsave];
            Ce = new double[nsave];
            Cm = new double[nsave];
        }
        for (int n = 0; n < nsave; n++)
            esave[n] = msave[n] = Ce[n] = Cm[n] = 0;
        if (ecum == null) {
            ecum = new double[2];
            mcum = new double[2];
        }
        for (int i = 0; i < 2; i++)
            ecum[i] = mcum[i] = 0;
    }

    void correl () {
        ++pass;
        // accumulate data for time autocorrelation functions
        // index0 = array index of earliest saved time
        int index0 = (pass - 1) % nsave;
        if (pass > nsave) {
            // compute Ce and Cm after nsave values are saved
            int index = index0;
            for (int t = nsave - 1; t >= 0; t--) {
                Ce[t] += e * esave[index];
                Cm[t] += m * msave[index];
                if (++index == nsave)
                    index = 0;
            }
        }
        // save latest value in array position of earliest value
        esave[index0] = e;
        msave[index0] = m;
        // accumulate for averages
        ecum[0] += e;
        mcum[0] += m;
        ecum[1] += e * e;
        mcum[1] += m * m;
    }

    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;
    }

    int mcs;                    // Monte Carlo steps per spin
    int accept;                 // accepted Metropolis steps

    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
                ++accept;
                M += 2 * spin[x][y];
                SS -= dSS;
            }
        }
        e = - SS - H * M;
        e /= N;
        m = M;
        if (m < 0)
            m = -m;
        m /= N;
        ++mcs;
        if (mcs > nequil)
            correl();
    }

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

        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 {
        String name;
        double[] Acum;
        double[] A;
        
        Graph (String name, double[] Acum, double[] A) {
            this.name = name;
            this.Acum = Acum;
            this.A = A;
            setSize(200, 200);
        }

        public void paint () {
            clear();
            setColor("black");
            drawAxes(0, nsave, -0.2, 1);
            setColor("blue");
            plotStringCenter(name, nsave / 2, 1.02);
            if (pass <= nsave)
                return;
            double Aav = Acum[0] / pass;
            double A2av = Acum[1] / pass;
            double yPrevious = 1;
            double xSum = 0, ySum = 0, xxSum = 0, xySum = 0;
            boolean negative = false;
            setColor("red");
            for (int t = 0; t < nsave; t++) {
                double y = A[t] / (pass - nsave) - Aav * Aav;
                y /= (A2av - Aav * Aav);
                plotLine(t, yPrevious, t + 1, y);
                yPrevious = y;
                // accumulate sums to compute slope
                if (y > 0 && !negative) {
                    double x = t + 1;
                    xSum += x;
                    xxSum += x * x;
                    double logy = Math.log(y);
                    ySum += logy;
                    xySum += x * logy;
                } else
                    negative = true;
            }
            double tau = ySum * xSum - xySum;
            if (tau != 0) {
                tau = (xxSum - xSum * xSum) / tau;
                setColor("magenta");
                plotStringLeft("tau = " + Easy.format(tau, 3), nsave, -0.2);
            }
        }
    }

    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("MC Step = " + mcs, 5, 1);
            if (pass == 0) {
                if (mcs > 0)
                    plotString("Thermalizing ...", 30, 1);
                return;
            } else if (pass <= nsave) {
                plotString("Initializing correlation data ...", 30, 1);
                return;
            }
            double eav = ecum[0] / pass;
            double mav = mcum[0] / pass;
            plotString(" / N = " + Easy.format(eav, 6), 40, 1);
            plotString(" / N = " + Easy.format(mav, 6), 70, 1);
        }
    }

    Lattice lattice;
    Graph eGraph, mGraph;
    Output output;
    Reader LReader, TReader, nsaveReader, nequilReader, skipReader;
    int skip;

    public void init () {
        initial();
        add(lattice = new Lattice());
        add(eGraph = new Graph("Energy Autocorrelation", ecum, Ce));
        add(mGraph = new Graph("Magnetization Autocorrelation", mcum, Cm));
        add(output = new Output());
        add(LReader = new Reader("L = ", L));
        add(TReader = new Reader("T = ", T, 4));
        add(nsaveReader = new Reader("Corr steps = ", nsave));
        add(nequilReader = new Reader("Therm steps = ", nequil));
        add(skipReader = new Reader("Skip steps = ", skip));
        addControlPanel();
    }

    public void step () {
        for (int step = 0; step < skip; step++)
            Metropolis();
        Metropolis();
        lattice.repaint();
        output.repaint();
        if (mcs > nequil) {
            eGraph.repaint();
            mGraph.repaint();
        }
    }

    public void reset () {
        L = LReader.readInt();
        T = TReader.readDouble();
        nsave = nsaveReader.readInt();
        nequil = nequilReader.readInt();
        skip = skipReader.readInt();
        initial();
        eGraph.Acum = ecum;
        eGraph.A = Ce;
        mGraph.Acum = mcum;
        mGraph.A = Cm;
        lattice.repaint();
        eGraph.repaint();
        mGraph.repaint();
        output.repaint();
    }

    public static void main (String[] args) {
        Autocorrelation autocorrelation = new Autocorrelation();
        autocorrelation.frame("Ising Model Autocorrelations", 650, 420);
    }
}


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