Fourier Transforms
Fourier transforms are at the heart of many of the operations performed by the CosmoInterface. They are used, among other things, to set the initial fluctuations of the fields at the beginning of a run, and to compute power spectra of the various fields during the evolution. Unlike the local, finite-difference operations (gradients, Laplacians, ...), a Fourier transform is intrinsically non-local: every output mode depends on all input sites. This is what makes it the most delicate operation to parallelize, and the reason CosmoLattice relies on dedicated, highly optimized FFT libraries to perform it. Within CosmoLattice these libraries are driven by TempLat, the lattice library that forms its backbone.
The good news is that, just as with the parallelization strategies described in Section Parallelization, the user normally does not have to choose an FFT library by hand. CosmoLattice ships support for three backends and automatically builds the appropriate ones for your hardware during the CMake configuration.
All the user has to do is enable the relevant capabilities through a few CMake flags; the code takes care of the rest, and the same model runs unchanged on a laptop, a multi-core workstation, a GPU, or a large HPC cluster.
Fourier conventions
The continuum and discrete Fourier transform conventions used throughout CosmoLattice are defined in Section Conventions and Notation [see Eqs. (1) and (2)]. The backends documented here only change how the transform is computed, never what is computed: all of them reproduce, up to round-off, the same discrete transform.
The three backends
CosmoLattice can compute its Fourier transforms with any of the following libraries:
FFTW— the always-present CPU backend. It can be used for both serial runs and for distributed runs parallelized along a single direction. With GPU builds, it can be used, but incurs copy overhead between GPU and CPU RAM, and is therefore not recommended for performance-critical runs.KokkosFFT— the single-node GPU backend. It is pulled in automatically whenever you build for a GPU, and forwards the transform to the vendor library (cuFFTon NVIDIA,hipFFTon AMD) through Kokkos.ParaFaFT— the distributed backend for transforms parallelized along several directions. It is the modern replacement for thePFFTlibrary used in CosmoLattice 1.0 and builds on top of eitherFFTWon CPUs, orcuFFT/hipFFTon GPUs. It is only used when the code is built withMPIand automatically distributes over \(d-1\) spatial dimensions.
The following table summarizes when each backend is used and how it is enabled:
| Backend | Hardware | Distributed FFT | Used when | Enabled by |
|---|---|---|---|---|
FFTW |
CPU | along one dimension | CPU-build without MPI | always available |
KokkosFFT |
GPU (NVIDIA / AMD) | no (single node) | single-process GPU runs | -DCUDA=ON or -DHIP=ON (auto) |
ParaFaFT |
CPU or GPU | along several dimensions | multi-process runs in \(\geq 2\) dimensions | -DMPI=ON -DPARAFAFT=ON |
How a backend is chosen
At run time CosmoLattice inspects the build options and the number of MPI processes nproc and selects a backend according to the following priority:
- If the code was built with
MPIandParaFaFT, and you run on more than one process (nproc > 1) in two or more spatial dimensions, the distributedParaFaFTbackend is used. - Otherwise, if the code was built for a GPU (so that
KokkosFFTis available) and you run on a single process, theKokkosFFTbackend is used. - In all other cases, CosmoLattice falls back to
FFTW, which is always linked.
Note
Because FFTW is always available, a CosmoLattice executable always has a working FFT backend, whatever combination of flags you compiled with. The optional backends simply take over when they are both compiled in and applicable to the run at hand.
The full list of FFT-related CMake flags is collected in CMake flags. We now describe each backend in turn.
FFTW: the CPU backend
FFTW ("Fastest Fourier Transform in the West") is the default backend and is always linked into CosmoLattice — you do not need any special flag to use it. It is used for single-node runs and for distributed runs parallelized along a single direction (see Section Distributed parallelization in one direction), where its built-in MPI transforms split the lattice along one direction.
By default the transforms are computed in double precision. You can switch to single precision — which roughly halves the memory footprint of the transform at the (heavy) cost of precision — by passing
FFTW is expected to be available on the system. If it is not, you can let CMake download and build it for you with -DAUTOBUILD_FFTW=ON. See Installation for installation details and guidance on HPC clusters.
GPU Fourier transforms: KokkosFFT
When CosmoLattice is compiled for a GPU, single-node Fourier transforms are handled by KokkosFFT. This keeps the transform on the device — there is no need to copy the fields back to the host — and dispatches it, through Kokkos, to the vendor's native FFT library:
cuFFTon NVIDIA GPUs (-DCUDA=ON),hipFFTon AMD GPUs (-DHIP=ON).
You do not enable KokkosFFT explicitly: the -DKOKKOSFFT flag is switched on automatically as soon as a GPU backend is requested (and single-precision FFTW, -DFLOAT, is enabled along with it). A single-GPU run therefore needs nothing more than the usual GPU build:
cmake -DCUDA=ON -DMODEL=lphi4 ../ # NVIDIA GPU
cmake -DHIP=ON -DMODEL=lphi4 ../ # AMD GPU
make cosmolattice
Single device only
KokkosFFT handles transforms living entirely on a single GPU. To spread a simulation across several GPUs or nodes, combine a GPU build with the distributed ParaFaFT backend described below, whose cuFFT/hipFFT backends likewise keep the FFT on the device. The choice between KokkosFFT (one device) and ParaFaFT (several devices) is then made automatically depending on nproc.
Distributed Fourier transforms: ParaFaFT
Parallelizing the FFT along a single direction limits the number of processes to the linear lattice size \(N\). To scale further, the transform itself must be distributed over more than one direction. CosmoLattice does this with ParaFaFT (Parallel Fast Fourier Transform), a modern, header-only C++ library that replaces the PFFT library used in CosmoLattice 1.0.
ParaFaFT distributes a \(D\)-dimensional transform over a pencil decomposition built on a \((D-1)\)-dimensional grid of MPI processes (see the right-hand side of Fig. 3 in Section Distributed parallelization in multiple directions). Rather than performing explicit local transposes between the successive 1D transforms, it redistributes the data directly with advanced MPI collective operations (MPI_Alltoallw over subarray datatypes), following the algorithm of Dalcin, Mortensen & Keyes 1. Like KokkosFFT, it offers fftw3 (CPU), cuFFT (NVIDIA) and hipFFT (AMD) backends, so the same distributed transform runs on CPUs or on GPUs.
To enable it, pass -DPARAFAFT=ON. However, note that with -DMPI=ON, ParaFaFT is automatically enabled, so the following will use ParaFaFT for distributed runs in two or more dimensions:
mpirun (or your cluster's equivalent):
ParaFaFT requires MPI
The -DPARAFAFT=ON flag only takes effect together with -DMPI=ON. ParaFaFT is also a genuinely multi-dimensional distributed transform: it is used for runs with at least two spatial dimensions distributed over more than one process. Single-process runs fall back to FFTW (or KokkosFFT on a GPU) automatically.
Migrating from CosmoLattice 1.0
Support for the old PFFT backend has been discontinued. The flags -DPFFT and -DMYPFFT_PATH are no longer recognized — use -DPARAFAFT=ON instead. See CMake flags for the full list of deprecated options and their replacements.
Constraints and practical notes
A few constraints are worth keeping in mind when planning large or unusual runs:
- Lattice divisibility. For distributed runs, the number of sites per dimension \(N\) must be divisible by the number of processes used along each parallelized direction. When all directions share the same \(N\), this simply means \(N\) must be an integer multiple of the number of processes (see Section Parallelization).
- Dimensionality.
ParaFaFTis used for lattices with at least two spatial dimensions; in one-dimensional or single-process runs CosmoLattice falls back toFFTW.KokkosFFTcovers the single-node GPU case in up to three dimensions. Note that in 1D, TempLat does not support distributed parallelization. - Precision. Single precision support (
-DFLOAT=ON) is optional on the CPU but is enabled automatically together with the GPU backends. Note that setting this flag only builds support for single-precision computations - to actually run a model in single precision, you must specifyin your model'sstruct ModelPars : public TempLat::DefaultModelPars { // ... using FloatType = float; // or double // ... };ModelParsclass.
For the broader picture of how these FFT backends fit into CosmoLattice's overall parallelization strategy — distributed (MPI) versus shared-memory and GPU parallelism — see Section Parallelization. For the complete reference of compilation flags, see CMake flags, and for library installation, Installation.
-
L. Dalcin, M. Mortensen, and D. E. Keyes. Fast parallel multidimensional FFT using advanced MPI. J. Parallel Distrib. Comput., 128:137–150, 2019. arXiv:1804.09536. ↩