Repository navigation
Add FigureErrorSag, a base sag profile plus a map of its figure error - #269
Merged
Merged
Conversation
`optika.sags.FigureErrorSag` adds a map of the figure error of a surface, such as one measured with an interferometer, to the height of a base sag profile. The map is a function array, evaluated at the positions with multilinear interpolation. The map raises the surface, which a physical-optics calculation that samples the surface sees, but the normal vectors and the intercepts of rays are those of the base profile, so the map does not deflect rays. The slope of a measured map between its pixels is mostly noise, and where the map shifts the phase of the wavefront by less than about a radian, it scatters a little of the light instead of deflecting all of it. Low-order terms which should deflect rays belong in the base profile, for example as a `ZernikeSag`. `axis` names the axes along which the map is sampled, and its other axes, such as one along which there is a separate map for each channel, are axes of the sag profile. The map and the positions may be uncertain, which needs named-arrays 2.18. The tests run the abstract tests of sag profiles, with the test of the intercepts replaced by one which requires them to be those of the base profile, and check: - the height above the base profile against an affine map, in the coordinate system of a transformed sag profile, with a map for each channel, with an uncertain map, and with none; - that the normal vectors are those of the base profile; - the shape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
The map has two components, so it is always sampled along two axes, and a single axis could never be resampled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
…annel With a grid for each channel, the default axes would include the channels, so the test fails if the explicit axes are ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
The slice at y = 10 mm ran near a node of the map, where its height is only about 1.4 nm. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #269 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 129 131 +2
Lines 10540 10681 +141
==========================================
+ Hits 10540 10681 +141
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
A system launches the rays of its stop solve from the height of the stop surface, which includes the figure error, so on a stop surface the map moves the rays of a raytrace slightly. Say so. Also say that the map is extrapolated linearly outside of it, and that leaving the map out of the intercepts moves them along each ray by its height divided by the cosine of the angle of incidence, rather than by no more than its height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
A misnamed axis, or a str, which was split into its characters, made the axes of the map look like batch axes of the sag profile, and the error only came when the height was evaluated, which a raytrace does only on a stop surface. By default, every axis of the inputs was an axis of the map, so a separate grid for each channel made the channel an axis of the map too. Now `axis` must name two distinct axes along which the inputs vary whenever there is a map, and `shape` fails fast otherwise, as it does for a misnamed axis of `ZernikeSag`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
optika.sags.FigureErrorSagadds a map of the figure error of a surface, such as one measured with an interferometer, to the height of a base sag profile. The map is a function array, evaluated at the positions with the multilinear interpolation of named-arrays.Design
ZernikeSag, with the rest of the map inFigureErrorSag.axisnames the two axes along which the map is sampled, and is required whenever there is a map. The map's other axes, such as one along which there is a separate map for each channel, are axes of the sag profile. The map may be sampled on a separate grid for each channel. A missing, misnamed or repeated axis, a str, or a third axis fails as soon as the shape of the sag profile is needed, as a misnamed axis ofZernikeSagdoes.named-arrays~=2.15to~=2.18.Things to note
test_interceptof the sag profiles requires the intercepts to lie on the surface,sag(position). Those ofFigureErrorSaglie on the base profile instead, by design, and miss the surface by up to the height of the map, which is nanometers for a measured map.TestFigureErrorSag.test_interceptreplaces the abstract test with one which requires the positions and directions of the intercepted rays to be exactly those of the base profile.optika.wavefieldsonfeature/wavefields, which samples each surface atposition.z = sag(position). Its PR, Add optika.wavefields: physical-optics propagation through a SequentialSystem #173, was closed unmerged two seconds after its base, Add optika.zernikes and ZernikeSag #172, was merged, and Add beam-footprint utilities and PSF metrics for the wavefield path #174 is still open on top of it. Until the wave optics are merged, the map only shows up where the height of the sag profile is evaluated directly, which includes the stop solve.Tests
TestFigureErrorSagruns the abstract tests of the sag profiles on a map of a flat surface, a parabolic one whose axes are given as a list, a separate map for each channel on a transformed spherical one, a separate grid for each channel, an uncertain map on top of aZernikeSag, and no map. Itstest_normalalso requires the normal vectors to be exactly those of the base profile.test__call__figure_errorchecks the height above the base profile against an affine map, which multilinear interpolation reproduces exactly, in the coordinate system of the transformed sag profile, for each of those cases.test_axis_andtest_shape_figure_errorcheck the axes of each case, and that the shape leaves out the axes along which the map is sampled.test_axis_invalidchecks that a missing, misnamed, single or repeated axis, a str, and a third axis each fail, for the shape and for the height.FigureErrorSagat 8979388 made at least one test fail, and so does each of 5 mutations of the checks ofaxis.Checks
test_to_dxfcases run on their own. Those all writetest_dwg.dxfin the working directory, so they race between xdist workers. CI runs the suite serially.🤖 Generated with Claude Code
https://claude.ai/code/session_01BYjDL98znSud1yFh9chnkP