Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Fix real-ray stop radius for decentered stops (#654)#684

Open
manuelFragata wants to merge 1 commit into
masteroptiland/optiland:masterfrom
fix/ray-aiming-654-decentered-stopoptiland/optiland:fix/ray-aiming-654-decentered-stopCopy head branch name to clipboard
Open

Fix real-ray stop radius for decentered stops (#654)#684
manuelFragata wants to merge 1 commit into
masteroptiland/optiland:masterfrom
fix/ray-aiming-654-decentered-stopoptiland/optiland:fix/ray-aiming-654-decentered-stopCopy head branch name to clipboard

Conversation

@manuelFragata

@manuelFragata manuelFragata commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #678, which fixed the tilted-stop, back-surface-stop and folded cases but left the offset-stop case out. That case is a real solver bug, not the system-definition inconsistency the earlier file suggested.

The bug

The entrance pupil is the image of the stop, so a decentered stop has a decentered entrance pupil. RealReferenceStrategy measured the stop radius by launching a probe at y = EPD/2, on the axis, and reporting where it landed relative to the stop centre. When the pupil is off axis that probe never goes near it, so the reported radius is unrelated to the stop.

On the system reported in the follow-up comment (a small R=5 lens, r_max 1.0, decentered to y=+5 behind a singlet):

launch y -> local stop (x, y)      [R=5 sphere: |local r| must be < 5]
  y= 0.000 -> (nan, nan)             the on-axis probe misses the stop entirely
  y= 1.131 -> ( 0.0000, -4.0392)     EPD/2 probe: 4 mm from the stop centre
  y= 5.673 -> ( 0.0000,  0.0000)     the actual pupil centre
  y= 6.804 -> ( 0.0000,  0.9773)     the actual pupil edge

So r_stop came out 4.039 against a true radius of ~1.0. The aimer then targeted the full pupil four times too wide: the outer rays missed the stop surface (NaN) and the rest were vignetted by its physical aperture, leaving only the chief ray. That is the degenerate spot in the report.

Note the aperture is self-consistent here: EPD 2.2622 puts the paraxial marginal ray at exactly 1.0, which is the stop's r_max. The system is correctly defined, unlike the earlier file (EPD 20 against a radius-5 stop) that #678 set aside.

The fix

Solve for the pupil centre first, the axial ray landing on the stop's own origin, which needs no stop radius, then offset EPD/2 from there. The solve reuses IterativeRayAimer._solve_core against target (0, 0) and is seeded with the first-order pupil decenter (stop decenter times pupil magnification), which predicts 5.6555 against the true 5.6727 and converges immediately.

For a centered system the seed is zero and the solve is a no-op, so the measured radius is unchanged by construction.

After the fix

Aimed rays land at local stop y [-0.977, -0.489, 0.000, 0.489, 0.977]: linear in Py, centred on the stop to 1e-9, all inside r_max 1.0. The full disk pupil traces unvignetted.

r_stop is bit-identical on every system that already worked:

system master this PR
CookeTriplet 3.8575 3.8575
ReverseTelephoto 0.1821 0.1821
tilted mirror (#654 bug 4) 9.9876 9.9876
back-surface stop (#654 bug 2) 9.7954 9.7954
tilted finite stop (#654 bug 1) 7.6383 7.6383
decentered stop 4.0389 0.9775

No system falls back to the paraxial path, so the real-ray measurement is exercised throughout.

Tests

Two regression tests in tests/test_ray_aiming.py, on both backends: the real-ray radius must match the paraxial reference for a decentered stop, and every pupil ray must aim inside the stop's clear aperture and reach the image unvignetted. Both fail on master and pass here. The existing ray-aiming, initialization, cached-aimer and image-simulation suites are unchanged (226 passing).

Refs #654

The entrance pupil is the image of the stop, so a decentered stop has a
decentered entrance pupil. RealReferenceStrategy probed the pupil edge by
launching at (0, EPD/2) -- on the axis -- and reported the distance from
the stop centre to wherever that ray landed. For a stop decentered off
axis the probe never goes near the pupil, so the reported radius is
unrelated to the stop.

On the system reported in #654, this returned 4.04 against a true radius
of ~1.0. The aimer then targeted the full pupil at a radius four times too
large: the outer rays missed the stop surface entirely (NaN) and the rest
were vignetted by its physical aperture, leaving only the chief ray.

Solve for the pupil centre first -- the axial ray landing on the stop's own
origin, which needs no stop radius -- then offset EPD/2 from there. The
solve is seeded with the first-order pupil decenter (stop decenter times
pupil magnification). For a centered system the seed is zero and the solve
is a no-op, so the measured radius is unchanged on every system that
already worked.

Refs #654
@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.55556% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
optiland/rays/ray_aiming/initialization.py 95.55% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

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.

1 participant

Morty Proxy This is a proxified and sanitized view of the page, visit original site.