CuAD: Source-to-Source Automatic Differentiation for CUDA
🔍 Project Overview
CuAD (CUDA Automatic Differentiation) reads CUDA kernels and writes their derivatives as new CUDA source: a forward (tangent) companion f_d and a reverse (adjoint) companion f_b for each __global__ / __device__ function. Because it differentiates the kernel source itself, every derivative is exact (no finite differences), and the generated kernels run on the GPU like the originals.
CuAD was developed for the exact discrete adjoint of CuDAFLOW, where it differentiates the flux, viscous, and turbulence-model residual kernels.
đź“„ Paper
CuAD: Source-to-Source Automatic Differentiation of CUDA Kernels for Discrete Adjoints in Computational Fluid Dynamics, arXiv:2610.26694 (publication page).
- Under the no-aliasing convention of CUDA kernels, the reverse sweep recomputes instead of storing. On a Biot–Savart summation the CuAD adjoint costs about four times the primal at every size, while the heap-based tapes of Clad and Enzyme (without
__restrict__) cost 9 to 4400 times the primal. - For a transonic NACA 0012, the residual, both boundary conditions and the wall force are differentiated without change to the source, and the adjoint and tangent shape sensitivities agree to 1e-13.


🛠️ Key Features
- Forward and reverse mode, including calls between user functions (each callee gets its own companion).
- Activity analysis: only variables that depend on active inputs are differentiated.
- Recompute rather than store: under the convention that a kernel’s inputs and outputs do not alias, loops are recomputed in the reverse sweep; only scalars carried between iterations are checkpointed, and pure accumulations (
v = v + e) need nothing. - Thread-local tape: values that must be restored go to a fixed-size per-thread array, not to the device heap.
- GPU-safe adjoint accumulation:
atomicAddfor shared arrays, plain+=for thread-local data. - Loops and control flow: grid-stride loops, per-iteration recomputation,
#pragma unroll, early exits,c ? a : b. - C++ constructs: function templates, default arguments, reference outputs, local pointers and arrays of pointers.
- Math library: trigonometric, exponential, power,
atan2,hypot,copysign,cbrt, and more, in float and double.
🆕 Improvements over the Version Bundled in CuDAFLOW
- Fixes for silently wrong derivatives, each checked against finite differences:
c ? a : b(its adjoint was dropped), a one-sidedifin the middle of a function (the reverse sweep ran in the wrong order), value-returning user functions nested in expressions (adjoint was 0), andcopysign. - Less tape: pure accumulations need no tape, and recompute loops replay their primal without pushes.
- Broader language coverage: templates, default arguments, reference outputs, array parameters, local pointers, early exits, branch-local declarations, bare blocks,
#pragma unroll, in-place updates of local arrays in loops. - More math functions:
atan2,atan,asin,acos,hypot,cbrt,copysign, and piecewise-constantfloor/ceil/round.
âś… Verification
The test suite checks every generated tangent and adjoint against central finite differences and with adjoint dot-product tests (⟨y̅, J ẋ⟩ = ⟨Jᵀ y̅, ẋ⟩):
| Case | Check |
|---|---|
| Small kernels (scalar math, loops, overwritten values, device calls, atomic scatter) | Tangent and adjoint vs. FD, relative error ~1e-11 |
| CuDAFLOW kernels (conservative-to-primitive, cell volume) | Tangent FD and adjoint dot test |
| Mesh shape optimisation and NACA 0012 inverse design | Adjoint gradient vs. FD, then converged optimisation |
| Spalart–Allmaras field inversion (FIML) | SA source adjoint dot test; recovers the correction field β |
| Loops carrying scalars between iterations (v0.2.1) | Adjoint vs. FD, relative error ~1e-10 |
| Transonic NACA 0012, 2-D Euler (paper) | Adjoint vs. tangent shape sensitivities, 5e-14 |
đź§Ş Technical Skills Demonstrated
- Languages / tools: C++17, CUDA, Clang LibTooling (AST analysis and source rewriting)
- Methods: Algorithmic differentiation (tangent and adjoint), activity analysis, taping, discrete adjoint methods
GPL-3.0.
