← Back
Home › Systems › Simulation and scientific computing

plasma-fusion-sim

plasma turbulence and fusion simulation

GENE, BOUT++

Open the plasma-fusion-sim pageplasma-fusion-sim Batch checkpoint restartdistributed: Large batch jobs (end-of-day, settlement, payroll runs) that checkpoint and restart idempotentlyHalo exchangedistributed: Each rank stores its block plus a border copy of its neighbours' edge cells, refreshed by small messages every step; communication scales with block surface, not volume.›Parallel file system stripingdistributed: Striping files across object storage targets (Lustre, GPFS); collective I/O and metadata serversGpu memory coalescing bankinghardware-os: Coalesced global loads, shared memory bank conflicts, L2 and HBM bandwidth on GPUsCUDA and GPU languageslanguages: Programming GPUs: thousands of lockstep threads, bound by memory bandwidth; libraries first, Triton for fused kernels, CUDA C++ for peak speed.›Collective communicationml-training: The family of group exchanges (broadcast, reduce, all-gather, reduce-scatter, all-to-all) and the latency-plus-bytes cost model that picks ring, tree or direct algorithms by message size and topology.›Kernel autotuningml-training: Searching tile sizes and launch parameters per shape/hardware, caching the best configsTensor layout transformsml-training: Choosing and converting tensor layouts (NCHW/NHWC, blocked, tiled) for kernel efficiencyAdaptive Runge-Kutta(Dormand-Prince)numerics: An embedded 5(4) Runge-Kutta pair estimates each step's error for free and resizes the step to meet a tolerance; the default non-stiff solver.›Fast Fourier transformnumerics: Computes the DFT in O(n log n) by recursively splitting into even and odd halves; the basis of fast convolution and spectral methods.›Finite differencesnumerics: Replace derivatives with weighted differences of grid values; simple stencils plus a stability condition (CFL) turn PDEs like heat, advection and waves into array loops.›Gmresnumerics: GMRES with restarts: Arnoldi, Givens rotations, for nonsymmetric sparse systemsMonte Carlo integrationnumerics: Estimate an expectation by averaging random samples; error falls as σ/√N in any dimension, and variance reduction (antithetic, control variates, importance sampling) shrinks σ.›Multigridnumerics: Smooths high-frequency error on the fine grid and solves the smooth remainder on coarser grids; O(n) elliptic solves at any resolution.›Runge-Kutta 4numerics: The classic four-stage, fourth-order ODE step; error drops 16× when the step halves, with no derivatives or past steps needed.›Spectral methodsnumerics: Represent the solution by a global Fourier or Chebyshev series; derivatives become multiplications by ik in coefficient space, giving exponential convergence for smooth problems.›Stiff solvers (implicit, BDF)numerics: Implicit steps solve a small nonlinear system so fast decaying modes stay stable at any step size; BDF methods are the stiff-ODE workhorse.›Chunked array storagestorage: Cut an N-dimensional array into a regular grid of independently compressed blocks, so a slice read touches only the overlapping blocks and writers to different blocks run in parallel.›Idempotency keysfinance: Client-chosen unique key per logical operation, stored with a request fingerprint and the final response, so retries replay the first result instead of acting twice.›Write-ahead logstorage: Append each change to a checksummed sequential log and fsync it before touching data pages; the basis of crash durability in nearly every database.›Cron schedulingsystems: Cron expression parsing and next-fire-time computation, with catch-up and time-zone rulesEager rendezvous protocoldistributed: MPI point-to-point: eager sends for small messages, rendezvous handshake for large onesZero-copy I/Onetworking: Move bytes between files, sockets and NICs by passing page references instead of copying through user space: sendfile, splice, MSG_ZEROCOPY, kTLS.›Rdmanetworking: RDMA verbs over InfiniBand/RoCE: queue pairs, memory registration, one-sided opsLeasesdistributed: A lock that expires on its own: bounded-time ownership that survives crashes and partitions, given bounded clock drift and fencing tokens on writes.›Range partitioningdistributed: Cut the sorted key space into contiguous half-open ranges kept in a boundary map; split hot or big ranges, merge small ones, move ranges between nodes.›Roofline modelhardware-os: Bound a kernel's speed by min(peak FLOP/s, arithmetic intensity × memory bandwidth) to know whether to optimize compute or data movement.›GPU compute shadersml-training: The vendor-neutral GPU launch model of Metal, Vulkan and WebGPU: a grid of workgroups, shared memory, barriers and subgroups, driven by recorded command buffers.›Tiled matrix multiplicationml-training: Block GEMM into tiles held in shared memory and registers, so each byte loaded from DRAM feeds many FMAs; the core of fast GEMM.›Robust statisticsstatistics: Location and scale estimates (median, MAD, trimmed mean, Huber M-estimator) that stay correct when a minority of the data is garbage.›+ 13 moreCryptographic hashes (SHA-2,BLAKE3)security: Collision-resistant fingerprints of data; SHA-256 for interoperability, BLAKE3 for speed, HMAC/HKDF for keyed uses.›Exponential backoff with jittersystems: Retry after delays that grow geometrically and are randomized, so failed clients spread out instead of hammering a recovering service in synchronized waves.›CRC32C checksumshardware-os: The Castagnoli CRC-32 with dedicated instructions on x86 (SSE4.2) and ARMv8. It is the standard fast integrity check for storage blocks, logs and network frames.›fsync, O_DSYNC and O_DIRECThardware-os: What fsync, fdatasync, O_DSYNC, O_DIRECT and F_FULLFSYNC really guarantee on Linux and macOS, and the exact call sequences for crash-safe files.›Fencing tokensdistributed: A number that grows with every lock grant and is checked by the protected resource, so a paused ex-holder's late write is rejected.›CPU caches and the memoryhierarchyhardware-os: Sizes, line widths and latencies of L1/L2/L3/DRAM on modern x86 and Apple M-series, and the data-layout rules that follow from them.›SIMD programminghardware-os: Process 4-16 lanes per instruction with AVX2, AVX-512 or NEON via Rust std::arch, with runtime dispatch and a portable fallback.›+ 3 more+ 2 more

