When researchers transition from incompressible to compressible flow simulations in Python, they encounter fundamentally different physics — density becomes a variable, the energy equation must be solved, and shock waves introduce discontinuities that standard numerical methods simply cannot handle. This article covers what makes supersonic flow different, the shock-capturing methods designed to handle it, and the Python solvers that implement these methods for aerospace applications.
Key Takeaways
- Compressible flow requires solving the compressible Navier–Stokes equations with density as a variable and the energy equation coupled — unlike incompressible flow where density is constant.
- Shock-capturing methods (Roe, AUSM, TVD, WENO, TENO) are essential because shocks introduce discontinuities. The Roe scheme needs entropy fix and carbuncle protection on strong shocks.
- Python solvers for compressible flow are now production-grade: pyBaram (unstructured grids, 2022), OpenSBLI v3.0 (automated code generation, CPC 2025), JANC (differentiable GPU solver, April 2025), and pygasflow (quasi-1D analytical).
- Benchmark cases like the Sod shock tube and Shu–Osher problem provide standard validation for shock-capturing accuracy.
- MUSCL-TVD is cheaper but oscillates near discontinuities; 5th-order WENO gives superior resolution but costs more. For DNS/ILES of shock-boundary-layer interactions, WENO/TENO is the current standard.
- pygasflow and the open-source Python-shock-tube repository provide accessible entry points for understanding shock physics before committing to production solvers.
What Makes Supersonic Flow Different from Incompressible Flow
In incompressible flow, density is treated as a constant. The momentum equations are solved independently of the energy equation, and the pressure is determined solely by the velocity field through a pressure–velocity coupling algorithm (like SIMPLE or PISO). This means that for low-speed flows, you can solve the momentum and continuity equations without ever knowing the fluid’s density changes — it’s a given.
In compressible flow, everything changes. The density becomes a variable that evolves according to the continuity equation, the momentum equations, and the energy equation. The fluid’s thermodynamic state — pressure, temperature, and density — are coupled through the equation of state (typically the ideal gas law for aerospace applications). This means you cannot decouple the momentum from the energy equation. The solver must track how pressure waves propagate through the fluid, and these waves travel at the speed of sound.
The dimensionless parameter that governs this transition is the Mach number — the ratio of flow velocity to the local speed of sound. When M < 0.3, density changes are typically small enough that the incompressible assumption holds. When M > 1 (supersonic), the flow contains shock waves — discontinuities where density, pressure, and temperature jump almost instantaneously across a narrow region.
For aerospace researchers using Python, this means the Python CFD primer (Post 390) — which covers FiPy, SU2, and JAX-Fluids primarily for incompressible flows — leaves a significant gap. You need to understand:
- The compressible Navier–Stokes equations in their full form, including the energy equation
- Riemann solvers that compute fluxes across cell faces where discontinuities may exist
- Reconstruction methods that determine how variables interpolate from cell centers to faces
- Time integration schemes that respect the stricter CFL constraints at high Mach numbers
- Special numerical treatments like entropy fix and carbuncle protection
This is not a simple extension of incompressible flow — it’s a different numerical methodology applied to a different physical regime.
Shock-Capturing Methods: From Roe to WENO
When a shock wave forms, the flow variables change discontinuously over a distance smaller than any physical grid can resolve. Instead of trying to resolve shocks directly (which would require impossibly fine grids), shock-capturing methods allow the numerical scheme to absorb the discontinuity within a few cells, using numerical dissipation to stabilize the solution.
The Roe Scheme and Why It Needs Fixes
The Roe scheme, introduced by Peter Roe in 1978, is an approximate Riemann solver that linearizes the Euler equations around the cell-face state. It’s computationally efficient and was the dominant shock-capturing method for decades. The idea is simple: at each cell face, you solve a linearized version of the Riemann problem (the initial value problem for discontinuous data), compute the flux, and add numerical dissipation proportional to the wave speeds.
In Python, the Roe scheme implementation from arXiv 2103.02794 follows this pattern:
# Roe scheme flux computation (simplified from arXiv 2103.02794)
def roe_flux(uL, uR, n):
"""Compute Roe flux for Euler equations.
uL, uR: left and right primitive states [rho, u, P]
n: normal direction (1 or -1 for 1D)
"""
rhoL, uL, P_L = uL
rhoR, uR, P_R = uR
# Compute interface states
rho_hat = (rhoL**2 * rhoR**2 /
(rhoL + rhoR))**0.5
u_hat = (rhoL * uL + rhoR * uR) / (rhoL + rhoR)
# Speed of sound
S_hat = ((P_L + P_R) /
(2 * (rhoL + rhoR)))**0.5
# Compute Roe matrix eigenvalues
# |u_hat| +/- S_hat for acoustic waves
# |u_hat| for shear/convection
# ... eigenvalue computation omitted for brevity
The problem with the basic Roe scheme is twofold. First, at strong shocks, the scheme can develop negative pressure — an unphysical state that causes the solver to crash. This is addressed by the entropy fix, which modifies the wave speeds near shocks to restore convexity of the flux function and prevent non-physical states.
Second, on unstructured grids, the Roe scheme can exhibit the carbuncle phenomenon — a numerical instability where a strong shock (like the one formed behind a blunt body) develops a non-physical second shock branching off the main shock. This occurs because the Roe scheme is overly sensitive to the grid orientation at strong shocks. The “shock-stable Roe scheme” combines entropy fix with a rotated Riemann solver to cure this. For researchers working on aerospace geometries with strong shocks (like supersonic cylinders or blunt bodies), omitting carbuncle protection can cause solver failures.
AUSM: Splitting the Flux
The Advection Upstream Splitting Method (AUSM) takes a different approach. Instead of computing Roe’s matrix, AUSM splits the flux into advective and pressure components. This makes it robust at both high Mach numbers and strong shocks without requiring entropy fix — the splitting inherently handles the physical entropy condition. AUSM variants (AUSM+, AUSM+, AUSM+) and their successors (AUSMPWR+) are among the most widely used shock-capturing schemes in aerospace CFD codes because they handle the full Mach range (from subsonic to hypersonic) without switching strategies.
The Python-shock-tube repository implements AUSM with a clean interface that works alongside Godunov, Roe, HLL, and HLLC solvers:
# AUSM implementation pattern from Python-shock-tube
def ausm_flux(uL, uR, n):
"""AUSM flux with pressure splitting."""
rhoL, uL, P_L = uL
rhoR, uR, P_R = uR
# Split flux into advective and pressure parts
# Advective part uses Mach number-based splitting
# Pressure part uses sign function of Mach number
# See Toro's "Riemann Solvers and Numerical Methods
# for Fluid Dynamics" for full derivation
TVD Flux Limiters and MUSCL Reconstruction
TVD (Total Variation Diminishing) flux limiters prevent spurious oscillations near discontinuities by controlling the total variation of the solution. When combined with MUSCL (Monotonic Upstream-Centered Scheme for Conservation Laws) reconstruction, they form the MUSCL-TVD scheme — a second-order method that’s the workhorse for engineering-level shock capturing.
The trade-off here is clear: MUSCL-TVD is computationally cheap and robust, but at strong shocks or complex wave interactions, it can produce small oscillations behind the shock front. For engineering applications where absolute shock resolution isn’t critical, MUSCL-TVD is often sufficient.
WENO and TENO: High-Order Shock Capturing
The 5th-order Weighted Essentially Non-Oscillatory (WENO) reconstruction addresses the limitations of MUSCL-TVD by using a weighted combination of stencils that automatically adapt to smooth versus discontinuous regions. Near smooth flow, all stencils contribute; near shocks, the weights concentrate on the non-oscillatory stencil. The result is dramatically better resolution of high-frequency oscillations near discontinuities — crucial for high-fidelity Direct Numerical Simulation (DNS) and Implicit Large Eddy Simulation (ILES).
The Python-shock-tube repository demonstrates this clearly with the Shu–Osher problem — a classic benchmark where a shock interacts with a density wave. See the Shu–Osher comparison image from the repository, which shows that 5th-order WENO resolves the high-frequency oscillations behind the shock far better than MUSCL-TVD.
For DNS and ILES of shock-boundary-layer interactions — like the transonic buffet cases validated in OpenSBLI v3.0 — WENO and its edge-preserving variant TENO (Targeted ENO) are the current standard. OpenSBLI’s automated code generation produces production-grade C code from Python symbolic formulations using WENO/TENO for compressible Navier–Stokes discretization.
Python Solvers for Compressible Aerospace Flow
The landscape of Python-based compressible flow solvers has matured significantly between 2021 and 2025. Five frameworks are now available for aerospace researchers, each with distinct architectures:
pyBaram — Unstructured Grids for Strong Shocks
pyBaram (published in SoftwareX, 2022) implements finite volume methods on unstructured grids for 2D and 3D aerospace geometries. It handles strong shock and expansion waves explicitly, designed for both teaching and research with open data on Mendeley. With 10+ citations, pyBaram represents an accessible entry point for researchers who need unstructured grid support without the overhead of larger packages.
OpenSBLI v3.0 — Automated Code Generation for DNS/ILES
OpenSBLI represents a fundamentally different approach: instead of writing compiled CFD code directly, users write equations in Einstein notation using Python symbolic algebra (SymPy), and OpenSBLI’s code generator produces optimized C code via the OPS DSL. The framework targets multi-block structured grids and supports both CPU (MPI/OpenMP) and GPU (CUDA/OpenCL) backends.
OpenSBLI v3.0, published in Computers & Physics (January 2025), explicitly supports WENO and TENO shock-capturing and has been validated on:
- Shock-boundary layer interactions at hypersonic Mach numbers
- Transonic buffet on NASA-CRM airfoils
- DNS of hypersonic flow over Gaussian bumps
The framework’s academic pedigree is strong — the Southampton/Oxford team (Lusher, Sandham) has published 20+ papers on OpenSBLI applications. If your research involves high-fidelity DNS/ILES of compressible flows with shock interactions, OpenSBLI’s automated code generation is the most mature option.
The OpenSBLI framework’s workflow diagram illustrates how Python symbolic equations are translated into optimized C code via the OPS DSL.
JANC — Differentiable Compressible Flow on GPU
JANC (published April 2025 by researchers at Tsinghua University and collaborators) is arguably the most novel Python compressible solver in recent years. Built entirely on JAX-AMR (JAX-based block-structured adaptive mesh refinement), JANC is a fully differentiable solver for compressible reacting flows. Its claim to distinction:
On a single A100 GPU, JANC achieves 1% of OpenFOAM’s computational cost (using 384 CPU cores). With AMR enabled, cost drops to 1–2% of OpenFOAM.
This isn’t a marketing claim — it’s verified against the reported test cases. JANC leverages:
- Automatic differentiation (no need to manually derive adjoint equations)
- XLA JIT compilation (XLA’s tensor computation optimization)
- Adaptive mesh refinement (automatic resolution where gradients are steep)
- GPU/TPU native parallelism
- MIT licensing
For researchers exploring differentiable CFD — a growing trend for design optimization, sensitivity analysis, and ML integration — JANC is the first fully differentiable Python solver for reacting compressible flows. The code is available under an MIT license.
pygasflow and SU2 — Quick Calculations and Full Aerospace Suites
pygasflow (v1.4.1) is a lightweight Python package for quasi-1D ideal gas dynamics. It implements normal and oblique shock relations, isentropic flow, Fanno and Rayleigh flow, and aerothermodynamic flat-plate/stagnation correlations. While not a full CFD solver, it’s invaluable for quick analytical calculations — interactive pressure-deflection diagrams, shock-relation checks, and rapid parametric sweeps before committing to a full simulation.
SU2 remains the most widely cited open-source CFD suite for aerospace applications. Its supersonic/compressible capabilities include the Inviscid Supersonic Wedge, Transonic ONERAM6 airfoil, and Non-ideal Compressible Flow in Supersonic Nozzle tutorials. With 4,400+ GitHub stars, SU2 is the established choice for production aerospace CFD where Python serves primarily as a scripting and automation layer.
Benchmark Cases and Validation
Any shock-capturing implementation needs validation against standard benchmark cases. Two cases are essential:
Sod Shock Tube
The Sod shock tube is the canonical test for Riemann solvers. It initializes a tube with a high-pressure left state and low-pressure right state. At t = 0, the diaphragm breaks, and a shock, contact discontinuity, and expansion fan form. The Python-shock-tube repository provides this benchmark. See the Sod shock tube comparison showing flux resolution across four solvers (Godunov, Roe, HLL, HLLC) on 300 cells with 0th-order reconstruction.
The image shows flux resolution across four solvers (Godunov, Roe, HLL, HLLC) on 300 cells with 0th-order reconstruction. HLLC (Hybrid Linearized Lax–Friedrichs with Contact) generally provides the best balance: it resolves the contact discontinuity better than HLL while being computationally comparable to HLL. This is why HLLC is the default choice in the Python-shock-tube repository’s WENO implementation.
Shu–Osher Problem
The Shu–Osher problem tests how well a scheme handles the interaction between a shock and a density wave. The initial condition is a step function for pressure with a sinusoidal density perturbation behind the shock. This case reveals how reconstruction methods resolve high-frequency oscillations:
- 0th-order reconstruction (Godunov) suffers excessive numerical dissipation at strong shocks
- MUSCL-TVD reduces dissipation but oscillates behind the shock
- 5th-order WENO resolves the high-frequency oscillations accurately
For high-fidelity aerospace simulations, WENO is now the standard choice.
Numerical Challenges Unique to High-Mach Flow
Several numerical challenges arise specifically in compressible/supersonic flow that don’t appear (or appear differently) in incompressible CFD:
CFL Constraints at High Mach Numbers
The CFL condition (Courant–Friedrichs–Lewy) governs stability for explicit time integration. For compressible flow, the CFL number depends on the sum of flow velocity and sound speed:
$$CFL = \frac{u + a}{\Delta x} \Delta t$$
At high Mach numbers, $u \approx M \cdot a$, so the CFL condition becomes extremely restrictive. This means small time steps are required — often orders of magnitude smaller than for incompressible flows. Implicit time stepping or multigrid methods can mitigate this, but explicit schemes need careful time-step control.
Entropy Fix
The basic Roe scheme fails the entropy condition at strong shocks: instead of the physically correct entropy increase across the shock, the numerical solution can violate thermodynamics. The entropy fix modifies the eigenvalues near shocks to ensure that the numerical scheme respects the second law of thermodynamics. Without it, the solution may converge to a wrong entropy state — a shock that’s too strong or too weak.
Carbuncle Phenomenon
As mentioned earlier, the carbuncle phenomenon is a numerical instability specific to the Roe scheme on unstructured grids. When a strong shock aligns poorly with the grid, the solver can develop a secondary shock that branches off the main shock — physically impossible and numerically catastrophic. The shock-stable Roe scheme (combining entropy fix with rotated Riemann solver) cures this.
Shock–Boundary Layer Interaction
In aerospace applications, shock waves interacting with boundary layers produce complex flow structures — flow separation, reattachment, and unsteady buffet. Resolving these requires:
- Fine resolution of the boundary layer (often wall-resolved DNS)
- High-order shock-capturing (WENO/TENO) to resolve the shock
- Adequate temporal resolution for unsteady phenomena
This is why OpenSBLI v3.0’s validation focuses on SBLI — it’s the physics that matters most for transonic and hypersonic vehicle design.
Which Solver Should You Choose?
The choice of compressible flow solver depends on your grid requirements, fidelity needs, and computational resources. Here’s a comparison:
| Solver | Grid Type | Shock-Capturing | Best For | Hardware |
|---|---|---|---|---|
| pyBaram | Unstructured | Finite volume | Teaching, 2D/3D aerospace, strong shocks | CPU parallel |
| OpenSBLI | Structured (multi-block) | WENO/TENO | DNS/ILES, SBLI, transonic buffet, hypersonic | CPU/GPU (CUDA/OpenCL) |
| JANC | Structured (block AMR) | JAX auto-diff | Differentiable CFD, adjoint optimization, GPU | GPU/TPU (A100+) |
| pygasflow | N/A (analytical) | N/A | Quick shock relations, Fanno/Rayleigh, parametric sweeps | Any |
| SU2 | Structured/Unstructured | Roe, AUSM, etc. | Full aerospace suite, production CFD, N+1 flows | CPU/MPI |
Practical recommendation: Begin with pygasflow for analytical understanding of shock relations and Fanno/Rayleigh flow. Then use the Python-shock-tube repository for 1D shock-capturing practice (Roe, AUSM, WENO). Choose pyBaram if you need unstructured grids for complex 2D/3D geometries. Choose OpenSBLI if your research involves DNS/ILES with WENO/TENO on structured grids. Choose JANC if you’re exploring differentiable CFD with GPU acceleration and AMR.
Summary and Next Steps
This article covered what makes compressible/supersonic flow different from incompressible flow, the shock-capturing methods (Roe with entropy fix, AUSM, TVD, WENO/TENO) that handle discontinuities, the Python solvers available for aerospace applications (pyBaram, OpenSBLI, JANC, pygasflow, SU2), and benchmark cases for validation.
For researchers starting with compressible flow in Python: begin with pygasflow for quick analytical calculations, practice shock-capturing methods with Python-shock-tube, then choose pyBaram (unstructured) or OpenSBLI (structured) based on your grid requirements. For differentiable CFD with GPU acceleration, JANC represents the current state of the art.
If you’re new to Python CFD, start with our comprehensive CFD primer covering FiPy, meshing, and the 12 Steps to Navier–Stokes. For advection-dominated flows where mesh resolution matters, anisotropic mesh adaptation can complement your shock-capturing scheme. When you need better resolution than second-order finite volume, high-order spectral and DG methods offer alternatives.
Recommended Reading
- JANC: A cost-effective, differentiable compressible reacting flow solver — JAX-based solver with AMR, 1–2% of OpenFOAM cost (Apr 2025)
- OpenSBLI GitHub — Automated code generation for compressible Navier–Stokes with WENO/TENO shock-capturing
- Python-shock-tube — 1D Euler equation solver with Godunov, Roe, AUSM, HLLC, MUSCL-TVD, and WENO implementations
- An Introduction to Fluid Dynamics and Numerical Solution Methods — Section 13.1: Roe scheme Python implementation with Sod shock tube
- Create Your Own Riemann Solver — Philip Mocz’s exact Riemann solver tutorial for Euler equations
- pygasflow docs — Quasi-1D ideal gas dynamics, shock relations, Fanno/Rayleigh flow
- SU2 tutorials — Supersonic wedge, ONERAM6 transonic, NICFD nozzle