Skip to content

🐛 Handle degenerate 4-fold Voronoi vertices in _assemble_forces#42

Merged
wwang721 merged 3 commits intomainfrom
fix/4-fold
Apr 7, 2026
Merged

🐛 Handle degenerate 4-fold Voronoi vertices in _assemble_forces#42
wwang721 merged 3 commits intomainfrom
fix/4-fold

Conversation

@wwang721
Copy link
Copy Markdown
Owner

@wwang721 wwang721 commented Apr 6, 2026

Closes #38

Summary

  • When 4+ seed points are co-circular (e.g. a perfect square), qhull can return a single Voronoi vertex incident to 4+ ridges. The force assembly assumes exactly 3 incident cells and throws ValueError: too many values to unpack when unpacking vertex_points[h].
  • Add a fallback in _assemble_forces for this degenerate case.
  • Extend the geometry test to cover the square configuration that triggers issue Handle degenerate 4-fold Voronoi vertices causing unpacking errors in _assemble_forces #38.

Test plan

  • pytest tests/test_geom.py — covers right-angle and square configurations
  • Run full test suite to confirm no regressions

When 4+ seed points are co-circular, qhull can produce a single Voronoi
vertex incident to 4+ ridges, causing "too many values to unpack" when
the code assumes exactly 3 incident cells. Add a fallback and extend the
geometry test to cover the square configuration.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@wwang721 wwang721 self-assigned this Apr 6, 2026
@wwang721 wwang721 added the bug Something isn't working label Apr 6, 2026
@wwang721 wwang721 added this to the Release v0.5 milestone Apr 6, 2026
@wwang721
Copy link
Copy Markdown
Owner Author

wwang721 commented Apr 7, 2026

Investigation note: same-looking pts, different behavior

During testing I observed that two point arrays that print identically as (±0.54296524, ±0.54296524) can produce different outcomes — one succeeds, one crashes with KeyError.

Root cause: the displayed values are rounded. The actual float64 bit patterns differ:

  • Points loaded from the .npy file are the result of simulation steps, so they're slightly off from any exact fraction.
  • A manually-constructed array like np.array([[1.,1.],[-1.,1.],[-1.,-1.],[1.,-1.]]) * 0.54296524 produces exactly ±0.54296524.

That tiny difference in the lower bits determines what qhull sees:

  • Exactly cocircular (e.g. exact ±0.5 square) → qhull emits 1 finite Voronoi vertex → no problem (fixed in commits above).
  • Nearly cocircular (evolved pts, off by ~1e-8) → qhull emits 2 nearly-coincident finite Voronoi vertices → the angle sort in build_point_edges is numerically unstable for those two vertices and can order them either way, causing the ridge lookup to fail ~50% of the time. It also produces divide-by-zero warnings because the edge length between the nearly coincident vertices is effectively zero.

When input points are nearly cocircular, qhull can emit two nearly-
coincident finite vertices whose angles from a cell center are
indistinguishable, making the polygon sort unstable and causing a
KeyError in geometry construction. Retry with QJ (joggle) on failure
to skip the degenerate frame cleanly. Adds regression test using
the saved degenerate point set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@wwang721 wwang721 merged commit 17ab96d into main Apr 7, 2026
4 checks passed
@github-project-automation github-project-automation bot moved this from Todo to Done in PyAFV project Apr 7, 2026
@wwang721 wwang721 deleted the fix/4-fold branch April 7, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Handle degenerate 4-fold Voronoi vertices causing unpacking errors in _assemble_forces

1 participant