tensor/transporter

Search:
Group by:

Transporter - Parallel Transport with MPI Halo Exchange

This module provides parallel transport operations for lattice gauge theory. Unlike stencils (which are local), transporters handle MPI communication for accessing neighbors across rank boundaries.

Key concepts:

  • Shifter: Shift fields in a direction (no gauge link multiplication)
  • Transporter: Parallel transport with gauge link multiplication (covariant)
  • HaloBuffer: Communication buffers for boundary exchange

Design Philosophy:

  • Explicit direction handling with compile-time safety
  • Support for forward (+) and backward (-) transport
  • Covariant derivatives: D_μ ψ = (U_μ(x) ψ(x+μ) - ψ(x)) / a
  • AoSoA-aware for SIMD vectorization
  • Multi-device and MPI compatible

Example usage:

# Create shifters for all directions
let shifters = newShifters(field, len=1)

# Shift field forward in direction 0
let shifted = shifters[0] ^* field

# Create transporters with gauge links
let transporters = newTransporters(gaugeField, field, len=1)

# Parallel transport: U_μ(x) * ψ(x+μ)
let transported = transporters[0] ^* field

# Covariant derivative in direction μ
let Dpsi = covariantDerivative(gaugeField, psi, mu)

Inspired by QEX's transporters but with a cleaner API for LGT.

Types

CovariantDerivativeDir = enum
  cdForward, cdBackward, cdSymmetric
Direction type for covariant derivative
HaloRegion[D] = object
  dim*: int
  direction*: int
  thickness*: int
  localGeom*: array[D, int]
  lo*: array[D, int]
  hi*: array[D, int]
  nSites*: int
Description of a halo region for communication
ShiftDir = object
  dim*: int
  len*: int
Direction and displacement for shifting/transport
Shifter[D; T] = object
  dim*: int
  len*: int
  indices*: ShiftIndices[D]
  sendBuf*: seq[T]
  recvBuf*: seq[T]

Shifter for moving fields in a direction

Handles MPI communication for boundary sites. Use ^* operator to apply: shifted = shifter ^* field

ShiftIndices[D] = object
  dim*: int
  len*: int
  localGeom*: array[D, int]
  nSites*: int
  localIdx*: seq[int32]
  isLocal*: seq[bool]
  sendSites*: seq[int32]
  recvSites*: seq[int32]
  nSendSites*: int
  nRecvSites*: int

Pre-computed indices for a shift operation

For each local site, stores where to get the shifted value:

  • If isLocali: source is localIdxi (within this rank)
  • Else: source is from receive buffer at recvIdxi
Transporter[D; U; F] = object
  dim*: int
  len*: int
  indices*: ShiftIndices[D]
  link*: ptr U
  sendBuf*: seq[F]
  recvBuf*: seq[F]

Transporter for gauge-covariant field shifting

Multiplies by gauge link during transport:

  • Forward: U_μ(x) * ψ(x+μ)
  • Backward: U_μ(x-μ)† * ψ(x-μ)
TransportPattern[D] = object
  stencil*: Stencil[D]
  shiftIndices*: seq[ShiftIndices[D]]

A pattern of transport operations

Combines stencil geometry with gauge link information for efficient multi-direction transport.

Procs

proc `$`(sd: ShiftDir): string {....raises: [], tags: [], forbids: [].}
proc applyShiftLocal[D: static int; T](shifter: Shifter[D, T];
                                       source: openArray[T];
                                       dest: var openArray[T])

Apply shift operation (local sites only, no MPI)

For sites that need data from other ranks, uses periodic wrapping within the local domain (single-rank mode).

proc backward(dim: int): ShiftDir {.inline, ...raises: [], tags: [], forbids: [].}
Backward shift in dimension dim (length -1)
proc backwardShiftIdx(pattern: TransportPattern; dim: int): int {.inline.}
Get index of backward shift indices for dimension dim
proc covariantShiftBackward[T](gaugeLinkShifted: T; psiShifted: T): T {.inline.}

Backward covariant shift: U_μ(x-μ)† * ψ(x-μ)

Note: gaugeLinkShifted should already be the adjoint of U_μ(x-μ)

proc covariantShiftForward[T](gaugeLink: T; psiShifted: T): T {.inline.}

Forward covariant shift: U_μ(x) * ψ(x+μ)

This is the basic building block for covariant derivatives and Wilson-Dirac operators.

proc forward(dim: int): ShiftDir {.inline, ...raises: [], tags: [], forbids: [].}
Forward shift in dimension dim (length +1)
proc forwardShiftIdx(pattern: TransportPattern; dim: int): int {.inline.}
Get index of forward shift indices for dimension dim
proc newBackwardShifters[D: static int; T](localGeom: array[D, int];
    len: int = 1): array[D, Shifter[D, T]]
Create backward shifters for all D directions
proc newHaloRegion[D: static int](dim: int; direction: int; thickness: int;
                                  localGeom: array[D, int]): HaloRegion[D]
Create a halo region description
proc newShifter[D: static int; T](localGeom: array[D, int]; dim: int;
                                  len: int = 1): Shifter[D, T]
Create a shifter for the given direction and length
proc newShifters[D: static int; T](localGeom: array[D, int]; len: int = 1): array[
    D, Shifter[D, T]]
Create shifters for all D directions
proc newShiftIndices[D: static int](dim: int; len: int; localGeom: array[D, int]): ShiftIndices[
    D]

Create pre-computed shift indices

For shift in dimension dim by len sites. Positive len = forward shift (access site at x+len) Negative len = backward shift (access site at x-len)

proc newTransporter[D: static int; U, F](localGeom: array[D, int];
    gaugeField: ptr U; dim: int; len: int = 1): Transporter[D, U, F]
Create a transporter for the given direction
proc newTransportPattern[D: static int](localGeom: array[D, int]; len: int = 1): TransportPattern[
    D]
Create transport pattern for nearest-neighbor transport
proc shift(dim: int; len: int = 1): ShiftDir {.inline, ...raises: [], tags: [],
    forbids: [].}
Create a shift in dimension dim with length len

Templates

template `^*`[D: static int; T](shifter: Shifter[D, T]; source: openArray[T]): seq[
    T]

Apply shifter to source field (single-rank mode)

Returns shifted field: resultx = sourcex + shift