Loading...
Searching...
No Matches
q3::lattice_fourier_transform Namespace Reference

Namespaces

namespace  internal
 

Functions

std::vector< Complex > to_kpoint (const Vector3D &kpoint_crystal, const std::vector< std::vector< Complex > > &values_at_lattice_vectors, const std::vector< IntegerVector3D > &lattice_translations, const std::vector< Real > &weights)
 
std::vector< std::vector< Complex > > to_real_space (const std::vector< Vector3D > &kpoints_crystal, const std::vector< std::vector< Complex > > &values_at_kpoints, const std::vector< IntegerVector3D > &lattice_translations)
 

Detailed Description

lattice_fourier_transform — the discrete Fourier pair between a k-point set and a set of lattice vectors.

f(R) = (1/N_k) sum_k e^{-2 pi i k.R} f(k) to_real_space() f(k) = sum_R w_R e^{+2 pi i k.R} f(R) to_kpoint()

k-points and translations are both in crystal coordinates, so the phase is the plain dot product with no lattice matrix in sight – which is why this belongs beside the k-point grid and the Wigner-Seitz supercell rather than inside any one consumer.

Values are flat blocks of arbitrary, equal size, transformed element by element: a matrix (Wannier interpolation transforms U^dagger E U) and a single band energy (a Fourier star-function fit; a block of one) go through the same code.

This is NOT an FFT and deliberately does not use the FFT machinery in layer 3. The forward transform lands on a Wigner-Seitz set with fractional boundary weights rather than on a rectangular box, and the inverse is evaluated at arbitrary k off any grid, which an FFT cannot do at all. At the sizes involved – hundreds of k-points, blocks of a few orbitals – a direct sum costs microseconds and an FFT plan would cost more than the work.

The weights belong to the inverse alone. The forward transform divides by the k-point count; the degeneracy weights of a Wigner-Seitz boundary vector enter when the sum over R is taken, and their total must come back to the k-point count – the identity every consumer of a transformed model checks.

Function Documentation

◆ to_kpoint()

std::vector< Complex > q3::lattice_fourier_transform::to_kpoint ( const Vector3D &  kpoint_crystal,
const std::vector< std::vector< Complex > > &  values_at_lattice_vectors,
const std::vector< IntegerVector3D > &  lattice_translations,
const std::vector< Real > &  weights 
)
inline

f(k) = sum_R w_R e^{+2 pi i k.R} f(R), the inverse, at one arbitrary k.

kpoint_crystal need not lie on any mesh – evaluating between the mesh points is what an interpolated model is for. weights are the Bloch-sum weights, 1/degeneracy for a Wigner-Seitz boundary vector and 1 otherwise; they are passed alongside the translations rather than as a struct so that a caller storing them in its own type needs no per-call conversion on what is, for a dense mesh sampling, the hot path.

Definition at line 132 of file lattice_fourier_transform.hpp.

References q3::lattice_fourier_transform::internal::phase().

◆ to_real_space()

std::vector< std::vector< Complex > > q3::lattice_fourier_transform::to_real_space ( const std::vector< Vector3D > &  kpoints_crystal,
const std::vector< std::vector< Complex > > &  values_at_kpoints,
const std::vector< IntegerVector3D > &  lattice_translations 
)
inline

f(R) = (1/N_k) sum_k e^{-2 pi i k.R} f(k), one block per lattice vector.

values_at_kpoints holds one equally sized block per k-point, in the order of kpoints_crystal. The k-set must be the full, unreduced grid the model was built on: a symmetry-reduced set would weight the sum wrongly, and this function has no way to detect that, so its callers own that guarantee.

k outermost so each k-point's phase is computed once per lattice vector rather than once per element, and the block is streamed contiguously.

Definition at line 67 of file lattice_fourier_transform.hpp.

References q3::lattice_fourier_transform::internal::phase().