diff --git a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py index 8794401b..61bef47a 100644 --- a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py +++ b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py @@ -1504,11 +1504,14 @@ class LamNI( 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 (13 points, 0 to 360 - degrees inclusive, see alignment_scan_angles()) and its own x-ray-eye-fit - offset source (lamni_compute_additional_correction_xeye_mu() instead - of get_alignment_offset()). + File format, as read by BEC_ptycho_align (MATLAB): + line 1 scans first scan number per angle + line 2 theta angle [deg] + line 3 scan_xpos X-ray-eye x correction at that angle [um] + line 4 scan_ypos X-ray-eye y correction at that angle [um] + Lines 3/4 are only used by its sinusoid branch (lamni_fit = false); + the LaMNI ellipse fit uses just the clicks, scans and theta. + lamni_compute_additional_correction_xeye_mu() returns mm, hence *1000. """ angles = self.alignment_scan_angles() scans_per_angle = (2 * self.lamni_stitch_x + 1) * (2 * self.lamni_stitch_y + 1) @@ -1516,20 +1519,19 @@ class LamNI( while len(scans) < len(angles): scans.append(scans[-1] + scans_per_angle) - x_vals = [] + x_um, y_um = [], [] for angle in angles: - x, _y = self.lamni_compute_additional_correction_xeye_mu(angle, verbose=False) - x_vals.append(x) - - zeros = [0] * len(angles) + x, y = self.lamni_compute_additional_correction_xeye_mu(angle, verbose=False) + x_um.append(x * 1000) + y_um.append(y * 1000) file = os.path.expanduser("~/data/raw/logs/ptychotomoalign_scannum.txt") os.makedirs(os.path.dirname(file), exist_ok=True) with open(file, "w") as f: f.write(" ".join(map(str, scans)) + "\n") f.write(" ".join(map(str, angles)) + "\n") - f.write(" ".join(f"{x:.2f}" for x in x_vals) + "\n") - f.write(" ".join(map(str, x_vals)) + "\n") + f.write(" ".join(f"{x:.4f}" for x in x_um) + "\n") + f.write(" ".join(f"{y:.4f}" for y in y_um) + "\n") def tomo_alignment_scan(self, force: bool = False) -> None: """Perform a laminogram alignment scan: a quick ptychography scan at diff --git a/tests/tests_bec_ipython_client/test_lamni_tomo_alignment_scan.py b/tests/tests_bec_ipython_client/test_lamni_tomo_alignment_scan.py index 944de437..d81ab1ce 100644 --- a/tests/tests_bec_ipython_client/test_lamni_tomo_alignment_scan.py +++ b/tests/tests_bec_ipython_client/test_lamni_tomo_alignment_scan.py @@ -248,3 +248,19 @@ def test_tomo_alignment_scan_with_stitching_records_first_scan_per_angle(tmp_pat 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, 217, 9)) + + +def test_write_alignment_scan_numbers_lines_3_4_are_x_and_y_in_um(tmp_path, monkeypatch): + """BEC_ptycho_align reads line 3 as scan_xpos and line 4 as scan_ypos, in + microns; the X-ray eye fit is stored in microns ([[Ax,Bx,Cx],[Ay,By,Cy]]).""" + lamni = make_lamni(monkeypatch, xray_eye_fit=[[0.0, 0.0, 12.5], [0.0, 0.0, -3.25]]) + monkeypatch.setattr( + "os.path.expanduser", + lambda p: p.replace("~", str(tmp_path)) if p.startswith("~") else p, + ) + + lamni.write_alignment_scan_numbers(100) + + lines = (tmp_path / "data/raw/logs/ptychotomoalign_scannum.txt").read_text().splitlines() + assert [float(v) for v in lines[2].split()] == pytest.approx([12.5] * 13) + assert [float(v) for v in lines[3].split()] == pytest.approx([-3.25] * 13)