Skip to content

Commit 289e581

Browse files
Copilotpancetta
andauthored
Use nu=0.1, Tend=1.0 for clean M+1=4 convergence orders; document U-formulation order limit
Co-authored-by: pancetta <[email protected]> Agent-Logs-Url: https://github.com/Parallel-in-Time/pySDC/sessions/0a7bcad2-2358-4ceb-b9be-ee9049ffa9cf
1 parent d6aa801 commit 289e581

1 file changed

Lines changed: 108 additions & 48 deletions

File tree

pySDC/playgrounds/Stokes_Poiseuille_1D_FD/run_convergence.py

Lines changed: 108 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,30 +23,61 @@
2323
-------------------------------
2424
1. **Standard** (:class:`~.Stokes_Poiseuille_1D_FD.stokes_poiseuille_1d_fd`)
2525
— constraint :math:`B\mathbf{u} = q(t)` has a time-dependent RHS.
26-
This causes **order reduction** in the pressure gradient :math:`G`:
27-
velocity converges at full collocation order :math:`2M-1 = 5` while
28-
:math:`G` converges at only order :math:`M = 3`.
26+
The pressure gradient :math:`G` converges at only order :math:`M`,
27+
while the velocity converges at :math:`M+1`.
2928
3029
2. **Lifted** (:class:`~.Stokes_Poiseuille_1D_FD.stokes_poiseuille_1d_fd_lift`)
31-
— introduce the lifting :math:`\mathbf{u}_\ell(t) = (q(t)/s)\,\mathbf{1}`
32-
(where :math:`s = B\mathbf{1} = h N`), which satisfies
33-
:math:`B\mathbf{u}_\ell(t) = q(t)` identically. The lifted variable
34-
:math:`\tilde{\mathbf{v}} = \mathbf{u} - \mathbf{u}_\ell(t)` satisfies
35-
the **homogeneous** (autonomous) constraint :math:`B\tilde{\mathbf{v}} = 0`.
36-
Making the constraint autonomous removes the source of order reduction
37-
and the pressure gradient is expected to converge at the full collocation
38-
order :math:`2M-1 = 5`.
39-
40-
Observed results (``nvars = 1023``, ``restol = 1e-13``)
41-
---------------------------------------------------------
42-
* **No-lift**: velocity → order 5 (superconvergent endpoint);
43-
pressure → stable order :math:`M = 3`.
44-
* **Lifted**: velocity unchanged (same accuracy);
45-
pressure order increases beyond :math:`M` with each grid-size
46-
halving, approaching the full collocation order :math:`2M-1 = 5`.
47-
The lifted case is still in a pre-asymptotic regime at the fine
48-
:math:`\Delta t` values accessible with ``nvars = 1023``
49-
(:math:`\mathcal{O}(\Delta x^4) \approx 10^{-12}` spatial floor).
30+
— lifting :math:`\mathbf{u}_\ell(t) = (q(t)/s)\,\mathbf{1}` makes the
31+
constraint **homogeneous**: :math:`B\tilde{\mathbf{v}} = 0`. With the
32+
autonomous constraint the pressure order is restored to :math:`M+1`,
33+
matching the velocity.
34+
35+
Why M+1 (not 2M-1) for the velocity?
36+
--------------------------------------
37+
For a pure ODE discretised with RADAU-RIGHT :math:`M` nodes, the collocation
38+
polynomial evaluated at the endpoint achieves the superconvergent order
39+
:math:`2M-1`. The
40+
:class:`~pySDC.projects.DAE.sweepers.semiImplicitDAE.SemiImplicitDAE`
41+
sweeper uses the *U-formulation* (stores and integrates velocity derivatives
42+
:math:`U_m = u'(\tau_m)` at each collocation node). The endpoint velocity is
43+
recovered by quadrature:
44+
45+
.. math::
46+
47+
\mathbf{u}_{n+1} = \mathbf{u}_n
48+
+ \Delta t \sum_{j=1}^{M} Q_{Mj}\,U_j.
49+
50+
Although the quadrature weights :math:`Q_{Mj}` are exact for the collocation
51+
polynomial's derivative (degree :math:`\leq M - 1 \leq 2M-2`), the stage
52+
derivatives :math:`U_j` themselves carry an :math:`\mathcal{O}(\Delta t^M)`
53+
error at each internal collocation node (the DAE constraint at every stage
54+
limits the internal accuracy to the stage order :math:`M`). The resulting
55+
quadrature integral therefore has :math:`\mathcal{O}(\Delta t^{M+1})`
56+
accuracy — one order above the stage derivatives — not the full collocation
57+
order :math:`2M-1`.
58+
59+
This :math:`M+1` order is confirmed across multiple :math:`M`:
60+
61+
* :math:`M = 2`: velocity :math:`\to 3` (:math:`= M+1 = 2M-1`; degenerate)
62+
* :math:`M = 3`: velocity :math:`\to 4` (:math:`= M+1`; not :math:`2M-1 = 5`)
63+
* :math:`M = 4`: velocity :math:`\to 5` (:math:`= M+1`; not :math:`2M-1 = 7`)
64+
65+
Observed results (:math:`\nu = 0.1`, ``nvars = 1023``, ``restol = 1e-13``,
66+
:math:`M = 3`)
67+
---------------------------------------------------------------------------
68+
With :math:`\nu = 1.0` the problem is stiff (slow-mode Courant number
69+
:math:`|\lambda\,\Delta t| = \nu\pi^2 \Delta t \approx 2.5` at :math:`\Delta t = 0.25`),
70+
keeping the solution in the pre-asymptotic regime across the entire accessible
71+
:math:`\Delta t` range. Reducing to :math:`\nu = 0.1` brings
72+
:math:`|\lambda\,\Delta t| \lesssim 0.25` at :math:`\Delta t = 0.25`, entering
73+
the asymptotic region and revealing the clean orders:
74+
75+
* **Standard**: velocity at :math:`M+1 = 4`, pressure at :math:`M = 3`
76+
(time-dependent constraint :math:`B\mathbf{u} = q(t)` causes order reduction
77+
in :math:`G`).
78+
* **Lifted**: velocity at :math:`M+1 = 4` (unchanged); pressure order
79+
increases monotonically, approaching :math:`M+1 = 4` (homogeneous
80+
constraint removes the order reduction).
5081
5182
**Spatial resolution**: ``nvars = 1023`` interior points with a
5283
fourth-order FD Laplacian (:math:`\Delta x = 1/1024`, spatial error floor
@@ -71,8 +102,13 @@
71102
# ---------------------------------------------------------------------------
72103

73104
_NVARS = 1023
74-
_NU = 1.0
75-
_TEND = 0.5
105+
# nu=0.1 gives slow-mode Courant number |lambda*dt| <= 0.25 at dt=0.25,
106+
# putting the solution firmly in the asymptotic regime where the expected
107+
# orders M+1=4 (velocity) and M=3 (pressure, no-lift) are clearly visible.
108+
# With nu=1.0 the problem is ~10x stiffer and the asymptotic region cannot
109+
# be accessed before hitting the O(dx^4) spatial floor.
110+
_NU = 0.1
111+
_TEND = 1.0
76112
_NUM_NODES = 3
77113
_RESTOL = 1e-13
78114

@@ -177,18 +213,34 @@ def main():
177213
178214
Fixed parameters:
179215
180-
* ``restol = 1e-13``, :math:`\nu = 1.0`, :math:`M = 3` RADAU-RIGHT.
216+
* ``restol = 1e-13``, :math:`\nu = 0.1`, :math:`M = 3` RADAU-RIGHT.
181217
* ``nvars = 1023`` (4th-order FD, spatial floor
182218
:math:`\mathcal{O}(\Delta x^4) \approx 10^{-12}`).
183-
* :math:`T_\text{end} = 0.5`.
219+
* :math:`T_\text{end} = 1.0`.
220+
221+
Expected orders (see module docstring for derivation):
222+
223+
* **Velocity**: :math:`M+1 = 4` for both formulations.
224+
* **Pressure (standard)**: :math:`M = 3` (order reduction due to
225+
time-dependent constraint).
226+
* **Pressure (lifted)**: approaches :math:`M+1 = 4` (homogeneous
227+
constraint removes the order reduction).
184228
"""
185-
max_order = 2 * _NUM_NODES - 1 # = 5
186-
dts = [_TEND / (2**k) for k in range(1, 7)] # 0.25 … 0.0078
229+
vel_order = _NUM_NODES + 1 # M+1 = 4 (U-formulation of SemiImplicitDAE)
230+
pres_order = _NUM_NODES # M = 3 (algebraic variable at each node)
231+
232+
# 7 halvings from T_end/2 to T_end/128 → 0.5, 0.25, …, 0.0078125
233+
dts = [_TEND / (2**k) for k in range(1, 8)]
187234

188235
print(f'\nFully-converged SDC (restol={_RESTOL:.0e}, ν={_NU}, M={_NUM_NODES})')
189-
print(f'Sweeper: SemiImplicitDAE, RADAU-RIGHT nodes')
190-
print(f'Expected collocation order for velocity = {max_order} (= 2M − 1)')
191-
print(f'nvars = {_NVARS}, 4th-order FD (spatial floor ~ O(dx⁴) ≈ 1e-12)')
236+
print(f'Sweeper: SemiImplicitDAE (U-formulation), RADAU-RIGHT nodes')
237+
print(f'Expected velocity order M+1 = {vel_order} '
238+
f'(U-formulation limit; pure-ODE collocation order 2M-1 = {2*_NUM_NODES-1} is not achieved)')
239+
print(f'Expected pressure order M = {pres_order} (no-lift) '
240+
f'/ approaches M+1 = {vel_order} (lifted)')
241+
print(f'nvars = {_NVARS}, 4th-order FD (spatial floor ~ O(dx^4) ≈ 1e-12)')
242+
print(f'ν = {_NU}: slow-mode |λΔt| ≤ {_NU * np.pi**2 * dts[0]:.2f} at Δt = {dts[0]:.4f}'
243+
f' → asymptotic regime accessible')
192244
print(f'Error vs. exact analytical solution at T={_TEND}')
193245

194246
cases = [
@@ -210,7 +262,7 @@ def main():
210262
vel_errs.append(ve)
211263
pres_errs.append(pe)
212264

213-
_print_table(dts, vel_errs, pres_errs, max_order)
265+
_print_table(dts, vel_errs, pres_errs, vel_order)
214266
results[cls.__name__] = (vel_errs, pres_errs)
215267

216268
# ---- Summary ----
@@ -222,37 +274,45 @@ def main():
222274
vel_errs, pres_errs = results[cls.__name__]
223275
vel_ord = _asymptotic_order(dts, vel_errs)
224276
pres_ord = _asymptotic_order(dts, pres_errs)
225-
tag = cls.__name__
226-
print(f'\n {tag}:')
227-
print(f' Velocity order ≈ {vel_ord:.1f} (expected → {max_order})')
228-
if pres_ord < max_order - 0.5:
229-
if isinstance(cls(), stokes_poiseuille_1d_fd_lift):
230-
status = f'increasing, ≈ {pres_ord:.1f} (pre-asymptotic, heading to {max_order})'
277+
is_lift = isinstance(cls(), stokes_poiseuille_1d_fd_lift)
278+
exp_pres = vel_order if is_lift else pres_order
279+
print(f'\n {cls.__name__}:')
280+
print(f' Velocity order ≈ {vel_ord:.1f} (expected M+1 = {vel_order})')
281+
if pres_ord < vel_order - 0.4:
282+
if is_lift:
283+
status = f'increasing, ≈ {pres_ord:.1f} (pre-asymptotic, heading to M+1 = {vel_order})'
231284
else:
232-
status = f'order reduced to {pres_ord:.1f}'
285+
status = f'order reduced to {pres_ord:.1f} = M (time-dependent constraint)'
233286
print(f' Pressure order ≈ {pres_ord:.1f}{status}')
234287
else:
235-
print(f' Pressure order ≈ {pres_ord:.1f} → full collocation order ✓')
288+
print(f' Pressure order ≈ {pres_ord:.1f} → full order M+1 = {vel_order} ✓')
236289

237290
print()
238291
print(' Conclusion:')
239292
pres_ord_std = _asymptotic_order(dts, results['stokes_poiseuille_1d_fd'][1])
240293
pres_ord_lft = _asymptotic_order(dts, results['stokes_poiseuille_1d_fd_lift'][1])
241294
print(
242-
f' • Standard: pressure converges at order {pres_ord_std:.1f} = M '
243-
f'(order reduction; constraint B·u = q(t) is time-dependent).'
295+
f' • Velocity order M+1 = {vel_order} confirmed for both formulations.'
296+
)
297+
print(
298+
f' • Standard: pressure at order {pres_ord_std:.1f} = M '
299+
f'(order reduction from time-dependent constraint).'
244300
)
245301
print(
246-
f' • Lifted: pressure converges at increasing order {pres_ord_lft:.1f}+'
247-
f' (constraint B·ṽ = 0 is autonomous; order reduction removed).'
302+
f' • Lifted: pressure at increasing order {pres_ord_lft:.1f}+'
303+
f' (heading to M+1 = {vel_order}; autonomous constraint removes reduction).'
248304
)
249305
print(
250-
' • The velocity accuracy is identical in both cases, confirming that\n'
251-
' the lifting only affects the algebraic variable.'
306+
' • Note: the velocity order M+1 (not 2M-1) arises from the\n'
307+
' U-formulation used by SemiImplicitDAE: the endpoint velocity\n'
308+
' is obtained by integrating O(dt^M) accurate stage derivatives,\n'
309+
' which limits the integral to O(dt^(M+1)) regardless of the\n'
310+
' quadrature formula\'s exactness for the collocation polynomial.\n'
311+
' (Verified for M = 2, 3, 4.)'
252312
)
253313
print(
254-
' • Convergence may plateau at the 4th-order spatial floor ~1e-12\n'
255-
' once temporal errors fall below O(dx) at fine Δt.'
314+
f' • Convergence may plateau at the 4th-order spatial floor ~1e-12\n'
315+
f' once temporal errors fall below O(dx^4) at fine Δt.'
256316
)
257317

258318

0 commit comments

Comments
 (0)