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

Lecture 14: February 16


Symmetries of the square lattice

It is convenient to take advantage of the symmetries of the square lattice in generating self-avoiding random walks and in studying their properties. Assume that the walk starts at a fixed lattice site which is chosen as the origin of coordinates for performing symmetry transformations. The group of transformations (point group) which does not change the origin, has eight elements:

  1. the identity transformation
            2                        2
    
        3   0   1       =>       3   0   1
    
            4                        4
    
    which corresponds to the permutation 1234 -> 1234 of nearest neighbor sites,

  2. a clockwise rotation by 90o
            2                        3
    
        3   0   1       =>       4   0   2
    
            4                        1
    
    which corresponds to the permutation 1234 -> 2341 of nearest neighbor sites,

  3. a clockwise rotation by 180o
            2                        4
    
        3   0   1       =>       1   0   3
    
            4                        2
    
    which corresponds to the permutation 1234 -> 3412 of nearest neighbor sites,

  4. a clockwise rotation by 270o
            2                        1
    
        3   0   1       =>       2   0   4
    
            4                        3
    
    which corresponds to the permutation 1234 -> 4321 of nearest neighbor sites,

  5. a reflection about the line x = -y
            2                        3
    
        3   0   1       =>       2   0   4
    
            4                        1
    
    which corresponds to the permutation 1234 -> 4123 of nearest neighbor sites,

  6. a reflection about the line y = 0
            2                        4
    
        3   0   1       =>       3   0   1
    
            4                        2
    
    which corresponds to the permutation 1234 -> 1432 of nearest neighbor sites,

  7. a reflection about the line = y
            2                        1
    
        3   0   1       =>       4   0   2
    
            4                        3
    
    which corresponds to the permutation 1234 -> 2143 of nearest neighbor sites,

  8. and, a reflection about the line x = 0
            2                        2
    
        3   0   1       =>       1   0   3
    
            4                        4
    
    which corresponds to the permutation 1234 -> 3214 of nearest neighbor sites.

Technically, this group of transformations is the "dihedral group" D4.

If (x, y) is the coordinate of any lattice point, these transformations take it into points with coordinates given in the following table:

  1.2.3.4. 5.6.7.8.
x xy-x-y -yxy-x
y y-x-yx -x-yxy
It is easy to see that these transformations applied to a walk or polymer will not "break" any of the polymer bonds, i.e., the walk or polymer is transformed rigidly. Note that if we consider polymers related by these transformations to be physical objects confined to a plane, then two polymers related by rotations are physically identical or isomorphic, whereas two polymers that can only be related by a mirror reflection are said to be enantiomorphic. Here is an example of enantiomorphic polymers with N = 4 related by transformation #8:
        o--o              o--o
        |                    |
        o                    o
        |                    |
     o--o                    o--o

The double cul-de-sac polymer

The textbook gives an example of a double cul-de-sac polymer configuration and claims that it cannot be obtained by the reptation method. The algorithm given on page 391 removes the tail link before attempting to add a link at the head. It would appear that this allows the reptile to bite its tail, i.e., for the head monomer to replace the tail. This interpretation gives rise to what might be called a tail-philic algorithm, which can in fact generate the double cul-de-sac polymer. The article of Wall and Mandel, J. Chem. Phys. 63, 4592 (1975) states:
Should the random choice for a new head location be the "tail site" (which would be possible for chains of an odd number of steps sufficiently longer than those illustrated in Fig. 1), that would not preclude the move because the tail necessarily moves away as the head moves in.

One could, on the other hand, design a tail-phobic algorithm:

  1. Attempt to add a link to the head of the chain.

  2. If the attempt succeeds, remove the tail.

  3. If the attempt does not succeed, retain the original configuration and interchange the head and the tail.

This algorithm would in fact not be able to generate the double cul-de-sac. If one started with the double cul-de-sac, then the polymer would "oscillate" indefinitely with the head and tail interchanging positions with each move.

The following applet, which is generated by the program DoubleCulDeSac.java, demonstrates that the double cul-de-sac polymer can in fact be obtained by the tail-philic reptation algorithm:

Here is the code which generates this applet:

// DoubleCulDeSac.java

import comphys.graphics.*;

public class DoubleCulDeSac extends Animation {

    int N = 19;                 // number of links in chain
    int[] xMonomer;             // x coordinates of monomers
    int[] yMonomer;             // y coordinates of monomers
    int polymerNumber;

    // polymer configuration in Fig. 12.7

    int[] dx = {0, -1, 0, -1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, -1, 0, -1, 0};
    int[] dy = {1, 0, -1, 0, -1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 1, 0, 1, 0, -1};

    boolean doubleCulDeSac () {
        boolean found = false;
        for (int xDir = -1; xDir < 2; xDir += 2) {
            for (int yDir = -1; yDir < 2; yDir += 2) {
                for (int i = 0; i < N; i++) {
                    found = xMonomer[i + 1] - xMonomer[i] == dx[i] * xDir
                        && yMonomer[i + 1] - yMonomer[i] == dy[i] * yDir;
                    if (!found)
                        break;
                }
                if (!found) {
                    for (int i = 0; i < N; i++) {
                        found = xMonomer[i + 1] - xMonomer[i] == dy[i] * yDir
                            && yMonomer[i + 1] - yMonomer[i] == dx[i] * xDir;
                        if (!found)
                            break;
                    }
                }
                if (found)
                    break;
            }
            if (found)
                break;
        }
        return found;
    }

