fix(LamNI): accumulate rotation-center shift across calibration iterations
lamni_move_to_scan_center's shift_x/shift_y are absolute offsets from the currently-configured lsamx_center/lsamy_center (unchanged until the operator confirms at the end of the procedure), not incremental deltas from wherever the stage currently sits. The extended-sample iteration loop was passing only the latest click's delta each time, so each new iteration partially undid the previous one's correction instead of adding to it. Fixed by accumulating the total shift across iterations and always applying the running total. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -185,13 +185,25 @@ def _make_calibration_align(client):
|
||||
return align, dev_mock
|
||||
|
||||
|
||||
def test_apply_rotation_center_shift_math(bec_client_mock):
|
||||
def test_compute_shift_to_fzp_math(bec_client_mock):
|
||||
client = bec_client_mock
|
||||
align, _dev_mock = _make_calibration_align(client)
|
||||
|
||||
target_x, target_y = align._compute_shift_to_fzp(
|
||||
fzp_x=0.0, fzp_y=0.0, center_x=0.4, center_y=0.5
|
||||
)
|
||||
|
||||
assert target_x == pytest.approx(-0.4)
|
||||
assert target_y == pytest.approx(0.5)
|
||||
|
||||
|
||||
def test_apply_rotation_center_shift_moves_by_given_absolute_shift(bec_client_mock):
|
||||
client = bec_client_mock
|
||||
align, dev_mock = _make_calibration_align(client)
|
||||
|
||||
with mock.patch(f"{XRAY_EYE_ALIGN}.dev", dev_mock):
|
||||
with mock.patch(f"{XRAY_EYE_ALIGN}.time.sleep"):
|
||||
align._apply_rotation_center_shift(fzp_x=0.0, fzp_y=0.0, center_x=0.4, center_y=0.5)
|
||||
align._apply_rotation_center_shift(-0.4, 0.5)
|
||||
|
||||
assert align.scans.lamni_move_to_scan_center.call_count == 2
|
||||
for call in align.scans.lamni_move_to_scan_center.call_args_list:
|
||||
@@ -200,6 +212,44 @@ def test_apply_rotation_center_shift_math(bec_client_mock):
|
||||
assert call.kwargs["angle"] == 0.0
|
||||
|
||||
|
||||
def test_extended_calibration_accumulates_shift_across_iterations(bec_client_mock):
|
||||
"""Regression test: lamni_move_to_scan_center's shift_x/shift_y are
|
||||
absolute offsets from the (not-yet-updated) configured center, so each
|
||||
iteration in the extended path must pass the running total shift, not
|
||||
just the latest click's delta -- otherwise iteration N+1 partially
|
||||
undoes iteration N's correction instead of adding to it."""
|
||||
client = bec_client_mock
|
||||
align, dev_mock = _make_calibration_align(client)
|
||||
|
||||
# Two clicks of the rotation centre across two iterations, at different
|
||||
# (px) positions -- deltas of (-0.4, 0.5) then (-0.1, 0.2) mm to FZP (0,0).
|
||||
dev_mock.omny_xray_gui.xval_x_1.get.side_effect = [400.0, 100.0]
|
||||
dev_mock.omny_xray_gui.yval_y_1.get.side_effect = [-500.0, -200.0]
|
||||
|
||||
with mock.patch(f"{XRAY_EYE_ALIGN}.dev", dev_mock):
|
||||
with mock.patch(f"{XRAY_EYE_ALIGN}.umv"):
|
||||
with mock.patch(f"{XRAY_EYE_ALIGN}.time.sleep"):
|
||||
with mock.patch(f"{XRAY_EYE_ALIGN}.input", side_effect=["n", "y"]):
|
||||
align.find_rotation_center(sample_type="extended", apply=False)
|
||||
|
||||
calls = align.scans.lamni_move_to_scan_center.call_args_list
|
||||
# 2 calls per iteration (the function is called twice for settling)
|
||||
assert len(calls) == 4
|
||||
# iteration 1: cumulative == first delta (fzp=(0,0), center=(0.4,-0.5) mm
|
||||
# -> target_x = 0-0.4 = -0.4, target_y = -0.5-0 = -0.5)
|
||||
assert calls[0].kwargs["shift_x"] == pytest.approx(-0.4)
|
||||
assert calls[0].kwargs["shift_y"] == pytest.approx(-0.5)
|
||||
assert calls[1].kwargs["shift_x"] == pytest.approx(-0.4)
|
||||
assert calls[1].kwargs["shift_y"] == pytest.approx(-0.5)
|
||||
# iteration 2: cumulative == first delta + second delta, NOT just the
|
||||
# second delta on its own (second click center=(0.1,-0.2) mm ->
|
||||
# target_x=-0.1, target_y=-0.2; cumulative = (-0.5, -0.7))
|
||||
assert calls[2].kwargs["shift_x"] == pytest.approx(-0.5)
|
||||
assert calls[2].kwargs["shift_y"] == pytest.approx(-0.7)
|
||||
assert calls[3].kwargs["shift_x"] == pytest.approx(-0.5)
|
||||
assert calls[3].kwargs["shift_y"] == pytest.approx(-0.7)
|
||||
|
||||
|
||||
def test_ensure_at_configured_center_skips_when_already_there(bec_client_mock, capsys):
|
||||
client = bec_client_mock
|
||||
align, dev_mock = _make_calibration_align(client)
|
||||
|
||||
Reference in New Issue
Block a user