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

Lecture 13: February 14


Reptation method for enriching a polymer sample

The reptation model was invented by de Gennes to explain the motion of polymer chains in a dense system of entangled chains. The basic idea is that the polymer chain in constrained to move inside a tube formed by other entangled chains.

Problem 12.13 on page 391 uses the reptation model of polymer motion to help generate a random statistical sample of polymer configurations. The method has the advantage that it cannot fail, unlike a self-avoiding random walk which can encounter a cul-de-sac.

The following applet, which is generated by the program Reptation.java, implements this reptation enrichment method. The idea is to generate a large number of chains of fixed length N starting from any particular chain. The bond angles are constrained to be +90o or -90o, so one could start from a simple "staircase". However, this program uses a self-avoiding random walk to generate the initial polymer to illustrate the phenomenon of cul-de-sacs. Once the initial configuration is found, the reptation algorithm takes over, and the mean squared head-to-tail distance of the generated chains is measured.

Here is the code which generates this applet:

// Reptation.java

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

public class Reptation extends Animation {

    int N = 5;                  // length of polymer chain
    int[] xMolecule, yMolecule; // x,y coordinates of molecules in chain
    int[] xCopy, yCopy;         // to copy polymer
    int nPolymers;              // number of polymers in sample
    double RSquaredSum;         // sum of head-to-tail distances squared

    int L = 10;                 // lattice points in each direction

    boolean occupied (int x, int y) {
        for (int n = 0; n < N; n++)
            if (xMolecule[n] == x && yMolecule[n] == y)
                return true;
        return false;
    }

    int xPrevious, yPrevious;
    int xCurrent, yCurrent;
    int xTrial, yTrial;

    void trialStep () {
        if (xPrevious == xCurrent) {    // step right or left
            yTrial = yCurrent;
            if (Math.random() < 0.5)
                xTrial = xCurrent + 1;
            else
                xTrial = xCurrent - 1;
        } else {                        // step up or down
            xTrial = xCurrent;
            if (Math.random() < 0.5)
                yTrial = yCurrent + 1;
            else
                yTrial = yCurrent - 1;
        }
    }

    boolean culDeSac () {
        if (xPrevious == xCurrent)
            return
                occupied(xCurrent + 1, yCurrent) &&
                occupied(xCurrent - 1, yCurrent);
        else
            return
                occupied(xCurrent, yCurrent + 1) &&
                occupied(xCurrent, yCurrent - 1);
    }

    int nTry;                   // number of trials made
    int nWalk;                  // number of steps in trial

    void randomStep () {
        if (nWalk == 0) {       // first step in a random direction
            switch ( (int)(4 * Math.random()) ) {
            case 0: ++xMolecule[1]; break;
            case 1: --xMolecule[1]; break;
            case 2: ++yMolecule[1]; break;
            case 3: --yMolecule[1]; break;
            }
            nWalk = 1;
            return;
        }
        xCurrent = xMolecule[nWalk];
        yCurrent = yMolecule[nWalk];
        xPrevious = xMolecule[nWalk - 1];
        yPrevious = yMolecule[nWalk - 1];
        if (culDeSac()) {       // need to start over
            initial();
            needToClear = true;
            return;
        }
        do {
            trialStep();
        } while (occupied(xTrial, yTrial));
        ++nWalk;
        xMolecule[nWalk] = xTrial;
        yMolecule[nWalk] = yTrial;
    }

    void initial () {
        nPolymers = 0;
        RSquaredSum = 0;
        if (xMolecule == null || xMolecule.length != N+1) {
            xMolecule = new int[N+1];
            yMolecule = new int[N+1];
            xCopy = new int[N+1];
            yCopy = new int[N+1];
        }
        // store all molecules at center of lattice for convenience
        for (int n = 0; n < N; n++)
            xMolecule[n] = yMolecule[n] = L / 2;
        nWalk = 0;
        ++nTry;
    }

    void copy () {
        for (int n = 0; n <= N; n++) {
            xCopy[n] = xMolecule[n];
            yCopy[n] = yMolecule[n];
        }
    }

