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

Lecture 30: April 4


Random Walk Quantum Monte Carlo

The following applet is based on a program QMWalk.java is a translation of PROGRAM qmwalk on pages 647-649 of the textbook.

The potential in this simulation is V(x) = 0.5 x2 + b x3. The red dots along the x axis in both graphs represent the positions of the ensemble of random walkers. The top graph in this applet contains a plot of the potential, and the current value of the energy E, with the scales of the x and V(x) axes fixed. The bottom graph shows the wave function: the scales of the x and y axes are adjusted as the applet runs to show all of the random walkers and the wave function.

Here is the code which generates this applet:

// QMWalk.java

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

public class QMWalk extends Animation {

    // define potential function

    double b = 0;               // anharmonic coefficient

    double V (double x) {
        return 0.5 * x * x + b * x * x * x;
    }

    double[] x;                 // walker positions
    double[] psi;               // wave function
    double E;                   // current estimate for energy

    int N0 = 50;                // desired number of walkers
    double width = 1;           // width of initial region
    int N;                      // number of walkers
    double ds = 0.1;            // step length
    double dt;                  // time step
    double Vref;                // reference potential
    double Vave;                // mean potential
    double Esum;                // energy sum

    int mcs;                    // Monte Carlo steps
    int nequil = 100;           // thermalization steps
    double binsize;             // binsize for psi array

    void initial () {
        if (x == null)
            x = new double[2001];
        for (int i = 0; i < 2001; i++)
            x[i] = 0;
        if (psi == null)
            psi = new double[1001];
        for (int i = 0; i < 1001; i++)
            psi[i] = 0;
        dt = ds * ds;           // time step
        mcs = 0;
        N = N0;                 // initial # of walkers = desired #
        // choose initial positions of walkers at random
        Vref = 0;
        for (int i = 1; i <= N; i++) {
            x[i] = (2 * Math.random() - 1) * width;
            Vref += V(x[i]);
        }
        Vref /= N;
        Vave = Vref;
        binsize = 2 * ds;       // binsize for psi array
        E = Esum = 0;
        data();
    }

    void walk () {
        int Nin = N;            // # of walkers at beginning of trial
        double Vsum = 0;
        for (int i = Nin; i > 0; i--) {
            if (Math.random() < 0.5)
                x[i] += ds;
            else
                x[i] -= ds;
            double potential = V(x[i]);      // potential at x
            double dV = potential - Vref;
            if (dV < 0) {                    // check to add walker
                if (Math.random() < - dV * dt) {
                    N++;
                    x[N] = x[i];             // new walker
                    // factor of 2 since two walkers at x
                    Vsum += 2 * potential;
                } else {
                    Vsum += potential;       // only do old walker
                }
            } else {
                if (Math.random() < dV * dt) {
                    x[i] = x[N];
                    --N;
                } else {
                    Vsum += potential;
                }
            }
        }
        Vave = Vsum / N;                      // mean potential
        Vref = Vave - (N - N0) / (N0 * dt);   // new reference energy
        ++mcs;
    }

    void zeroData () {
        Esum = 0;
        for (int i = 0; i < 1001; i++)
            psi[i] = 0;
    }

    void data () {
        // accumulate data
        Esum += Vave;
        // bin walkers
        for (int i = 1; i <= N; i++) {
            int bin = (int) Math.round(x[i] / binsize);
            bin += psi.length / 2;
            psi[bin] += 1;
        }
        int n = mcs;
        if (n > nequil)
            n -= nequil;
        if (n > 0)
            E = Esum / n;
    }

    double Vmin = 0;            // minimum energy for plotting
    double Vmax = 2;            // maximum energy for plotting
    double xmin = -3;           // minimum x for plotting
    double xmax = 3;            // maximum x for plotting
    
    class Graph extends Plot {
        Graph () {
            setSize(400, 250);
        }
        
        public void paint () {
            clear();
            setColor("black");
            drawAxes(xmin, xmax, Vmin, Vmax);
            int points = 100;
            double delta = (xmax - xmin) / points;
            double xOld = xmin;
            double yOld = V(xmin);
            setColor("green");
            for (int i = 0; i < points; i++) {
                double x = xOld + delta;
                double y = V(x);
                plotLine(xOld, yOld, x, y);
                xOld = x;
                yOld = y;
            }
            setColor("blue");
            plotLine(xmin, E, xmax, E);
            setColor("red");
            double rx = 0.01 * (xmax - xmin);
            double ry = 0.01 * (Vmax - Vmin);
            for (int i = 1; i <= N; i++)
                floodCircle(outer.x[i] - rx, outer.x[i] + rx, E - ry, E + ry);
            setColor("blue");
            double y = Vmax + 0.02 *(Vmax - Vmin);
            plotString("Energy E", xmin, y);
            setColor("green");
            plotStringLeft("V(x)", xmax, y);
            plotString("V = " + Easy.format(Vmax, 4), 0, y);
            y = -0.08 * (Vmax - Vmin);
            setColor("black");
            plotStringCenter("x", 0, y);
            plotStringCenter(Easy.format(xmin, 3), xmin, y);
            plotStringCenter(Easy.format(xmax, 3), xmax, y);
        }
    }

