The lattice

A lattice object fixes the geometry: how many dimensions there are and how long each is, how the sites are spread over the ranks, and the default number of colors. Everything else hangs off it. More than one lattice may be alive at once, and fields on different lattices never mix; the field constructors are methods of the lattice for exactly that reason.

qcd.lattice

qcd.lattice{d0, d1, ...}                          --> lattice
qcd.lattice({d0, d1, ...}, options)               --> lattice

Creates a lattice of the given dimensions. Every extent must be positive, and the number of dimensions must not exceed QLUA_MAX_LATTICE_RANK. The options are

KeyMeaning
networkthe process grid, one entry per axis; the product must be the number of ranks
netblocka blocking of the process grid; needs network, and each entry must divide it
nodemap"lex" or "rlex" — how grid coordinates map to rank numbers

Without network, QDP chooses the grid.

local L  = qcd.lattice{16, 16, 16, 32}
local L2 = qcd.lattice({16,16,16,32}, {network = {1,1,2,2}, nodemap = "lex"})

Length and indexing

#L                                                --> number
L[d]                                              --> number

#L is the number of dimensions; L[d] is the extent along axis d, counted from 0. A lattice is read-only: assigning to L[d] raises.

L:volume

L:volume()                                        --> number

The total number of sites.

L:node

L:node()                                          --> number

The calling rank's number — the same value as os.node(). It is a method of the lattice only because QDP keeps the number there; it says nothing about the lattice.

L:network

L:network()                                       --> table

The shape of the rank grid this lattice was laid out on, as a list with one entry per axis: how many ranks the sites along that axis are divided among. The product is the number of ranks in the job.

L:report

L:report()                                        --> nothing

Prints, from every rank, a line naming the rank, the host, its coordinates in the process grid and the range of sites it owns, then waits at a barrier. A diagnostic for checking a layout.

L:defaults

L:defaults()                                      --> table
L:defaults{colors = n}                            --> table

Reads or sets the lattice's default number of colors, which is what the un-suffixed constructors (L:ColorVector(), not L:ColorVectorN(n)) use. It starts at 3.

L:pcoord

L:pcoord(d)                                       --> L:Int

A lattice Int field holding each site's coordinate along axis d. The usual way to build masks, momenta and time slices.

local t = L:pcoord(3)
local on_t0 = L:Subset(qcd.eq(t, 0))

L:planewave

L:planewave(x0, p)                                --> L:Complex

The field exp(2πi · Σ_mu p[mu]·(x[mu] − x0[mu]) / L[mu]). x0 is a site coordinate as a list, p is a list of numbers of the same length.

L:everywhere

L:everywhere(f, ...)                              --> f's results

Calls f(...) with the lattice's subset temporarily set to all sites, and restores the subset afterwards. The escape hatch from inside a Subset:where block.

Subsets

A subset restricts which sites the operations inside a block touch. It is not a separate field type: it is a mode the lattice is in while the block runs, which is why the entry point is Subset:where rather than a per-call argument.

L:Subset

L:Subset("all" | "even" | "odd")                  --> subset
L:Subset{axis = d, pos = k [, semispace = "upper"|"lower"]}
L:Subset{axis = d, pos = {k1, k2, ...}}
L:Subset(mask)                                    --> subset

The four forms are: a named subset; one hyperplane at coordinate k along axis d, optionally extended to the half-space above or below it; a list of hyperplanes; and an arbitrary subset given by a lattice Int mask, where a non-zero entry selects the site. position is accepted as a synonym for pos; giving both raises.

local even   = L:Subset("even")
local t5     = L:Subset{axis = 3, pos = 5}
local future = L:Subset{axis = 3, pos = 5, semispace = "upper"}
local picked = L:Subset(qcd.lt(L:pcoord(0), 4))

Subset:where

U:where(f, ...)                                   --> f's results

Runs f(...) with the subset active and returns whatever f returns. Every field operation inside — assignments, reductions, solves — sees only the selected sites. The subset is restored even if f raises.

local s = L:Subset("even")
s:where(function() psi:set(chi) end)              -- only the even sites
local n = s:where(function() return psi:norm2() end)

Subset:lattice

U.lattice                                         --> lattice

The lattice the subset belongs to. Every lattice-derived object carries this field.

MultiSets

A multiset labels every site with a small integer, so that a reduction can produce one number per label instead of one number overall. The standard use is a time-slice sum.

L:MultiSet

L:MultiSet(size, labels)                          --> multiset

size is the number of labels, labels a lattice Int field whose values pick one each. Sites labeled outside [0, size) are dropped.

local t    = L:pcoord(3)
local tset = L:MultiSet(L[3], t)
local c2pt = qcd.dot(prop, prop):sum(tset)        -- vector.complex of length L[3]

Lattice fields describes the :sum that takes one; L:Complex:project is the other consumer.