Week 12 — Solving Saddle-Point Systems: Schur Complement · Block Preconditioners · fieldsplit · Stokes and Darcy
Process Systems Laboratory
Department of Chemical and Biomolecular Engineering, SeoulTech
| Part | Topic | Time |
|---|---|---|
| Quiz | Week 11 (Stokes, inf-sup, rates, P1–P1) | 10 min |
| A | Theory — Schur complement, block preconditioners, S\sim M_p, MINRES/GMRES, Darcy | 55 min |
| B | DOLFINx 0.11 + PETSc — blocked and nested systems, fieldsplit, null space |
40 min |
| C | Measurements — spectra, iterations vs h, time vs DOFs, Darcy | 30 min |
| D | LLM pitfalls with iterative solvers · HW11 | 15 min |
Lab notebook: W12_lab.ipynb · Homework: W12_HW11.ipynb (due before Week 13)
| Week | Problem | Linear algebra |
|---|---|---|
| 5 | Poisson | SPD: CG + AMG, iterations \approx const in h |
| 9–10 | nonlinear, time-dependent | a linear solve per Newton step / time step |
| 11 | Stokes, discretised | MUMPS LU on the indefinite matrix |
| 12 | the same matrix, solved iteratively | block preconditioners built from Week 11’s \beta_h |
| 14–15 | Navier–Stokes | same structure, A non-symmetric, Schur complement depends on \mathbf u |
Week 11 used LU everywhere. LU is exact and robust — and its cost grows faster than the problem: in 3D, 14 times more DOFs made today’s factorisation 135 times slower (0.98 s → 132 s). This week: why iterative solvers work for saddle points, and how to make them h-independent.
\mathscr K=\begin{pmatrix}A&B^\top\\B&0\end{pmatrix},\qquad A_{ij}=\mu\!\int\nabla\boldsymbol\phi_j:\nabla\boldsymbol\phi_i,\quad B_{kj}=-\!\int\psi_k\,\nabla\cdot\boldsymbol\phi_j,\quad (M_p)_{kl}=\int\psi_k\psi_l .
| N | 4 | 8 | 16 |
|---|---|---|---|
| \max|\lambda|/\min|\lambda| | 1.65\times10^4 | 6.86\times10^4 | 2.77\times10^5 |
Factor 4 per refinement, \propto h^{-2}, like the Poisson stiffness matrix. MINRES without preconditioner: about 320, 770, 1480, 2670 iterations for N=8,\dots,64.
\begin{pmatrix}A&B^\top\\B&0\end{pmatrix} =\begin{pmatrix}I&0\\BA^{-1}&I\end{pmatrix} \begin{pmatrix}A&0\\0&-S\end{pmatrix} \begin{pmatrix}I&A^{-1}B^\top\\0&I\end{pmatrix},\qquad S=BA^{-1}B^\top .
Definition — Schur complement and the inf-sup constant (Week 11)
\beta_h^2=\lambda_{\min}(S,M_p) on L^2_0 (with \mu=1). The discrete inf-sup condition says exactly: the generalized eigenvalues of (S,M_p) are bounded away from 0, uniformly in h.
Theorem (Murphy, Golub, Wathen 2000)
With \mathscr P_D=\begin{pmatrix}A&0\\0&S\end{pmatrix}, the matrix \mathscr P_D^{-1}\mathscr K has at most three distinct eigenvalues: 1,\ \tfrac{1\pm\sqrt5}{2}. MINRES with \mathscr P_D converges in at most 3 iterations.
Proof sketch: \mathscr P_D^{-1}\mathscr K\binom{\mathbf u}{p}=\lambda\binom{\mathbf u}{p} ⇔ \mathbf u+A^{-1}B^\top p=\lambda\mathbf u, S^{-1}B\mathbf u=\lambda p. If \lambda\ne1: \mathbf u=A^{-1}B^\top p/(\lambda-1) ⇒ S p=\lambda(\lambda-1)Sp ⇒ \lambda^2-\lambda-1=0.
Lemma (Stokes)
For \mathbf v\in H^1_0: \|\nabla\cdot\mathbf v\|_0\le|\mathbf v|_1. With the discrete inf-sup constant \beta_h: \beta_h^2\,q^\top M_p q\ \le\ q^\top S q\ \le\ q^\top M_p q\qquad\forall q\perp 1 \qquad(\mu=1). For viscosity \mu: S=\mu^{-1}BA_1^{-1}B^\top ⇒ use \mu^{-1}M_p.
With \mathscr P=\mathrm{diag}(A,\hat S) and \sigma\in\operatorname{eig}(\hat S^{-1}S), the same algebra as in §A3 gives \lambda=1\quad\text{or}\quad\lambda=\frac{1\pm\sqrt{1+4\sigma}}{2},\qquad \sigma\in[\beta_h^2,1]. Taylor–Hood, \hat S=M_p: \sigma\in[0.1336,\,1.0000], \beta_h=0.366 (Week 11’s value) ⇒ \lambda\in[-0.618,-0.119]\cup[1,1.618] — for every N (measured: N=4,8,16).
Bounded spectrum on two intervals that do not depend on h ⇒ MINRES iterations bounded independently of h. The inf-sup constant is the convergence constant.
| Exact block | Replacement | Why it is enough |
|---|---|---|
| A^{-1} (vector Laplacian) | one AMG V-cycle (BoomerAMG, GAMG) | spectrally equivalent to A^{-1}, constants independent of h |
| S^{-1} | M_p^{-1} | Lemma in §A4 |
| M_p^{-1} | Jacobi: \mathrm{diag}(M_p)^{-1} | P1 triangles: \operatorname{eig}(D^{-1}M_p)\in[\tfrac12,2] exactly (measured, N=8,16) |
Mixed Poisson / Darcy, \boldsymbol\sigma=-K\nabla u, \nabla\cdot\boldsymbol\sigma=f, RT1 × DG0: \begin{pmatrix}M_\sigma&B^\top\\B&0\end{pmatrix},\qquad (M_\sigma)_{ij}=\int K^{-1}\boldsymbol\phi_j\cdot\boldsymbol\phi_i,\quad B_{kj}=-\int\psi_k\nabla\cdot\boldsymbol\phi_j .
Two remedies:
selfp) — a sparse, Laplacian-like matrix on which AMG works.Rule (Mardal–Winther): the preconditioner is the Riesz map of the spaces in which the continuous problem is well-posed.
A\ \to\ F=\mu\,\text{Laplacian}+\text{convection}(\mathbf u_k)\quad\text{(non-symmetric)},\qquad S=BF^{-1}B^\top .
fenicsx-pctools (Rehor & Hale) implements PCD as a PETSc Python preconditioner inside fieldsplit. Its backward-facing-step demo runs on DOLFINx 0.11 after three small API fixes: 4 Newton steps, 19–31 GMRES iterations each (Re = 100, local run).| Monolithic | Blocked | Nested | |
|---|---|---|---|
| Spaces | one mixed_element([P2v, P1]) |
two spaces V, Q |
two spaces V, Q |
| Forms | one form | [[a00, a01], [a10, None]] |
same list |
| Matrix | MPIAIJ, interleaved DOFs |
MPIAIJ, block layout per rank |
MATNEST of four sub-matrices |
kind= |
— | None (default) |
"nest" |
| fieldsplit index sets | from W.sub(i).collapse() maps |
you compute offsets | automatic (getNestISs) |
| Direct solver | MUMPS ✓ | MUMPS ✓ | MUMPS ✓ (same solution as blocked) |
Same Taylor–Hood MMS, N=16, -np 2: monolithic (MUMPS), nested (MINRES) and blocked (MINRES) give \|\mathbf u-\mathbf u_h\|_0=9.7063\times10^{-5} to all printed digits; \|\mathbf u_{\text{nest}}-\mathbf u_{\text{mono}}\|_0=2.6\times10^{-11}.
a = fem.form([[mu * inner(grad(u), grad(v)) * dx, -p * div(v) * dx],
[-q * div(u) * dx, None]])
a_p = fem.form([[mu * inner(grad(u), grad(v)) * dx, None],
[None, p * q / mu * dx]]) # diag(A, Mp/mu)
A = assemble_matrix(a, bcs=[bc]); A.assemble()
P = assemble_matrix(a_p, bcs=[bc]); P.assemble()
b = assemble_vector(L, kind="mpi") # L = [f.v dx, ZeroBaseForm((q,))]
apply_lifting(b, a, bcs=bcs_by_block(extract_function_spaces(a, 1), [bc]))
b.ghostUpdate(PETSc.InsertMode.ADD, PETSc.ScatterMode.REVERSE)
set_bc(b, bcs_by_block(extract_function_spaces(L), [bc]))
Vm, Qm = V.dofmap.index_map, Q.dofmap.index_map
nu = Vm.size_local * 2 # owned velocity rows
off = Vm.local_range[0] * 2 + Qm.local_range[0]
is_u = PETSc.IS().createStride(nu, off, 1, comm=comm)
is_p = PETSc.IS().createStride(Qm.size_local, off + nu, 1, comm=comm)is_u, is_p: the global rows of each field in the blocked matrix — fieldsplit needs them to cut out the blocks.PETSc.NullSpace with the vector (0,\dots,0,1,\dots,1), attached to A (and removed from b).fieldsplit optionsksp.setOperators(A, P) # operator K, preconditioner matrix P
pc.setType("fieldsplit"); pc.setFieldSplitIS(("u", is_u), ("p", is_p))
opts = {"ksp_type": "minres", "ksp_rtol": 1e-8,
"pc_fieldsplit_type": "additive", # block diagonal
"fieldsplit_u_ksp_type": "preonly",
"fieldsplit_u_pc_type": "hypre", # one BoomerAMG V-cycle on A
"fieldsplit_p_ksp_type": "preonly",
"fieldsplit_p_pc_type": "jacobi"} # Jacobi on Mp/mupc_fieldsplit_type |
meaning | with |
|---|---|---|
additive |
\mathrm{diag}(\hat A,\hat S) | MINRES (SPD blocks) |
schur + schur_fact_type diag/lower/upper/full |
the factors of §A2 with \hat A, \hat S | GMRES (FGMRES if inner solves are Krylov) |
schur_precondition a11 / selfp / user |
\hat S from P_{11} / B\,\mathrm{diag}(A)^{-1}B^\top / your matrix | Stokes: a11 with P_{11}=M_p/\mu; Darcy: selfp |
Nested systems name the splits 0, 1 (fieldsplit_0_pc_type, …); blocked systems use the names you gave in setFieldSplitIS. High level: LinearProblem(a, L, bcs=..., P=a_p, kind="nest", petsc_options={...}).
mat_mumps_icntl_24 = 1 (null-pivot detection).RuntimeError: Diagonal sub-block (1, 1) cannot be 'None' and have DirichletBC applied. Consider assembling a zero block.assemble_matrix(a, kind="nest") for a form with a None block and no bcs raises TypeError: 'NoneType' object is not iterable in 0.11 — pass bcs=[].N=8: no preconditioner \max|\lambda|/\min|\lambda|=6.9\times10^4; \mathrm{diag}(A,M_p): 13.5 (13.4, 13.5, 13.6 for N=4,8,16); \mathrm{diag}(A,S): exactly \{-0.618,\,1,\,1.618\}, ratio 2.618. The negative interval ends at (1-\sqrt{1+4\beta_h^2})/2=-0.119.
Stokes (rtol 10^{-8}, -np 2): diag(LU, LU(M_p)) 29–31; diag(BoomerAMG, Jacobi) 45–50; upper Schur (BoomerAMG, Jacobi) 47–58 — flat. GAMG with default options: 62 → 123 — not quite flat (an AMG is not automatically h-independent for P2 vector problems).
| \mu | P_{11}=M_p/\mu | P_{11}=M_p |
|---|---|---|
| 1 | 49 | 49 |
| 10^{-2} | 53 | 79 |
| 10^{-4} | 55 | 106 |
MINRES, diag(BoomerAMG, Jacobi), N=32. Same answers, more iterations: the unscaled block is spectrally equivalent with constants \propto\mu^{-1}.
The tolerance is relative to the preconditioned residual, not the error. N=256, rtol 10^{-8}: MINRES \|\mathbf u-\mathbf u_h\|_0=2.57\times10^{-8}, LU 2.38\times10^{-8} — the algebraic error is already visible. Rule: tighten rtol until the discretisation error stops changing (Week 7, again).
KSP setup + solve, minimum of two runs, -np 2 on the build machine (Colab has 2 slow cores — measure there). Same solutions: |x_{it}-x_{LU}|/|x_{LU}|\le2.3\times10^{-7} in 3D.
| DOFs | LU (MUMPS) | MINRES diag(AMG, Jacobi) | |
|---|---|---|---|
| 2D, N=32\to256 | 9.5 k → 592 k (×62) | 0.12 → 15.7 s (×130) | 0.17 → 12.0 s (×70, BoomerAMG) |
| 3D, N=8\to20 | 15 k → 216 k (×14) | 0.98 → 132 s (×135) | 1.06 → 13.8 s (×13, GAMG) |
| N | DOFs | diag(M_\sigma,M_u) [L²] | diag(M_\sigma+\nabla\!\cdot\nabla\!\cdot,\,M_u) [H(div)] | Schur upper, selfp + AMG |
|---|---|---|---|---|
| 16 | 1 312 | 104 | 4 | 22 |
| 32 | 5 184 | 178 | 4 | 22 |
| 64 | 20 608 | 284 | 3 | 21 |
| 128 | 82 176 | 510 | 3 | 21 |
MINRES / GMRES iterations to rtol 10^{-8}, K=1, u=\sin\pi x\sin\pi y, -np 2. LU errors: \|u-u_h\|_0=4.09\times10^{-3}, \|\boldsymbol\sigma-\boldsymbol\sigma_h\|_0=1.57\times10^{-2} at N=128 (rate 1).
selfp + AMG: 21–22 and scalable.LinearProblem(...) construction, Taylor–Hood N=8, -np 2 |
time |
|---|---|
| a new form (code generated, compiled) | 2.38 s |
| the same form again (JIT cache) | 0.05 s |
The solve itself: 0.01–0.02 s. Time the solver (ksp.solve incl. setup), after the forms exist; run the smallest case once before timing.
| Kind | What it looks like | Symptom |
|---|---|---|
| Viscosity ignored | P_{11}=M_p for \mu\ne1 | same answer, more iterations (49 → 106 for \mu=10^{-4}, §C3) |
| Recipe transferred | the Stokes block diagonal \mathrm{diag}(A,M) for Darcy | iterations \propto h^{-1} (104 → 510, §C5) |
| JIT in the timing | the first LinearProblem or fem.form inside the timer |
2.4 s of compilation in a 0.02 s solve (§C6) |
| Pin in a blocked form | dirichletbc on the pressure with a None (1,1) block |
RuntimeError (§B4) |
| Constant pressure | neither a pinned DOF nor a null space | LU: a pressure shifted by an arbitrary constant, or a failed factorisation (Week 11) |
| Older API | fem.petsc.create_vector_block, assemble_matrix_block (not in 0.11) |
AttributeError |
Verification habit: first the discretisation (Week 11’s MMS rates), then the solver — iterations vs h and \mu, and the answer against something you trust.
W12_HW11.ipynb (100 pts)
Rules as always: Restart session and run all, -np 2 where stated, the AI-usage log, numbers only from your own cells.
Timings vary between runs: report what you measured, compare growth over a wide range, and never compare a converged solve with a failed one.
| Concept | Key idea | DOLFINx 0.11 / PETSc |
|---|---|---|
| Saddle point | indefinite: MINRES or GMRES, not CG | ksp_type minres / gmres |
| Schur complement | S=BA^{-1}B^\top, dense; \beta_h^2=\lambda_{\min}(S,M_p) | never formed |
| Ideal preconditioners | diag: 3 eigenvalues; triangular: GMRES in 2 | pc_fieldsplit_type schur, fact_type diag/upper/full |
| Stokes | S\sim M_p/\mu with constants \beta_h^2, 1 | P=[[A, None], [None, Mp/mu]], additive |
| Darcy | S\sim Laplacian: use H(div) or selfp |
schur_precondition selfp |
| Practice | AMG for A, Jacobi for M_p; null space for the pressure constant | fieldsplit_u_pc_type hypre, NullSpace, icntl_24 |
| Cost | 2D: LU competitive; 3D: block preconditioners win | time vs DOFs slopes |
Next week — advection–diffusion: Péclet number, Galerkin oscillations, SUPG; HW12.