    void reptate () {
        // save a copy in case reptation fails
        copy();
        // remove tail
        for (int n = 0; n < N; n++) {
            xMolecule[n] = xMolecule[n+1];
            yMolecule[n] = yMolecule[n+1];
        }
        // head attempts to move
        xCurrent = xMolecule[N-1];
        yCurrent = yMolecule[N-1];
        xPrevious = xMolecule[N-2];
        yPrevious = yMolecule[N-2];
        trialStep();
        // test whether move is allowed
        if (!occupied(xTrial, yTrial)) {
            // accept new head position
            xMolecule[N] = xTrial;
            yMolecule[N] = yTrial;
        } else {
            // interchange head and tail in previous configuration
            for (int n = 0; n <= N; n++) {
                xMolecule[n] = xCopy[N - n];
                yMolecule[n] = yCopy[N - n];
            }
        }
        ++nPolymers;
        double dx = xMolecule[0] - xMolecule[N];
        double dy = yMolecule[0] - yMolecule[N];
        RSquaredSum += dx * dx + dy * dy;
        moveToCenterOfScreen();
    }

    void moveToCenterOfScreen () {
        // if polymer moves off screen
        boolean needToMove = false;
        for (int n = 0; n <= N; n++) {
            if (xMolecule[n] < 0 || xMolecule[n] > L ||
                yMolecule[n] < 0 || yMolecule[n] > L) {
                needToMove = true;
                break;
            }
        }
        if (needToMove) {
            int xShift = xMolecule[N / 2] - L / 2;
            int yShift = yMolecule[N / 2] - L / 2;
            for (int n = 0; n <= N; n++) {
                xMolecule[n] -= xShift;
                yMolecule[n] -= yShift;
            }
        }
    }

    boolean needToClear;        // clear screen if true
    boolean initializing;       // true while finding first polymer
    boolean reptating;          // true while reptating

    class Walk extends Plot {
        public void paint () {
            if (needToClear) {
                clear();
                needToClear = false;
                setWindow(0, L, 0, L);
                setColor("blue");
                for (int x = 0; x < L; x++)
                    for (int y = 0; y < L; y++)
                        plotPoint(x, y);
            }
            setColor("blue");
            boolean toggle = true;
            for (int n = 0; n < nWalk; n++) {
                if (reptating) {
                    if (toggle)
                        setColor("orange");
                    else
                        setColor("black");
                    toggle = !toggle;
                }
                plotLine(xMolecule[n + 1], yMolecule[n + 1],
                         xMolecule[n], yMolecule[n]);
            }
            if (reptating) {
                setColor("red");
                double r = 0.2;
                floodCircle(xMolecule[N] - r, xMolecule[N] + r,
                            yMolecule[N] - r, yMolecule[N] + r);
            }
        }
    }

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

        public void paint () {
            setWindow(0, 12, 0, 3);
            clear();
            if (reptating) {
                setColor("magenta");
                plotString("Reptating ...", 1, 1);
                plotStringCenter("Polymers: " + nPolymers, 6, 1);
                double RSquaredAverage = RSquaredSum;
                if (nPolymers > 0)
                    RSquaredAverage /= nPolymers;
                plotStringLeft(" = " + Easy.format(RSquaredAverage, 4),
                                 11, 1);
            } else if (initializing) {
                setColor("red");
                plotString("Initializing ...", 1, 1);
                plotStringCenter("Trial No: " + nTry, 6, 1);
                plotStringLeft("N = " + nWalk, 11, 1);
            } else {
                setColor("green");
                plotStringCenter("Polymer Reptation Simulation", 6, 1);
            }
        }
    }

    Walk walk;
    Output output;
    Reader NReader, LReader;

    public void init () {
        initial();
        needToClear = true;
        add(walk = new Walk());
        add(output = new Output());
        add(NReader = new Reader("N = ", N));
        add(LReader = new Reader("L = ", L));
        addControlPanel();
    }

    public void step () {
        if (nWalk < N) {
            initializing = true;
            randomStep();
        } else {
            needToClear = reptating = true;
            reptate();
        }
        walk.repaint();
        output.repaint();
    }

    public void reset () {
        needToClear = true;
        reptating = initializing = false;
        N = NReader.readInt();
        L = LReader.readInt();
        nTry = 0;
        initial();
        walk.repaint();
        output.repaint();
    }
    
    public static void main (String[] args) {
        Reptation reptation = new Reptation();
        reptation.frame("Polymer Reptation Simulation", 500, 600);
    }
}


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