How it is built

Architecture overview

A fusion plasma loses heat through small-scale turbulence, and how fast it loses it decides how large and expensive a reactor must be. A turbulence simulator evolves the plasma in a magnetic geometry over many turbulent eddy times and reports the heat and particle fluxes. Two model families are used. Gyrokinetic codes (GENE, CGYRO) follow the full distribution of particles over space and velocity, with the fast gyration around the field line averaged out, which leaves a five-dimensional field (three space dimensions, two velocity dimensions). Fluid codes (BOUT++) evolve a few moments (density, momentum, pressure, vorticity) of the plasma in three dimensions and are cheaper and more flexible about geometry. In both, the one idea that makes it work is a split of the problem by direction: a spectral method in the directions where the physics is local in wavenumber and periodic, finite differences or implicit solvers along the field line and in velocity, and a data transpose between the layouts that each step needs, which turns the whole system into a stencil-plus-FFT-plus-all-to-all machine.

Parts:

 equilibrium (shape, profiles, gradients) ─► setup ─► initial perturbation
                                                         │
        ┌───────────────── time loop (per step) ─────────▼──────────────────────┐
        │ collisionless step (explicit RK):                                     │
        │   streaming + drifts (finite diff) ─► field solve (allreduce)         │
        │   nonlinear bracket: FFT (kx,ky) ◄─ transpose ─► real space ─► FFT    │
        │ collision step (implicit): transpose ─► matrix-vector per (kx,θ)      │
        └───────────────────────────────┬───────────────────────────────────────┘
                                        ▼ fluxes, spectra, snapshots, checkpoints
        transport solver: profiles ◄── turbulent fluxes (reduced model or full code)

One run answers one question (the flux for given gradients at one radius, in a local "flux tube"). A profile solver wraps many such runs, or a fast surrogate model fitted to them, in an outer loop to predict how the whole plasma profile settles, which is why GACODE ships both the turbulence codes and a profile-evolution tool (TGYRO) and a reduced transport model (TGLF) (source: GACODE README).

How the parts fit together

Discretisation

