fix(lamni): fully reset tomo progress when a new tomo scan starts
tomo_scan() only reset the timing/ETA fields, so after a finished scan the progress GUI kept showing the old subtomo, angle and projection == total (rings at 100 %) while the initial 0-degree reference shot ran, with an ETA computed from the old projection count against the new start time. New _reset_progress_for_new_scan() resets every field (incl. the right totals for the tomo type) in one global-var update and refreshes the GUI. Resumes are unaffected. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fd4e8a2de1
commit
15c720e89e
2 files changed
+111
-8
No files matched your search
@@ -1478,6 +1478,56 @@ class LamNI(TomoQueueMixin, LamNIAlignmentMixin, LamNIOpticsMixin, LamniGuiTools
|
||||
print(f"Estimated finish time: ........... {finish_str}\x1b[0m")
|
||||
self._lamnigui_update_progress()
|
||||
|
||||
def _reset_progress_for_new_scan(self) -> None:
|
||||
"""Reset ``tomo_progress`` (and refresh the progress GUI) for a brand-new
|
||||
tomogram, in one global-var round-trip.
|
||||
|
||||
Every field must be reset, not just the timing/ETA ones: a finished
|
||||
previous scan leaves projection == total_projections (100 %), its last
|
||||
subtomo and angle behind, and the new scan's very first
|
||||
_print_progress() -- fired by the 0-degree reference shot, before the
|
||||
grid loop has written a single field -- would otherwise show those
|
||||
stale values (rings at 100 %, old subtomo/angle, and an ETA of "0 s"
|
||||
computed from the old projection count against the NEW start time).
|
||||
|
||||
subtomo is set to 1 (not 0) so a scan interrupted during the 0-degree
|
||||
shot is still resumable by tomo_scan_resume().
|
||||
"""
|
||||
if self.tomo_type == 1:
|
||||
tomo_type_name = "Equally spaced sub-tomograms"
|
||||
subtomo_total, _, total = self._tomo_type1_actual_grid()
|
||||
elif self.tomo_type == 2:
|
||||
tomo_type_name = "Golden ratio tomography"
|
||||
subtomo_total = self.golden_ratio_bunch_size
|
||||
total = self.golden_max_number_of_projections
|
||||
elif self.tomo_type == 3:
|
||||
tomo_type_name = "Equally spaced, golden ratio starting angles"
|
||||
subtomo_total = 360 / self.tomo_angle_stepsize
|
||||
total = self.golden_max_number_of_projections
|
||||
else:
|
||||
raise ValueError(f"Unknown tomo_type: {self.tomo_type}.")
|
||||
|
||||
self.progress.update(
|
||||
{
|
||||
"tomo_type": tomo_type_name,
|
||||
"subtomo": 1,
|
||||
"subtomo_projection": 0,
|
||||
# totals are used as divisors by the GUI rings -- never 0
|
||||
"subtomo_total_projections": subtomo_total or 1,
|
||||
"projection": 0,
|
||||
"total_projections": total if total and total > 0 else 1,
|
||||
"angle": 0,
|
||||
"tomo_start_time": datetime.datetime.now().isoformat(),
|
||||
# no leftover ETA from a previous scan until this one has
|
||||
# accumulated enough projections to compute a fresh one
|
||||
"estimated_remaining_time": None,
|
||||
"estimated_finish_time": None,
|
||||
"heartbeat": None,
|
||||
"accumulated_idle_time": 0.0,
|
||||
}
|
||||
)
|
||||
self._lamnigui_update_progress()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Tomo scan orchestration
|
||||
# ------------------------------------------------------------------
|
||||
@@ -1857,14 +1907,7 @@ class LamNI(TomoQueueMixin, LamNIAlignmentMixin, LamNIOpticsMixin, LamniGuiTools
|
||||
"BEC",
|
||||
)
|
||||
self.write_pdf_report()
|
||||
self.progress["tomo_start_time"] = datetime.datetime.now().isoformat()
|
||||
# reset stale estimates from any previous scan, otherwise the GUI
|
||||
# would keep showing a leftover ETA from before this scan has
|
||||
# accumulated enough projections to compute a fresh one
|
||||
self.progress["estimated_remaining_time"] = None
|
||||
self.progress["estimated_finish_time"] = None
|
||||
self.progress["accumulated_idle_time"] = 0.0
|
||||
self.progress["heartbeat"] = None
|
||||
self._reset_progress_for_new_scan()
|
||||
# Unconditional single 0-degree reference projection at the very
|
||||
# start of a new tomogram, independent of
|
||||
# zero_deg_reference_at_each_subtomo /
|
||||
|
||||
@@ -129,6 +129,65 @@ def test_all_eight_subtomos_are_equally_spaced_when_combined(stepsize):
|
||||
_assert_equally_spaced(combined, "full (all 8)")
|
||||
|
||||
|
||||
# ── progress reset at the start of a new scan ───────────────────────────────
|
||||
#
|
||||
# A finished scan leaves projection == total (100 %), its last subtomo and
|
||||
# angle in tomo_progress. The new scan's first _print_progress() (from the
|
||||
# 0-degree reference shot) used to render those stale values in the progress
|
||||
# GUI, because only the timing/ETA fields were reset.
|
||||
|
||||
|
||||
def test_new_scan_resets_stale_progress_before_first_projection(monkeypatch):
|
||||
lamni = make_lamni_for_tomo_scan(monkeypatch, 10.0, active_account="")
|
||||
lamni.progress.update(
|
||||
{
|
||||
"tomo_type": "Golden ratio tomography",
|
||||
"subtomo": 8,
|
||||
"subtomo_projection": 36,
|
||||
"subtomo_total_projections": 36,
|
||||
"projection": 288,
|
||||
"total_projections": 288,
|
||||
"angle": 355.0,
|
||||
"estimated_remaining_time": 0.0,
|
||||
"estimated_finish_time": "2020-01-01T00:00:00",
|
||||
"accumulated_idle_time": 99.0,
|
||||
"heartbeat": "2020-01-01T00:00:00",
|
||||
}
|
||||
)
|
||||
lamni.add_sample_database = lambda *a, **k: 0
|
||||
seen = []
|
||||
lamni._tomo_scan_at_angle = lambda angle, subtomo_number: seen.append(
|
||||
(angle, subtomo_number, dict(lamni.progress.as_dict()))
|
||||
)
|
||||
|
||||
lamni.tomo_scan()
|
||||
|
||||
angle, subtomo_number, prog = seen[0]
|
||||
assert (angle, subtomo_number) == (0, 1)
|
||||
assert prog["tomo_type"] == "Equally spaced sub-tomograms"
|
||||
assert prog["subtomo"] == 1
|
||||
assert prog["projection"] == 0
|
||||
assert prog["subtomo_projection"] == 0
|
||||
assert prog["angle"] == 0
|
||||
assert prog["total_projections"] == 36 * 8
|
||||
assert prog["subtomo_total_projections"] == 36
|
||||
assert prog["estimated_remaining_time"] is None
|
||||
assert prog["estimated_finish_time"] is None
|
||||
assert prog["accumulated_idle_time"] == 0.0
|
||||
assert prog["heartbeat"] is None
|
||||
assert prog["tomo_start_time"] is not None
|
||||
|
||||
|
||||
def test_resume_does_not_reset_progress(monkeypatch):
|
||||
lamni = make_lamni_for_tomo_scan(monkeypatch, 10.0, active_account="")
|
||||
resets = []
|
||||
lamni._reset_progress_for_new_scan = lambda: resets.append(1)
|
||||
|
||||
lamni.tomo_scan(subtomo_start=2, start_angle=85.0)
|
||||
|
||||
assert resets == []
|
||||
|
||||
|
||||
# ── resuming mid-sub-tomogram (start_angle) ─────────────────────────────────
|
||||
#
|
||||
# start_angle used to be treated as the ORIGIN of a fresh 360-degree sweep,
|
||||
@@ -218,6 +277,7 @@ def make_lamni_for_tomo_scan(
|
||||
obj._print_progress = lambda: None
|
||||
obj._format_duration = lambda seconds: "0s"
|
||||
obj.lamnigui_show_progress = lambda: None
|
||||
obj._lamnigui_update_progress = lambda: None
|
||||
obj.at_each_angle_hook = None
|
||||
obj.OMNYTools = types.SimpleNamespace(printgreenbold=lambda msg: None)
|
||||
# These tests exercise tomo_scan()'s account-handling/heartbeat/progress-GUI
|
||||
|
||||
Reference in new issue
Block a user