Uh oh!
There was an error while loading. Please reload this page.
ePIE.reconstruct() runs the reconstruction as it should - #91
Merged
Conversation
ePIE.reconstruct() contained a `yield`, so it was a generator function. Calling it built a generator object and returned immediately without doing any work, which is what most callers do -- including the tutorials and example_scripts/exampleReconstruction_pcPIE.py:126. Those runs have been silently producing an unreconstructed object. reconstruct() now drains the loop to completion. The generator behaviour is preserved as reconstruct_stepwise(), for callers that want to interleave their own work between scan positions. Also removes the unconditional `with cp.cuda.Stream(non_blocking=True)` around the position body. It made ePIE raise AttributeError on any machine without CuPy, since `cp` is None there, so the engine could not run on CPU at all. The per-position stream.synchronize() went with it -- it forced a host/device round trip after every scan position for no benefit. Adds five ePIE goldens (Fraunhofer, ASP, Fresnel, mixed-state, polychrome). Verified they fail against the unfixed engine: the CPU goldens mismatch, and the GPU-vs-CPU comparison raises AttributeError because _prepareReconstruction() lives inside the generator body and never ran, so reconstruction.error was never created. BREAKING: callers doing `for _ in engine.reconstruct()` must switch to reconstruct_stepwise(). Updated tests/Engines/test_propagator.py and the two documentation snippets, which were already broken -- they iterate the FPM and e3PIE engines, neither of which was ever a generator. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 3, 2026
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 freeto 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.
Second in the series that builds a safety net before performance work. Follows #90.
The bug
ePIE.reconstruct()contained ayield, which makes it a generator function. Calling itbuilds a generator object and returns immediately, without running anything.
Most callers call it plainly:
So those runs have been silently producing an unreconstructed object. The tutorials do the
same.
The fix
reconstruct()now drains the loop to completion. The generator behaviour is kept asreconstruct_stepwise(), for callers that want to interleave their own work between scanpositions.
Also removed: the unconditional CUDA stream
The position body was wrapped in:
Two problems:
cpisNone, so this raisesAttributeError. ePIE could not runon CPU at all.
stream.synchronize()fired after every scan position, forcing a host/device round trip forno benefit.
Both are gone.
Test coverage
Five ePIE goldens added: Fraunhofer, ASP, Fresnel, mixed-state (
nosm=2, npsm=3), polychrome(
nlambda=3). Suite goes 20 → 30 passing.Verified the goldens are meaningful by running them against the unfixed engine — all ten fail:
AttributeError: 'Reconstruction' object has no attribute 'error', because_prepareReconstruction()lives inside the generator body and never ran.Anyone doing
for _ in engine.reconstruct():must switch toreconstruct_stepwise().Updated in this PR:
tests/Engines/test_propagator.pydocs/fpm/overview.mddocs/advanced/multislice.mdThe two doc snippets iterate the FPM and e3PIE engines, neither of which was ever a generator
—
for loop, posLoop in engine.reconstruct()would have raisedTypeErrorthere today. ePIE wasthe only generator in the codebase.
Version
0.2.5→0.2.6. Not published on its own; grouped with the next two fixes into one release.