fix(lamni): alignment scan-number file lists first scan of each stitch series
CI for csaxs_bec / test (push) Successful in 3m9s
CI for csaxs_bec / test (push) Successful in 3m9s
The file written before the alignment scan predicted first_scan + k per angle, which is wrong with stitching ((2*sx+1)*(2*sy+1) scans per angle). Predict with that stride, and rewrite the file after every angle so an interrupted run still leaves correct numbers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ALDnH16dC6iyHjhe5Ey4w9
This commit is contained in:
1 parent
c75a170af3
commit
de14963f3e
2 files changed
+68
-18
No files matched your search
@@ -1486,22 +1486,28 @@ class LamNI(
|
||||
) -> None:
|
||||
"""Write the scan-number/angle/offset log consumed by BEC_ptycho_align.
|
||||
|
||||
``scans`` (optional): the actual scan number of each alignment point,
|
||||
used to rewrite the file after the scan when a retried angle consumed
|
||||
extra scan numbers. Defaults to the contiguous ``first_scan + k``
|
||||
prediction written before the scan starts.
|
||||
One scan number per alignment angle: the first scan of that angle's
|
||||
stitch series (with stitching, each projection is
|
||||
(2*lamni_stitch_x+1)*(2*lamni_stitch_y+1) scans).
|
||||
|
||||
Mirrors Flomni.write_alignment_scan_numbers() exactly (same 4-line
|
||||
format), adapted to lamni's own alignment-scan angle set (12 points
|
||||
across the full 360 degrees, see tomo_alignment_scan()) and its own
|
||||
x-ray-eye-fit offset source (lamni_compute_additional_correction_xeye_mu()
|
||||
instead of get_alignment_offset()). Assumes exactly one scan per
|
||||
alignment point (no stitching) -- same assumption flomni's own
|
||||
version makes.
|
||||
``scans`` (optional): the actual first scan number of the angles
|
||||
acquired so far (possibly fewer than all 12), used to rewrite the
|
||||
file during/after the scan when a retried angle consumed extra scan
|
||||
numbers. Angles not yet acquired are predicted from the last known
|
||||
one, stepping by the number of stitch tiles per projection. Without
|
||||
``scans`` the whole list is predicted from ``first_scan``.
|
||||
|
||||
Mirrors Flomni.write_alignment_scan_numbers() (same 4-line format),
|
||||
adapted to lamni's own alignment-scan angle set (12 points across the
|
||||
full 360 degrees, see tomo_alignment_scan()) and its own x-ray-eye-fit
|
||||
offset source (lamni_compute_additional_correction_xeye_mu() instead
|
||||
of get_alignment_offset()).
|
||||
"""
|
||||
angles = list(np.linspace(0, 360, num=12, endpoint=False))
|
||||
if scans is None:
|
||||
scans = [first_scan + k for k in range(len(angles))]
|
||||
scans_per_angle = (2 * self.lamni_stitch_x + 1) * (2 * self.lamni_stitch_y + 1)
|
||||
scans = list(scans) if scans else [first_scan]
|
||||
while len(scans) < len(angles):
|
||||
scans.append(scans[-1] + scans_per_angle)
|
||||
|
||||
x_vals = []
|
||||
for angle in angles:
|
||||
@@ -1593,14 +1599,13 @@ class LamNI(
|
||||
first_scan_per_angle.append(start_scan_number)
|
||||
alignment_scan_numbers.extend(range(start_scan_number, end_scan_number))
|
||||
|
||||
# Keep the file current after every angle, so an interrupted run
|
||||
# still leaves correct first-of-stitch-series numbers behind.
|
||||
self.write_alignment_scan_numbers(first_scan_per_angle[0], scans=first_scan_per_angle)
|
||||
|
||||
self.alignment_scan_progress.update(angle_index=idx + 1, angle=angle)
|
||||
self._lamnigui_update_alignment_progress()
|
||||
|
||||
# The file written up front assumes first_scan + k per angle; a retried
|
||||
# angle consumes extra scan numbers, so rewrite it with what was
|
||||
# actually acquired.
|
||||
self.write_alignment_scan_numbers(first_scan_per_angle[0], scans=first_scan_per_angle)
|
||||
|
||||
umv(dev.lsamrot, 0)
|
||||
self.OMNYTools.printgreenbold(
|
||||
"\n\nAlignment scan finished. Please run BEC_ptycho_align and load the new fit"
|
||||
|
||||
@@ -203,3 +203,48 @@ def test_tomo_alignment_scan_projections_are_not_queued_for_reconstruction(monke
|
||||
|
||||
assert len(kwargs_seen) == 12
|
||||
assert all(kw.get("_reconstruct") is False for kw in kwargs_seen)
|
||||
|
||||
|
||||
def test_write_alignment_scan_numbers_steps_by_stitch_tiles(tmp_path, monkeypatch):
|
||||
"""With stitching each angle is (2*sx+1)*(2*sy+1) scans; the file must list
|
||||
the first scan of each angle's stitch series."""
|
||||
lamni = make_lamni(monkeypatch, xray_eye_fit=[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]])
|
||||
lamni.client.set_global_var("lamni_stitch_x", 1)
|
||||
lamni.client.set_global_var("lamni_stitch_y", 1)
|
||||
monkeypatch.setattr(
|
||||
"os.path.expanduser",
|
||||
lambda p: p.replace("~", str(tmp_path)) if p.startswith("~") else p,
|
||||
)
|
||||
log_file = tmp_path / "data/raw/logs/ptychotomoalign_scannum.txt"
|
||||
|
||||
lamni.write_alignment_scan_numbers(100)
|
||||
assert [int(s) for s in log_file.read_text().split("\n")[0].split()] == list(
|
||||
range(100, 208, 9)
|
||||
)
|
||||
|
||||
# partial actual list (angle 1 retried, +1 scan): rest predicted from it
|
||||
lamni.write_alignment_scan_numbers(100, scans=[100, 110])
|
||||
assert [int(s) for s in log_file.read_text().split("\n")[0].split()] == [100] + list(
|
||||
range(110, 209, 9)
|
||||
)
|
||||
|
||||
|
||||
def test_tomo_alignment_scan_with_stitching_records_first_scan_per_angle(tmp_path, monkeypatch):
|
||||
lamni = make_lamni(monkeypatch, xray_eye_fit=[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]])
|
||||
lamni.client.set_global_var("lamni_stitch_x", 1)
|
||||
lamni.client.set_global_var("lamni_stitch_y", 1)
|
||||
monkeypatch.setattr(
|
||||
"os.path.expanduser",
|
||||
lambda p: p.replace("~", str(tmp_path)) if p.startswith("~") else p,
|
||||
)
|
||||
|
||||
def _projection(angle, _internal=False, **kw):
|
||||
builtins.__dict__["bec"].queue.next_scan_number += 9
|
||||
|
||||
lamni.tomo_scan_projection = _projection
|
||||
|
||||
lamni.tomo_alignment_scan()
|
||||
|
||||
log_file = tmp_path / "data/raw/logs/ptychotomoalign_scannum.txt"
|
||||
scans = [int(s) for s in log_file.read_text().splitlines()[0].split()]
|
||||
assert scans == list(range(100, 208, 9))
|
||||
Reference in new issue
Block a user