[ESSREDUCE] Project chopper axle onto incident beam for flight distance#630
[ESSREDUCE] Project chopper axle onto incident beam for flight distance#630SimonHeybrock wants to merge 2 commits into
Conversation
The chopper-cascade LUT derived each chopper's flight distance from `norm(axle_position - source_position)`. A disk chopper's axle sits above or below the beam by design, so that straight-line distance overestimates the beam-path length. For closely-spaced choppers a large transverse axle offset can even reorder the cascade: e.g. DREAM's pulse-shaping choppers PSC1 (axle 0.7 m off-beam, 6.145 m downstream) and PSC2 (on-beam, 6.155 m) swap order under the norm (6.185 m vs 6.155 m), so PSC1 is applied last or, over a narrow distance range, never at all. Compute the distance as the projection of the axle position onto the incident-beam direction (source to sample) instead. This matches the straight-line `Ltotal` used for detectors and monitors, where the component lies on the beam and the projection reduces to the norm, so on-axis choppers are unaffected. This adds `sample_position` as an input to `compute_frame_sequence` and `simulate_chopper_cascade_using_tof`; workflows built from NeXus already provide it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| def simulate_chopper_cascade_using_tof( | ||
| choppers: DiskChoppers[RunType], | ||
| source_position: Position[snx.NXsource, RunType], | ||
| sample_position: Position[snx.NXsample, RunType], |
There was a problem hiding this comment.
@nvaytet Not sure about this, as it would require always having a sample-position. Alternative would be to simply default to beam=Z.
| """ | ||
| source_position = source_position.to(unit=axle_position.unit) | ||
| incident_beam = sample_position.to(unit=axle_position.unit) - source_position | ||
| return sc.dot( |
There was a problem hiding this comment.
I had assumed that for balancing purposes, choppers are always installed vertical?
In the case of a tilted guide, I think the dot product is not quite right, because the chopper disk goes vertically from its axle center towards the beam, instead of perpendicular to the beam?
Instead we may need to somehow use the gravity vector?
We also need to make it work for the case where the chopper is neither above nor below the beam, but on the side (as is the case for one of the Dream choppers).
There was a problem hiding this comment.
This comment seems to go beyond the immediate fix -- the old solution didn't handle curved guides either, did it? Or do you think it is worse than before?
There was a problem hiding this comment.
the old solution didn't handle curved guides either, did it? Or do you think it is worse than before?
No and no. It's just a case I thought about when reading your use of the dot product.
I think we should either fix this additional case, or at least write a comment in the code and/or open an issue?
There was a problem hiding this comment.
Conclusion from in-person discussion: use the z-component, which also removes the need for having a sample position.
Project the chopper axle onto the incident beam by taking the z-component of the offset from the source, assuming the beam runs along z. This keeps the correct cascade ordering for off-beam axles without requiring a sample position as workflow input. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Problem
The chopper-cascade wavelength LUT derives each chopper's flight distance from
norm(axle_position - source_position). A disk chopper's axle sits above, below, or to the side of the beam by design, so this straight-line distance overestimates the actual beam-path length.Usually the error is negligible, but for closely-spaced choppers a large transverse axle offset can reorder the cascade. Concrete case on DREAM: the pulse-shaping choppers PSC1 (axle 0.7 m off-beam, 6.145 m downstream) and PSC2 (on-beam, 6.155 m). Under the norm their distances become 6.185 m and 6.155 m, so PSC1 is sorted after PSC2 and applied last — or, when the LUT is evaluated over a narrow distance range around the choppers, never applied at all. The result is that PSC1's phase/delay has no effect on the table.
Fix
Compute the distance as the projection of the axle position onto the incident-beam direction. The neutron crosses the disk where the incident beam intersects it, so this is the correct flight distance. Assuming the incident beam runs along the z axis, the projection is simply the z-component of the offset from the source. This is consistent with the straight-line
Ltotalused for detectors and monitors, which lie on the beam where the projection reduces to the norm, so on-axis choppers are unaffected and existing results are unchanged.Taking the z-component (rather than a source-to-sample dot product) avoids needing a sample position as input, keeping the workflow API unchanged.
Tests
Existing analytical and simulation LUT tests pass unchanged.