Skip to content

Add a spectral map onto the sphere - #129

Merged
m-reuter merged 2 commits into
Deep-MI:mainfrom
m-reuter:sphere
Oct 24, 2026
Merged

m-reuter merged 2 commits into
Deep-MI:mainfrom
m-reuter:sphere

Conversation

@m-reuter

@m-reuter m-reuter commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Adds a general spectral map onto the sphere, and builds tria_spherical_project on the same eigensolve. This is the follow-up to #128 that brings the looser eigensolver tolerance to the sphere maps.

Changes

  • New spherical_spectral_map(tria, flow_iter=3, tol=1e-6, use_cholmod=False) in lapy.diffgeo: the first three non-constant eigenfunctions, scaled to [-1, 1], a few steps of mean curvature flow and a radial projection onto the unit sphere. Unlike tria_spherical_project, it assumes no orientation of the surface in space and does not reject maps that fold, so it can be used to find where a surface folds. The result is mirrored if needed so that most triangles keep their orientation.
  • New flipped_triangles(sphere, t): the triangles of a map onto a sphere that face its centre, i.e. where the map folds over.
  • tria_spherical_project keeps its alignment to brain axes, its scale and its checks, and gains tol (default 1e-6) and use_cholmod. It counts flipped area with flipped_triangles.
  • Both compute 6 eigenpairs instead of the 4 needed: with a loose tolerance, ARPACK can otherwise miss one copy of a repeated eigenvalue, which folds about half of the map. A fixed start vector makes the maps reproducible; before, tria_spherical_project started from a random vector. Meshes with at most 6 vertices, where the sparse solver cannot return that many eigenpairs, are solved densely; before, a tetrahedron failed in the eigensolver.

Effect on tria_spherical_project

On four cortical surfaces (smoothwm.nofix of FastSurfer's 1.0 mm and 0.8 mm test cases, both hemispheres), the flipped area is the same as with LaPy 1.7.0 to three digits, all four pass the checks, and vertices move by at most 0.02 degrees (median 0). With the faster flow from #128, the projection takes 3.4 to 5.2 s instead of 5.2 to 8.0 s.

Tests

New test_spherical_map.py:

  • A square voxel slab, whose second and third eigenvalues are equal, maps without any flipped triangle. With 4 eigenpairs instead of 6, half of its triangles flip and the test fails.
  • A tetrahedron and an octahedron map without folds; without the dense solve both fail in the eigensolver.
  • An ellipsoid and a rigidly moved copy map to the same sphere up to an orthogonal transform, to 1e-5.
  • Mirroring a cap of the sphere flips exactly its triangles.
  • tria_spherical_project maps the extreme points of an ellipsoid in each direction near the matching poles. The test fails if one axis comes out with the wrong sign.

The suite passes with the current and the minimum dependency versions, and the docs build with -W.

@codecov

codecov Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.65517% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.20%. Comparing base (43f9161) to head (e290e41).

Files with missing lines Patch % Lines
lapy/diffgeo.py 89.65% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #129      +/-   ##
==========================================
+ Coverage   67.10%   69.20%   +2.09%     
==========================================
  Files          19       19              
  Lines        3590     3588       -2     
  Branches      464      468       +4     
==========================================
+ Hits         2409     2483      +74     
+ Misses        998      907      -91     
- Partials      183      198      +15     
Flag Coverage Δ
unittests 69.20% <89.65%> (+2.09%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

🟡 Changes recommended

The unconditional six-eigenpair request fails on valid closed meshes with four to six vertices.

1 open issue
What changed in this PR

Adds an orientation-independent spectral sphere map and shares its eigensolve with tria_spherical_project, extending the performance improvements from #128.

Changes:

  • Adds spherical_spectral_map and flipped_triangles for mapping surfaces and detecting folds.
  • Uses six reproducible eigenpairs with configurable tolerance and solver backend while preserving brain-axis alignment and projection checks.
  • Adds tests for repeated eigenvalues, rigid-motion invariance, fold detection, and axis alignment.
File Description
lapy/​utils/​tests/​test_spherical_map.py Adds regression tests for spectral maps and spherical projection.
lapy/​diffgeo.py Adds mapping helpers and shares the configurable eigensolve between sphere maps.

Review effort: Balanced

Comment thread lapy/diffgeo.py Resolved
@m-reuter
m-reuter merged commit 398a736 into Deep-MI:main Oct 24, 2026
15 checks passed
@m-reuter
m-reuter deleted the sphere branch October 24, 2026 22:19
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