fix(lamni): tomo_scan_resume resumes at the interrupted angle, not a shifted sweep
_subtomo_angle_plan() used an explicit start_angle as the origin of a new 360-degree sweep. Resuming subtomo 2 at 85 deg generated 435..85; the >360 artifacts were silently skipped by _tomo_scan_at_angle's range gate, so the resume began at 355 deg, re-measured done angles, never reached the rest and reported wrong progress indices. start_angle is now the literal resume point on the sub-tomogram's own grid: the plan returns the remaining tail of the normal sweep plus a subtomo_offset used for progress numbering (mirrors Flomni). Off-grid angles raise ValueError. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -129,6 +129,53 @@ def test_all_eight_subtomos_are_equally_spaced_when_combined(stepsize):
|
||||
_assert_equally_spaced(combined, "full (all 8)")
|
||||
|
||||
|
||||
# ── resuming mid-sub-tomogram (start_angle) ─────────────────────────────────
|
||||
#
|
||||
# start_angle used to be treated as the ORIGIN of a fresh 360-degree sweep,
|
||||
# so resuming e.g. subtomo 2 at 85 deg generated 435..85 (flipped): the >360
|
||||
# artifacts were silently skipped, the resume started at 355 deg instead of
|
||||
# 85, re-measured done angles and never reached the remaining ones.
|
||||
|
||||
|
||||
def _resume(stepsize: float, subtomo_number: int, start_angle: float):
|
||||
lamni = make_lamni(stepsize)
|
||||
recorded = []
|
||||
|
||||
def _record(angle, subtomo):
|
||||
recorded.append((float(angle), int(lamni.progress["subtomo_projection"])))
|
||||
|
||||
lamni._tomo_scan_at_angle = _record
|
||||
lamni.sub_tomo_scan(subtomo_number, start_angle=start_angle)
|
||||
return recorded
|
||||
|
||||
|
||||
@pytest.mark.parametrize("stepsize", STEPSIZES)
|
||||
@pytest.mark.parametrize("subtomo_number", range(1, 9))
|
||||
def test_resume_yields_tail_of_normal_sweep(stepsize, subtomo_number):
|
||||
full = make_lamni(stepsize)
|
||||
full_recorded = []
|
||||
full._tomo_scan_at_angle = lambda angle, subtomo: full_recorded.append(float(angle))
|
||||
full.sub_tomo_scan(subtomo_number)
|
||||
|
||||
for k, start in enumerate(full_recorded):
|
||||
resumed = _resume(stepsize, subtomo_number, start)
|
||||
assert [a for a, _ in resumed] == pytest.approx(full_recorded[k:])
|
||||
assert [i for _, i in resumed] == list(range(k, len(full_recorded)))
|
||||
assert all(0 <= a < 360.05 for a, _ in resumed)
|
||||
|
||||
|
||||
def test_resume_reported_case_subtomo2_at_85_deg():
|
||||
resumed = _resume(10.0, 2, 85.0)
|
||||
assert resumed[0] == (pytest.approx(85.0), 27)
|
||||
assert resumed[-1][0] == pytest.approx(5.0)
|
||||
assert len(resumed) == 36 - 27
|
||||
|
||||
|
||||
def test_resume_off_grid_start_angle_raises():
|
||||
with pytest.raises(ValueError):
|
||||
_resume(10.0, 2, 80.0)
|
||||
|
||||
|
||||
# ── tomo_scan()'s new-scan account handling ─────────────────────────────────
|
||||
#
|
||||
# bec.active_account used to be passed through .decode() (as if it were
|
||||
|
||||
Reference in New Issue
Block a user