Skip to content

Fixed the stop root-finding problem for transmissive stop surfaces#170

Open
jacobdparker wants to merge 1 commit into
fix/object-field-stopfrom
fix/transmissive-stops
Open

Fixed the stop root-finding problem for transmissive stop surfaces#170
jacobdparker wants to merge 1 commit into
fix/object-field-stopfrom
fix/transmissive-stops

Conversation

@jacobdparker

Copy link
Copy Markdown
Contributor

Third PR in the stop-solver stack — stacked on #169 (the diff shown here is relative to that branch).

Problem

The reversed trace in _calc_rayfunction_stops propagates the solved stop rays back to the object by re-applying every surface from the stop backward. That only works when the stop is a mirror: reflection is an involution, so applying the stop surface to its own forward output turns the rays around exactly. A transmissive stop that modifies the rays — a transmission grating or a Fresnel zone plate — is not an involution: its diffraction was applied a second time instead of undone, corrupting the computed field extents by an order of magnitude (~20× for the FZP tutorial, #153).

(For the record: a true time-reversed trace through transmissive rulings would require negating the diffraction order, while reflective rulings are time-reversal symmetric with the same order, because the sign(direction · normal) factor in incident_effective flips along with the reflection. This PR sidesteps reversed traces through transmissive elements entirely instead.)

Changes

  • New _stop_is_involutory predicate (mirrors and no-op vacuum surfaces qualify; surfaces with rulings or refraction do not).
  • For non-involutory stops, the stop's own diffraction/refraction is included inside the root-finding problem (the solved variable becomes the pre-stop ray), and the stop's material and rulings are stripped on the reversed leg so only its geometry participates.
  • _ray_error now takes explicit propagators / transformation_last arguments so callers control which surfaces are inside the solve.

Tests

Adds TestSequentialSystemFZP: a telescope whose only element is a transmissive Fresnel zone plate (HolographicRulingSpacing) acting as the pupil stop, asserting the recovered field half-angle equals arctan(sensor half-width / focal length) to 1e-3 deg.

🤖 Generated with Claude Code

The reversed trace in `_calc_rayfunction_stops` propagates the solved
stop rays back to the object by re-applying every surface from the stop
backward. That is only correct when the stop is a mirror: reflection is
an involution, so applying the stop surface to its own forward output
turns the rays around exactly. A transmissive stop that modifies the
rays (e.g. a transmission grating or a Fresnel zone plate) is not an
involution — its diffraction was applied a second time instead of
undone, which corrupted the computed field and pupil extents by an
order of magnitude.

For non-involutory stops, the stop's own diffraction/refraction is now
included inside the root-finding problem (the solved variable becomes
the pre-stop ray), and the stop's material and rulings are stripped on
the reversed leg so only its geometry participates.

A true time-reversed trace through transmissive rulings would require
negating the diffraction order (reflective rulings are time-reversal
symmetric with the same order); this approach sidesteps reversed traces
through transmissive elements entirely.

Adds a Fresnel-zone-plate regression test asserting that the recovered
field half-angle matches arctan(sensor half-width / focal length).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 99.37%. Comparing base (40c7ea5) to head (df9358d).

Files with missing lines Patch % Lines
optika/systems/_sequential.py 94.11% 1 Missing ⚠️
Additional details and impacted files
@@                  Coverage Diff                   @@
##           fix/object-field-stop     #170   +/-   ##
======================================================
  Coverage                  99.36%   99.37%           
======================================================
  Files                        116      116           
  Lines                       6024     6053   +29     
======================================================
+ Hits                        5986     6015   +29     
  Misses                        38       38           
Flag Coverage Δ
unittests 99.37% <96.66%> (+<0.01%) ⬆️

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.

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