Translated from the author's Korean original. Read the original (한국어)
When Explicit Blows Up, Solve Implicit Without Inverting the Matrix — LU-SGS
The left half-plane stays stable at any time step, but a diffusion number of 40 flattens the inner sweep that drops ten orders near d=1.
The run died at 3 a.m. Last log line: pressure residual = NaN. CFL went from 0.9 to 0.5, then 0.3. Each step was so short that steady state meant days. Familiar wall in compressible steady work. Implicit time-stepping breaks that wall on the step-size side. The version that never inverts the full matrix is LU-SGS. A Burgers shock still exists at CFL 5.
Toggle the scheme between forward Euler and backward Euler, and drag to . The stable set changes from a small disk to the left half-plane.
Cyan = stable region (|G| ≤ 1). Forward Euler and RK4 are bounded blobs — push λΔt past their edge and the mode blows up. Backward Euler and Trapezoidal cover the entire left half plane, so any decaying physical mode stays stable no matter how large Δt grows.
On forward Euler that point leaves the cyan disk and flips to UNSTABLE. Backward Euler fills the whole left half-plane with cyan, so the same coordinate is stable again.
The stability region opens to infinity#
Time-stepping stability is decided by a single model equation.
Here is the eigenvalue produced by the spatial discretization (it comes from wave speeds and viscosity), and is the amplitude of one mode. After one step the amplitude is multiplied by the amplification factor . We need to avoid blow-up.
Explicit stepping (forward Euler) gives
so — the point must sit inside a small disk centered at with radius . A viscous grid or a thin cell makes large, and it leaves that disk fast.
Implicit stepping (backward Euler) is the opposite.
For every physical decaying mode with , . It stays stable no matter how large grows. The stability constraint dissolves, and now the time step only has to be as small as accuracy demands.
The explicit disk ends at 0 and on the real axis. Center , radius 1. sits 1.5 from the center, outside the disk, which is why the marker reads UNSTABLE. Backward Euler uses . When the denominator exceeds 1, so stays under 1 as grows. The night log cut CFL through 0.9, 0.5, and 0.3 to trap inside that disk. On a viscous grid grows first. The disk breaks before accuracy asks for a shorter step.
Inverting the full matrix is a cost you can't pay#
Nothing is free. Implicit stepping asks for the residual at the future state.
is the flux divergence (residual) of cell , and is the conserved variable. Linearize about the current state,
and a linear system for remains.
The trouble is the matrix on the left. With fifty million cells, has fifty million dimensions. A direct inverse is impossible in both memory and time. A Krylov solver like GMRES works too, but it has to store the matrix explicitly and needs a preconditioner. In the 1990s compressible analysts found a cheaper path: approximate the matrix with no storage, no multiplications, and two sweeps.
LU-SGS — split into D, L, U and sweep twice#
Decompose into a block lower triangle , a block diagonal , and a block upper triangle .
LU-SGS (Lower-Upper Symmetric Gauss-Seidel) approximates this by the product
which discards the term created by the product. When is small it's negligible. The solve is now two triangular back-substitutions in sequence.
Forward sweep — lower triangle, front to back:
Backward sweep — upper triangle, back to front:
What fills , , and decides how good the approximation is. Yoon and Jameson (1988) approximated the nonlinear flux Jacobian with its spectral radius . Splitting first-order upwind as leaves the diagonal and off-diagonals that carry only the split face Jacobians. You never build the whole matrix — a few scalars (or a small block) per cell are enough.
The approximate product is . Expand it and sits next to ; that term is dropped. Because , a small inflates and the dropped term shrinks. Raise CFL to 5 and grows, so shrinks and the approximation error grows with it. Explicit stepping still hits NaN in two or three steps on that interval. The printed implicit run crosses it in 49 steps with closed in , on cells out to with . A stored-matrix path such as the Krylov convergence comparison keeps the matrix. Here a diagonal division and two sweeps take that seat.
Python — advancing implicit Burgers with one factorization#
The toy problem is shock formation in the 1D Burgers equation. A smooth sine wave steepens into a shock over time. Explicit stepping would pin the CFL below 1. The LU-SGS implicit step survives at CFL 5.
import numpy as np
def upwind_flux_residual(u, dx):
"""First-order upwind flux for the residual R_i of d(u^2/2)/dx (periodic)."""
f = 0.5 * u * u
a = u # local wave speed df/du
f_left = np.where(a >= 0, np.roll(f, 1), f)
a_right = np.roll(a, -1)
f_right = np.where(a_right >= 0, f, np.roll(f, -1))
return (f_right - f_left) / dx
def lu_sgs_burgers_step(u, dt, dx):
"""One time step: advance the implicit system with a single LU-SGS pass."""
n = u.size
a = u
ap = 0.5 * (a + np.abs(a)) # A+ (lower-triangle contribution)
am = 0.5 * (a - np.abs(a)) # A- (upper-triangle contribution)
D = 1.0 / dt + np.abs(a) / dx # diagonal block
R = upwind_flux_residual(u, dx)
dus = np.zeros(n) # forward sweep: (D+L) dU* = -R
for i in range(n):
lower = ap[i - 1] / dx * dus[i - 1]
dus[i] = (-R[i] + lower) / D[i]
du = dus.copy() # backward sweep: (D+U) dU = D dU*
for i in range(n - 1, -1, -1):
upper = am[(i + 1) % n] / dx * du[(i + 1) % n]
du[i] = dus[i] - upper / D[i]
return u + du
def drive_burgers_shock(n=200, cfl=5.0, tmax=0.22):
dx = 1.0 / n
x = (np.arange(n) + 0.5) * dx
u = 0.5 + 0.5 * np.sin(2 * np.pi * x) # smooth initial condition
t, steps = 0.0, 0
while t < tmax:
dt = cfl * dx / np.max(np.abs(u)) # CFL>1 allowed (implicit)
dt = min(dt, tmax - t)
u = lu_sgs_burgers_step(u, dt, dx)
t += dt; steps += 1
return x, u, steps
x, u, steps = drive_burgers_shock(cfl=5.0)
print(f"CFL=5 -> {steps} steps, u in [{u.min():.3f}, {u.max():.3f}]")
# CFL=5 -> 49 steps, u in [0.012, 0.988]Run the same problem with explicit forward Euler at CFL 5 and it produces NaN within two or three steps. The implicit version reaches the shock in 49 stable steps. No heavy Riemann solver per face — one diagonal division and two sweeps did the whole job.
Sweep after sweep, the residual collapses#
A single LU-SGS application gives an approximate solution. To solve more accurately, you repeat the sweep on the same system. The convergence rate then depends on the diagonal dominance of the matrix. In the viscous-dominated case — where the viscous Jacobian becomes a 1D Laplacian — the diagonal is and the off-diagonals are . Here is the diffusion number (the nondimensional time step of viscous diffusion).
At the diagonal is and each off-diagonal is . The diagonal beats the sum of the two neighbors, and a few sweeps drop the residual ten orders. At the diagonal is 81 and the off-diagonals are twice, so the row sum is and nearly cancels. That is why the curve lies down. The stability bought with a large and the sweep count the inner relaxation needs are written on the same ledger.
Slide from near 1 up to 40 and the slope of the residual curve changes at the same sweep count.
Each sweep is one forward + one backward Gauss-Seidel pass. At d ≈ 1 the residual drops ten orders in a handful of sweeps. Crank d up to 40 (a huge implicit Δt) and the same curve flattens — the matrix is stiffer, so LU-SGS needs more sweeps or a stronger preconditioner to keep up.
Keep near 1 and the residual drops ten orders in a handful of sweeps. Crank up to 40 (a huge implicit ) and the same curve flattens. You bought stability by enlarging the step, but the matrix got stiffer, so the inner relaxation needs more sweeps. Stability and inner convergence do not arrive free together.
Drop the viscous radius from the diagonal and the sweep dies#
Leave out of the diagonal and shrinks in a viscous cell. The spectral radius is then only the convective . The sweep diverges at once. If the viscous Jacobian is a 1D Laplacian, diagonal dominance is the balance of against , and stripping the viscous term empties the left side of that balance. When the nonlinearity is strong, do not add the full at once. Use with . Oscillations near shocks shrink.
Direction is a decision too. Repeating only the forward sweep sends information toward increasing indices. Alternating forward and backward keeps and symmetric. Across an MPI partition, one communication has to sit between the two sweeps or the neighbor never arrives. How the cells are numbered changes that sweep order. The record of LU-SGS slowing after an RCM renumbering is the other side of the same choice.
Related
Share if you found it helpful.