Moiré patterns in a pair of hexagonal lattices

(7 comments)

A Moiré pattern is an interference pattern that occurs when two grids of repeating lines or shapes are rotated by a small amount relative to one another (oblig. xkcd).

A recent application concerned the experimental verification of Hofstadter's butterfly: Douglas Hofstadter (he of Gödel, Escher, Bach fame) predicted in a 1976 paper that the energy structure of the electrons in a two-dimensional lattice of atoms in a magnetic field has a fractal structure. The problem with the experimental verification of this prediction is that the lattice dimensions of a typical solid material are so small that it would be unfeasible to generate the necessary magnetic field to make the energy structure measurable.

In 2013, three research groups were able to verify the claim by placing a layer of graphene on a substrate layer of boron nitride (which has a very similar hexagonal atomic structure), at such an angle that the resulting Moiré pattern had a much larger repeating length scale.

The code below generates an SVG image of two hexagonal lattices, rotated by a specified amount, which shows the repeating Moiré pattern that results.

Hexagonal Moiré pattern

import numpy as np

# Image dimensions and grid lattice size, a.
width, height = 600, 400
a = 5

# a.sin(60) and a.cos(60)
gx, gy = a * np.sqrt(3)/2, a/2
# The number of unit cells, horizontally and vertically.
nx, ny = int(width / 2 / gx)+1, int(height / (a + gy))+1
# We'll need the coordinates of the centre of the image when we come to rotate.
cx, cy = width / 2, height / 2

def svg_line(x0, y0, x1, y1, th=0, cls=None):
    """Return the SVG for a single, line possibly rotated by th radians."""

    def rotate(x, y, th):
        """Rotate the coordinates (x,y) about the centre (cx,cy)."""
        c, s = np.cos(th), np.sin(th)
        xp, yp = x-cx, y-cy
        x, y = c*xp - s*yp, s*xp + c*yp
        return x+cx, y+cy

    if th != 0:
        x0, y0 = rotate(x0, y0, th)
        x1, y1 = rotate(x1, y1, th)

    # If an SVG class has been provided, add it to the line element.
    s_cls = 'class="{}"'.format(cls) if cls else ''
    return '<line x1="{}" y1="{}" x2="{}" y2="{}" {}/>'.format(
                                                    x0, y0, x1, y1, s_cls)

def add_unit_cell(s, x0, y0, th=0, cls=None):
    """Add a unit cell from the lattice to the SVG output.

    The "unit cell" consists of the arrangement of lines: \ /
                                                           |
    centred at the vertex where they meet. th is the angle of rotation, in
    radians and cls is an optional SVG class to add to the <line> element.

    """

    s.append(svg_line(x0, y0, x0, y0+a, th, cls))
    s.append(svg_line(x0, y0, x0-gx, y0-gy, th, cls))
    s.append(svg_line(x0, y0, x0+gx, y0-gy, th, cls))

def svg_preamble(s):
    """The usual SVG preamble and style definitions."""

    s.append('<?xml version="1.0" encoding="utf-8"?>')
    s.append('<svg xmlns="http://www.w3.org/2000/svg"\n' + ' '*5 +
         'xmlns:xlink="http://www.w3.org/1999/xlink" width="{}" height="{}" >'
            .format(width, height))
    s.append("""<defs>
    <style type="text/css"><![CDATA[
    line {
        stroke-width: 2px;
        stroke: #000;
    }
    .lattice1 {
        stroke: #824e4e;
    }
    .lattice2 {
        stroke: #4a5f70;
    }
    >]]></style>
    </defs>
    """)

s = []
svg_preamble(s)

# Angle of rotation of the lattices (degrees)
th = 10
# An internal variable to offset every other row of the unit cells when drawing
_ph = 0
for iy in range(ny):
    _ph = 0 if _ph else gx
    for ix in range(nx):
        add_unit_cell(s, ix*2*gx + _ph, iy*(a+gy), cls='lattice1')
        add_unit_cell(s, ix*2*gx + _ph, iy*(a+gy), np.radians(th), 'lattice2')

s.append('</svg>')

with open('lattice.svg', 'w') as fo:
    print('\n'.join(s), file=fo)
Current rating: 4.5

Comments

Comments are pre-moderated. Please be patient and your comment will appear soon.

Alfonsi Jessica 4 years, 11 months ago

Wonderful blog! It makes Python even more appealing to me, I just need a good problem to start learning by coding.
Have a look at my Mathematica Demonstration I published 5 years ago
http://demonstrations.wolfram.com/MoirePatternsAndCommensurabilityInRotatedGrapheneBilayers/

Link | Reply
Current rating: 5

christian 4 years, 11 months ago

Thank you! I think we may have been reading the same papers about rotated graphene layers. I was going to write something about Hofstadter's Butterfly as well but never got round to it...

Link | Reply
Currently unrated

Alfonsi Jessica 4 years, 11 months ago

I have been thinking often about plotting Hofstadter's butterfly for different lattices, square and hexagonal, but now I'm looking into other systems. There's a recent IOP ebook https://iopscience.iop.org/book/978-1-6817-4117-8

Link | Reply
Currently unrated

Vishal Kumar 4 years, 6 months ago

Is it possible to get an animation of changing angles? That will be really good.

Link | Reply
Current rating: 5

RODOLFO 4 years, 6 months ago

LOS INVITO A VER ESTO QUE SUBI HACE 8 AÑOS A YOUTUBECUANDO AUN NO SE HABLABA DE ANGULO MAGICO.
Y NO TIENEN IDEA DE LO QUE ESCONDE ESTE PATRÓN.

https://youtu.be/2lYp1uDG_ic

Link | Reply
Currently unrated

Yitzhak Weissman 3 years, 10 months ago

I am presently investigating the Moire effect in three dimensions, using Python. This Blog is a true goldmine for me. Thank you, Christian.

Link | Reply
Currently unrated

christian 3 years, 10 months ago

Thank you for your comment – glad you're finding it interesting!

Link | Reply
Currently unrated

New Comment

required

required (not published)

optional

required