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

Lecture 21: March 12


Counting States: Energy versus Entropy

The following applet, which is generated by the program Macrostates.java, counts the number of microstates of the 2-d Ising model corresponding to each macrostate with fixed energy and magnetization.

Here is the code which generates this applet:

// Macrostates.java

import comphys.graphics.*;
import comphys.Easy;
import java.awt.event.*;

public class Macrostates extends Animation {

    // Count microstates in each macrostate
    // specified by sum(s_i) and sum(s_i * s_j)

    int Lx = 4;                 // lattice extent in x direction
    int Ly = 4;                 // lattice extent in y direction
    int N = Lx * Ly;            // number of spins
    int[][] spin;               // 2-d array of spin variables
    boolean hotStart;           // initial random spins

    int M;                      // total magnetic moment (spin sum)
    int SS;                     // sum s_i * s_j (bond sum)
    int microState;             // microstate number
    int[][] macroState;         // to count micros in each macro
    int maxMacro;               // max number of micros is any macro

    int Nmax = 30;              // max N for exact evaluation
    boolean exact;              // do exact evaluation if N <= Nmax
    int exactMicroStates;       // exact number of microstates

    double T = 2;               // absolute temperature kT
    double[] F, E, TS;          // free energy, energy, entropy
    double FESmin, FESmax;      // for plotting
    
    int spinSum () {
        int sum = 0;
        for (int x = 0; x < Lx; x++)
            for (int y = 0; y < Ly; y++)
                sum += spin[x][y];
        return sum;
    }

    int bondSum () {
        int sum = 0;
        for (int x = 0; x < Lx; x++) {
            int right = x + 1;
            if (right == Lx)
                right = 0;
            for (int y = 0; y < Ly; y++) {
                int up = y + 1;
                if (up == Ly)
                    up = 0;
                int neighbors = spin[x][up] + spin[right][y];
                sum += spin[x][y] * neighbors;
            }
        }
        return sum;
    }

    void initial () {
        N = Lx * Ly;
        if (N > Nmax)
            exact = false;
        if (N <= Nmax) {
            exactMicroStates = 1;
            for (int i = 0; i < N; i++)
                exactMicroStates *= 2;
        }
        // allocate spin and macrostate arrays if necessary
        if (spin == null || spin.length < Lx || spin[0].length < Ly) {
            spin = new int[Lx][Ly];
            macroState = new int[N + 1][N + 1];
        }
        // initialize spins 
        for (int x = 0; x < Lx; x++)
            for (int y = 0; y < Ly; y++) {
                spin[x][y] = +1;
                if (hotStart && Math.random() < 0.5)
                    spin[x][y] = -1;
            }
        M = spinSum();
        SS = bondSum();
        microState = maxMacro = 0;
        for (int i = 0; i < N + 1; i++)
            for (int j = 0; j < N + 1; j++)
                macroState[i][j] = 0;
        // allocate F, E, S arrays if necessary
        if (F == null || F.length < N + 1) {
            F = new double[N + 1];
            E = new double[N + 1];
            TS = new double[N + 1];
        }
        for (int i = 0; i < N + 1; i++)
            F[i] = E[i] = TS[i] = 0;
    }

    void updateMacroState () {
        ++microState;
        int l = ++macroState[(N - M) / 2][(2 * N - SS) / 4];
        if (l > maxMacro)
            maxMacro = l;
    }

    void nextExact () {
        int n = microState;
        for (int bit = 0; bit < N; bit++) {
            int s = n % 2;
            int x = bit % Lx;
            int y = (bit - x) / Lx;
            if (s == 0)
                spin[x][y] = 1;
            else
                spin[x][y] = -1;
            n -= s;
            n >>= 1;
        }
        M = spinSum();
        SS = bondSum();
        updateMacroState();
    }

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

    void nextRandom () {
        // flip random spin for next microstate
        int x = (int) (Lx * Math.random());
        int y = (int) (Ly * Math.random());
        spin[x][y] = -spin[x][y];
        M += 2 * spin[x][y];
        SS += 2 * spin[x][y] * sumOfNeighbors(x, y);
        updateMacroState();
    }

    void computeFES () {
        FESmin = FESmax = 0;
        for (int n = 0; n < N + 1; n++) {
            E[n] = 4 * n - 2 * N;
            int states = 0;
            for (int i = 0; i < N + 1; i++)
                states += macroState[i][n];
            if (states > 0) {
                TS[n] = T * Math.log(states);
                F[n] = E[n] - TS[n];
                if (FESmin > E[n]) FESmin = E[n];
                if (FESmin > TS[n]) FESmin = TS[n];
                if (FESmin > F[n]) FESmin = F[n];
                if (FESmax < E[n]) FESmax = E[n];
                if (FESmax < TS[n]) FESmax = TS[n];
                if (FESmax < F[n]) FESmax = F[n];
            } else {
                TS[n] = -1;     // minus infinity
            }
        }
    }

    String[] color = {"lightGray", "pink", "orange", "yellow",
                      "green", "cyan", "blue", "magenta", "red"};
    boolean mouseInPlot;
    int xMouse;
    int yMouse;

