| name | adjoint-method-cfd |
| description | Adjoint method in CFD — continuous/discrete adjoint, sensitivity derivation, shape optimization, gradient computation, drag minimization, adjoint boundary conditions, OpenFOAM/SU2. |
| metadata | {"priority":7,"promptSignals":{"phrases":["adjoint method CFD","adjoint optimization","CFD shape optimization","sensitivity gradient CFD","discrete adjoint","continuous adjoint","drag minimization CFD"],"minScore":3}} |
Adjoint Method in CFD — Complete Skill
Motivation
Problem: design optimization requires gradients dJ/dα of objective J (drag, lift, pressure drop) with respect to n design variables α (shape parameters)
Finite difference: n+1 CFD solves → cost scales with n (expensive for 100s of variables)
Adjoint method: 1 adjoint solve (same cost as 1 primal CFD) → all n gradients simultaneously
Cost: O(1) regardless of number of design variables → enables high-dimensional optimization
Formulation
Primal problem (governing equations):
R(U, α) = 0 [R = residual vector; U = flow state (V, p, T); α = design variables]
Objective function:
J = J(U, α) [e.g., drag = ∫ (p n_x + τ_x) dA]
Lagrangian (augmented objective):
L = J(U, α) + λᵀ R(U, α) [λ = adjoint variables (co-state)]
Total derivative (exact gradient):
dJ/dα = ∂L/∂α = ∂J/∂α + λᵀ ∂R/∂α
Condition for adjoint equations (eliminate dU/dα):
(∂R/∂U)ᵀ λ = -(∂J/∂U)ᵀ ← Adjoint equations (same LHS structure as linearized primal)
Solution sequence:
- Solve primal: R(U, α) = 0 → U
- Solve adjoint: (∂R/∂U)ᵀ λ = -(∂J/∂U)ᵀ → λ
- Compute gradient: dJ/dα = ∂J/∂α + λᵀ ∂R/∂α
Continuous vs. Discrete Adjoint
Continuous Adjoint
Derive adjoint PDEs analytically from governing PDEs; then discretize
For Euler equations:
Primal: ∂U/∂t + ∂F_i/∂x_i = 0 [F = inviscid flux]
Adjoint PDEs: ∂λ/∂t + (∂F_i/∂U)ᵀ ∂λ/∂x_i = 0
Adjoint boundary conditions (from integration by parts):
On walls (no-slip): n_i λ_i = 0 [derived from primal BC]
At inlets/outlets: λ = specified from objective sensitivity
Advantages: physical interpretation; clean implementation; adjoint BCs analytically derived
Disadvantages: discretize adjoint separately → may not be consistent with primal discretization
Discrete Adjoint
Differentiate the discretized residual directly:
(∂R_h/∂U_h)ᵀ λ_h = -(∂J_h/∂U_h)ᵀ
R_h, U_h, J_h = discrete residual, state, objective
Implementation: algorithmic differentiation (AD/automatic differentiation) of primal solver code
Tools: Tapenade, ADOL-C, dco/c++, JAX, PyTorch (for DNN-based surrogates)
Advantages: exact gradient of discrete objective → consistent with line-search optimization
Disadvantages: requires access to source code; memory intensive (tape storage)
Shape Sensitivity and Mesh Morphing
Gradient on boundary (surface sensitivity):
After solving adjoint, surface sensitivity:
∂J/∂n = λᵀ ∂R/∂n [n = surface normal direction]
Volume mesh sensitivity:
Requires Jacobian of volume mesh deformation with respect to surface shape change
Methods: RBF (radial basis function) morphing; linear elasticity analogy
Shape gradient in parameterization:
If shape = Σ α_i φ_i(x,y,z) (control points, CAD parameters, FFD box)
dJ/dα_i = ∫_surface (∂J/∂n) × ∂n/∂α_i dA [chain rule through mesh]
Optimization Algorithm Integration
Gradient-based optimization loop:
- Primal solve → U, J
- Adjoint solve → λ
- Compute dJ/dα
- Update α: α_new = α_old - t × dJ/dα [steepest descent; or BFGS quasi-Newton]
- Mesh deformation
- Repeat until convergence (|dJ/dα| < ε)
BFGS update (recommended over steepest descent):
H_{k+1}⁻¹ = (I - ρ s yᵀ) H_k⁻¹ (I - ρ y sᵀ) + ρ s sᵀ
s = α_{k+1} - α_k; y = g_{k+1} - g_k; ρ = 1/(yᵀ s)
L-BFGS: limited memory version; suitable for 100s–1000s of design variables
Convergence criteria:
||dJ/dα|| < 10⁻⁴ × ||dJ/dα_0|| [relative gradient norm]
J change < 0.1% per 10 iterations → converged
Typical Drag Minimization Results
2D airfoil (Euler):
Starting NACA 0012; target Cl = 0.5 at M = 0.7
Variables: 24 Hicks-Henne bumps
Drag reduction: 20–40 counts (1 count = 10⁻⁴) in 20–50 iterations
Optimization time: ~10 primal solves equivalent
3D wing (RANS):
Variables: 100–500 shape parameters
Drag reduction: 10–30 counts in 30–100 iterations
Time: 50–200 primal solve equivalents (includes mesh deformation)
OpenFOAM and SU2 Implementation
SU2 (open source; MIT):
Built-in discrete adjoint for RANS equations
Run: SU2_CFD_AD config.cfg (primal + adjoint)
Run: SU2_DOT_AD grad.cfg (project gradient to design variables)
OpenFOAM adjointOptimisationFoam:
Continuous adjoint for incompressible RANS
constrainedOptimisation; volume/surface shape control
MeDiPack + SU2: automatic differentiation library coupling for external adjoint
Output
Provide: adjoint type (continuous/discrete), objective J definition (drag/pressure drop/lift), design variables (shape parameterization type and count n), sensitivity gradient dJ/dα vector, optimization algorithm (steepest descent/BFGS/L-BFGS), line search step size, convergence history (J vs. iteration), mesh morphing method (RBF/linear-elastic), expected drag reduction [counts or %], number of primal+adjoint solve pairs to convergence, and software tool (SU2/OpenFOAM).