Skip to content

Commit 2da9b66

Browse files
committed
Address Copilot review: add flat->tensor fan-out to DDt fallback
Copilot flagged that after the shape fix, the multicomponent projector writes into _psi_star_flat_var but update_pre_solve() never unpacks the solved flat (1, Nc) field back into psi_star[0]. Mirrors the fan-out already in initialise_history() (~ddt.py:1540): walk _psi_star_indep_indices, copy flat var k-th component into psi_star[0][:, i, j], and symmetric-fill [:, j, i] for SYM_TENSOR. In practice the SemiLagrangian advection step at line 1016 then modifies psi_star[0] in place, so the missing fan-out wasn't producing an immediate symptom in this short test — but the projected flux value was being silently discarded. Fix restores the intended semantics: psi_star[0] reflects the current psi_fn (projected flux) before SL advection updates it for the upstream sample. Reverted the over-eager second test (asserting psi_star[0] non-zero after one solve) since the SL advection masks the missing fan-out in that observation window. Kept the ShapeError regression test which remains a definitive guard for the original visible failure. Underworld development team with AI support from Claude Code
1 parent d299361 commit 2da9b66

2 files changed

Lines changed: 15 additions & 7 deletions

File tree

src/underworld3/systems/ddt.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,6 +1776,17 @@ def update_pre_solve(
17761776
self._psi_star_projection_solver.smoothing = 0.0
17771777
self._psi_star_projection_solver.solve(verbose=verbose)
17781778

1779+
# For tensor vtypes the projection writes into the flat (1, Nc) variable,
1780+
# so we must fan it back out to psi_star[0] — otherwise subsequent
1781+
# history operations read a stale tensor. Mirrors the same fan-out in
1782+
# initialise_history() (~line 1540).
1783+
if getattr(self, '_psi_star_use_multicomponent', False):
1784+
for k, (i, j) in enumerate(self._psi_star_indep_indices):
1785+
vals = self._psi_star_flat_var.array[:, 0, k]
1786+
self.psi_star[0].array[:, i, j] = vals
1787+
if i != j:
1788+
self.psi_star[0].array[:, j, i] = vals
1789+
17791790
# 3. Compute the upstream values from the psi_fn
17801791

17811792
# We use the u_star variable as a working value here so we have to work backwards

tests/test_0610_navier_stokes_slcn_projection.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
"""
2-
Regression test for the NavierStokesSLCN DFDt projection source shape.
2+
Regression test for the NavierStokesSLCN DFDt projection fallback.
33
44
When ``SNES_MultiComponent_Projection`` was wired into the ``SemiLagrangian``
55
DDt path, the ``psi_fn`` setter and ``_setup_projections`` were updated to
66
flatten the source tensor to a ``(1, Nc)`` row matrix via
77
``_build_projection_source``. The fallback path inside ``update_pre_solve``
88
(taken when ``uw.function.evaluate`` raises on expressions containing
9-
derivatives — which is the NavierStokes viscous flux every step) missed
10-
the migration and assigned ``self.psi_fn`` directly, producing:
9+
derivatives — true for the NavierStokes viscous flux every step) missed the
10+
migration and assigned ``self.psi_fn`` directly, producing:
1111
1212
sympy.matrices.exceptions.ShapeError:
1313
Matrix size mismatch: (1, 3) + (2, 2).
1414
1515
See: https://github.com/underworldcode/underworld3/issues/180
16-
17-
The test does one ``solve(timestep=dt)`` of NavierStokesSLCN on a tiny mesh.
18-
Before the fix this raises ``ShapeError`` from the DDt fallback. After the
19-
fix it converges normally.
2016
"""
2117
import pytest
2218
import sympy
@@ -26,6 +22,7 @@
2622
@pytest.mark.level_2
2723
@pytest.mark.tier_a
2824
def test_navier_stokes_slcn_solve_does_not_raise_shape_error():
25+
"""First solve completes without ShapeError from the DDt projection fallback."""
2926
mesh = uw.meshing.UnstructuredSimplexBox(
3027
minCoords=(0.0, 0.0),
3128
maxCoords=(1.0, 1.0),

0 commit comments

Comments
 (0)