    class Macro extends Plot implements MouseListener, MouseMotionListener {
        Macro () {
            setSize(300, 300);
            addMouseListener(this);
            addMouseMotionListener(this);
        }
        
        public void paint () {
            clear();
            setWindow(0, N + 1, 0, N + 1);
            for (int m = 0; m < N + 1; m++) {
                for (int ss = 0; ss < N + 1; ss++) {
                    int n = macroState[N - m][ss];
                    if (macroState[m][ss] > 0) {
                        int i = (int) (n / (double) maxMacro * 8.99999);
                        setColor(color[i]);
                    } else
                        setColor("white");
                    boxArea(ss, ss + 1.1, m, m + 1.1);
                }
            }
            setColor("blue");
            double d = 0.05 * (N + 1);
            plotStringLeft("x-axis: bond sum = 2N...-2N", N + 1 - d, d);
            plotStringLeft("y-axis: spin sum = -N...N", N + 1 - d, N + 1 - d);
        }

        public void mouseClicked (MouseEvent me) { }
        public void mouseEntered (MouseEvent me) {
            mouseInPlot = true;
        }
        public void mouseExited (MouseEvent me) {
            mouseInPlot = false;
        }
        public void mousePressed (MouseEvent me) { }
        public void mouseReleased (MouseEvent me) { }
        public void mouseDragged (MouseEvent me) { }
        public void mouseMoved (MouseEvent me) {
            xMouse = (int) xWorld(me.getX());
            yMouse = (int) yWorld(me.getY());
            if (xMouse >= 0 && xMouse <= N && yMouse >= 0 && yMouse <= N) {
                mouseInPlot = true;
                output.repaint();
            } else {
                mouseInPlot = false;
            }
        }
    }

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

        public void paint () {
            clear();
            setColor("black");
            if (FESmin == FESmax)
                return;
            drawAxes(0, N + 1, FESmin, FESmax);
            double v = FESmax;
            plotStringCenter("Energy versus Entropy", N / 2, v);
            for (int n = 0; n < N + 1; n++) {
                if (TS[n] < 0)
                    continue;
                setColor("red");
                v = E[n];
                plotLine(n, v, n + 1, v);
                setColor("green");
                v = TS[n];
                plotLine(n, v, n + 1, v);
                setColor("blue");
                v = F[n];
                plotLine(n, v, n + 1, v);
            }
            v = FESmin - 0.07 * (FESmax - FESmin);
            setColor("red");
            plotString("energy E", 0, v);
            setColor("green");
            plotStringLeft("T log n(E)", N, v);
            setColor("blue");
            plotStringCenter("F = E-TS", N / 2, v);
        }
    }

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

        public void paint () {
            setWindow(0, 100, 0, 3);
            clear();
            setColor("blue");
            boxArea(0, 100, 0, 3);
            setColor("white");
            plotString("N = " + N + "   n = " + (int) microState, 5, 1);
            if (mouseInPlot) {
                int n = macroState[yMouse][xMouse];
                plotStringCenter("n(E, M) = " + n, 50, 1);
                int SS = 2 * N - 4 * xMouse;
                int M = 2 * yMouse - N;
                plotStringLeft("E = -(" + SS + ") J - (" + M + ") H", 95, 1);
            } else {
                plotString("Move mouse into left plot to view n(E, M)", 30, 1);
            }
        }
    }

    Macro macro;
    FreeEnergy freeEnergy;
    Output output;
    Reader LxReader, LyReader, skipReader, exactReader,
        TReader, hotStartReader;
    int skip = 100;

    public void init () {
        initial();
        add(macro = new Macro());
        add(freeEnergy = new FreeEnergy());
        add(output = new Output());
        add(LxReader = new Reader("L_x = ", Lx));
        add(LyReader = new Reader("L_y = ", Ly));
        add(skipReader = new Reader("skip states = ", skip));
        add(exactReader = new Reader("Exact (N < 31)", exact));
        add(TReader = new Reader("T = ", T, 4));
        add(hotStartReader = new Reader("Random Initial", hotStart));
        addControlPanel();
    }

    public void step () {
        for (int step = 0; step < skip; step++) {
            if (exact) {
                nextExact();
                if (microState >= exactMicroStates)
                    break;
            } else {
                nextRandom();
            }
        }
        computeFES();
        macro.repaint();
        freeEnergy.repaint();
        output.repaint();
        if (exact && microState >= exactMicroStates)
            stopAnimation();
    }

    public void reset () {
        Lx = LxReader.readInt();
        Ly = LyReader.readInt();
        skip = skipReader.readInt();
        exact = exactReader.readBoolean();
        T = TReader.readDouble();
        hotStart = hotStartReader.readBoolean();
        initial();
        computeFES();
        macro.repaint();
        freeEnergy.repaint();
        output.repaint();
    }

    public static void main (String[] args) {
        Macrostates macrostates = new Macrostates();
        macrostates.frame("Macrostates of 2-d Ising Model", 630, 500);
    }
}


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