CGYRO, the clearest documented case, treats each dimension with the method that suits it (source: GACODE CGYRO computational-performance page):

  • Perpendicular plane: Fourier in the radial and binormal wavenumbers (kx, ky), so the gyroaverage becomes a multiplication by Bessel functions of k⊥ρ and the gyroradius operator is diagonal. This is Spectral methods with a plane wave per mode.
  • Along the field line (θ): finite differences (Finite differences) with upwind dissipation for the streaming term; the equilibrium is not periodic here.
  • Velocity space: pseudospectral expansions: Legendre in pitch angle, generalised Laguerre in energy (parameters N_XI, N_ENERGY; defaults 16 and 8 in its docs). These make the collision operator a dense matrix of modest rank.
  • Nonlinearity: the E×B convolution (a Poisson bracket) is evaluated in real space by FFT with 3/2 zero-padding to prevent aliasing, using FFTW on CPU and cuFFT or rocFFT on GPU (Fast Fourier transform). Padding by 3/2 is the standard de-aliasing rule for a quadratic nonlinearity; omit it and energy piles up in the highest wavenumbers.

BOUT++ is the finite-difference counterpart: curvilinear coordinates, derivative operators on staggered or unstaggered grids, and a "shifted metric" or flux-coordinate-independent (FCI) parallel transform so the grid can follow sheared field lines (source: BOUT++ manual, "Parallel transforms"). Its design goal is that equations appear in readable form: ddt(rho) = -V_dot_Grad(v, rho) - rho*Div(v); (source: BOUT++ README), and the framework handles the grid, the operators, MPI and the time integrator.

Time advance

CGYRO uses operator splitting (source: same page). The collisionless part (parallel streaming, magnetic drifts, the instability drive, the nonlinear bracket) is advanced explicitly with RK4 or adaptive RK5(4)/RK7(6) (Runge-Kutta 4, Adaptive Runge-Kutta); its time step is limited by the fastest wave or flow crossing a grid cell (a CFL limit; its docs say the explicit scheme needs a smaller time step than a long-wavelength code). The collisional part is stiff, so it is advanced implicitly with a generalisation of Crank-Nicolson that reduces to a single matrix-vector multiply per (kx, θ) point; the matrix rank is the number of pitch-angle points times energy points times species. This is the plasma version of Stiff solvers (implicit BDF) done by a precomputed dense solve because the stiff coupling is local in space and small.

BOUT++ takes the other route: it hands the whole right-hand side to an ODE library. The manual lists solvers from a built-in RK4 to PVODE and the SUNDIALS family (CVODE, IDA, ARKODE), selected with the option solver:type, and calls CVODE the most commonly used one (source: BOUT++ manual, "Time integration"). CVODE is an implicit BDF/Adams solver with a Newton-Krylov inner loop, so its diagnostics print Newton iterations per step and linear iterations per Newton iteration, and it benefits from a preconditioner that the physics model supplies (BOUT++ has a preconditioning chapter). That is Newton root finding with a Krylov linear solver, i.e. gmres (no page yet) accelerated by something like Incomplete factorization preconditioners. Explicit Euler shows up only as a baseline or inside small subsystems.

Linear solves

