Skip to content

fix(maths): CellWiseIntegral evaluates on the mesh DS, not a mis-cloned P1 DM (BF-03)#311

Open
lmoresi wants to merge 1 commit into
developmentfrom
bugfix/track0-cellwise-integral
Open

fix(maths): CellWiseIntegral evaluates on the mesh DS, not a mis-cloned P1 DM (BF-03)#311
lmoresi wants to merge 1 commit into
developmentfrom
bugfix/track0-cellwise-integral

Conversation

@lmoresi

@lmoresi lmoresi commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

Fixes audit finding LE-02 (worklist item BF-03, docs/reviews/2026-07/REMEDIATION-WORKLIST.md): CellWiseIntegral.evaluate() in src/underworld3/cython/petsc_maths.pyx computed cell-wise integrals against the wrong discretisation. It cloned mesh.dm, attached a fresh single-P1-field DS (FE.createDefault + setField + createDS), and then handed DMPlexComputeCellwiseIntegralFEM a solution vector packed for mesh.dm's multi-field layout. The layout mismatch made the integral read the wrong DOFs and silently over-count.

Reproduction (before the fix)

On a unit-square UnstructuredSimplexBox with a P2 and a P1 variable:

  • CellWiseIntegral(mesh, fn=1.0).evaluate() summed to 2.0 (should be 1.0; control Integral gives 1.0) — exactly as reported in the audit (LE-02, reproduced live).

Fix

Rewrite evaluate() to follow the working Integral pattern in the same file: set the JIT objective on mesh.dm's own DS (mesh.dm.getDS()) and integrate on mesh.dm directly, so the compiled objective, the DS field layout, and the packed solution vector all agree. Per-cell results are collected in a plain Vec of local size num_local_cells * num_fields (PETSc's implicit cell-major layout when the output vector carries no section); the field-0 column is returned, one value per rank-local cell. The TODO(BUG) comment at the defect site is removed.

Caveat (issue #171): setting the objective on the shared mesh DS re-inherits the repeated-call cost-growth behaviour that Integral has (issue #171, historical context: the clone-DM approach introduced in PR #172 to avoid it was reverted in 88807c26 because it produces wrong answers). Correctness parity is accepted here; #171 remains a separate performance item and is NOT closed by this PR.

Tests

  • De-xfailed tests/test_0501_integrals.py::test_cellwise_integrate_constants and ::test_cellwise_integrate_meshvar — these failed on the unfixed build (sums 2.0 and ~2x 2/pi) and now pass. Assertions reduce the local sums across ranks (no-op in serial) since evaluate() returns rank-local per-cell values.
  • pytest tests/test_0501_integrals.py -q: 11 passed, 1 xfailed (the pre-existing unrelated piecewise-derivative xfail).
  • MPI: mpirun -np 2 python -m pytest tests/test_0501_integrals.py -q: 11 passed, 1 xfailed on both ranks (rank-local sums 0.4986 + 0.5014 = 1.0 exactly).
  • Serial gate pytest tests/ -m "level_1 and tier_a" -x -q: identical before and after the fix — 295 passed, 7 skipped, 4 xfailed, 1 xpassed (the xpass is pre-existing).
  • Cross-check on the fixed build: cell-count matches getHeightStratum(0), all per-cell values positive, and the cell-wise sum of a P2 integrand matches the global Integral to machine precision.

Underworld development team with AI support from Claude Code

…ed P1 DM (BF-03)

CellWiseIntegral.evaluate() cloned mesh.dm and attached a fresh
single-P1-field discretisation (FE.createDefault + setField + createDS),
then handed DMPlexComputeCellwiseIntegralFEM a solution vector packed for
mesh.dm's multi-field layout. The layout mismatch made the integral read
the wrong DOFs: fn=1.0 on the unit square summed to 2.0 instead of 1.0
(reproduced before the fix; the control Integral gives 1.0). This is
audit finding LE-02 / worklist item BF-03
(docs/reviews/2026-07/REMEDIATION-WORKLIST.md).

The fix rewrites evaluate() to follow the working Integral pattern in the
same file: set the JIT objective on mesh.dm's own DS and integrate on
mesh.dm directly, so the compiled objective, the DS field layout, and the
packed solution vector all agree. The per-cell results are collected in a
plain Vec sized num_local_cells * num_fields (PETSc's implicit
cell-major layout when the output vector carries no section) and the
field-0 column is returned, one value per rank-local cell.

Caveat: setting the objective on the shared mesh DS re-inherits the
issue-#171 repeated-call cost-growth behaviour that Integral has. That is
accepted here for correctness parity — the clone-DM approach that avoided
it is exactly what produced wrong answers (PR #172, reverted in 88807c2).

The two xfail markers on tests/test_0501_integrals.py
(test_cellwise_integrate_constants, test_cellwise_integrate_meshvar) are
removed and the tests now pass, with the global sum reduced across ranks
so they also pass under MPI (verified serial and np=2). The serial
"level_1 and tier_a" gate is identical before and after the fix
(295 passed, 7 skipped, 4 xfailed, 1 xpassed).

Underworld development team with AI support from Claude Code
Copilot AI review requested due to automatic review settings July 3, 2026 22:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes CellWiseIntegral.evaluate() to compute cell-wise FEM integrals on the mesh’s DM/DS (matching Integral), eliminating a discretisation/layout mismatch that previously caused incorrect results (notably ~2× over-counting for simple integrands).

Changes:

  • Reworked CellWiseIntegral.evaluate() to set the objective on mesh.dm.getDS() and call DMPlexComputeCellwiseIntegralFEM() on mesh.dm with the mesh-packed solution vector.
  • Adjusted the cell-wise result collection to use a plain PETSc Vec sized as num_local_cells * num_fields, returning field-0 values per rank-local cell.
  • Updated tests by removing the prior xfail expectation and reducing per-rank cellwise sums across MPI ranks to assert correct global totals.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/underworld3/cython/petsc_maths.pyx Fixes CellWiseIntegral.evaluate() to integrate on the mesh DM/DS so the objective, discretisation, and packed solution vector agree.
tests/test_0501_integrals.py Converts prior xfailed CellWiseIntegral parity checks into regression tests (with MPI-safe global reductions).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants