Lattices
Overview
In many-body physics we often want to study systems defined on crystal lattices. In such cases, states, interactions, and correlation functions are most naturally defined in terms of the coordinates of the lattice. Simultaneously, it is optimal for performance reasons to store data in linear arrays. The lattice module provides a convenient and expressive way of defining lattices and lattice coordinates, and transforming those coordinates into linear indices.
Lattice Coordinates
Any crystal lattice can be defined in terms of a Bravais lattice and an atomic basis. A -dimensional Bravais lattice is defined in terms of a set of primitive vectors, where and the embedding dimension for the lattice. Any Bravais lattice point is identified by the vector,
which is a function of the primitive indices . We can define a crystal basis of additional sites that repeat on each Bravais lattice point, . The position of an arbitrary lattice site is then,
In theory, a crystal lattice extends infinitely in all directions. For computational purposes all lattices must have finite size. We denote by the length of the lattice along dimension . With this notation in place, we can express any point on the crystal lattice in terms of the lattice coordinate,
In aleph, this is represented by the LatticeCoordinate type, which can be constructed using the lattice_coordinate function,
var coord = lattice_coordinate([11,2,7], 2)
coord.primitive_vector() //-> [11, 2, 7]
coord.basis_index() //-> 2
If no basis index is specified the default is zero.
By itself, a lattice coordinate has no meaning, since lattice coordinates do not carry information about primitive vectors or the
crystal basis. For this, we need Lattice, which we discuss below.
Often we want to get lattice coordinates relative to other coordinates, such as when we define interactions. To this end, latice coordinates support basic arithmetic operators
var x = lattice_coordinate([10,1],1)
var y = lattice_coordinate([2,2], 0)
x + y //-> lattice_coordinate([12,3],1)
Lattice
In aleph, a Lattice is best thought of as a tool for interpreting lattice coordinates. Each instance of Lattice contains four pieces
of information:
- The primitive vectors of the lattice.
- The positions of each site in the crystal basis.
- The length of the lattice along each dimension.
- The boundary conditions of the lattice (either open or periodic) along each dimension.
Just as with a lattice coordinate, Lattice objects are created with the lattice function. There are several way to use lattice. First,
one can create a predefined lattice (any of the two dimensional Bravais lattices),
var rectangular_lattice = lattice("rectangular", [10, 14], ["a" : 1.25, "b" : 0.5]) //-> a 10 X 14 rectangular lattice with sides lengths 1.0 and 0.5.
rectangular_lattice.primitive_vectors() //-> [[1.25,0],[0,0.5]].
rectangular_lattice.basis_positions() //->[[0.0,0.0]]
Below are the predefined lattices and their expected parameters,
| Name | Parameters |
|---|---|
| "square" | "a" Intersite spacing |
| "rectangular" | "a" Intersite spacing along x-axis."b" Intersite spacing along y-axis. |
| "triangular" | "a" Intersite spacing. |
| "oblique" | "a" Intersite spacing along x-axis."b" Intersite spacing along other axis."theta" angle between primitive vectors. |
By default lattices have open boundaries. For more examples of lattices that can be constructed one can refer to the Lattice tutorial page.
Now that we have a Lattice we can use it to translate lattice coordinates into either physical positions or linear indices.
var LC = lattice_coordinate
rectangular_lattice.to_index(LC[10, 0]) //-> 10
rectangular_lattice.to_position(LC[10,2]) //-> [12.5, 1.0]
A Lattice can also be used to validate whether a coordinate is in the lattice.
rectangular_lattice.contains(LC([2,3])) //-> True
rectangular_lattice.contains(LC([100,12])) //-> False
It's useful to be able to loop through all the coordinates in the lattice in a systematic way. This can be achieved with the use of the lattice range method. For example,
for(coordinate : lattice_range(rectangular_lattice)) {
print(coordinate)
}
Neighbourhoods and Neighbourhood Rules
Interactions between degrees of freedom interacting on a lattice are often defined in terms of neighbourhoods (e.g. nearest neighbours, plaquettes, etc...). More precisely, a neighbourhood of sites is a collection of displacement coordinates, with . Let denote a lattice and let denote a set of neighbourhoods on the lattice. Any Hamiltonian may be written as,
where is an operator acting on a single lattice site that depends on the neighbourhood and is an interaction strength that depends on the neighbourhood and the position.
For example, on the lattice above, the nearest neighbour and next nearest neighbours along the and directions are given by,
var nn_x = neighbourhood_rule("nn_x", LC([0,1]))
var nn_y = neighbourhood_rule("nn_y", LC([1,0]))
We can store all the neighbourhoods associated with a list of neighbourhood rules using the neighbourhood table,
var neighbourhoods = neighbourhood_table([nn_x, nn_y], rectangular_lattice)
neighourhoods("nn_x") //->Pairs of indices for all the x nearest neighbours.