On a flat, axis-aligned wall add_rotated_freeslip_bc(0.0, "Top") and
add_dirichlet_bc((None, 0.0), "Top") are the same discrete constraint: the
measure-weighted node normal is exactly (0,1), so striking the rotated normal
row is striking u_y. The two solves do not agree.
Minimal reproduction
Unit box, StructuredQuadBox(elementRes=(32,32)), uniform viscosity 1,
bodyforce = (0, cos(pi x) sin(pi z)), free slip on all four walls (Left,
Right, Bottom by component Dirichlet), petsc_use_pressure_nullspace = True,
tolerance = 1e-9. Reference is a monolithic LU solve of the component-Dirichlet
problem. The two top corner nodes are EXCLUDED from every norm (they are the
known recovery corner, #608).
| run |
‖u − u_ref‖ / ‖u_ref‖ |
| component Dirichlet, default solver |
8.9e-09 |
component Dirichlet, pc_type=lu |
0 (the reference) |
| rotated free slip, default solver |
2.0e-03 |
rotated free slip, _rotated_use_lu = True |
2.1e-03 |
The last row is the point: with an exact linear solve on both sides the answers
still differ by 2e-3, so this is the discrete problem, not convergence.
What it is not
- Not the corner. Dropping a ball of radius 1/32, 2/32, 4/32, 8/32 around each
top corner takes the ratio of velocity errors from 1.49 to 1.19; a 20% excess
survives dropping a quarter of the domain.
- Not the tolerance.
tolerance = 1e-9 and 1e-12 give bit-identical
answers on the rotated path (3.313e-03 both, SolCx eta_B=10).
- Not the pressure gauge. The rotated path builds the constant-pressure null
vector; its pressure comes back with a non-zero mean (−0.224 where the
Dirichlet run gives 1e-12), but a constant pressure has no gradient and cannot
move the velocity.
- Not the viscosity contrast — and this is the odd part. Same comparison
against contrast: uniform 3.2e-03, eta_B=10 2.7e-03, eta_B=1e6 9.3e-08.
The two agree on the hard problem and disagree on the easy one.
Why it matters
It is the reason a SolCx velocity error reads 1.7e-03 with a component-Dirichlet
lid and 3.3e-03 with a rotated one, which reads as the rotated constraint being
half as accurate on a geometry where it should be identical. On curved boundaries
there is no component condition to compare against, so this comparison is only
available on a box — which is where it should be guarded.
Found while measuring boundary-condition treatments for UWTN 2026-016;
reproduction in that note's examples/solcx.py.
Underworld development team with AI support from Claude Code
On a flat, axis-aligned wall
add_rotated_freeslip_bc(0.0, "Top")andadd_dirichlet_bc((None, 0.0), "Top")are the same discrete constraint: themeasure-weighted node normal is exactly
(0,1), so striking the rotated normalrow is striking
u_y. The two solves do not agree.Minimal reproduction
Unit box,
StructuredQuadBox(elementRes=(32,32)), uniform viscosity 1,bodyforce = (0, cos(pi x) sin(pi z)), free slip on all four walls (Left,Right,Bottomby component Dirichlet),petsc_use_pressure_nullspace = True,tolerance = 1e-9. Reference is a monolithic LU solve of the component-Dirichletproblem. The two top corner nodes are EXCLUDED from every norm (they are the
known recovery corner, #608).
pc_type=lu_rotated_use_lu = TrueThe last row is the point: with an exact linear solve on both sides the answers
still differ by 2e-3, so this is the discrete problem, not convergence.
What it is not
top corner takes the ratio of velocity errors from 1.49 to 1.19; a 20% excess
survives dropping a quarter of the domain.
tolerance = 1e-9and1e-12give bit-identicalanswers on the rotated path (3.313e-03 both, SolCx eta_B=10).
vector; its pressure comes back with a non-zero mean (−0.224 where the
Dirichlet run gives 1e-12), but a constant pressure has no gradient and cannot
move the velocity.
against contrast: uniform 3.2e-03,
eta_B=102.7e-03,eta_B=1e69.3e-08.The two agree on the hard problem and disagree on the easy one.
Why it matters
It is the reason a SolCx velocity error reads 1.7e-03 with a component-Dirichlet
lid and 3.3e-03 with a rotated one, which reads as the rotated constraint being
half as accurate on a geometry where it should be identical. On curved boundaries
there is no component condition to compare against, so this comparison is only
available on a box — which is where it should be guarded.
Found while measuring boundary-condition treatments for UWTN 2026-016;
reproduction in that note's
examples/solcx.py.Underworld development team with AI support from Claude Code