    class Output extends Plot {
        Output () {
            setSize(400, 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);
            plotString("E = " + Easy.format(E, 4), 30, 1);
            plotString("V_ref = " + Easy.format(Vref, 4), 55, 1);
            plotString("N = " + N, 80, 1);
        }
    }

    class PsiGraph extends Plot {
        PsiGraph () {
            setSize(400, 250);
        }

        public void paint () {
            clear();
            int i0 = psi.length / 2;
            int i = i0;
            double pmax = psi[i] * psi[i];
            double sum = pmax;
            double P = pmax;
            double Vmin = 0;
            double Vmax = 0;
            do {
                ++i;
                P = psi[i] * psi[i] + psi[2 * i0 - i] * psi[2 * i0 - i];
                if (P > pmax)
                    pmax = P;
                double x = binsize * (i - i0);
                double v = V(x);
                if (v < Vmin)
                    Vmin = v;
                if (v > Vmax)
                    Vmax = v;
                v = V(-x);
                if (v < Vmin)
                    Vmin = v;
                if (v > Vmax)
                    Vmax = v;
            } while (P > 0);
            int imax = i - i0;
            double norm = Math.sqrt(sum * binsize);
            double ymax = Math.sqrt(pmax) / norm;
            setColor("black");
            drawAxes(-imax, imax, 0, ymax);
            setColor("magenta");
            for (i = -imax; i <= imax; i++) {
                plotLine(i - 1, psi[i0 + i - 1] / norm, i, psi[i0 + i] / norm);
            }
            setColor("green");
            double xOld = binsize * (- imax - 1);
            double yOld = (V(xOld) - Vmin) / (Vmax - Vmin) * ymax;
            for (i = -imax; i <= imax; i++) {
                xOld += binsize;
                double y = (V(xOld) - Vmin) / (Vmax - Vmin) * ymax;
                plotLine(i - 1, yOld, i, y);
                yOld = y;
            }
            if (Vmin < 0) {
                yOld = - Vmin / (Vmax - Vmin) * ymax;
                plotLine(-imax, yOld, imax, yOld);
            }
            setColor("red");
            double rx = 0.01 * 2 * imax;
            double ry = 0.01 * ymax;
            for (i = 1; i <= N; i++) {
                xOld = outer.x[i] / binsize;
                floodCircle(xOld - rx, xOld + rx, -ry, +ry);
            }
            double y = (E - Vmin) / (Vmax - Vmin) * ymax;
            setColor("blue");
            plotLine(-imax, y, imax, y);
            y = 1.02 * ymax;
            setColor("magenta");
            plotString("psi(x)", -imax, y);
            setColor("green");
            plotStringLeft("V(x)", imax, y);
            plotString("V = " + Easy.format(Vmax, 4), 0, y);
            y = -0.08 * ymax;
            setColor("black");
            plotStringCenter("x", 0, y);
            double x = imax * binsize;
            plotStringCenter(Easy.format(-x, 3), -imax, y);
            plotStringCenter(Easy.format(x, 3), imax, y);
        }
    }

    Graph graph;
    Output output;
    PsiGraph psiGraph;
    Reader bReader, N0Reader, widthReader, dsReader, nequilReader, skipReader;
    int skip;

    public void init () {
        initial();
        add(graph = new Graph());
        add(output = new Output());
        add(psiGraph = new PsiGraph());
        add(bReader = new Reader("b = ", b, 4));
        add(N0Reader = new Reader("N_0 = ", N0));
        add(widthReader = new Reader("width = ", width, 4));
        add(dsReader = new Reader("ds = ", ds, 4));
        add(nequilReader = new Reader("Therm steps", nequil));
        add(skipReader = new Reader("Skip steps", skip));
        addControlPanel();
    }

    public void step () {
        for (int s = 0; s <= skip; s++) {
            walk();
            if (mcs == nequil)
                zeroData();
            else
                data();
        }
        graph.repaint();
        output.repaint();
        psiGraph.repaint();
    }

    public void reset () {
        b = bReader.readDouble();
        N0 = N0Reader.readInt();
        width = widthReader.readDouble();
        ds = dsReader.readDouble();
        nequil = nequilReader.readInt();
        skip = skipReader.readInt();
        if (skip < 0)
            skip = 0;
        initial();
        graph.repaint();
        output.repaint();
        psiGraph.repaint();
    }

    QMWalk outer;               // hack to get around problem on unix
    public QMWalk () {
        super();                // create comphys.graphics.Animation
        outer = this;           // allows access to x[i] in inner classes
    }

    public static void main (String[] args) {
        QMWalk qmWalk = new QMWalk();
        qmWalk.frame("Random Walk Quantum Monte Carlo", 430, 730);
    }
}


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