Two solves occur in every step. The field solve (quasi-neutrality and Ampère's law in a gyrokinetic code) is, for each (kx, ky, θ), a tiny linear system whose right-hand side is an integral over velocity space; in CGYRO it is computed with a reduction over the velocity-space ranks (its kernel table lists an MPI_ALLREDUCE for this). In a fluid code the equivalent is the Laplacian inversion: from vorticity to the electric potential. BOUT++ ships several: a parallel cyclic solver, PETSc-based solvers, a geometric multigrid, an iterative solver for non-Boussinesq terms, and a serial tridiagonal solver (thomas-tridiagonal-solver, no page yet) (source: BOUT++ manual, "Laplacian inversion"). Multigrid is chosen when the operator is a full 3D elliptic one and the grid is large; the tridiagonal solve is O(n) and wins when the problem separates by Fourier mode.

Decomposition and communication

The distribution function is a large multi-index array, and each kernel wants a different index to be local. CGYRO defines three layouts, one for the linear terms (streaming, field), one for the collisions (velocity indices local, space distributed) and one for the nonlinear FFT (kx, ky local); it moves between them with MPI all-to-all transposes, uses all-reduces for the field solve, and its documentation names the communication cost of each kernel next to its compute cost (source: CGYRO performance page). The cost model is therefore: compute per kernel plus a transpose per layout change. This is the central trade of the system and is the reason tensor-layout-transforms (no page yet) matter: a layout change costs a global exchange (Collective communication), so the choice of process grid decides how much of that exchange stays inside a node.

BOUT++ is a simpler case: a 3D domain decomposition in x and y (z is kept local for the spectral and shifted-metric steps), and a Halo exchange of guard cells between neighbours before each derivative. Graph partitioning enters only for unstructured grids and is not the usual case here.

Node kernels

Inside a rank, the work is arithmetic on large arrays with little reuse, so the kernels are bandwidth-bound: the Roofline model is the standard check. CGYRO is written in Fortran with GPU offload by OpenACC or OpenMP, GPU-aware MPI, and has been ported from NVIDIA to AMD systems (source: CGYRO performance page). The knobs are the usual ones for CUDA and GPU languages: coalesced loads along the fastest-varying index (gpu-memory-coalescing-banking, no page yet), kernel launch shapes tuned per machine (kernel-autotuning, no page yet), SIMD programming on CPU, and layouts that fit CPU caches and memory hierarchy. Precision is a lever too: CGYRO has flags to run the upwind communication and the nonlinear term in 32-bit precision (UPWIND_SINGLE_FLAG, NL_SINGLE_FLAG), trading a little accuracy for speed and message size (source: CGYRO input parameter docs).

Particle methods

The alternative to a grid in velocity is to follow markers: a sample of particles carrying weights, advanced through the fields and deposited back on a mesh (particle-in-cell). It scales to high dimension because cost does not grow as a grid product, and handles complex geometry well, but the result carries sampling noise that falls only as 1/√N (Monte Carlo), so noise control (weight schemes, conservation fixes, sorting for cache efficiency) is its main engineering problem. Marker loading draws from the equilibrium distribution, which is where rejection-sampling (no page yet) comes in. The Eulerian (grid) codes above have no noise and exact conservation properties for the discretisation, at the price of a velocity grid.

Output and restart

A run is long (many eddy times, on thousands of devices), so it must survive failures: periodic checkpoints of the distribution function, written in parallel (Checkpoint and restart), and diagnostics (fluxes as time series, spectra, snapshots) written far more often but much smaller. Large arrays go into chunked, compressed containers (Chunked array storage, Zstandard) on a striped parallel file system (parallel-file-system-striping, no page yet), and the allocation logic that resubmits a job from its last checkpoint is batch-checkpoint-restart (no page yet).

Data and control flow

One time step of a gyrokinetic code (CGYRO-style):

  1. Evaluate the field solve: velocity-space integrals of the distribution on each rank, an all-reduce, the three field potentials per (kx, ky, θ).
  2. Evaluate the streaming kernel (linear terms) with finite differences along θ and add the drive from the gradients.
  3. Evaluate the nonlinear term: transpose to the (kx, ky)-local layout, apply the 3/2-padded 2D FFTs, multiply in real space, transform back, transpose back.
  4. Advance the explicit scheme (RK stages repeat 1-3, with the field solve each stage).
  5. Collision step: transpose so velocity indices are local, apply the precomputed matrix, transpose back.
  6. Every N steps: record fluxes and spectra; at a longer interval, write a checkpoint. Time goes to the nonlinear kernel (FFT plus its transposes), the collision matrix-vector product and the all-to-all communication; the CGYRO performance page tabulates the dominant operation of each kernel and its communication.

One physics answer end to end:

  1. Choose a flux surface, geometry and the local gradients from an experimental or predicted profile.
  2. Run a linear scan first (cheap): which wavenumbers are unstable and how fast they grow. This sets the resolution and time step for the expensive nonlinear run.
  3. Run the nonlinear simulation until the fluxes reach a statistically steady state, discard the transient, average.
  4. Feed the flux into the profile solver or fit a reduced model to many such runs; iterate until the profiles stop changing.

Scaling

In the order they bite:

  1. Resolution in five dimensions. Cost grows with the product of the grid sizes and the number of steps, and steps grow as the grid refines. Levers: flux-tube (local) geometry instead of the full torus, fewer toroidal modes, velocity spectral methods with few points, adaptive time step.
  2. Communication. The transposes are global exchanges and stop scaling when the message size per pair gets small. Levers: a decomposition that keeps the big all-to-alls inside a node or a fast sub-network, 32-bit communication, overlap with compute.
  3. Per-device speed. Levers: GPU offload, fewer passes over the array, fused kernels, layouts matched to the fastest index.
  4. Statistics. Turbulence needs long averages; a short run gives a noisy flux. Levers: longer runs, ensembles, and the reduced-model ladder (a fast model screens, the full code verifies).
  5. IO and reliability. Checkpoints are the size of the state; at scale they dominate if too frequent. Levers: interval from expected failure rate, striping, compression of diagnostics. For measured scaling, read the CGYRO papers on petascale and GPU-portable performance listed on its documentation page rather than quoting numbers here.

Failure modes

FailureSymptomCauseFix
Aliasingenergy piles up at the highest wavenumbers, run blows upnonlinear product without zero-padding3/2 padding, or filter; check spectra
Time-step violationNaN or exponentially growing noisestep above the CFL limit of streaming or E×B flowsmaller or adaptive step, check the largest wavenumber
Under-resolved velocity spacespurious oscillation in the distribution, wrong fluxestoo few pitch-angle or energy pointsconvergence scan on N_XI/N_ENERGY
Unconverged statisticsflux changes with run lengthaveraging window too short or transient includedrun longer, discard initial phase, check time series
Wrong layout communicationscaling stops at modest node countall-to-all too large or off the fast networkchange the process grid; match decomposition to topology
Particle noiseflux dominated by sampling noisetoo few markers, weight growthmore markers, noise control, conservation correction
Solver stagnation (fluid)CVODE takes many Newton or Krylov iterations per stepweak or no preconditioner, very stiff parallel termsprovide a physics preconditioner; tune tolerances
Checkpoint mismatchrestart changes the answerdifferent build, precision or layoutrestart with identical settings; test restart on a short run
Profile solver not convergingouter iteration oscillatesnoisy fluxes fed to the transport solversmooth fluxes, damped update, a reduced model between

Real implementations

namewhat it isrepolicencenotes
CGYRO (GACODE)Eulerian gyrokinetic solver, global-spectral, GPU capablegafusion/gacodeGPL-3.0also holds GYRO, NEO, TGLF, TGYRO; Fortran
BOUT++framework for fluid and plasma models in curvilinear geometryboutproject/BOUT-devLGPL-3.0C++; RK4, PVODE, SUNDIALS and PETSc solvers
GENEEulerian gyrokinetic turbulence code, local and global versionsgenecode.org—project site; reference papers below

The alternative: a particle-in-cell gyrokinetic code trades the velocity grid for markers: it handles geometry and high dimension more easily and has a noise floor instead of a resolution floor. The continuum approach suits cases where quiet, conservative results and clean linear-to-nonlinear convergence studies matter; the particle approach suits large-scale global runs with edge geometry. Use a fluid model (BOUT++ style) when the physics is collisional enough that moments are a good description or when edge geometry dominates and a kinetic code is too costly.

Sources

  • Candy, Belli and Bravenec, A high-accuracy Eulerian gyrokinetic solver for collisional plasmas, Journal of Computational Physics (2016). doi
  • Candy and Waltz, An Eulerian gyrokinetic-Maxwell solver, Journal of Computational Physics (2003). doi
  • Dudson et al., BOUT++: A framework for parallel plasma fluid simulations, Computer Physics Communications (2009). doi
  • Görler et al., The global version of the gyrokinetic turbulence code GENE, Journal of Computational Physics (2011). doi
  • Jenko, Dorland, Kotschenreuther et al., Electron temperature gradient driven turbulence, Physics of Plasmas (2000). doi
  • GACODE documentation: CGYRO and computational performance.
  • BOUT++ manual: bout-dev.readthedocs.io (time integration, Laplacian inversion, parallel transforms, preconditioning); GENE.

Similar systems

Share the most building blocks with this one.