    void initial () {
        if (xMonomer == null) {
            xMonomer = new int[N + 1];
            yMonomer = new int[N + 1];
        }

        // initial polymer staircase
        xMonomer[N] = N / 2 - 1;
        yMonomer[N] = N / 2;
        for (int i = N; i > 0; i--) {
            if (i % 2 == 0) {     // step up
                xMonomer[i - 1] = xMonomer[i];
                yMonomer[i - 1] = yMonomer[i] + 1;
            } else {              // step right
                xMonomer[i - 1] = xMonomer[i] + 1;
                yMonomer[i - 1] = yMonomer[i];
            }
        }
        polymerNumber = -N;
    }

    void makeDoubleCulDeSac () {
        // remove tail
        for (int i = 0; i < N; i++) {
            xMonomer[i] = xMonomer[i + 1];
            yMonomer[i] = yMonomer[i + 1];
        }
        // add monomer at head
        int i = N + polymerNumber;
        xMonomer[N] = xMonomer[N - 1] + dx[i];
        yMonomer[N] = yMonomer[N - 1] + dy[i];
    }

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

    void reptate () {

        // save tail monomer position
        int xTail = xMonomer[0];
        int yTail = yMonomer[0];

        // remove tail
        for (int i = 0; i < N; i++) {
            xMonomer[i] = xMonomer[i + 1];
            yMonomer[i] = yMonomer[i + 1];
        }

        // try to add a monomer at head in one of two possible positions
        int xTry = xMonomer[N - 1];
        int yTry = yMonomer[N - 1];
        if (xTry == xMonomer[N - 2]) {      // left or right at random
            if (Math.random() < 0.5)
                xTry += 1;
            else
                xTry -= 1;
        } else {                            // up or down at random
            if (Math.random() < 0.5)
                yTry += 1;
            else
                yTry -= 1;
        }
        if (!occupied(xTry, yTry)) {
            xMonomer[N] = xTry;
            yMonomer[N] = yTry;
        } else {     // interchange head and tail in original configuration
            xMonomer[N] = xTail;
            yMonomer[N] = yTail;
            for (int i = 0; i <= (N - 1) / 2; i++) {
                xTail = xMonomer[i];
                yTail = yMonomer[i];
                xMonomer[i] = xMonomer[N - i - 1];
                yMonomer[i] = yMonomer[N - i - 1];
                xMonomer[N - i - 1] = xTail;
                yMonomer[N - i - 1] = yTail;
            }
        }
    }

    class Lattice extends Plot {
        Lattice () {
            setSize(400, 400);
            setBackground("white");
        }

        String[] colors = {"red", "green", "blue",
                           "cyan", "magenta", "yellow"};
        
        int pbc (int i) {
            while (i < 0)
                i += N;
            while (i >= N)
                i -= N;
            return i;
        }

        public void paint () {
            clear();
            setWindow(-0.5, N - 0.5, -0.5, N - 0.5);
            
            // draw the lattice points
            setColor("black");
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    plotPoint(i, j);
                }
            }
            
            // draw the polymer
            double r = 0.15;
            int x = pbc(xMonomer[0]);
            int y = pbc(yMonomer[0]);
            floodCircle(x - r, x + r, y - r, y + r);
            for (int i = 0; i < N; i++) {
                int c = i;
                while (c >= colors.length)
                    c -= colors.length;
                setColor(colors[c]);
                x = pbc(xMonomer[i]);
                y = pbc(yMonomer[i]);
                int x1 = pbc(xMonomer[i + 1]);
                int y1 = pbc(yMonomer[i + 1]);
                if (Math.abs(x - x1) <= 1 && Math.abs(y - y1) <= 1)
                    plotLine(x, y, x1, y1);
            }
        }
    }

    boolean foundDoubleCulDeSac;
    int doubleCulDeSacs;

    class Output extends Plot {
        Output () {
            setSize(400, 20);
            setBackground("blue");
        }

        public void paint () {
            clear();
            setWindow(0, 100, 0, 3);
            setColor("white");
            plotString("Polymer number: " + polymerNumber, 5, 1);
            if (foundDoubleCulDeSac)
                plotStringLeft("Found double cul-de-sac #"
                               + doubleCulDeSacs, 95, 1);
        }
    }

    Lattice lattice;
    Output output;

    public void init () {
        initial();
        add(lattice = new Lattice());
        add(output = new Output());
        addControlPanel();
    }

    public void step () {
        if (polymerNumber < 0)
            makeDoubleCulDeSac();
        else
            reptate();
        ++polymerNumber;
        if (foundDoubleCulDeSac = doubleCulDeSac()) {
            ++doubleCulDeSacs;
            stopAnimation();
        }
        lattice.repaint();
        output.repaint();
    }

    public void reset () {
        initial();
        lattice.repaint();
        foundDoubleCulDeSac = false;
        doubleCulDeSacs = 0;
        output.repaint();
    }

    public static void main (String[] args) {
        DoubleCulDeSac dcds = new DoubleCulDeSac();
        dcds.frame("Double Cul-de-sac", 430, 520);
    }
}


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