Pseudo-Time Stepping
TL;DR
The empirical residual loss can be small on a spurious solution — sharp transition layers hide between collocation points. Pseudo-time stepping augments the residual with an implicit-Euler damping term toward the previous iterate, which (together with resampling) amplifies these hidden defects so the optimizer must fix them. Based on Wang, Koohy, Lu & Perdikaris, When PINNs Go Wrong, 2026.
The problem: spurious solutions with small losses
PINN training sometimes converges to physically wrong solutions despite tiny residual losses. The paper argues this is not an optimization failure but a defect of the empirical loss itself: profiles with a sharp transition layer of width
The fix: relax in pseudo-time
Introduce an artificial relaxation
i.e. the plain residual plus a damping term
Why it works (the paper's key insight): one pseudo-time update
Adaptive step size
The amplification grows with
smoothed with momentum and clipped — a local estimate of the residual's Lipschitz constant. An optional cosine shrink schedule decays the weights as the true residual converges, so the damping vanishes near the solution.
In JAXPI
pseudo_time.enabled = True
pseudo_time.strategy = "dynamic" # adaptive tau; "constant" for fixed weights
pseudo_time.pts_weights = {"u": 1.0, "v": 1.0, "p": 1.0} # 1/tau per variable
pseudo_time.update_schedule = {"start": 100, "every": 1000}
pseudo_time.shrink.enabled = TrueThe residual components and their weights are matched by name — hence the variable-keyed residual convention.
Where it's used
Every example ships pseudo_time.py / fixed_pseudo_time.py config variants. The clearest demonstrations are Gray–Scott and Ginzburg–Landau (spurious steady states), inviscid Burgers (spurious weak solutions), and the high-Re lid-driven cavity.