Summary
The AI-based rotation-axis detection (--rotation-axis-method ai) works with tomocupy recon in try mode, but crashes with TypeError: cannot unpack non-iterable NoneType object when combined with tomocupy recon_steps --reconstruction-type full. The failure happens after preprocessing and backprojection have already completed — output h5 is written correctly, then the process dies while trying to hand caches to the AI classifier that were never actually built.
Steps to reproduce
Any recon_steps invocation combining --reconstruction-type full with --rotation-axis-method ai:
tomocupy recon_steps \
--file-name <some_raw.h5> \
--reconstruction-type full \
--rotation-axis-auto auto --rotation-axis-method ai \
--infer-model-path <model.pt> \
--retrieve-phase-method paganin --retrieve-phase-alpha 0.001 \
--propagation-distance 200 --pixel-size 1.4 --energy 30 \
--fbp-filter shepp \
--remove-stripe-method vo-all --vo-all-la-size 201 \
--flat-linear True
Expected behavior
Either
(a) recon_steps internally runs try+AI to find the center, then full recon with that center (the useful behavior), or
(b) recon_steps refuses the combination up front with a clear error message and points the user at the two-step workflow.
Actual behavior
Reconstruction runs to completion (preprocessing, phase retrieval, backprojection, tiff/h5 writing all succeed), then crashes:
Traceback (most recent call last):
File ".../tomocupy/bin/tomocupy", line 6, in <module>
sys.exit(main())
File ".../tomocupy/__main__.py", line 347, in main
results = args._func(args, cl_reader, cl_writer, save_test_results_ok=save_test_results_ok)
File ".../tomocupy/__main__.py", line 236, in run_recsteps
img_cache, center_of_rotation_cache, _ = clpthandle.recon_steps_all()
TypeError: cannot unpack non-iterable NoneType object
recon_steps_all() returned None because the underlying rec_fun for full mode (recon_sino_parallel in reconstruction/backproj_parallel.py:344) has no cache_to_infer branch and never returns anything. Meanwhile run_recsteps unconditionally expects a 3-tuple back.
Root cause
Compare run_rec and run_recsteps in src/tomocupy/__main__.py:
run_rec (line 166) — correct:
cache_to_infer = args.reconstruction_type == 'try' and use_ai
Only try+ai gets the cache-building path.
run_recsteps (line 233) — wrong:
Full+ai also flips cache_to_infer to True, promising caches that full-mode rec paths never build. Then line 236 unconditionally unpacks a 3-tuple return from recon_steps_all(), which crashes when it returns None.
Additionally, in reconstruction/backproj_parallel.py, only the recon_try_* variants have the if self.cache_to_infer: … return img_cache, center_of_rotation_cache, id_slice_cache branch. The full-recon variants (recon_sino_parallel, recon_sino_proj_parallel) do not. So no matter what cache_to_infer is set to, full-mode rec_funs never return anything.
Suggested fix
Two options, pick based on desired UX:
Minimal — match run_rec's gating and error clearly when the combo is requested:
# in run_recsteps
cache_to_infer = args.reconstruction_type == 'try' and use_ai
if args.reconstruction_type == 'full' and use_ai:
log.error("--rotation-axis-method ai requires --reconstruction-type try in recon_steps. "
"Run try mode first to find the center, then re-run with "
"--rotation-axis-auto manual --rotation-axis <value from try>.")
exit()
Non-breaking; users get a helpful error instead of a crash.
Better — actually do the useful thing:
When --reconstruction-type full --rotation-axis-method ai is requested via recon_steps, internally run a try+ai pass to find the center, then continue to full recon with that center. Mirrors what a user would want: one command → correct center → full volume.
Environment
- tomocupy
1.1.0 installed from source (with the earlier inference_pipeline return-value fix applied — without that fix the crash surfaces earlier as set rotation axis None, but this bug is separate)
- Python 3.10, cupy 12.x
- CUDA 12.x
- Linux, 2-BM beamline workstation
Workaround
Split into two tomocupy invocations mediated by the center_of_rotation.txt file that inference_pipeline writes:
# 1. AI center detection (try mode)
tomocupy recon \
--file-name <raw.h5> \
--rotation-axis-auto auto --rotation-axis-method ai \
--infer-model-path <model.pt>
# 2. Read the center and do the full recon
CENTER=$(tail -1 <dirname>_rec/try_center/<basename>/center_of_rotation.txt)
tomocupy recon_steps \
--file-name <raw.h5> \
--rotation-axis-auto manual --rotation-axis "$CENTER" \
--reconstruction-type full \
<all other flags…>
Summary
The AI-based rotation-axis detection (
--rotation-axis-method ai) works withtomocupy reconin try mode, but crashes withTypeError: cannot unpack non-iterable NoneType objectwhen combined withtomocupy recon_steps --reconstruction-type full. The failure happens after preprocessing and backprojection have already completed — output h5 is written correctly, then the process dies while trying to hand caches to the AI classifier that were never actually built.Steps to reproduce
Any
recon_stepsinvocation combining--reconstruction-type fullwith--rotation-axis-method ai:Expected behavior
Either
(a)
recon_stepsinternally runs try+AI to find the center, then full recon with that center (the useful behavior), or(b)
recon_stepsrefuses the combination up front with a clear error message and points the user at the two-step workflow.Actual behavior
Reconstruction runs to completion (preprocessing, phase retrieval, backprojection, tiff/h5 writing all succeed), then crashes:
recon_steps_all()returnedNonebecause the underlyingrec_funfor full mode (recon_sino_parallelinreconstruction/backproj_parallel.py:344) has nocache_to_inferbranch and never returns anything. Meanwhilerun_recstepsunconditionally expects a 3-tuple back.Root cause
Compare
run_recandrun_recstepsinsrc/tomocupy/__main__.py:run_rec(line 166) — correct:Only try+ai gets the cache-building path.
run_recsteps(line 233) — wrong:Full+ai also flips
cache_to_inferto True, promising caches that full-mode rec paths never build. Then line 236 unconditionally unpacks a 3-tuple return fromrecon_steps_all(), which crashes when it returns None.Additionally, in
reconstruction/backproj_parallel.py, only therecon_try_*variants have theif self.cache_to_infer: … return img_cache, center_of_rotation_cache, id_slice_cachebranch. The full-recon variants (recon_sino_parallel,recon_sino_proj_parallel) do not. So no matter whatcache_to_inferis set to, full-moderec_funs never return anything.Suggested fix
Two options, pick based on desired UX:
Minimal — match
run_rec's gating and error clearly when the combo is requested:Non-breaking; users get a helpful error instead of a crash.
Better — actually do the useful thing:
When
--reconstruction-type full --rotation-axis-method aiis requested viarecon_steps, internally run a try+ai pass to find the center, then continue to full recon with that center. Mirrors what a user would want: one command → correct center → full volume.Environment
1.1.0installed from source (with the earlierinference_pipelinereturn-value fix applied — without that fix the crash surfaces earlier asset rotation axis None, but this bug is separate)Workaround
Split into two
tomocupyinvocations mediated by thecenter_of_rotation.txtfile that inference_pipeline writes: